From fa19fe63c994486bfd34df941fabf1eeac5361ba Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 25 Jul 2024 16:40:04 +0800 Subject: [PATCH 001/336] fix(update): fix update to v1.3.6 --- internal/migrations/migrations.go | 1 + internal/migrations/v21.go | 32 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 internal/migrations/v21.go diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index 8a259684..463f68ed 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -96,6 +96,7 @@ var migrations = []Migration{ NewMigration("v1.2.1", "add password login control", addPasswordLoginControl, true), NewMigration("v1.2.5", "add notification plugin and theme config", addNotificationPluginAndThemeConfig, true), NewMigration("v1.3.0", "add review", addReview, false), + NewMigration("v1.3.6", "add hot score to question table", addQuestionHotScore, true), } func GetMigrations() []Migration { diff --git a/internal/migrations/v21.go b/internal/migrations/v21.go new file mode 100644 index 00000000..880852f8 --- /dev/null +++ b/internal/migrations/v21.go @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package migrations + +import ( + "context" + "xorm.io/xorm" +) + +func addQuestionHotScore(ctx context.Context, x *xorm.Engine) error { + type Question struct { + HotScore int `xorm:"not null default 0 INT(11) hot_score"` + } + return x.Context(ctx).Sync(new(Question)) +} From 46fba3e2bd7dd4269611a41bb5c542962c76ff7c Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 30 Jul 2024 10:47:12 +0800 Subject: [PATCH 002/336] docs(docs): remove the images about installation --- docs/img/install-database.png | Bin 13214 -> 0 bytes docs/img/install-site-info.png | Bin 43093 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/img/install-database.png delete mode 100644 docs/img/install-site-info.png diff --git a/docs/img/install-database.png b/docs/img/install-database.png deleted file mode 100644 index 09fbf36a18bb039cfaec997dd76fc6e4b9c12599..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13214 zcmcI~byOVBv+n`{0zpC`I0Sc>;O-D45M*(;#Vts%KycUK8c1LlSsa1|g1ZbJ90H4z z#RHG;@BZ`7d2-*CcTP>$r+d1qYO1DtS|(acLkSm~92*1z;i@RhYlA>&00@Md_7v^0 z1enm$dCXX7y?Lkb@bG{{B7dLUgZLlz4vxoWmS`DSr>3UJBHumM6c7?~@($wQ;U{`Y z?D^hbQ(Ld?d;8tp-=^jkYdgsO{r&Rt%7@_4`i3S2Wwo=jb4gi+qoX4`M>hdcnXK&G zx%q{)wY8bq*`1@i>)1WlMi1i8b0Thr)7Nh4g3`RF}$#-B(I>*FCcJv>$LHEe|tw~ zVOdRdY&*&PH;P5yX--q4(!|mVz56Bd!kE_~opd=M6wq7;7!3H$VW?;#@L!O;HU?EGPK>mecI;eE)1 zobCgo%)|2j*5Tnp$=8Rjf$61{hk@Y-9gBzOLJu>ubLrg`h@;c;;b!-$c(c+Fp=9f7 zVPPc@i04X0Ugn+e;=wcuE(nCvQ@Gl>cWvK=b}1bPB$Wtm+2e{B$|d|a!MH#%dk6Zb zJ;Gz2e&LMuMMbl^_S%+C6pTnB`2iVwL-IF8?enVj0?Maai`XxEb+W0S6usw`@IQZk z7ao6na1fWH^^}P6$8B4dL_z0mv8I1Y6k5$Rsp9TO_+dn_sC;&vC~dP#vWl z6;=Le2z%WuTm_T;=HLK?wrXyos;aBi;prqtvqWg?OhJ1D3cYc@l$C-pzqKht$W+x; z>hPve^4QX{6KttU=|wqN1gS*|Zp5B^J%R6F`8F ztPz<+!G-_A4Xj)>a;MY}C$<5Iin{PYwx3~@i>X0z55O#iz4A5=*KHeDntj@p>E9pAkl&li)PF}a8#cqUDwRy6dglV$V)1x& z&MQ8SU5qi4O&MKyly6IwP50B1V zM#v+@i|tMW;$}QNoGzngpmIgvNL%Siv>HAOv~R#T9wsbrD5q+E#iGtizQFlL_%|Za+|@-oqn%6UOo$W@q#mkx|fmJp^qoS z;n94YJ%fz+}?cOZo3f9qeK`tFPpJD$E%QuCWGDVB{~9?w12qAeUR# zd4SmR1hl6V9Qo6Q@-M5-(nr}b9b)e+^z*4 zkpM6RvE?wRZqEpo}@ z50ma`8Os?@W<~lQNm&Qi?|N)d#o&XC0VA#T324~V*a6z{^y?jYqRzF2!YkSyp_osi zP!D9pyLjPUDUa&Gi4)gj1fRS~+&g>dkLh9-kaC@A2=-$X(x_spYfP<=GaP{1lkXS! zVkMKyeGJ3*6$>93jD2DqS#)v-crV7^Gu(8AGJ6ZcK!Iv~q=Od_}O7KNy%b^11Ez zj+bu`MM>Yn-_g7*PeNTd1bN>0m@UO!vG(TSv@SRX} zsddvq$J&P@R(4-krcX%?bhd5+H~Vgu2{=u&J=tS74!x|C#(vScM(^7YZQ@W(#lfn* z#QcYX?KnG9f|e{dRE5VjoIwU*ac+Q*YbGIb1;u5V+%RK0G5V{eP)OQc>NVH+N%m7P zA{_csWH*v3iD1AG+T^!*6vfoBU^J;K_Eoe-if=H6WZQeXc!%77uWHB2$mq`E`x zLg$%XUITUQ@3$KaBE8$1LgBLXe&QW!uGznA31(UTO=N8W)eKSmOweyPpkOryPb7fj zLgn+)Y*^I_nxporSzT($MrjJa^I6f#Ur1t9QiH~TVJsW7r~qtqLz0PL$Uj|ykqJQ( zE0-;7jIQuSQF6-gJKiPAUN@Hmk`Oe*zd3k=S z#_&zL`;q7-#g99PH_YFwQuQHad+oc^TYm$oM_tNo@+jTQ;$em!xhnXa7Co&K=c$A zS?zU+oa)kg90>)(zdRO6&Agwsn{fEtjt5dJ-tTZ($-G6eIP9je#0g9%xQN(X#)^>s zORW|kcUp^MvQTf!uw|II7!w2%u$~V)a*Lj-xbRvLY20)ogYh>KCt7(BkBkawJpq%< zm4vPPo>Z*nt`-J2)tcP<^Ur^;1fI^w0iaJ|P!w!TFd7ja9D{|@8dpnrfV|KxNl<#7 z1`_f^=6|X%=6bOwjqy0?G*9Y8N_2QAL*^&Red;5qU=~XMZ7^@X!D<@gBPgnP*WNOe z+l?VsVR8pU$x&M2o7bGV!EM5NJ9Q8b4?IHjKS!N|{v&^h*Fa5y2~q?8;%Jn=MfB_f zHP5b*r}H7fkCWA#Hy&m=$TwB16mFlJAbk3^ftouuXn0;(gMlUhy`OVew=G|W&EFAZ zAR3-e%T5a$B6)t+4b^qfAPqUvfx=v4$2H{N1YM^zT_CXu9G(v$ByHgw5=XhAo6KgO7I!aG_^<3__1Z-5R8s4yNc%!=s=?JY z>VIBz>I7X@-3P;|?b=MPHsuHP|7j=;h9u+oKTFa{OhyWR80s)sinPF~c*yg9BJ0ok zyg2DqIF#9fRBq?7&$AH^$~_tZl1mlrSSZa4%@}ZT>g1G-Zke<0_Fj>{92s78=eFZk zn)DE8{m|ALlCigZp;*-(e0kzy<=qhsJgYK#@*;F$@N-yM^x#sMv7wWRzGUlBtH+_k zoC#=ZA#?ba-hOc;!&YrUoirl2Cq?ih1Da^IJDV8qQ>XdE{5|Mu8B6?b;pp7g`OFDP zPHn$wmOw#;?H;dAX#YU`7gp78r1fVMs-Irf3^Ibo2f?7>t;{!3DOBM*Gn}e=5;#34 z4!-a{BC<%guCmPpXq&CS=wQSv*!cM(M=4Z2G4InmyPitqJ@{C0Z_7!Vc2rQs+L$6R9`)Oo7$RSEEcp7y;(eNIp20b(#qG7ho0 z5)c4qdIzQV^kA__>1M#70i!Ivh4RY8pIMQgY6+20sWCp3IxxQ{Ywa26~%U!}< zYAL|XH1YFWY)M2pyevx9t#ziK;EGkCE7dYZno*@eQJkJk+96RHc--qHwn9Ci-Ik$K zR&90lvQJrUZWP z@N{&Aed$zxr)T!wW<`P?{K>A|`!3tKfMWD$A47e451s`5BE_ZHYdHu(F8w>z2@* zw31!1U`4@mf6Z5 z0O=`M9~4!aeHT$ojXC9H2T0gC*+ioHJ#$LF7AOtOYhV_?`LuJaLia+0gQ53`!wZaFBClIub7=pFc&=epQ)zGis~u;?~IU2P<-mpYP!kOs}fA zOB-lg03{GK%dx}>Q5yDli4iT7=3n760xwA)lYJ6X9wQ!Pu+0W1zS)CH&GdPU@|@q8 zCMRk!U0i77V%i3(c(Cu#cse0R{S{UuOWqtEnsoErkwrkuFX^3@2f%55!>`zU=uI-M zXZIvZ>R(|@nW=Q3CA~;h2SpQk1MX9LMQyLIsppqzv(kq@B&0C=ngh*6=EJkk{=)O= z$p$=Fx8fCPcLrV1HIuue!GUAt%Q#x&+wNBOe`z+)Dd5-S&_ur}nfpvJt za0@%Ci1lg0v73neAC`wMgt+JKMhb!+()ltTM;Bf;k1_u#A3inis+G(BGWbv@i^Df^ zqA|vw5zU#axTiB)CQ_j>0Dmn`Jfv_F*0V{(@7z@K9YXCrSBO6FJk2Re`wtCP&&eLE z-QR%mi(N`D-1>Skpi6~bSo1$|Xbyd?K4uM(fx{gjRvA7)657zwD zra8XH+=vzh31ai)+D{Uf8Qx3#x+ug(4edwlhziH64#c7^FwOIFjh(Y3AMRpxSRDj^ z|G?!OjzZdBfOkohU@k#uHQT82m8tQ5pFxr3?bq3Gwt76rT7qCL(I{t`QmW3?Ic>nnL*#T*uWdLjDgOgku2BkdIw)$H{B)=_ zpjvwcp=fY=Y2dwW(%p^p89fSl z`P&W%%vUrI#l4`oI!czX-}sYU=hkj$_VAQo`X>`&)TT9K+Tj>!N+9^nr1iyM@}Flw zu34U-ZGL=p_pHjV$f!NbR3z`KENaAp@yDjhjTT=xyZkimD;l@u_;DI;eMXV3 z%e@+(Pb=ac2$)4qSzFrMv!DqNGh~|SuQGp6Z&UWVHi?uXOY!b5WA9927c8KnP^vRc z$wI*KT(i`9Ny!^mc>nH)$Y+^(oCnA?j)XwfSFaQa@=eYpWR+c-GLRfu5xYsH7o!YQ zcNrANZx*oLzZCVQJ^Umgoj}ve6ks?cs>b(hm9GUYndO-yo@snb_jZ;6S=>Xfw$!iZU zQ@)@RRcQaj-olnCw)J)kZ*87rX+bPC^*V^i*@J}B%m{(v6rH)4^|o#-T#A-ij#;HL z2sY9!_?ag4+cATk%aA{TU=IWTb6y=|_z^=(e3zn|W4$!om9)w;rH%H#9Nw<&_`$Zwy0Ov;kIv$$^Um_u}1&-O%etTE-^yvTtj z?^(&AOWGBvzp%GnsR0Jam5|KMuT#JCl#lZBs(pYfx+=BzaO?vZ^Al*A`J;HD-e)3? zx#zPq5MjAg=pe!m!mAz!$B0=<-`q{F6?^J;rr7_q`w8k(RT2hJrpjRebr4&gz;|yO0c}8Mwj71~Lq%B;+@-B*-FY^E zf*sMQ=Y1(CE^t}V5TAi;n48U9FvDK{lb2~arNiq=LfkV8^HFatHRfVun2lKuw9@zX!b!7RF;=SWxz# zx@M05IO+O*?>2{<)?MH*@=LzGG^vCFQkZFC?Va^>@43ozg8Y33uXCUX(xmbClf?ON zt7&L0>Gr|ErFT{jNoQhaQyhQXA>~+hZC($UztK||5n`A{8rwWzv%)K?aue(nda+O1 zSL{#;E{|h8pC#E%y2lQQ{4-8T8bmw^>JkdXv6`%(g}&M?aQEb2&;Xe3s-h)9 zEbaiu;*SACH39o}Qnwe1K!E%<)K4K-Ft*XzE|2D$UKEwI<7y-{ku|E$mViVNP+bMB zc>r+)hi`yCx}aj2XJ2gF#l)Ezokv3wY`|aEoMw%dv&+iv(aa8B?)oGIsfez$ZsJdS z?0SoN+5z|+m6QXbR&%>m3ULaGzTj!e5K_N{H!S1R3^E9GyVfR)m(+wZVtehW4 z`pF3$~P#MMI? zCmF_{7*@i;Knrm_7cVich3#K*o-IZ+KXvh?2M&-xRN2obG%-IdZ!X>_tx_Z3DBGl* zf#56iTSOt7oJ1jCFIU@zLfBMZgLtWtTqwCzE-Bv2w*xk=0>q9&R>{w80XdMnZWBw= zJK~VdVCzN~jJ-d(rR?0t+u5Wlns3Y-Dc>o#n${a2KzT7iJ&m0zfOjCK*6WZ|IZF=g zA0s!G$!4qGiOSa~BX{8H92wQr6c7y>ce9Hp(lxN=iqls$X0uhKL4%{Qcd1K;261P^ z87PJT_9=oftDq{lO+3pEjQ|l}#Gfu=aiZ_AQ42-2t^Bnh}>ljUp;N zLz_<-_FPqQN#QwVtB9BP-fuJe<9y1NX$tMgzOY?>^dP^ij;-w@OU53KIxZB>PY2R$ zx!%hdcS`LMwl{WI$NgsjSg!l;hPP&vL}n>@@jKA-gx4t6ZtEN^OGDhB_C36rJx zQPEbE0CGr=KH2u%^|gP$^?DpqJaV~-tdm!(;Yr_nDOt`_Bk^ZD^Xbr5^B|S z5?Xfa#&ife`i<}@>%dKjD@UMX7Mi3`D%zkUf>n?zp$2FKUAmsX@ZvSq3?-q;+KVJA}ytq+~{`2 z%vahby~DipL)yLWBFYQWE2Kj3Q`nLglipRB!?{8bksTX9lpIQMXX;YMUUf@14cvh2 zDOD>vYFwA~ESJ3jVIdxj*fSy&=1Vv#lZg)h*kyn_#af7tFZ!DA_ymf5uJaFJ1ZT*v zO-p-P!gli-UZOy$?Op(MutIBt6&P zC_FEDmmzNV&E}PiEkxw2?S>-id3yrR|KpAS zyVtp^O&f2#n*Dl;B<4yuVypWTch;Lv5X2tv?VpPe?DgNYTkeUSZ-h4 z)c9gk>bl@$Hb@c{wV(RMY1!7P{sxxKl+ik@tB|&nIgHIJg~-qRqnV+1a}DQU=e5%I z1&RLmR{YDnE34f*aH`6NFka^o`+`Afa+2e-C2MaIv>(J(4zD<8FsUhWbG7yQzOAW%{&MM?@MP7;<7VD`#5tkgp>`3wy83hwa~hDFOI1`PBdy6-#(UfRDpuxTMr zxeorg+RiXkH5*tI#oZ(05QrW(NP}ze=RGN!%3>Ii8|^ck3%48Ab(9*@m86jee6lsw zG!UHV)JB*E#<}J$1*7<)9TudXZ?a?rA?c!k`EsWVOS2q8?8kDGMs6RCJ8h^pMa^h0 z07wotx%c3Z0LWpce>sOEesj6m$=L`!a-jutEr%+_Pl^sk-;oAzo#fr)!bn2wj$sX! znSd3DlQ#I4vP(ex+~uDN8GuwscW1FTVbpXd49U#HP-ctr-gt)QWyS5$eQR=R5Lv@fr!mkO$b*5#K%3Ybz3iHf9Y1|i?qPAk3SS4 z0n{VWaG42o?NDLck2`J?EJ@ZDpHrVyjgHt#4_ZAJmREQ`&oY&5$P-jB<}^m|MAuRn zs}ASmYb@;P?i#YB1zp&=WbPzJX9`&d=Y3%VVKZx!20{Ngii5NfSsKk}`ZuDz`#UzccS*4>;A2p{|(`2^#WBpm+iq&PpZN&h=bb zSxsoz95gVGpLIjMugpED=p0e}ESV4;{%0Rdxw>-SIIPTSjhEbSsB+@y(8Q7q3s#8D5+Qs;)%Kzc0u$B zBJr-AQ_=1j!xffY)aJ6N%^kOTJ)K=feAhP$4l6FNl@hAL78?QAQClCF0eBe9>`@rZ z9ha@+ml&hV7@9i&1u3!iMaA3C5*4W-cXbP0sQ^BiH7 z-#mF}4R5oWF+ZuXs}42%!1^qoO7#YfCCL&l2f;V;8Ys*|)iSjE=gAzLvu5~`OboAM zD%Q-^MZYjGdev}b;wr?qvR z6Q+*yz($8hrWFwtMgIA83E5$jtwk3}sa=e$E?)o?J>y_&#p$tv`YNmPb*0=zQ93h8eLu$qpqt>N6# zZ&rMRD(zpp4qF%+Nv9H#P{4*uebH5k+-E4`0LH>ELmj+qh8~?l`sptoR1jx7uWl&a z8Xy>-YS9f|BP3^Ats(*DuB67NN5^(MgqCD^A`FjOMmEr-wK-!e8P`5x9!(M{51zOU zJa$yOwKSsCcz}$4IqBb?r}~cZ9%H)c=7+{#fjbRN z|2jO^-crJ73MCg?o9Ok;`Z3BEJn{$`J`vMu4)M3dq2c8EW){eG5r*mDo8DZe7bS;P z#A@DF*+D6c2@QaM{`wnVf)|f|iviM+&(oevoJAk7rak(QIj&;6s3FKsXI9yGuA*De zIAG>>wt@dzn_T)bISO0o>2&sA+0G&7@T-?bI0qtYiYrUAoQUxi9$x+&l%9qiU)+wq zUav|ny*pz&&3!vn_Z4EfE2@IxqoL2mSHYRQ;ENhjK>&~&qePe+I#|dZt?$i)dLS4yg@DAuvxaW8m+3( zx?RD|I@G;;m%de$e%BZ5sMG82$zmAnLL5$opJEJlbe58KN3g=2iztK~q}>VZ1gS&t zEi-uSwej$~^@FdUWC|y_npnLD(sa3=WsgI%{KOvLp?Bb>3-TPs2iFR`XT$Y`6TNwy zuxAqm-|-8Z$(-t|0+I}*ST_blp2GsIO5$Sto~m*u-kkp2!Ai8Sf&bZ5;SRH7T>kL! zrOBKIYL!pCyS4+|`sMS$lkPZk^XtIN*Frr2R#hQO6}fS zPa4C_&<+Q`RvoX#cKm(x#WF45w{#;2-GJMh!f$^M-VJtD`RvQ;0HQ?9Mkn5zjQX!n z5%H>vc*7$o?7peo%*vhqCfMEH_LAmkQb?L|x?tiZ#ZQMs%~hd3x3MX5DnmI$mQ@{1l;L47w1xE`#0r2uIb_?7utEm zk7lwn(h3;e;IB5^m*O=Uu1I+e~;R^so?OUccY- z!Nys^@nEh?K`k}LZ+H<;#kt&R&0_c$1Jw>UWVjM!TyJ~+xdF_z#0tU}ZAuxi&(6nJshz>-93bx+bZtDzNhu4)o z;)*Ikm?5NjufOVVTRlOaJLN;#ZbaCzmm6JC*e5)61x(g-=|Xp$y{#jy8aWK1wkT@6 z*EAB8*|O_NP{xtBJ#l*k8>k!<^@ z##t68en|0B%6D$az#~{+&?%|uhek(~S11+@{lmX177aXdrFe`wCPyn^Bs&UBxTmP_ z0~-B8{@+Q9WdP>Pxz15xJ}&4`_lJ*QaQm<;4MXOeeI zEzSWI(-H%s9ZP(;bs9xEnpIDJZBP7pYuuI5sGwC3kERoh1Q%F#^9rt-&AKy#;B+s_Jq+yi=X!>uS{g;<11+Hni=Z4CY6m z*#1@B5|s7aSd8yUkHFI62J1V~=-jd+te({*q*a5~&PUU#BITAVm|Sga`*MrOmTeSz z14BX>`7l@gdA`~a>xHGB-{1$lKc3Pf>T|!t)QsrjN9RhL`l%hGLsj}zR$7c$Y@sD~ zzMEL6jmVv!2AAv&tyV8gm0UULdscW9`QGa6R!1&F-@ZD{7WLV!lPX`3hzR#(el0u$ zdpTDfpa@A#&woe8avLai%@z{#iGBSvDt46YuHUwE1$`E^b*f^?Whb&?xbOrVAW||p z-s*AzU)eCaA3yfT6^6Tqu~WO(iiAb}r50AvJGrbJm*nnFH_$VA5})eLj>VwLgkVS- z^k?g~1QSaP64xa>9^YHHf7UbkcK`@416jWT@FE0mVmC4MsFk9XjGe~T zXqg>mQ9o!HUh*E~?NhUO0ZfbWG!UFhWlb#U;vVRxyRF10sM%qKq@4NW!zM%KEl4w= z1bGF1?-(+DkO*WIAJ-dt?%;FXe^+vnr&*#QWzmheK>jr=98#Z*I zDs~)OtDtdOcOb;+H@WD{4++KrYPI+H&ys5>G${(8hviV6^6*d5;!o2vNDZY0Q3v zA*j4&_o*H?fv?=Ca@euN_h9=Jq(<-63W%i%Z8?=>01uJx5EDG6*@ZPi_5Nb!<}2Ct zr{MnSDSy0daRj*=t0KF@&e$yEkFc1Z)LBHc%g5Q1C5rxHXi2*xaSnZ@?_!K2-XGzt zk)O_+G~9{5x6V1$b^wA`)mGPPr0r_(USqng(I9cnnV6p-Ok*&Hl0oErlAz1$ZR;)6}QTkbM@=uyIvFhUx>|eq6 zOxIRjK!Sqr8O1+&KE7uU^R-s=;T9~|AA=Q91fOeTp*J%}V(Wf1qVWhOl6G`ht6l10 z6tc!8Jaleve`N8$^bm3Y&+Me0m@06xUS7SR2ai}t_yz1K4U+Fr1Q^-8VuTo2I_*|A zwcH?<71N>XQiJ3h1OEjw{*0^(;Xe7!f#^Rp?aDC`du>7bw3x=9;_o~SdP2BC_{X2$ zwA(@|f24mUL+%k%a^xE9AbA#+yL2GhKwSdH8V25|3OMrO5%?%*16+aRA?v0o%r?#@ zb2A{E*CzWJ=?!XjXgu?*euhA!%BejF!#}(pYzh!hS>kr_tSVp+k1W1cQ4==9=IL6p zO0EaH06QiijD42{aE{+dB?zZxZ2h9z78FAZDWrsB4E-P2-C{W!+2ihDh|E23c{N1) cpZXUOt4XkddA&E}UuQ-t3L5fNvgRNE2XLVHF8}}l diff --git a/docs/img/install-site-info.png b/docs/img/install-site-info.png deleted file mode 100644 index b8166caf426bca8f51a475b8c23da10617761ed1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43093 zcmce-1yG#NvnaZF2o?w$+zAc|Zo!=pH0VNbcV7q+T!On3f@^SDEVu;-5^RwLf-dZ0 zi(dY}^QvCeIq$u5?tSOps;|H4`o6B7neLhHneLfrO$|l7=dYdv002B?B{?ks01XTP zU@kmEd-_r=l~V!$poVIy>Bv7mK3-g0{5^e``n^KW{F)+CXLfeh(JKh>=5hZB_C)OB z8*+dD@K#v-^78WT?tW!;jg$8+5{bOIx!u^@+CMm)n*Hq&@MUvrySA?WOGMPw)%DTw zao^yGww~ed`Nj8IdR<-Mn7D-brRCZA#naO>Nf`xCAOG*w4Zguqf#LD7DcOnXc^1}o ztLqzkdw)-0r{QsFBO{}&ZS6k?hk&1~s%vWHmDNs8PQqf6MI_!qp}U#+rI9gl0b#Lc zXYlmg5*c~r)bz~r^YgOuiog5&)4ygMoL$?xdWS|QyZZ*~n%Z`D_kJ`rFE0I2R?~#T z5%mo}`uYZ(Ts=GkBl1fs$ERl8y?pcxjB6TO!9BhHfx&AK$mHZyaOjuZ{6Ylcys5oA zJ2yW%G1JA}du)871Ki)(+Nq|g{m}^M`$Qd;SYFdOGBMrwqbVypx3scu;@8~b@@i2@ z>9^9d!tYh_Uz7R<1~W3VXJ%(j%q*(vn?avL3{A{dH?}IOs%`9@TRMAEvI?zi9de4w zl2g)faq&i`SBObS6OvLOkd1<(;tlBE>EA2UbMp<&9jRGGdk4qcP-s*_dPirMouf;0 zOB-bS@AC4>8zHgc@|vF`<6HX|6}8PfN4I;hyMx1{!;>>FU(nU{6heCT_ia&W+OUex!#M-#Re>Y3WR3rADEY1DJJhGqP51Zl&>Q`xk1Nnz6}U7@ z)^Z;HpQ1}u7U^G#dE>UlPiIel6@Gyxt}uT{(flUufw1Q8n^ci0GJJ)L##;1xSo735 z2t!I1SS@;WAYnK{f%^6IZfIa&lk@Y`)F-fG=CVTy9)Rs8MRXKrzctL=?dz z=!j-n6Hmq$6lP#=-WRhY=FKLnT%xAB-l;^co=7$o|Lewe+fKin^mj+> z8Pes4Y#2_$A6R9NLvQLnd{2xE&k(5)eCwv@htY+D+zo39LoWB?#a5d!#q{WX=NWru z0AvUw_56c1Lo)nKM_!~)OC43{V|EmgqV45LEX&%Q>2K`TG*-ghPW6dJ%)k$0A0Gy2 z-hKe<8W6@ZCMSC3VFoqzyAf}6ql1?^!!p?Vc@wtpHX`>hiP+P*Fj}?SGCO}Npm*$) z>eYnJv~+xt_9_qi)WL+kS=1G+9FTHC9oj2Z_?dGzaBpodFK?7Yv`bsOKzq64aHkV7 zHG!yI$b+$xX%vUH~Fg^&?|4qe0?*)%CRLh@g{P~=M|-r&i<-QG57H2 z%uEkX?mok^Qe;FK5_9o;L--Ph2sX*R4i{bwBl()P;mp|OS!50P*8UZMC89-UV%G1A z+{)8b%g}&bT@>h)^={L};C-h?B_ahSjr3Eh&#P(u%Y3V1Y4tchVFF^{gIn`{(v-eUSD0V5) z%s=x9TrPUH3f4}(+whHhn)YX3Lf)Lr96%Jez6W^yWP(I!_&fk-#%-u0>41%H0734gO0`=2~03&hCieOjAoisyzKKWG#Pp-^!3t+@|Nc0|CKg53@`0CSS|m+Ioga zgB>)VG;i)?rQucfx`FwI+iluN3V5WYQ!7;Gz1jKKgt~KLiC+*J4Bq9*fbkZHTbfAC zmGQoX1Y4T%8@_DP+Zaj5;7f&tN4=gIJL8H1x>N2`S`Z}9R1O2`_j&J_-6E0a5b=! zqV2Y4Iz%*{Jx(IO2*VaEUyO|KocLiJ%Eu0z3FOm{{fnFr*R?ou)3RwoFNCf$E}zg2 z*=yZ+CcFe>yCm6y>5tDi9hBmx^gV|KX>Y4c9O4@=JCbmDuE=xx?G6SncbYxy{>2s3 zGe_^y&(L3N#t%UROx(nGgV#;=TN14hUI9|~=irC}8 zXM7bOs^YSI{41(*qzp+Ky-TTSfJv;aQgPo_f;jHt7o@wiOHFE< zTC#tyz?|}JJSDC>g5Ib2@O0JW@8BiMzx8ddxH-fe=j|&K@)CHrTFLBS@B3Fmi62|O zD%F(t@Oh6d@#l)YEna!y;m&3Jk8pFj3^RC-iazhyd4i`iU)#Ic0{iF((W`}si5wyq zs`e*Zol$@NGf(BxD>_HmW^OPobin1mZcwU3m8-D#th{p%QLs#9e%tC=o9VRv4a|)E zr<=TQngo+BG8HUUDDz+}FPo!rd}zC_PscIzL*FQuVU?-b5N&z<{JFKd6S;C2{~Jr+ z{vRpMrF%IHscUH{EADlAju~T-XO<#Jr&vXQoc_)lfA~Q1kE(es%^C&aQi^-Ac~K&y z>Abx1Hds@*d9SZ)d54`z`2L~MOt2G3vXS>*%4Y?xe$Bkq*ZPTPc<(2yN?1dwRQ0Ar z9AEaI{-;V9&W(65g{AC`k&)?VF0_dgKu~H9U*I&3Xatp<~%^lak>v@<|2^Sr~*y2Ff=9A*q7Y-c-S;<8BabAvvH+RphtC&}Htm7*|`Tr#|u zT+AgOhIB59n07Ya+?5Mp=xS!yX+3gI>fc)z;43}3YykTG=e2})QX}c$`cfXpeH^2k z{{K#NsFpfM@P)iIu?g!->>q`w#P=UDguPk5JlB+e{(11Ex1QhEXCs$}`zsb&GZg2) z`3ai#nYbV_!^-eVkb;Wkqj;ZF!FB`G;Wt6KWE+q?T1Xw!;uSn^^xgx-8{zhTR}5*I z;%694ooDU7mJd?`lbYGQp~yi5?w(xspJ-f(x9*A&edeL+Rpb}k75l;6i&C9Mi7@dn z3Px+QTFZnnTcF^ZK^yrXKMm3FH*+1Qd{FSE!J4Z7zn{a%yj!H*tGI392La@lxiL1% z=r}7iqT%Q`Gjr=NnYw0Ve~1Yfc_a7|pJ7SZS`uM1MTGe?+6%ve(Wu>_-Ahg{H|H67 z$&J{9>(C5}RuELaUn3tfp&W9S%3v9}^#6b?2<+W%xTZePrd06}6%!DS`E2$5GPdH> z$bV(_P*~*(K9#T_{^8dlxzDMol>8zvN(ua?I4#gWwpw^p|F|H>xq2q8jZy= z>~seD2h+Fk_=3z+omOSBFn)!=%8+=?D3OgD#2SDj>BVOrBIM9_!X||=rjO~V`pn*E zb?_Q#KK?&^9fot_hxTzzU(K|cT*+r z&T5Ca*2h8up&r`(we>2nGC4E!ecVzT%A#6+69%sXl}eVQF*a8gCDhls zU)S_Q$iN=q%y*agq|-?T0qF^9OUi_aXV}tc1w2`1ti;6WE`z~kAF(H|ywIFnI-xnX zy~9hF@H`nh$XC~_A62$1v@AQ97T3hXGKl*Ql!Bv}4A{5mmK>&^8+)B7dBecH&QCID z_RmL!%HaXv*XYbE$o>qMUwfZi6^@8ehRu;IjnCNPS`Y$gXgGY=NYMspklrT~M9s(a z+7dg11uTZ_kVY?7zbcf{%Sh1pxX1Rbrgao4mjjk#Hqddp8!&z?oYh1lJNh#axeGq- zqH)<1d$eEk9uUwjIN_Am9^Z3fD;rPqaG;4XG&4$HzfDxkzSwh+^=lF2hclyDjg9KR zR&#RBmkyAX!3BX|PH*r+1g;ds5Xa(h(6b$^*HVQ#G6)k^()ZG53F5FsJ&ZR9sMUr1 z&Y{E{hePy7NvuJtGX?#*Y_y0aV(vn5Y4P!pTYFAcTZI) z_Vjh#zofMLIREg>n=~CJY$v2v@2Lo8)a0D~^v1007_>K108@)g6??Eb3SHa8a)?*3 zunTR%kvLvQ<_A-7d@IGP&p4qAXZ>~@9LP$KDFsPDlVa<_9`(`jvPGW~P3woNYmSpH z*(-v*H>ePtsgWAsVd4>=+@`Ka`GQa`O-KHB1e*fW%*t}6z=wS<1h-pvYFz13 zkh|q8I7rZjK^$Vvo3e~szcNMVGit5`4wYvCav=}Mmp@E{3buX7=rf$Y>>8ox(CuQH#;^VDNg~0#U29!Y9ebV6((e_K&KNvjd3%%Z_imp#MjNtkBDJ{dSL?zkn2<5fPl|g} zZ(^Slo_r?(k)3^R77P7I_3D*qk0-dbSLI6CjeX+7BXarS9_R@bTTOC#UQK#k9oqV@ zYMvu&8C~IC*OZxA&!7Rjw;XndQ0J6%q4}XwL|!m_>9I({CS$~B*k@X2?G(O-Rpklo zd~TK1*qyF3p?0=UMAI6 z^K~}Y#SW?V zGybf^7w8I}V4_BDEgA4P(wW#JW#W|D{|vAr8Gy`IOo?p3)eqlXYvF@ce85y{Et)&mJl6spWvVH{yPtAzC)zPuz>44Pex)F)}!7B>qsJ;)`JZ_{lZ`|3Th)%}cc^D03uTlngcYXy8WJ#5ul zSrr`DAUu`9cR4Ico%pZS+_Rg<4(gB~P2kepe~7-&U+xE^KheDV^|*Na>^$s$Vx^~g zv^MGRQkrV$tl)a%bfW0?NCdf%781Y03#3+w9oaa7hH#C2n`-j`FL>>$p3}meP}weG-7Qdi zyRIKtfZ}Fgxkq}4$cC~?)9*KCHwAF{JS35cFIWVidlrxOQI~?JbDTlDRt%4--Tuh! za5DU&;V&qUat*o5pSC-^(&Ecs>kxY^Sxa;H{$>%TEA?kqum$|9x>F`q#|tdIe$ z1B3*ZyP`xL(I>vN3dCAoyEQ?sdz`-%&#enYpVsBk!Wn^5v&mAl>wFR9%%6Ap<-HKj zmbEpa|GXE+NK|g`_EkvQ0|Y^BigqfR3;X>7l@{|JbhX(~o3?>)?`{a~1;1d{;zW|7 zq*^n;C!q-ZUn6^qS`3GP-1rn)48Y3@2qNuO@cSYVf#J(Nh<*WzFdVL{f^*9ZNVoUz z>A-o^UEv0>b&3CR1*{SlGsQ4NB-iG5EriI%gu1-a@-e^PhAnfLAQKFFRazJ!x>%Wb z{y{|0&a&Eys^iEb3xM`P2cYovSR95Lyo=>uEg8$gnEqLEUI3@Y%#EWdweO9s1zmjC zZ(xLYcAGYo?z{=Eo>~O@Q1@2&@L&n+ERqz`FY^ITfFBqJQ|fTz7*5|(=hbENEjNfs zTnB(fjU2I%5rDr4xJlwh?QO9HI-DWUKcWmUf%5@%FsW{#r^Q@)rHeKT_WYE2+ipkf zS01b|TP#p2w@yNE!`Em--k`}y6aoWCT8U$r=|>T<)q$6*YKrZJ5&%yQ%Wh(AJUi-HFegk0-j(LCV>-0}cVei^k$wZ;z zv}rK>U#YgDz~el$rzwS;LSu}bO+L(mkphgOlDQHgAJ!aR(OUp zE7GPfojPs6Zvg4xY=5>!e8_v-t`7h$VsI1epe+&fQ;T zYMNcix)C*K2Bi_D%9L26kdypt903hz`gnBrC$6&ffg1Yj-ii!}`Pv)g_ub7Z;ci5? zflT3$I;YBaUwGR5jJKH0vG!;&URUECXy@p)VQ$!K?AHLJ+4Oug)BO*DSSp(dAA94X z)X-X2I9lXao~S$7xL!L=~8Mh=YDj3?e1;T@RM8423s^L zmszo~h=(&^yV}!X{CpR+*^q(3Ny97d{ETTs8lPN$w9)yKu-QeSx&BxC%Z^C(JG53r z4pLog#f_2~bLbw7k6wD;#MG5XVSDPN^7_As;R1S3yitoYp-KikRcheZH0~yor z>!u3enu=7@D|RpGcAd%#B6wg87O<52#OmOJ8G7q*kib^T{a52)QFY|%y@Ze6!Ipc4 z6c0T_|MdqIlaB}U%+Q=!P+G?eqvYKx9T_{Y3Um4s^69^h+|Dm|$W`!^AWhSeGw{_B z89mTG->UkDgIEv@NwX!4L-fJbwGmD+O*Jyo+WIGKQ=|FjGp5R{T%X&`x82`v`0^Dn zA&8`z=0P{w$f(T`S}c5WlJI~cxzf8(yK>?C_XX%1|B&J@qDAjhZ@`G1mfy(39=H<< zd5Vh@jv1&Kv4pYe!}9mO4_P=m^*FY;zX(dZ=o#@bvacl^6*}3)9c^s}sO7w`s(LA$ zq=^9ing6%{bX-L?k7+IoA=pbvE)F=W24{JwDZpf&*zCIJcRX+_9hq@K2uKpb972W! z_2|U+`x1U1$VDJYVaFwkgI7cyoj&KbE+566kRXM)bP!lKt`sE6m4BI&Hs%*#X@9vl zP*R=STZkSJLh|_9Q(0dU7^<~iyBw_qKGC!Q|5z0B){9^unAcr3a3q`_8krjT_HnaZ z3wy)|HRz=S3RQ|r6^_-}jxl*srL^#bs2Ob|o-y(ZU&>1hxa3fS{&+O?D8ONBAJe+q zHfX>XOsHW6L$QPcT7JH=cR+N|Mq(KBva5LZ?{*&dyWIeh_;sJ!c20|CjeIe0ts1}B z6slJim#CN^K{f|<)>8cyqxuU)bl?JY9R?|sRhw)HfobfzN4oHxYKd%g;EQ@R%A>@~ znJye+_7#lYV}deF$rJIZ>;ksyG4W;4GB$9%h15%IMe<*8fY$QE~^bCN)DDVH?ELK@< zMCfp3>dkWBvFXkMocad6Ouxz1x1&1#sgULCz*ie98+4cfl|VXTG`=A5#p+iLGhj5X z+Li9zr$5DYT&MrsZcJON^3uGi{H;5!@4snWsg^ZJ2h3`)nJ(c?B25~lo785ThabPR z!1BKr%ZqAgZxd$Xe-_Iyi{H(=M+;eN@(H2xwtld~Y@Z_O=k7 z@Oe{CVyqoC%Gva+=UOU(z2BoJQ##3LV@W4O;xjvs-tGjmrfuwat6TrBgL8lWWa~PS zaNiGS>__a6MDNLdk^a+@*75N8jo)WVj$n7d&cYd{oHGR5 zolT(Dd}{l@YFP{rBWYR$j$e@y-^sdv?at=fm0g4}d(HK^6*W9dKkzNDg6E zh*!l4o4H{GvK;vlGIlTVN)4Y4#zaEBmAu92H0Cwwzg)#|2=-Lk>MD zc?{px8KF*V{&rf(TBm}epe{~25=u3)0+OiGOwV;-NaxP*w`oAWlJ)4s?`>Lyu{e%q zi9or3aB`fE0=*SbsTmn5y(>Rh14Jp|@mb~5LIJd^l+s|u;M=p&nxw577NlU@0f&$d z5!@uqv>jVQs{qDE+$F?ZA&MnRdm9|>Xbjf7xslk&`n)5~bvy5sG|UUZ%6SMs%=|4^ zb`v{zNObTeB?4r@;s_q1BzyiDiOhfZnlV58J2Lx2X>yv2H!9rXlsEawragFlOsU*E zeTTaCj!zQE(M?dLr5nnec}DPahsN0DmcDI&dZ!b$i_8I6uLS8Fy%gOBisx4-DELds zXPpgoP)t+N0lPoD>N{>kM$mTeWN)Z7lzbxDkah$cRfXkza+DqoLc`6!!P=5J&A9JP zCC^%uDPrdLq7+W)W#WA~*~)bGQV>{TiJ-=08T4@KQU>#ts4&w(t}d%2l3`-vd6&Al z1`VVkYR2HsjqHzb?g{k!Kb$gE&l|weL+L;uF}tN)ZxaHlN}KV#uAjAkJn+mHFs(0WA-hCu2;)EyC}_xiA)g zt}N>MkW-PaET*F0*ieaga&7Tx7ahGM15Vre(wypu`_OQq4Q68RhX`O>eczmjlMqy{ z)o|{WgBI~OgQzo8N6JmFE35KdUOM$Af-0^SGYm`HkAC&f(f%Of>C{|b&ll^V=evo7 zDX?aD+85{cg%4QhTy9en645Z|~&-3q2NY0U~5s6^s02&;)#1AaqioJF^ zNP3G+X0ufb26D*iuD?28zj~xK9)!WWnO4H}NErio zcq0_YYLsj&nJ1O`zwiV8@3!`d|LKW}|C@mMa=(DNh&N&Dnqtb=#gHAHtcxAWf`KIH z>uVIOF@7HZjQ&~Vs?0Z6+vh-4Sy+AKVKY@IQD@(PM8VD#<hEyyktu_@+z;qB#8cv> zrWQ{pELXI_L@pnoISdB!e1;9He$LR)8FEX0VOd5i9VhMf<3tNtQIDPjD#;zeMl-tYp1F^g`Rg*`o#s0eVDM7VF zNxN#@FI*vG7$Q4=zq4D!H-FD}A+?UlhzXg1`qG0QX&oz1W;nQIKjw(%x;PC}?e(l2 z2DyY(!_zEdnIJ(}X4`X`+=(u{lb(3?$g*V)iQNE{6Pz86QBq~F_x7pnjm3=%G9ftU zLa&0w_%ao?iqBgY#;Dw83vZUmVlCT01&wQ79%~TXX@i?*!_3JF!Nnlv%_kwG08M;O z9YN0~eJFw~X>~(nzGkqD`wI!O5P4yN48&XvlgH zcJ}jKqlSbO4RCw|R%dS)oFrNlIF8C_juh3bZ6e`FQ$8e*;0Q=}FCt&+SVn=5=@aq9 zfN-?6??c}2gFb=->YX;T>s_YTQRd%)@878+Rkq}lU~ESi&YJmHh#KEm(zjfz^ru7l zZ-Zs%fVbGI>_FuXHaIm(<-#TD(#1|EZbA1Tp{q^)(a)dqL!!_g#dp81Sd0KY`uT{ha3re?ed)goLP`iG))d#4YXg4C!kv@-!!|g9{B=lOwtUa zi|IrAnS7tYVcY1IBz$W_B?$ROpqg%k^x6S9V361Z^GqL?= zXNBP^)Sqt~=i3787>X6O1%7VQ~4mzSdExP|Z>btNLz--caTH4LJSP3eC+Mt0iQ^XzMPO{y+ zD==GCc=w!;naXrG10;Q^o7e9Bawv#rm~8jL_{mgzIQD*H+zSN(d)`c}Ah<_-EYZGO zagGSV!=(~O$YTDZK?Po(?3UJWCJbErZ1m|m*ZSy`^Drs!8elMASZT`e&0D{DWkE&) zERG88uqBJAl(#GLoblGTR>`osG$Gz4$nDBKl-P#~T4l=5u1Oj6SbsgD8Eokw+>pNN|h^5$zk8WVj5u?Vd~d9tgXH7R5J@hlkfp zA2|9t2nhW3Hr?lJNitl@Muw=b_T6LIUz~P`cSvy<4Z3lY?Aw@Rz{J0uOO5o(9J*d- zYzx=YPKx8zvFP|5G%d~K9XcJTNVDbXzwJ5}mJh7T{yr6eyjK@2n*z+fckg)FQ%vuI zb<`^+e`CM{?M#`5Eo~FHnbldfX`ta&m=6pnLEZo@jWS@2U`7gR{kPBSYh2V&`aBf= zvIKBk<6Hh@AEj!U01y1Flc=Ra;ZB9b86P4nrGKoONX%F)Q@S^(62vsmQi3+KBPqr8Ir~`UZwxbb zJG~$2e9Ak{EE}HW+sy zJ|ZLNyQQRh(54lUh8KT>1fz>9E1RjR%l76Zs<#Bo3h0`d3ZV5izmmj){Fx3W)BaZH zWd$C6>lHnnOtU#|P?8!lAMJ6_6_)u*utze{%L!|MKboKsE+N5HZby)rWVJ2|GNH5D zecuZ^=+d$ls-=TaYz$E~Me5x?1sXMi-2`@u%CphfM%nsnUo8}sD}6p30ufMUtIR|sO{$eRs$`Wly10JQ!$Le#l)#ExGrcFrh2FN7 z({4+kPU==_^K8}Z$*E0;u{JucMAkibWdUO3f2s2vTQmtx+YO6d13+bjM$Ii3PVA+U z8ZeKtgi;z~&fA?Q7G2CSv>@Y)(G?ZXCn2lStk-Kn(k<3gQ$r}ch{8Y3+DI#xd?r}OvB^@l=48W66f zNe)9xZS{UI!+otHT)@DT;P6}FNM3OQ$Cs1s-sd?#6I7QS_ zdeNY6_x<9A@M~(~_zX&dgudTrw4uSJDB&!i!H%m1P-IA)$Z`R?6vTUrK1Z1M&&N0W zWfP16r4i!3bIIJBYDwTl93=SaJ#D}QfOx2MiMd{f^6lRZT$SvwH>0%6JGUghReJAh zdb)VuVju2W4DVYh&tcE0kHmPvYLM)@xv$QqFGGzWn=Xay&1-U4y<4spXCn1)p;Ap% zA4`0+kt;WK|5Ra$no85-K=Eb+r7jl#;Z}-dL)FzOr$`-)2AIl2lPY~WmOK;tV5BVm z*>49he@b$=ehli7Sbe<%kpiL<^{6-reYg|o-9P!buzgb6kOMH)sgkE#D;Gx*k-stJ zfl{t~=U(KuF3cV*zp10mN^Zgv8O1$@2P((5vItvS8l$FE8VzO;0I^Rb#DVdS+c~SL z<}S0u9InHv6?XoF1MQ1ZR8btWR~_6C&ZEpTzUrzI>1K4O;Sg?hM-_f=jotZ`GD}9O z@M)|i-caLHkb=}hhNnLh=E&_YWq5dg>$klHf{}8bv*XTz+0^ zmtBoAr;F=nyq8TEt+%P@kLlbQCu{DCaYv;@$50%T#(6HI;=Q&Yws8BaH(2}+reMd! z)!h9tx&Jxzqz>~u!^QpTjNISTt>@J*b1=`zBCKeo;BMglPjDMDzic0lxYC$Il6Ra- zs;^$iLqRBsJTFL*sOCxkzR*hn;UH0a-jzy&JAKWm$^~s*5@FSnbwq$i``=I7B>6u8 zoiW2#(43zq6y*X+71H3A#yiyJMm>il7j{vK;ODGqznOq5ay{=%x|gff!7WNz2p-om zdezwGvBegKoutr^96XEkG3#S^bJO$Qyah`xxWqTB^;p2_wmHX)<0{ig8W`4V6t2V$Dj6V2KXrnhb9?Ox+FZ5yHoavaTEt zwGp0T*fTPpotuSrYQWpB<9w3o(+D;|!nm8lI9YX{i_%5{?qmCAp<;|>zKXYtWlvx~I; zAz~It%8*X^yYdo0%~0fP``m#FsS8#3pewLtj3&9+QIDoX|H>TNXfT~E1pmW{3nW-B zQ~skrba#X)60O*L@2YpXDIA*z>r4E$9DH_`*`R=eUBhBwv%>)n38r)Zv=b1vL^{gPAjEP{uS=68)>!=+*XwJ{Ui7Vbh~yTRU&M%yJ4QO^ z9|cFX+OGWf(^r^+0l?8kuvfF9_lrNeP%Po8{@q*bhCn!JFIs!}l44_6YwZZ>FM%|r zTAF$mkwbST2z`@mBY{)O^HWKgS?k(8~PLP$ikyo~&=?xjNjwc;ai zdtcd%n_LOyij!!}Om~Uz;;qXg(B9RCOGGH0;nmwnVE$Ook!T?1o!uuOGirlz>&WWE@NJ<8A3OULzlesk|xh=KKesh$r;_bxPb2) zoJ_^YwEo5S%iyw*0EDJSwslijH3=5nLQ2;qYoF|5^T3Ag&o@Z)^AJSBwFl@AUjEZ@ z@;AY7ZR|%KyvEHn*et1J;qN}i*p?yLtnd7Yp~nRJQ)`pmA*Y) z@bLy?!o|hX;2T9taDTpIH)ZJSU zX-So}tr{nv6eNA&{H>9=6)l9=FMWK)pc?qWJ_>?~`7lX}#OB{fc8b5aJadS^A9YYM zhO)*&5M#T`!`=B_{_SPmk5go^EWS`o3g4)}#9Gqv%$Q+VGK?%)`q97A6U?HpE+OHS zIidetbGUn1DJkGxt(>5L__RKg{)P8(P}RKtcef~Tu2}5 zWgC~8R_7+$uss~j7Gv6Vnz%JKWzi`otDBfz*ChBbc_$EWl$H)#3EUaIWj>Uc-jZ9# zRJbZ2%awmR^fq=CQ~iz-PSkJ|@#&jEn3I^_fe!LEocwBYpG zce#rc6qkr7-B4dG43nRFWu>XdnoAZ(!+>QJimkLRhVj>kLF3!+QY>0hOUnO8n%UX8C&Y28^tjCUDvKOd5b`PhcNdx5TbzWR#lk`q-HhgcTl88LSJ zFHSb-rz=+2=$TYXT;^iXb^NjEE2M(>kgrQU6LKn-`~4!*0y89Q<+{VAo(1_ZdUaGq zHJ%Kc@RD+_e+n|EgXmSkiOj%}WFE^=vZr|SQ`Gr??KAD=$wryo)9t)#S$J$&tr5mc zR!b`uO4eGy0wLR~o%^{Sqexfa+jo?T^6tuoCzM3v_af(}Ok29@-5Ik01>FP7} zpaNA|75z4l_GJr>+``jcz5h*cui-9Z8T$<3b*P#)d6&5aCH(av$DdR0Me(DFC32lx zIv^+G^GN(fh3VNmKwR1^`3U!0_0d$KQSCfTlP zdK4Q(mudIN^wpFkj0IUs1 zCUY^2`uN_I^%%Xu0O;x4`y)}8@pi32`vvh3yTG$Nn;GcK;e(A_$r{WPIltOMB+-a<|)K?q^&1*jW zAQG2Pl?`N$9t`nN908^j!AODAs$tlJ8tzo{a5FFAw6SG84awT2%rqOf?nQ_t{ET3@gu^_bq)@PKa` zb5aYatEeY3IA6+xfx(%%N%%(d8o!P45bDtjfRntGx?83XYZ~FmDS$2T01SIDU#uKm zyqntY)~yYn1LZ~jxY%LIzV(h5|AZB+^>;kuynnpd~>OE}znZNX5tHB_w zb>R*+$c)OQY%nr8oMA)=my5o~5D!gYH)O~K?#1eAFH>hM@>v98(2O;a;YcD6K4~xD z&qi(hBn-&z8NDKZ=U1Ah)+*EwQUt6%bRzKs01K){IjZ9ZyQ-Jb48RH$hlFz|8JW;| zH@$unqX2|F7seKxE;;IuR)_Dg58GXl3=}gl16vj-!JPoMO8THzOJsibhI|cMXY$DO zLGceCh@GS+^vB*QH~rCIb%L9;D}ZT(@vz(PwzD{imBG%WryxGV-RKeG#6Xr1*2?m1 zM3EjV2d5hGsY_L`%xUi5^VB;-ME8+Qa+__H9R@6;YV_) z*6--h_6nvV!@u4m{TuSvLXh~< zSx@)r+;_67i9dj6LyCCXi;65fop1|s>flAU(IrWoO*$MCt*~!(#@NEs(?MJ1?}N<1 zvtP~vLy*aV#bf$+*tQJ`j1hC1D6bC-0#uD-i%UBRScat_b4ZnwG_rJY&tCzthBf7)!6?Sv$O_K<9s%P8fj1q zHl7|ab9Nr;`dcnalp*O{eAD<@pXExemfp1I>?a`uw0!g zZ}&Ft8|^J7$X3dqKi>;!s=UYzvV)B_vqM;se}e1onWnQrE1EnLmtxDwAlNxx=B!8E zNGr29kJ@rd3ms(qEZk3GF%&dSMajEA@|56RgyAACyKvyte}e5OaNzNvO#&u(c=3No z#%^Zhb^6&c#-j;8yafA>SrV1}QWz~y{G(k?F2GEbZu>Ta1$CG z(YaYS35P`bdcemeDOW^S981%mwYg8HNGi)>#3gZ0ApaXXtn~3kH_ZR<*Mh~g59qQo zZKd`*Wh9?lE()RzLG9vEwq!~;Ou_b56w=L~IB|TU|E9dOOL&UT?$EM!y`n0gV< zXtvlL=8ZYZIOX%|dP9}T8=EtF8#f^`(}g|BWfdILuYxXZ=^`EwpPlwWR z@bk^L)%aXIoV6sq|GRibSI?S(7b-u)QjAcU-xa>qSSy=j+VHRnjaevt6VIsIJ}CX5uIx$ zp^(WCWmnGfUd+%#JN1Lo4G+o|L(t2Iw|N!l%_3|+z z>D##lC6Da6-QEU8>&B@Lm$4){B+awsc@;W_z73Z&Vst0k5sRN}MS*#iTPf+;xSJ}- zU7G7LFEVJEHX(zaHF)-%aWUuu6@ukIu!PhV6Q6?>f>;~V8V5v5gdpvfi@vEd{7Jhp zldahUzTJ@**2cNR$9+31n7bLyq};)8Zg26k2#|;Fo=zQj#*;MpH7GB)Se-<*0X#>u zT~P%yl%~$iArg6YL_rQsfzf`}YuZg}QLGHuOZ-209ZFZE3@Zt9c)si#TG6!C|KRL_ zrV8Rq;4!eQpquE_<{%kO_0qK|Oy00Vj>qP{HzyW3evp>uy? z0iLRSZc2HV{HdZvM}d0QZJ6wjL0tk2n> zOAF;y2LZuzz8sjt%t5^ikI$Ru`4;@(?(XjHF2P*` z1RV$(+;t$3-~ocW1t+-sK!6~@32uXHut5hxvh)4Dt=ir9-qw5j-&WnJTh()KPj{d0 zp6=74cXsY+d9pI*KHei_N;iXm3fR@gtWLJXy&WpAqCex$Wc;dMPB=R#WFj)X%iW04a z8!2`_brl zQ-E*Jj#0@d>&dPm3S3|4!FBU+VO~7REM`oNK1^m8Vz9{Daebb*N69ATfg9T>WQ)}# z=nl3|iQ$(cFO<4m!aMD{;zS1)zcU}H@=XLEqwPT4Mu@|F5K3ZDfevYJc9P%g1Z?gc z5RyQJc2*icD~*pRglkMAYvyWU|5+tL>~PyYgog^_ZiDhB+avp?|a2<6s>Oxsq4fLfn~e zD^GH^@HfyOUd{>}@%Xd#88=JnZvY$$Ob2#1d#;EUcpBHte^(s|Qa)fJ< zIdiImaRfXbP!X3|^S!k8UKw}WXwufaU#Dg``1>!U(aw=n zUgZ066G8}od`&P>#&l<)w<4=D>)qs9@uiX?U+u%>iD>joZ-5=VdTo@#Z@T4C)M>KP#(P&-*oxK0hhaZ9}xB z+iTh8IkF9;XbEBH-1~Kjzo%v#Ai!dlO;UPdE>zcUPyxbt0LCDRzCq|so2(^*xj*8w z*$2OZo%8Ch|5=wIet zlHF`{;8GWeD1_t1aj`!#ngra~SH({(QzU~l_4Iu7zbf~G_#$X5bx@O(I0$99>Hw~B21s8gIFsKMZ)G&N z{nC;omEP7?pae|$+DQRoK|$*W5mJkObLT80x*kp>D#?GW*P?RFXPn(=g=)yiQo zq->@`2&q&++j3OicR|hegGs{G7~BK;&z7lR7%oeM)-!Vf@}aAtK3@?)RA~ai&cCJ* zMsMo@{=-at8a3BF?P2H785<{vtj8XTb&}W6i}2$)!ym!vQ>qwSEpb;~KNa8r2qp>l z?sXKmf3_J9L{D}hLAWp5qmi#zL=NPFH>Dmlk;mpBEfktzipSLz^d8~qUN&A}F4ITp zYgqbafn;Flv@g-w^F$a-b{t>gMmY!JN5ENf#~w_+Oqx|@C9@2HlL0@i zu!=AQy^UD6oa$bbthZ%5W|z-?uh6pAiMWu;pMN_J=Z1bJv`UJ-#de%7J7On;(nSD za1S=VIUC{-)CZJ4z!;qUYZi)jYh3@)-jj0`Hp)U{%R(;Hyn;hnZ zxEnDke~+K?_{#c^>SErKc?PHy3g$>SZ+zwD6Br>_Q|YeBXy1_d1C zoom7-)ov+S9_dB^_ts3c$%m3#dk;j5{0|=KbB&`H?kKrBii-%->mPPfigU$@HlIi-(RtE~Nm(OjIgbesQA^yGbBcqK zf9{II1d?vnrzZIMZU*Jxn;Q^OTmeZnsKGF{Op7v3IR;%_GS9rAn*MMpwZU*!u<>4f z3yD3Bfjb{-P7tjo>r_ehxo25g~ zQ$CIzgeV?@druv1LQj1`Z;~quxLjYw6Hh~7r0V`HkoNZ#mu|J~yQ$?ck-c}8FxkJD z)-yCr-mt=CCP3a)hiZ2t{WzAZqR+x86o$G_1z4B+`5~vVt~4(tm?s{v-Y3=f@q8YWtaC6ac~Ro5sRNPdfBNO<8n7Vk5&X`_P>lO+j2jy zHn-AkXvFpu#*n?8BqiwdpLK4^kKlYc|9TizwETPalX` z5ScHpnmnBjW1&tm5d>wm+sOt)=bGmc8$st;7_TPm1@j^P zeUKqC{{g~34N;7k}=*I)wSj;eyFN-C>N^M(B3kob-ZeK*{>)) zE~0bh(=!=Bov_@DKmce77RPN#UzW{8$m#?x|F|A2wxc|G z^t<_|U?%IFJv4Xj!#@GGZQ_Wmy$c8k)yi|yPf;ldvP5&=@ZabRh0(BIG;{HPJY5C& zKV8PSZHr^$@MHN7Uh$Rl&0dfhC$7sM@jh2$v_e5h?+VM^=_2IU z>bz}7O(*)`>m&Il&p&(B!IxcNc^66@bNOrf`DJx!LrgMxIqZkn3jmzqu#QSzJB2Iz zx#4D5n#z=t>!Lw(58xCJ){#!ACkfqi{o1)T-t$~k#)s-M@A|q@OUXxV>mrcvXGD`! zkIOc%Is|3%jlY5)!8h3=ndZ7~gvofBK^0$734R;wJ3zhX$s-=L>sdoozWCLJdo@=Lkv$_VN z<&f>lGjp5L#|~=iv3}}vouqR0C6iyRCj8fD;Sq-43fxkR&jxf(rNb{MFuIklMJnL3 z#(3flcOS__og2Dn>vJg!Jpb{oE;qQ|sP0o{I}KD|hLu)373^1&`XxK-?);i<<8|t^ z#tRZ|=tLtegE(aj7w5;A+9_jRQc2MtM$5B6WTUgw zv*A11N23|=S@kT#r{g>-K8FZ|KSq$#Bi4=x=v!AeKhE9hU^xAdYYfFWd!&*$#gI^? zNz8BiSUHrZM?XZ3jC)wdQ%89DQVuEndmQ4k+GLblAobnahb0q7Co(7S*GnG0m>IOs z=_J12q0NKm%<^3wVA^^2aFVt>A-H0f$OkF1wjnLBu3PBchn2*W+Yi`VGg z#%KQ$R>9Mg{KVeR45iQs!1Mt=DTtV=2o1*w#*nuAlz~B7{^Jkv18r^(o=-IV*dTj$fSkfMX)=&VfqB6s}n-NjqZtaUD_D zi>=;Qdzn2pHLG+w?$W^uf>QSuH^|bief>pXKRqK+raRE?CZ;vYcGVE$8&>#fI(K3G zhL(-|bl;R^YcT)-N)q(RDDz0JY9PWZb;$tlk+BYkYzLh7U|6i!p^ZPeU#X_ow18jk z5`qByvm_co(v}N?4hjOxRrMjlU#AArF7e)!KGxxT%%MRkJhYzAnqg@zqIDlLn|us# zKFHM~e#h1~DJ=x(n9=?&L8x+&dx zGRSg5+TA7+f9^BVN4wB>PW|jY7D#7jixIn1kAWENMkY?7h6wyUw;>Mzok!uLk%rf2 z@}GP;D(u3ae0yb(FZ$lkEt@0OCCKn8mI60x5r(j5^kumWZUMd_%S=PSFKT|_Ys;_$ zZ1id1d;s?LmwNm^ybQ($>FJI4}X7z5vL(CWnW?o7r=grtgh#J zF*)YiSdcZ*sAs&#D;Ef zqq@|q6W=QZg^vEAPaE)9y*H_3)(Tv&Tiq8+4Sg%R7P#wy>q@D8#(Jiy`Z-#)R7ffP z*%gpo(fS~2t^ouSrfrFe3doXi`8}uIm9`a>V;BqTY>^rS>4W^+7#u)nPsU9g?bn`B zX@Pz|7~_L`gL;Ja{0xZ++&?{?9f)MphwkI*GTZC$1Fx9M1sA~m4KLKp*+^?7)5e%i?PJE(w*iB zF9bxlS{B!O&jy(prwAPxMFSrXh@V(kgfUULRxmSDA%nFx1vt8XOa4Z^Hrv)+rTkQ& zc|=HP$&HRF=>HZZOX<(Bq7}(zEY+5uenQxE2W-%j&XQ$j_!I1XD&T!Gb(L26Gb+yG z#8vX@ueC-~F=^IjD&#|tAz4^A)<>f};)ArPBcgYg)*=BjTp5Jx_vhtQ-+3cPNp-4% zVT01pg6fsSk1v}OGWU{DOYD6q!_D`C=AB*qFkVz>fgd=AZ+t7j?(ZLS#GA2zie?F5 zc=Z?=0ERdM-@(H7tq%Vm-d4vSoMdqSj1tE5-)fD1!I$JYX zb;Ck4ZdcA$I^B%zt4cE3&v0=pUp>oXsVIxdZ^sNdJGDqjkUX+GPD<*_pA1lq!7Z#m z8)JGO04_>8QB(AnDuz3ceAQ8nPNl(-=#o`4Q;er8J905sOj-=fyL6=Cs2n4cTkR@Z zV*MbVuqU_k&9FUB1hbt3#>8Bxp_$j3%4kq`S7LPbYOW&wO%?6!>{}yl%=wSObzfAk zFJ4`tNVZ53If_;53#@%R@|hRuX-f9+_jhbZyJm*?=vjSg{US|Jim8g_4z9=J0Xtc zBQ+;7>#2DjJ}w8nIAWCRc@m#iQeCrbHEz9}0>XQS3XKV7xCIEp$)K z!|lZ~KfYgXq+Ocov!1CV2I<4MHV=nXlb^iLNz?IC+X@p3lt;ewrVLZ3vyV5}_LIpf zniIH*d=PZ=AF9(!Z^Ur()&qMeuYYWxl$u#6VuMWw3^^-O_&C^##S`XD?MtN)xuKdV zzQrq^yglsUYdX?9WIjuJHE)h*n6m9>RgRKdJ zJ!CTL>4q8dtS4C#`6}S)kg_%Ht+d*a6lasV6Uq^PiwsQkyVENSmOApB>uwA$&DPC@ zr?W+za?YQ6^=n9xQqFrODKr6-JY0GjNKnhvVO#cx96p+X&mgj5i^s5%b<%R|a^9so zUvN!ocr#Pn`pZoyS9F(HhA5J~37jfMGRM2hYH40^(#n3P4hsI&Xab;`~4vngg5v zB9ss6m@9o(X|yz)ORWQDxpm6h@YJ`c7)vVC?#ep$pHV;5jG6X?_QeSsPIsRyuFz_L zFK1n*a3iQ*+>`q=TB%!0$QfEcj6W2R6Wo+TJRfiR0B+Y!DChMsSEi#@p-51`7v#@% zJ$fa!4&(bF0+{FiA${y7^LzWvYk>-7xb_kvnYh1D;HVa7Yw+y^XzU^Qkl}^pIfT#b z0`d6MH-6~U_w#c{clf-DS#Lb`GL=CifplIab=Kmb(;{Zr(P6a~D#{}8WC+WQ9NSR@ zPfZfL)E{j8ZenXxz!(|};ON13Spa1bf9ac!%M^1-D?d@Pv!l(G@ULhqdi$5K-{A>Sp@S^gRjzd9T@mZZbMa!tN zkCoDNe*4GB4b)bhsy}a{M9J0;=cK>1>vZtb1BDh=?ECj6f5X5rP_3oi0`AaK#vS|H$BFSlD$;6Ow@T8|`6 z*Kmwv-+2W#nQDIdbsS_?)*gO2@?1UE@+h==^vg^DT?NM|$MeR^Ym}wDL40VR-NpJU8SX0LrhusLz*PDPk` zg5?|iuz}tNXf(`V3H~0@kB^h<@)$}S(@S3#YZ!T?+Pp^#ocscSG2Y+(rEO>4ot1P- znSG&=dPpdARHmS)%YKrzB;{HTOdM7+@0OK)moq&BOs`*O8D4TWXsQf)>824lENJ-b z*)$B|IG;U|QginX?U7;mI~G?OvUu+O%3zwO;dQ^X92>_DD5POcmO|sl_=&R!Fuh1v zQ0{#%t5Wn|7$Lz83tZ<8Wc2v|<%7clVS9DeNN<@)pN-E5WrP?4{L5=FUq{CFj+1Fl zX0cBdfzDL3`Sj!EV7s_CEE?BvxZcH7M{-dY#1w}mg)d7HV_+t7ZW?rPN zIqgjxsbzku8w*B8w0Ajkc?f{o(w<{>Yf+J-)4SPuD?+>2WqPiWRo)kyV zuTs;BfX#FfNF1?$wH}-)swCl0WjBagUNwILElU;{7z;rn&}_g!;hVre^Zpj(ny1rj z%SC`ZAVr!3*rr`;7nB8{vH|m;eC2<=jo4nEXstT-F*-q@`mhE;@6EK>vun-l`_3^j zNjJQB%w8Pm3kql=N}7C(Jk1?E6&l#oKK9_`t%N%?WIZ%T&`8m#T*wk&JqIn%FbLt?xDEW#@664F{wRidOLS9*&|sHfY7eHIzBwO(Ny-sIamaN1iOFGq3K9fPj?U8eKxcZJ z8LhJP5)j;3cMY=;JF+GLt{*0O?&%%`+i!gj6uiMugx-g9>?@^_Y@_{}Ja%B^tFnF8 zqxIXkHn&)NEoYdOq9qp6mGDmqw5#AB^4jwZ`JCIYfDwC-G5MRg{(Fh`lXU(U+351* z0BdVD6;y2BK_pE47-w!@*NZo5a?$z%b|9n1Kx4 z{}82@Q$bP3W~rA&O`;0;yY0-7eh)5c+0n#9!pYCCV$D-Qf5ArH_+paurjhs^EU@-# zKBy(D1SW&KI@E2iXkRLSLYN2LOEdKn=m;e#*;5C@(Whnw*&grhn*Ez>zQu|sp(tf_ zESFww`c!n7I4F4Hh))Ar*^<&e_(QxLzLXiqw>2XTdFP|^_x#;0M`00ddT5r7=0Ym1 z;5^ z-4&<=J^GF@r}O#f*(s8TF1k-4>3ICqf7*Y=8#8^Zc3ig&oy7q&v~w)8&lrq%d=R1p zT+@OA?^b(@E48gxH1-_8dB{$ z+mCbaD+&>nQ$;!*2JKk)51tXtB3dtp{2cPye=;vW?Kp=OdH4h5mFgJiknktc6eB=L zpNL8lx28K9EDBqTL5x8&#Droq>1taDr_9e^lqT#|O^lzLO-bAy$zcSZxv2k#5HT>7DZ<*}>sR}pM{ z3O1zc`yqzIqzOh$rl;UjQM|GnlPK8v@Z5$`d*=4=>6GK`@HpIu8PoO7CuKg&;)sgL zG{(mAATP3Ap&s@Q?FNVU-=x#^aas5`h>0Isfj?S7=&qGbPM1t3pSm-P5rn-z=Cd7( zU?>Ts0?#>T7J3!17+xhj!s^>+mVx>ETx;-#XLD`V2FF^=k7eExdt(g+PiT88EsLQp zkT;S}c6j8Qj7-gmAkUzUoA^fQOe}wK`Qvi^w%=D9y!Pw6aiIo=-oatYlKBNb%xT=h zGM822gd>aXECOWoWzxe9FKLNN5<--Uw==E=F5&Vu1EUBEpq2l90wuOQFmrjbjO$8x zV{q<%3iXkA_cEGRU(~=+xX!@N=L@!F{`sdE&OuhFJfLFB`m(rwfVHosxxzFfBrSX( zl3Ql>4SPK5462=GN**H#gdg~l=fOuQZb9bdTQ11#fgg;ND}%`?&FV9oUFt^k8O;z= zE6*k3!Ww_8gJ2NBSir(ez(-aHLn?0iC(_2*oW z071p5RYbcEH1V$#b+~Ar-9+!5B6tot@v%M2Xk9!6_SRr~xN>nUuOiuaIm8406VSHm9CBW50OGVG!cIK(U)NU=rYy>(t$r17Yozz(#Ub&w-D#OF}bmGCVezS}rl8JKREMr~_&z#MUwf zV(Lk`ZW5i2t`m^A1Pk|E3EpS&UGa_mdj`_rzcY#We~KgZzodz4S{+aUzgcJCoTdaaf~KnuXq4Q1(Z}(alav z81k~JSQ6U=zRwed8>(nT)cBQTo`Jf=B)>$@neY5w%ioJX`5Z z4LlR>Th`h9)bHGnw`{Lf;>Qdj&|yEhd;=cI&jNkSe1EzO6*aL+%P?5N080b?YPamLy ztH@ysQOemA;U0@h3QOKN7oEOpi8g({kt0g)wH<)mr9Xt#66wwAsvGh^;fxs6zh97r z2JxgW$AF>{q`m7W4RPO&AVp$t;{x%Vl&)_G>if#@A-p(OBWRZ+cGi%Ry)7~$rBAPj z$Z|e01IP};G95{B5RErde-A=Mvg9jo&d1@6SsxrKSUP4>thxpWCON5DR;)(!I1oO& z>;2Ts+p&WCO5_Lihji#bQa%`PzYFphhoPQ?DGUD0Y)}VJAFj(;pmIu%H&na~v?pmJ ziqO{KjF|tW)3@oXU_~ zb6>uHfN;px&zX4_(;I`Fqu61QRebS2xQJW!02&Iqr4Ze>=LV*MXeO4W>I2-5MBq(< z9b49cNuliE`GaZGJK9>OZ#MRxxJ-LYmBd%OQ$sA(i8SqsHOy1j`*hd(3g`bTBLMfa#cc&2=4bqc;HRpn0~1s1z8Y- zZ~y03GK4T9TGz-uXpJQ3iYB@d8h$H)n6^66Yb%L!5ZiT+qyUle8?-GTZD@f$n58o( zQDbB9sAnB~#+moAa$XX-C4NTDWI+%M-;TM1$bmQr=`||LCKi3CpCrV+c!llVZr`S# zJ#T~%Ts3la`@JVz9KwZ=9MU9%4=^+!+8$Z^CXR1M!hy7>s@gTl2`xKD72VLZth_P8 zD3&fnnum9jUZEdiMhv19oggDMBCO0sZ~67X(mhf+u6exlgS(7(HK)sw#d}>7JUmBY@0TXlvs-hlfBM^B<7niNz+93U>Q@7yfIW0vYn5?!nyrC)on`0Dyj zvlkz}K5-AY6n%Bkfr$Q!0{%@BEx$Ak-I)lZ$pD}a=n<1xA>r5w5go?>N%^Z7SQEZU z(D1H*Ocl~q1-ra`P?*cC#er=l@huc|Q9)&z`Q+ycOBw$0_wX~{iUu`s%bV6mgP4Gi zuNZ;k8eslRkPSC%@C`JoX&=jWoNOeOFM$O}t_cSHT6?95_=9D-~5aXQ@+XE9uK=+5U+MY@Zh)A94-uL(TLz zaNS2!!bE^Cvl2&26-dlgif^I-L54viM(N-Tv7I{uVcS$89W(mi>=#m&LOO2r0oV5! zZ==}xZ>^v>gGd-5i!n7ks*vV`Tu0L6n}AjKKAS11UxxRvzRX{HkW=60_4~@v<&3Y9 zrPT{jY85Nv#wL+tde;-nC$@}aC?Fr~b2DYw8l3%xzvgdmPi8AsauDt=-aN2)2*@=d zWEA?&3;7|+IHWx%i~nxw28Z9qgM@$4YO=$4XrT+Ag2Nvsi@;tK`g{p^A~Zlhc>V@3 zOXt%Q$HNRpB1iqh6rT1Sgm5|F(RVWb`Hfvg=fV1I_|IdC-(MYNyWimT1%cDl>ZlbW zB7*^(pJ2f_7;OlT3U(!(2YJ=Ynn_MffEq?B0NAefkq;8#6atV{Zjs&&VgU9n{1~Xm z&tZ3m{b}-e;KV_;A&%DdYQ!92F@GFY!TO1jN=(3_t<{_%mq%<)PVfOCP0|S+UEvCM z7^|`4263}sH9334-(uQOM`#gC2n6C%dm4zmjc=sQgtc2QjAJAablpfn2opFc6qrBf zPj&=0Thh|5f%?bD>`*5_EmF8}|Msn5FhXstbhH|6SC&VJse!lM!QXc!UVTI%Er_L?PL|%7>P)c=3FXwA$7b&Q%bVUHD`k zl*CIM5}sglV&u;4#7mno@B%4vqgc!%y}X5 zUo_#5d4r8uRdgF@$zbg{xiMDr_5aFBAuT7@@kV*H)To;CpWjE}rOQFTm{*%gfsSg4 zxIe9$%~7nz5F{&-3s9_%KFEZ}CfLxV`o!+1guoE<4iZb-((00ck+I@M4YBON6p$g9 z@oy&d#ij$-nI8EAeZ0;*F8M2QMFeW`I)upjSXp1rpqU|ElHpXo|La9L{*b~~3l2tw zzBuz0zgredzBD>Q%$@E=g@&G4$^W#xln1K@&CIsdBt^j0Nxuh+UL@Ni@KHr`Y@h<>>BSiMFg0fYT@-#nbh!)WWCP;#-1HA< zhIGU)Y?zxV1O(fQ_?&}#tz4n z{HHg%XJ0J7#b4UdxjcGf@*mlYqW5HTXXaEhTL-Re1DDJO`0 zS!A)fjT>fZx3u}-;D2N;P2qmzrFkF?mW;<{)gpdpH)|}7rl)_3I8b09CGQW(P%!KM zg9k1T^{_jel=~xHOAi*PwvumECr$Y#qK;FW(tzNq z)>hl@I+yPI!fL8mKQ@`wKJLdoll=QbR6OzGPE=v*IMu48F7bp#U~jnvercZ7S+M4!N7KB^_N9rFVBTyFRx%Y08d8?%GhvClIVD24*NT7a+!81;IAI`(N?3h zMo^jtnNo*bDVzTlfDL_eUs{S&ngsGeYKNYeLQAP!zwe_e+TGmk^5ODvMh->dmeZJ?Qrkp~J}R=ie0}^#Z=^DCiU`@(h*uB)CVl+g;BJmo z!IRmGwH3&)ynH*cNrW*_@Qb=*C{Y&Kcd|-5p4AE(lM231r`J@{g5x$_g#A49>hAX+ zNPhhEXrQSq>ha7%c~vBh`C)ah`D!od#ZUj~QJKfF$8H&cSD+ z(mU(z0*)k0uv(;b(N<2w-+E00w}D`uep;;=%N1AK_}#v)!|W&a@BVqMVD}-8_vL<% zZ~b4hhBQXoakt$g91AH|v*G+`-_2ujz)g1s!?Y#AC-bv(pl|Y+@iKzYf^)L{;9h#L zs-4KDgHUvUfuCgvL;epi)t35b1XX>}TgIT4BC9Xbq3dqh!54#W1-RcQ_PzcxN(U6U zi&TWlmbC?;G%alOcN#33cX7zb-+TTFiE2Onz7PdV+~$X&YK=OpRMj%oo?(PO^@k;-GYcSTmgQ){<{b@M$wcMT_&8lYvsuV04Pgx7Aa zbI%+$WM{mGB+3-DGf7LPQHvR}qknEvOW1Ip@_er?rG1D=WEOS4i&;|2orpNMT;o_A z9fo>;KY7G7&~B5ctQtDi7Y=Lj5v{9c)+d*(-+~9c7F{MS;UbyW*V<5KR6&n$vatK2 zu+7W(!BpuLpBm|){IH*3vgN+}Q2?%`-&3hUuIME8{`6!IM!BWY(b-A!*Sud|gPj~? zMUIVyV`;R%>S&?X-j7{50qx#cUH!%Qgv73_M(ym5WD+rt)a zm(($EEx2vL#>NGRI)5aMka!BGurv4OcOlwolQ(5r$6;r6LuFj-fW zE*y5P-Hm*^)p01Vua6b;jc-f{Nq~nK7sc~jdzp4C?H~4zuXe>7ZDQB_L$nj z{QZXHfCDIEM=~u8&>e?&EwgM4p{6H=jbol(Uk3n|qgpac<3&)deRD0PIKNS3^_lKe z&R!6hHFkuINiVLSgfd;)XzgWaAgLL1E}?>U62c~y5vUD|39oV|ULS^EAriSgqvLx- z`RW2bB|dgTI-V-cM)^MRX#-RN6#i4-Yfx+Zt|pEtx)*|Vc?pOn(W9`YqV|ut0Helh zqppRBirykDYhWUL^-l!}_GOuVOnVjXL8g%T9dqpXv9Ow2UCs=Yr6z2*+oE;-EoFTH zj$`|G!8ek3MDllRc^|2?6FZZ413;VkhpVdVoE& zyyHH+3){eQ%yo@@Jh%Tr?9Nc+TeYjIIrylb%f}i?OcH!J`z)V!z83AVwC;W@Hy~DM z=r{4x0v^fF>=lE|*dd^k5hw?us*sO)L;Z_Jy7#S0LhohLyEsvJ(_*Q#q^fIF<) z?EEua1t#kIyZg}rVFhh6GwTPnXD1D$mpg+@SP}|0kBL>?omkwJuNqEUzKB-z;~kQ? zzDaokKpayMlgNQaba*EVs35-I<~~WF@1uV(mw)SU_bD3*?>oLg^fPs=#s#JJ5DiLUOqjP4DUBU#sK`=}fEY^Q@*k^qbvh@A(& z)tBgA)Xj#WA85{ZNFD^CU@0(7gJf>rH4Q%3kNdCpEw1pOQ8+aHykOybjVI(PR82h} zDKJM6S*?v$JC!(xZynlaEH6-?wtZ9!Fk4xreGuf*CMGyLI$2Vd*qOs znEX(o%bq>WyesV%GDNCW_-+7IG0Hc3+g?*0CBRz)0+FU(;Xe3Mjf`iKMrz2$>ncE&AcKw zMEE_i-oLWEP1n!tS6Z`)E#WBwU>S6a83TQeN4F`Pq`-$;%lQtOnWr=JmEQJbH~KYt zO$ddu{Z#_%GTTeKy3ub`8asl=R>h!y$gb-EFz6&r6Nl3*FBT>?+iw> zzJ|$Uggcr_8HP#L?rGvywEKF*29fRQ?$prC61P+~FSyal=Jlm0F21H+W<`F%yVBm+ z{NA@d^CkLn?15`f=ctiNFlT8q3h4H(ue{wGY30=YZ&`L1D(N4nAg&^@TNg^KkC7x| z?1@E=BHKV4O#64iFoPCQ|htCXf6%`w;7kB55F0(^tA9x?$@&Yd{Pw)-X(k-9XSn!R$|Tz$5roRna69 zI{jZ$(7Jrbn5udbV>vO~owDw==)IVx*X9xo?NJt~!K?lyGn$XHxd%ECoy-9?F8VBE z7hSI#{OK4Kf4-^{FyxJ0JRqUM8t%k4k@s6t4}_kMQ=jmK4e;Z9$-a8-2S5a zGvKXYlyKq+MnpF(UAq)X3xTN#Le@O85MGND>u{}7ez?Y|#Krj&hgK#V#pl==l3l2c zu-_R=dx2HQ5}p)%9BmNtc7gj2q1G(R+yqF)-T@A!LlU38Ch0S-pS;AY4IiQB$g8R{ zDVUsTgz&ec`x@~C1?>jF^aYY7o+4?r~;nY~3U-|;2`RmzLe zCi1n}D`6si;XVG*u~lzj@(r?O0=}d1<66(^NCsV~g|um6-K)}i-zWA`J%SP5O2?hY zUQ*)A-Mol7J*up3A-*F_-o@uiKcPFvn;% z2Hl^$nfJ$8%Jv17@>CL0X)wBYmgCh4HzUNl)O2Bi?E%Kf;9n#)&g!@6&PD?w{^-Uh z3OLh*S;O!_u=&p*2ta~hTd)KSKNMq@!#lrzJKlg<`9=+0=i<-nMX9iZzDts;Uom#v zcBFlHoPrw@u0(43Zxs0^4U6m0kw<=l-l40wYb-vkw$HuI)!yQBOIicyloy({X^p_*T>X4%N^aq2b`MKa~Y^jNR zKA8rxOZEJn_gJyu7nwQ{pZ+TI=NWezCwHL3eZo?VzhmndtpmZec(S9XOiFfg)c+~SeXu&O_R{C2ya7eevrRp*2zO0zalx_pwYBdBAxkfgk4 zfXs*G%5vtA-K$KwQ(w9cAF^EYT735!cNI$FSqZzYc)EkNi3@zPDi1c-w8Ma@FrjVJ zs%BC=S{6lT_N-D*tL9CP)uNcfZQH&rH35?Xu4TeCoEZ%~!L}cKZg??hnQto34?aiL zqy?SbB!>1OhkzYMcccVOSQ(=ZrBK9lep;e!dNSvS6m7`{coxu9uTY8B7^0aws7{gQ zi{_0&pql`*f<%2PUJY4b=c8WV3wCgKy<*ucs3y{o0*Ij9!bFd=?v~r;b>N8z6aKqo zG}f^{SiRU0yvm15dE=@n^JvFtU=3d87xX~4?WfBV6PKR6%NjUCfmO`%H(;J~L)`jR zXT=CO_#sH*g8!qm?+%LM>$V*-5*5KA=VT)193*E!5D7z2keq}8W`-b=B}+y!D9IrR zLu^1m$w`u=K_q7x(hQ()e&2gluj;;AukLs6KV97??0vdV_vxy$*Io-r1q-q82q$J% zUfi2WmFHB=Il=vk5N4T?$)JqpwelEjib*)mN=-g zeW`LD4av2$2arYX**7H8k^R09#BB`s#|xVVme>f~x@D-dn-6eXxr0*hJ|v}VJ@+r< zoH#$bBcgms`=>~~FuTwwit8nOK%uOIlGatGWjkeeHd|w%Z3g4`Srj1q3j>s5L?667vvv_6t)zUp(2uPw0V#+8?Am6?Xa8x1k+d<@wK*dA!2soHQbA+ z6`?v~nSyLIbcb7lxKc`=^7u>ChfxC%_A6CbqzhK@7FHQX0Y>0T^g7dQ>#8K8L};jr>+$?x9)y&Oks0NC;2P&c{_8 zh*4CVdhhN`Uf2tdolN#JZAwFpZOY-{iVx7~S9sVWo~`h&g+7+%!LDv;6FYkI(F8Q= zmxh5_ByMQ0;z9UZw-)?%za;j62o>QR__g)zr=KoPea@_3Hk(&lKwWs7@4S$4U9a9G z%(e@9kxSz7kjxko37D8PLDtJ3*G)ur+}x6fPW}P7pEm2+!X~TOvjBA*Kib^zVH9cC z-H$aZATrk`0zad7MztY+b>Azr?<{7qb}IP`S9bl2b?q&cD<{J zavqI@QQ!*{Ap451=+>+l&;}RrlQC<#`;1E(DOkEPF0>bWV#qM+Wc+m!mhQR+-oOAF z&fJQB-)51(O+h5mo-aFX7xzGlo7j{$l2fqsn9!H#P8{iX!8a1Ns^%;C~*%|i2(Nb0uMl(oZrGz`RnLwY3RK!8l#R zwgu4(vdTLI;H$h%>8ewxj!G|_0Q=P*)ic`)epb2jdqEZ8=>gBPfJ*glYa2)|I*;A{|cdn3%+-r|Af8%-rS2lpo-@B z?v5Tj_QW-8ME7vGltUNRM~DU5hOr0f>ql=ypJuEFq&sEpb)s={sNcskA?b$BZ4aQ6 z`a`ES=XChI5ZFvpk>J~3-u)+G(fZ4A0@5<0D_rlG9dnGvxrir!u(Q^`5@IBzj?)Yu z;McPgnW5}g)dRysm{OCI$IRZtke}88Q_^M2)$|+K`L5o&dCrxpiPW_R^iYF`o;?M+s$5x%y;=p4C9y`lIZ ze11mTHA>gI8(wDgoG~}ei;ibD?ZzI@<^v3yO8tj|LMjW){%PT>nCUQ7aU)w-B`>m< zZ;gm^wG5TCILcPn^}4=u7?r0+F>kC1Sz8EuT*N@@w`RD$gNV;#Si{b6vKe@2H??r} z&K2TGA}bqmgT<9asZ;KbkfQAFp@*wR!-g8emkUR+WmQQ5N6o`>2ltVcBK-Cq?ZHJ#XS3xsmoBj-4WMXd(2Bho4938-wrH_GHC96KT?Bl=8 z*#s|`L8;U5nj00?yT^{mq^ll6-F?fPq`1BptNg~k({dEcjO$)+J06RoE%JkDY>&)A zD;x1}wn2qwU3VGsh?)!Ej-48RtJ%N4L739v}?eX;mVg3bKp6r5-@3IEfqA z)PjfL^1Q?01UC%2EJtSf?D@yk+k92y2}}%1H50<#Py{;+mwJQOfKiL#ly6%p#-yX> z7;0^DP`rewFz>dDjCG7fE{%?3OB7_=(eN~b5>JRW_Zi-?cJHkx$U4?Mr*!HV?oU;x z^sO46?WM2p9>QG=Y)!4-7&c|G>1f9e{NiOK^ge;T#f_=yN{vj{uC*UpdOXG5TJgLuIL+OMU3#x-0FrCQn!% z>4%2;PL*8j4K#uz+9GCbljB7FIr(f>aacLm{4?T}>~~g$ZpV^%gd0=x@@>p>sc$O! zxBH|B(ukn-E7Rg$rivNVZ0;>nu4kCQ(ldciT^X;L)Jj` z;lm+!IuHY-uU-=XsE5)k>Lgy%(@iu2Ed$}K;$)L=p2jpDpAsgC86dLHe-Q3G;_-R8 zAxSXwF9TlSETh=|-OV5EAQ8XVE3TP=%+cv!3lxDF*i79?x*xqjiaT@F@>ulkG}?ZK z6>^`u?JuC2W<)`k_+%*|RmrCcyyC+Tam3SMCc6Oew)WWz_Pr(tf-^Zh!>Q{OjN;on zpOW11*$%sqMWb%k)8~b+nuz9h*DggnEsyE5FYLhC0U?<gLh4g|oE| zlYaMJT3`wPzW#UgD$yJPqbmYFe2Kr54beRkDshB20ts)|m9BcklIpyTV0E_bOM-B9)IjhE(mW2)H!SuUa50-f20@!dzBqBv%% z!wh8zT0h~B*4gcojp|8S%ko+#ZtVBdMhcQ#iGU)z3E}ZujC3YCF_he`;MLn51W+~O zEbmJrm4f9AGosB5xgwGkTzu3>?Ot!87t>8SXMfPu1LH+p{#oz=?ddh8Oc9EYfLy+` z}1t(Uf7wmQ>1Q}sI9)nDAFG3oC-x$cLB;)GrtSiXlj|d_En*HX7%)TE7&mXs>>DmGHr2Gn-jQC0zb>{0^ zVh_0Lw)BKJTOS3fOf|QMQk73~m(%vsP7&v)&ylnb?smzFdf4e}*zxG1O;_rlbVC!< zv6Uq|)sxa>!zBi(;@y2F+=X65sp3EW*wcp1aXJ|!ut3bL~h%}rlj3j}FN1*oT9MOd_*P|I*9P+5tnMV0ZeBerif z^HdTor+ds6y^K6*ypET6c*+5pT1GrWXrR^Y$Op=u9i3QG^Yyzl2y~`X&(t16uW;s^ zE$8!{QO`?HMvmP9g1#)ceo^xi+;YVqT^e4~A2Hms*+?&ur}hX765it53Vq_8fS7wX zc{a<$kd{7WZJd|eYhZX_rx%@i8%A>8^SKn27{Jm_6?^hq%(gw=-FVG}cRhYWx zH5(alszDgI#QkkG9VRn{!s0;3u5WX9D`~$ZPGvIZvu1$21(01OSX_o#NY!9yI`P;= zQ@E9jUz$u1g`Gwd94Yqnq~?BIiN)K`fMN`lS4WyNZ(XnotZCds2T{;`?x%8O!tbjR z_mSl76o&arDo%5;m4fVksTYHHJ5K?Kh`W{So{kVlS{nXs z0!I_BSj@6=OU>5jz#4HFqeDR5(%-Hz3~bg=pNRFoRh*y+3umv^+_?mc!nz*qx~cB4 ztfk8TW+Y%ULVtCS3E?wJLXnMnIVS=??MO}ycC;KQWD9pAgY-xgO1%WtqF(SwA>u*4 zB>wBhjU;`b08rlgKr-FJhYbDvIA+H{rA zWU_~0#^rWy9X+9yd{&LDZz53`$r-t%Vk10YMf7x2>{t=<^Zq!cG2qln{hkaIkuzl^ z%$=0|+{0BX3cIwbh(AM99rbTJYs<2?Y&0JzAoNOoGmiMjZqk8nxMGK>i`{JAGyBaV z{6Y|VcI=~ZYrh!74m@}d6~<2X^}5pmd6XfKKo}Mm6~Qot>MJ1{xZ!niqQGw$eL}6- zzt#4p_ru|U``#=;K*6D*>;&#H1GO%Quk{Pjhr>oJ&K4&$N^`Ym%%VhmUf#L)pj^0x zMuBvk*Cf^8uP0ae68R|p5U zhH2pu@zkB~nGIg%z9}Q~)h0HXL;0mIQqAs6W>z#pNx}vJ<;y>1xno+pFw(-H<97zq zo4YJD=Ei8sl^kB@_HOAwB?(-Jg2Sw|2;VgYRV*%;CYXH+%D~9s$K4RV$Hx3Q1_)mM zc$Y-8z_v4b&EC-jk*$B9%vvGzE~njRz`sy`_+>tRh9frtxdo{Xr>aE~M-LW+GCO|J zblPJXhf9Ua-M**=Hkr#3gbo z7kAwESaZ8g=g)$6wnN>`3Sw4H{R2r>Aay&0a14JzCodMYct!*=E*}N z&yig1A@x0+SeuIHl$QlTv+J<6OPLi>`xKO-Q6VVo@cEtT%p4Uj9(i`v8AG!$OoOi* zVIj}qL6-}}IyMt`MzGjO!;Sa!vB_MSmVjQnfv|91sHRS};w9oR?5j?2O`OH42Pk3T z&yZc@iGf7e$mMUQ=%aY)(SB85oH#CkKq1B6^5P+`oYeSv><_x5Em`4{Mgr?G(j1zH z)m|F}aS1C#-Gd*bcnu{#BKKvzIm(1j`)CW)h19ud1fQW3>GWAU%Mb5ndDqgnhIo`$ z38qqQywN)yvr;bcVz(ZueSm*+i@bKs83(}uPAt|&4LYJnUvG(nCL0zMJX|^gTJ^9pa(OmE;vrVW!co@x=V-GzhDQ0-M z;Wzi?mTU22-k$oKNq~Lzs;<&cVW>keiR2UO?F*|WlxLjzii~*;M~HBp5%RH>4aRb)`v7LmgVVpE@l-T)IJ!$DJW2>SrDAmGfCVp3w&MDuYr%=7hV^=`R| zv|GIeNPF7)wl0PL1M}zHB=|oi|NI}7as})$HrjKN_k3jTCMRQ=+z|oPJTt`CsMI1& zN^~Q;Be`0P$is=j;f*!gZ3D3VDGp_QJRrI+RhS+xR*v5s!(R-vy0EUIsDDijfH$U3 z>)rur!oyoP_2lr3nBsl){8+V=h0C9ukSq=G(C!+g-xS?MMAE??1;2H^aDg;rmE9a^(DJnjSFn2{-Y{W8n~kacV$Temfgd?~{j}AFfI; ze)GBdgiNhZBc@p$W9&Du-4 zmwGxju)x2`*wfO4Gl`l!g^WX(j^4uWzBG86MEZqh(|)DTCy(@77YF%izk(vtv0_d23Ota(ASx02E$`T&1De#4K(&*zMB=E z+m+}8f8qIp9?g@rtWni_PStW_kq@mr+D1|#29dZEiQJQC={uJzhvqNlufU?)bGbvv zU1)$K@EfGH8@?MdYu@h|?)Lgn;2Fp>Et6}c2Yh`OuGqPmM3_z=m@jSYVt*_a;zgu5 zwwu!j)e(!uL$!93HFo!i(ZA}PKrE%!m6Bv=_OLB5P{JA@puY^-VnC~mM|g6=!5>4v zK;x~uiP0r%q+uS{LGrp6LQZ7E7H%DHbbzt` z7ofwSnkSBnX(h={D^<*(Rz85Iw-JHLMh+LHd5{?t)|kzne;-3Y0`kEXpOMgDy<^^|&EQgGdS}S(ZjIh}})G5ax^h0`iA<@-b2do1E zxxyU03zW%~m?v$Z#T$TppKmp@N+}x|0)(c{R}j{T!YCSiViW$2P*>8-)A&@HH zd=E1+w|bf7Wu^Q?B8_clX@h(#3%>eNM=a0F9YduHM{jJxAnqNSISraZ>N(+Fj9&Y- zE4jw|PWwAWPry2cf^aa3X!A0>onQn7+Ao}Voxd!(rR2;@c_Y^kU5h<2n2Q|_(e_zKHR9VWUW;9YL@Fj5{h{Zn%w9y=E z!0Z#noYZ;kd|o7XvB67~J*3q9-I0i}n)wDC_W#mueWaxI*oJ@1@92qA>d9J5(IAP` z3Mzb~@Z#sV4B*>SXaY|%TXFmS*r#`BtV-Yz!q-CKVh&WA9I+A1nYt_q>hht&wMnp> zSV9k0NQ(_x5Ew1MF7t74x<$AYLk)rO8Y~U#wE$~=+QZ(Sy{i-mRRK>SQ`T3DvwVY9 z813ck;15qjYi_J>f{t4;R0wdjz&v4J-P3H#<~Se?c4gQ$?G#!qZn8u@=s$L&gOG(D zkOom{NLxsI6@*D}K&B_))3(^pCZ)8&Z8(^@QXi@R6GqG+r-T0XW^`qe;6l@bpscu~bh0-&Jr?XY@4?r9FQ)Rs`L_QWKGD6{-s3tfDn(6!kPc_Dhs& z9Nb=AQUjL65S}PuNKE$d$ zJC6LkM(HvDo=g=k<%4MNa$s#Ky$NT3!e;~TtPtnd(QLH!!UzmkU9lp^7AH z!!3TxUj*$K>bOh$mpW?&w`Ik;AfM;u0R!FMuc6t5y+l|NW!c#TSB2hZ(AEW#@gbi7 zWPEsCwEtTXvhab3?w>fQ>R$+oXPkED-wAI18*NFnLhse@3om#5<4Z@w@X;qVyVw5< DY$>gM From 969592589cf85940c41a2077e5ebe4d22d68569c Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 31 Jul 2024 10:32:10 +0800 Subject: [PATCH 003/336] feat(badge): init entity --- internal/base/constant/object_type.go | 23 +++++++++----- internal/entity/badge.go | 43 +++++++++++++++++++++++++++ internal/entity/badge_award.go | 39 ++++++++++++++++++++++++ internal/entity/badge_group.go | 35 ++++++++++++++++++++++ 4 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 internal/entity/badge.go create mode 100644 internal/entity/badge_award.go create mode 100644 internal/entity/badge_group.go diff --git a/internal/base/constant/object_type.go b/internal/base/constant/object_type.go index b3e3883d..eef952c4 100644 --- a/internal/base/constant/object_type.go +++ b/internal/base/constant/object_type.go @@ -27,6 +27,9 @@ const ( CollectionObjectType = "collection" CommentObjectType = "comment" ReportObjectType = "report" + BadgeObjectType = "badge" + BadgeAwardObjectType = "badge_award" + BadgeGroupObjectType = "badge_group" ) var ( @@ -38,15 +41,21 @@ var ( CollectionObjectType: 6, CommentObjectType: 7, ReportObjectType: 8, + BadgeObjectType: 9, + BadgeAwardObjectType: 10, + BadgeGroupObjectType: 11, } ObjectTypeNumberMapping = map[int]string{ - 1: QuestionObjectType, - 2: AnswerObjectType, - 3: TagObjectType, - 4: UserObjectType, - 6: CollectionObjectType, - 7: CommentObjectType, - 8: ReportObjectType, + 1: QuestionObjectType, + 2: AnswerObjectType, + 3: TagObjectType, + 4: UserObjectType, + 6: CollectionObjectType, + 7: CommentObjectType, + 8: ReportObjectType, + 9: BadgeObjectType, + 10: BadgeAwardObjectType, + 11: BadgeGroupObjectType, } ) diff --git a/internal/entity/badge.go b/internal/entity/badge.go new file mode 100644 index 00000000..d310ef79 --- /dev/null +++ b/internal/entity/badge.go @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package entity + +import "time" + +// Badge badge +type Badge struct { + ID string `json:"id" xorm:"id"` + CreatedAt time.Time `json:"created_at" xorm:"created_at"` + UpdatedAt time.Time `json:"updated_at" xorm:"updated_at"` + Name string `json:"name" xorm:"name"` + AwardTotal int64 `json:"award_total" xorm:"award_total"` + Description string `json:"description" xorm:"description"` + Status int8 `json:"status" xorm:"status"` + BadgeGroupId int64 `json:"badge_group_id" xorm:"badge_group_id"` + Single int8 `json:"single" xorm:"single"` + Collect string `json:"collect" xorm:"collect"` + Handler string `json:"handler" xorm:"handler"` + Param string `json:"param" xorm:"param"` +} + +// TableName badge table name +func (*Badge) TableName() string { + return "badge" +} diff --git a/internal/entity/badge_award.go b/internal/entity/badge_award.go new file mode 100644 index 00000000..fe1dab96 --- /dev/null +++ b/internal/entity/badge_award.go @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package entity + +import "time" + +// BadgeAward badge_award +type BadgeAward struct { + ID string `json:"id" xorm:"id"` + CreatedAt time.Time `json:"created_at" xorm:"created_at"` + UpdatedAt time.Time `json:"updated_at" xorm:"updated_at"` + UserId int64 `json:"user_id" xorm:"user_id"` + BadgeId int64 `json:"badge_id" xorm:"badge_id"` + ObjectId int64 `json:"object_id" xorm:"object_id"` + BadgeGroupId int8 `json:"badge_group_id" xorm:"badge_group_id"` + IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"is_badge_deleted"` +} + +// TableName badge_award table name +func (*BadgeAward) TableName() string { + return "badge_award" +} diff --git a/internal/entity/badge_group.go b/internal/entity/badge_group.go new file mode 100644 index 00000000..14535299 --- /dev/null +++ b/internal/entity/badge_group.go @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package entity + +import "time" + +// BadgeGroup badge_group +type BadgeGroup struct { + ID string `json:"id" xorm:"id"` + Name string `json:"name" xorm:"name"` + CreatedAt time.Time `json:"created_at" xorm:"created_at"` + UpdatedAt time.Time `json:"updated_at" xorm:"updated_at"` +} + +// TableName badge_group table name +func (*BadgeGroup) TableName() string { + return "badge_group" +} From b70229492031fcf117e25aa5a50e5dc8a1a6dcd5 Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 31 Jul 2024 14:00:18 +0800 Subject: [PATCH 004/336] feat(badge): update entity --- internal/entity/badge.go | 27 ++++++++++++++++----------- internal/entity/badge_award.go | 14 +++++++------- internal/entity/badge_group.go | 8 ++++---- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/internal/entity/badge.go b/internal/entity/badge.go index d310ef79..0b296f61 100644 --- a/internal/entity/badge.go +++ b/internal/entity/badge.go @@ -21,20 +21,25 @@ package entity import "time" +const ( + BadgeStatusAvailable = 1 + BadgeStatusDeleted = 10 +) + // Badge badge type Badge struct { ID string `json:"id" xorm:"id"` - CreatedAt time.Time `json:"created_at" xorm:"created_at"` - UpdatedAt time.Time `json:"updated_at" xorm:"updated_at"` - Name string `json:"name" xorm:"name"` - AwardTotal int64 `json:"award_total" xorm:"award_total"` - Description string `json:"description" xorm:"description"` - Status int8 `json:"status" xorm:"status"` - BadgeGroupId int64 `json:"badge_group_id" xorm:"badge_group_id"` - Single int8 `json:"single" xorm:"single"` - Collect string `json:"collect" xorm:"collect"` - Handler string `json:"handler" xorm:"handler"` - Param string `json:"param" xorm:"param"` + CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` + UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` + Name string `json:"name" xorm:"not null default '' VARCHAR(256) name"` + AwardCount int64 `json:"award_count" xorm:"not null default 0 INT(11) award_count"` + Description string `json:"description" xorm:"not null default '' MEDIUMTEXT description"` + Status int8 `json:"status" xorm:"not null default 1 INT(11) status"` + BadgeGroupId int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` + Single int8 `json:"single" xorm:"not null default 1 TINYINT(4) single"` + Collect string `json:"collect" xorm:"not null default '' VARCHAR(64) collect"` + Handler string `json:"handler" xorm:"not null default '' VARCHAR(64) handler"` + Param string `json:"param" xorm:"not null default '' VARCHAR(128) param"` } // TableName badge table name diff --git a/internal/entity/badge_award.go b/internal/entity/badge_award.go index fe1dab96..01100b1f 100644 --- a/internal/entity/badge_award.go +++ b/internal/entity/badge_award.go @@ -24,13 +24,13 @@ import "time" // BadgeAward badge_award type BadgeAward struct { ID string `json:"id" xorm:"id"` - CreatedAt time.Time `json:"created_at" xorm:"created_at"` - UpdatedAt time.Time `json:"updated_at" xorm:"updated_at"` - UserId int64 `json:"user_id" xorm:"user_id"` - BadgeId int64 `json:"badge_id" xorm:"badge_id"` - ObjectId int64 `json:"object_id" xorm:"object_id"` - BadgeGroupId int8 `json:"badge_group_id" xorm:"badge_group_id"` - IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"is_badge_deleted"` + CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` + UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` + UserId int64 `json:"user_id" xorm:"not null index BIGINT(20) user_id"` + BadgeId int64 `json:"badge_id" xorm:"not null index BIGINT(20) badge_id"` + ObjectId int64 `json:"object_id" xorm:"not null index BIGINT(20) object_id"` + BadgeGroupId int8 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` + IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index TINYINT(1) s_badge_deleted"` } // TableName badge_award table name diff --git a/internal/entity/badge_group.go b/internal/entity/badge_group.go index 14535299..9953d067 100644 --- a/internal/entity/badge_group.go +++ b/internal/entity/badge_group.go @@ -23,10 +23,10 @@ import "time" // BadgeGroup badge_group type BadgeGroup struct { - ID string `json:"id" xorm:"id"` - Name string `json:"name" xorm:"name"` - CreatedAt time.Time `json:"created_at" xorm:"created_at"` - UpdatedAt time.Time `json:"updated_at" xorm:"updated_at"` + ID string `json:"id" xorm:"not null pk autoincr BIGINT(20) id"` + Name string `json:"name" xorm:"not null default '' VARCHAR(256) name"` + CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` + UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` } // TableName badge_group table name From a4830a4119838d95d012a66662b2145e2a4a0097 Mon Sep 17 00:00:00 2001 From: Sonui Date: Wed, 31 Jul 2024 12:49:00 +0800 Subject: [PATCH 005/336] fix: Update Test_emailRepo_VerifyCode to handle additional parameters This commit updates the `Test_emailRepo_VerifyCode` function in the `email_repo_test.go` file. It adds support for additional parameters in the `SetCode` function call, specifically the `user_id` and `skip_validation_latest_code` parameters. This change ensures that the `VerifyCode` function can properly handle the updated code format. --- internal/repo/repo_test/email_repo_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/repo/repo_test/email_repo_test.go b/internal/repo/repo_test/email_repo_test.go index f9f43372..62d1ccb8 100644 --- a/internal/repo/repo_test/email_repo_test.go +++ b/internal/repo/repo_test/email_repo_test.go @@ -30,8 +30,8 @@ import ( func Test_emailRepo_VerifyCode(t *testing.T) { emailRepo := export.NewEmailRepo(testDataSource) - code, content := "1111", "test" - err := emailRepo.SetCode(context.TODO(), code, content, time.Minute) + code, content := "1111", "{\"source_type\":\"\",\"e_mail\":\"\",\"user_id\":\"1\",\"skip_validation_latest_code\":false}" + err := emailRepo.SetCode(context.TODO(), "1", code, content, time.Minute) assert.NoError(t, err) verifyContent, err := emailRepo.VerifyCode(context.TODO(), code) From 95f20c9827af4222b50b42e8b57cf1070dac0d3f Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 31 Jul 2024 14:28:44 +0800 Subject: [PATCH 006/336] feat(badge): update entity --- internal/entity/badge.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/entity/badge.go b/internal/entity/badge.go index 0b296f61..7a375af7 100644 --- a/internal/entity/badge.go +++ b/internal/entity/badge.go @@ -24,6 +24,13 @@ import "time" const ( BadgeStatusAvailable = 1 BadgeStatusDeleted = 10 + + BadgeLevelBronze = 1 + BadgeLevelSilver = 2 + BadgeLevelGold = 3 + + BadgeSingleAward = 1 + BadgeMultiAward = 2 ) // Badge badge @@ -32,10 +39,12 @@ type Badge struct { CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` Name string `json:"name" xorm:"not null default '' VARCHAR(256) name"` + Icon string `json:"icon" xorm:"not null default '' VARCHAR(1024) icon"` AwardCount int64 `json:"award_count" xorm:"not null default 0 INT(11) award_count"` Description string `json:"description" xorm:"not null default '' MEDIUMTEXT description"` Status int8 `json:"status" xorm:"not null default 1 INT(11) status"` BadgeGroupId int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` + Level int64 `json:"level" xorm:"not null default 1 TINYINT(4) level"` Single int8 `json:"single" xorm:"not null default 1 TINYINT(4) single"` Collect string `json:"collect" xorm:"not null default '' VARCHAR(64) collect"` Handler string `json:"handler" xorm:"not null default '' VARCHAR(64) handler"` From dc56fce18a89e0fa2f1dfe89df65ee1c0aea5be4 Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 1 Aug 2024 11:19:21 +0800 Subject: [PATCH 007/336] feat(badge): init version update --- i18n/en_US.yaml | 249 ++++++++++++++++++++++++++++++++++++- internal/migrations/v22.go | 184 +++++++++++++++++++++++++++ 2 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 internal/migrations/v22.go diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index a123d70d..bfe53305 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -421,7 +421,7 @@ backend: tags_title: other: Tags no_description: - other: The tag has no description. + other: The tag has no description. notification: action: update_question: @@ -526,6 +526,253 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out [profile] information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. # The following fields are used for interface presentation(Front-end) ui: diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go new file mode 100644 index 00000000..20b1eb3c --- /dev/null +++ b/internal/migrations/v22.go @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package migrations + +import ( + "context" + "github.com/apache/incubator-answer/internal/entity" + "time" + "xorm.io/xorm" +) + +var ( + defaultBadgeGroupTable = []*entity.BadgeGroup{ + {ID: "1", Name: "Getting Started"}, + {ID: "2", Name: "Community"}, + {ID: "3", Name: "Posting"}, + } + + defaultBadgeTable = []*entity.Badge{ + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.autobiographer.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.autobiographer.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.editor.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.editor.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "question", + Handler: "FirstQuestion", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.first_flag.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.first_flag.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.first_upvote.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.first_upvote.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.first_reaction.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.first_reaction.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.first_share.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.first_share.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.scholar.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.scholar.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.badges.solved.name", + Icon: "", + AwardCount: 0, + Description: "badge.badges.solved.desc", + Status: entity.BadgeStatusAvailable, + BadgeGroupId: 2, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + } +) + +func addBadges(ctx context.Context, x *xorm.Engine) (err error) { + // create table + err = x.Context(ctx).Sync(new(entity.Badge)) + if err != nil { + return + } + + err = x.Context(ctx).Sync(new(entity.BadgeGroup)) + if err != nil { + return + } + + err = x.Context(ctx).Sync(new(entity.BadgeAward)) + if err != nil { + return + } + + // insert default data + _, err = x.Context(ctx).Insert(defaultBadgeGroupTable) + if err != nil { + return + } + _, err = x.Context(ctx).Insert(defaultBadgeTable) + return +} From 37981c139b04a70d29a459ab3737a0df32bfc9f8 Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 1 Aug 2024 15:44:11 +0800 Subject: [PATCH 008/336] feat(badge): init badge update data --- i18n/en_US.yaml | 2 +- internal/base/constant/object_type.go | 3 - internal/entity/badge.go | 7 +- internal/entity/badge_award.go | 2 +- internal/entity/badge_group.go | 2 +- internal/migrations/init.go | 21 ++++ internal/migrations/init_data.go | 3 + internal/migrations/migrations.go | 1 + internal/migrations/v22.go | 152 +++++++++++++++++++++----- 9 files changed, 159 insertions(+), 34 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index bfe53305..5cd06573 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -527,7 +527,7 @@ backend: tooltip: other: "{{ .Names }} and {{ .Count }} more..." badge: - badges: + default_badges: autobiographer: name: other: Autobiographer diff --git a/internal/base/constant/object_type.go b/internal/base/constant/object_type.go index eef952c4..e4ac3d20 100644 --- a/internal/base/constant/object_type.go +++ b/internal/base/constant/object_type.go @@ -29,7 +29,6 @@ const ( ReportObjectType = "report" BadgeObjectType = "badge" BadgeAwardObjectType = "badge_award" - BadgeGroupObjectType = "badge_group" ) var ( @@ -43,7 +42,6 @@ var ( ReportObjectType: 8, BadgeObjectType: 9, BadgeAwardObjectType: 10, - BadgeGroupObjectType: 11, } ObjectTypeNumberMapping = map[int]string{ @@ -56,6 +54,5 @@ var ( 8: ReportObjectType, 9: BadgeObjectType, 10: BadgeAwardObjectType, - 11: BadgeGroupObjectType, } ) diff --git a/internal/entity/badge.go b/internal/entity/badge.go index 7a375af7..976bb47d 100644 --- a/internal/entity/badge.go +++ b/internal/entity/badge.go @@ -22,8 +22,9 @@ package entity import "time" const ( - BadgeStatusAvailable = 1 - BadgeStatusDeleted = 10 + BadgeStatusActive = 1 + BadgeStatusDeleted = 10 + BadgeStatusInactive = 11 BadgeLevelBronze = 1 BadgeLevelSilver = 2 @@ -52,6 +53,6 @@ type Badge struct { } // TableName badge table name -func (*Badge) TableName() string { +func (Badge) TableName() string { return "badge" } diff --git a/internal/entity/badge_award.go b/internal/entity/badge_award.go index 01100b1f..235d369c 100644 --- a/internal/entity/badge_award.go +++ b/internal/entity/badge_award.go @@ -34,6 +34,6 @@ type BadgeAward struct { } // TableName badge_award table name -func (*BadgeAward) TableName() string { +func (BadgeAward) TableName() string { return "badge_award" } diff --git a/internal/entity/badge_group.go b/internal/entity/badge_group.go index 9953d067..3be4d820 100644 --- a/internal/entity/badge_group.go +++ b/internal/entity/badge_group.go @@ -30,6 +30,6 @@ type BadgeGroup struct { } // TableName badge_group table name -func (*BadgeGroup) TableName() string { +func (BadgeGroup) TableName() string { return "badge_group" } diff --git a/internal/migrations/init.go b/internal/migrations/init.go index a56216aa..40e9a91a 100644 --- a/internal/migrations/init.go +++ b/internal/migrations/init.go @@ -65,6 +65,7 @@ func (m *Mentor) InitDB() error { m.do("init version table", m.initVersionTable) m.do("init admin user", m.initAdminUser) m.do("init config", m.initConfig) + m.do("init badge", m.initBadge) m.do("init default privileges config", m.initDefaultRankPrivileges) m.do("init role", m.initRole) m.do("init power", m.initPower) @@ -126,6 +127,26 @@ func (m *Mentor) initConfig() { _, m.err = m.engine.Context(m.ctx).Insert(defaultConfigTable) } +// initBadge init badge's table and data +func (m *Mentor) initBadge() { + uniqueIDRepo := unique.NewUniqueIDRepo(&data.Data{DB: m.engine}) + _, m.err = m.engine.Context(m.ctx).Insert(defaultBadgeGroupTable) + if m.err != nil { + return + } + + for _, badge := range defaultBadgeTable { + badge.ID, m.err = uniqueIDRepo.GenUniqueIDStr(m.ctx, entity.Badge{}.TableName()) + if m.err != nil { + return + } + _, m.err = m.engine.Context(m.ctx).Insert(badge) + if m.err != nil { + return + } + } +} + func (m *Mentor) initDefaultRankPrivileges() { chooseOption := schema.DefaultPrivilegeOptions.Choose(schema.PrivilegeLevel2) for _, privilege := range chooseOption.Privileges { diff --git a/internal/migrations/init_data.go b/internal/migrations/init_data.go index adbe7175..f9a09f52 100644 --- a/internal/migrations/init_data.go +++ b/internal/migrations/init_data.go @@ -69,6 +69,9 @@ var ( &entity.UserNotificationConfig{}, &entity.PluginUserConfig{}, &entity.Review{}, + &entity.Badge{}, + &entity.BadgeGroup{}, + &entity.BadgeAward{}, } roles = []*entity.Role{ diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index 463f68ed..a32e851a 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -97,6 +97,7 @@ var migrations = []Migration{ NewMigration("v1.2.5", "add notification plugin and theme config", addNotificationPluginAndThemeConfig, true), NewMigration("v1.3.0", "add review", addReview, false), NewMigration("v1.3.6", "add hot score to question table", addQuestionHotScore, true), + NewMigration("v1.4.0", "add badge/badge_group/badge_award table", addBadges, true), } func GetMigrations() []Migration { diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index 20b1eb3c..d55a57d9 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -21,7 +21,9 @@ package migrations import ( "context" + "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/repo/unique" "time" "xorm.io/xorm" ) @@ -37,11 +39,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.autobiographer.name", + Name: "badge.default_badges.autobiographer.name", Icon: "", AwardCount: 0, - Description: "badge.badges.autobiographer.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.autobiographer.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -52,11 +54,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.editor.name", + Name: "badge.default_badges.editor.name", Icon: "", AwardCount: 0, - Description: "badge.badges.editor.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.editor.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -67,11 +69,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.first_flag.name", + Name: "badge.default_badges.first_flag.name", Icon: "", AwardCount: 0, - Description: "badge.badges.first_flag.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.first_flag.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -82,11 +84,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.first_upvote.name", + Name: "badge.default_badges.first_upvote.name", Icon: "", AwardCount: 0, - Description: "badge.badges.first_upvote.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.first_upvote.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -97,11 +99,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.first_reaction.name", + Name: "badge.default_badges.first_reaction.name", Icon: "", AwardCount: 0, - Description: "badge.badges.first_reaction.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.first_reaction.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -112,11 +114,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.first_share.name", + Name: "badge.default_badges.first_share.name", Icon: "", AwardCount: 0, - Description: "badge.badges.first_share.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.first_share.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -127,11 +129,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.scholar.name", + Name: "badge.default_badges.scholar.name", Icon: "", AwardCount: 0, - Description: "badge.badges.scholar.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.scholar.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -142,11 +144,11 @@ var ( { CreatedAt: time.Now(), UpdatedAt: time.Now(), - Name: "badge.badges.solved.name", + Name: "badge.default_badges.solved.name", Icon: "", AwardCount: 0, - Description: "badge.badges.solved.desc", - Status: entity.BadgeStatusAvailable, + Description: "badge.default_badges.solved.desc", + Status: entity.BadgeStatusActive, BadgeGroupId: 2, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, @@ -154,10 +156,101 @@ var ( Handler: "", Param: "", }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.default_badges.nice_answer.name", + Icon: "", + AwardCount: 0, + Description: "badge.default_badges.nice_answer.desc", + Status: entity.BadgeStatusActive, + BadgeGroupId: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeMultiAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.default_badges.good_answer.name", + Icon: "", + AwardCount: 0, + Description: "badge.default_badges.good_answer.desc", + Status: entity.BadgeStatusActive, + BadgeGroupId: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeMultiAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.default_badges.great_answer.name", + Icon: "", + AwardCount: 0, + Description: "badge.default_badges.great_answer.desc", + Status: entity.BadgeStatusActive, + BadgeGroupId: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeMultiAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.default_badges.nice_question.name", + Icon: "", + AwardCount: 0, + Description: "badge.default_badges.nice_question.desc", + Status: entity.BadgeStatusActive, + BadgeGroupId: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeMultiAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.default_badges.good_question.name", + Icon: "", + AwardCount: 0, + Description: "badge.default_badges.good_question.desc", + Status: entity.BadgeStatusActive, + BadgeGroupId: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Collect: "", + Handler: "", + Param: "", + }, + { + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + Name: "badge.default_badges.great_question.name", + Icon: "", + AwardCount: 0, + Description: "badge.default_badges.great_question.desc", + Status: entity.BadgeStatusActive, + BadgeGroupId: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeMultiAward, + Collect: "", + Handler: "", + Param: "", + }, } ) func addBadges(ctx context.Context, x *xorm.Engine) (err error) { + uniqueIDRepo := unique.NewUniqueIDRepo(&data.Data{DB: x}) // create table err = x.Context(ctx).Sync(new(entity.Badge)) if err != nil { @@ -179,6 +272,15 @@ func addBadges(ctx context.Context, x *xorm.Engine) (err error) { if err != nil { return } - _, err = x.Context(ctx).Insert(defaultBadgeTable) + for _, badge := range defaultBadgeTable { + badge.ID, err = uniqueIDRepo.GenUniqueIDStr(ctx, entity.Badge{}.TableName()) + if err != nil { + return + } + _, err = x.Context(ctx).Insert(badge) + if err != nil { + return + } + } return } From ecbfd61bac6573fc4bd56515eb9e10adb11dd11d Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 1 Aug 2024 16:14:07 +0800 Subject: [PATCH 009/336] feat(badge): init badge update data --- internal/migrations/v22.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index d55a57d9..b0016671 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -180,7 +180,7 @@ var ( Description: "badge.default_badges.good_answer.desc", Status: entity.BadgeStatusActive, BadgeGroupId: 3, - Level: entity.BadgeLevelBronze, + Level: entity.BadgeLevelSilver, Single: entity.BadgeMultiAward, Collect: "", Handler: "", @@ -195,7 +195,7 @@ var ( Description: "badge.default_badges.great_answer.desc", Status: entity.BadgeStatusActive, BadgeGroupId: 3, - Level: entity.BadgeLevelBronze, + Level: entity.BadgeLevelGold, Single: entity.BadgeMultiAward, Collect: "", Handler: "", @@ -225,7 +225,7 @@ var ( Description: "badge.default_badges.good_question.desc", Status: entity.BadgeStatusActive, BadgeGroupId: 3, - Level: entity.BadgeLevelBronze, + Level: entity.BadgeLevelSilver, Single: entity.BadgeSingleAward, Collect: "", Handler: "", @@ -240,7 +240,7 @@ var ( Description: "badge.default_badges.great_question.desc", Status: entity.BadgeStatusActive, BadgeGroupId: 3, - Level: entity.BadgeLevelBronze, + Level: entity.BadgeLevelGold, Single: entity.BadgeMultiAward, Collect: "", Handler: "", From 4a07fdb4a8b180bd28684e54c66a3a7caf51bfcc Mon Sep 17 00:00:00 2001 From: Sonui Date: Thu, 1 Aug 2024 23:53:55 +0800 Subject: [PATCH 010/336] fix: set last answer ID to zero if no answers --- internal/service/question_common/question.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index fce3761e..b9f2fd53 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -145,6 +145,15 @@ func (qs *QuestionCommon) UpdateAnswerCount(ctx context.Context, questionID stri if err != nil { return err } + if count == 0 { + err = qs.questionRepo.UpdateLastAnswer(ctx, &entity.Question{ + ID: questionID, + LastAnswerID: "0", + }) + if err != nil { + return err + } + } return qs.questionRepo.UpdateAnswerCount(ctx, questionID, int(count)) } From 80f139ef9ea7bd4da6376e1d7f9c70b603292c53 Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 2 Aug 2024 00:01:01 +0800 Subject: [PATCH 011/336] typo: GetCss swagger annotation content --- internal/controller_admin/siteinfo_controller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/controller_admin/siteinfo_controller.go b/internal/controller_admin/siteinfo_controller.go index 623ab5f7..6429d671 100644 --- a/internal/controller_admin/siteinfo_controller.go +++ b/internal/controller_admin/siteinfo_controller.go @@ -188,12 +188,12 @@ func (sc *SiteInfoController) GetRobots(ctx *gin.Context) { ctx.String(http.StatusOK, resp.Robots) } -// GetRobots get site robots information -// @Summary get site robots information -// @Description get site robots information +// GetCss get site custom CSS +// @Summary get site custom CSS +// @Description get site custom CSS // @Tags site -// @Produce json -// @Success 200 {string} txt "" +// @Produce text/css +// @Success 200 {string} css "" // @Router /custom.css [get] func (sc *SiteInfoController) GetCss(ctx *gin.Context) { resp, err := sc.siteInfoService.GetSiteCustomCssHTML(ctx) From 5383b9058101974b666332388ed4f658b5f712d5 Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 2 Aug 2024 09:33:48 +0800 Subject: [PATCH 012/336] perf: optimize search for unanswered questions using answer_count --- internal/repo/question/question_repo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 5a683af7..83a84157 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -385,7 +385,7 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, case "score": session.OrderBy("question.pin desc,question.vote_count DESC, question.view_count DESC") case "unanswered": - session.Where("question.last_answer_id = 0") + session.Where("question.answer_count = 0") session.OrderBy("question.pin desc,question.created_at DESC") } From d055507c800ac2a877a8329a366dbbda124712fa Mon Sep 17 00:00:00 2001 From: robin Date: Mon, 5 Aug 2024 14:29:22 +0800 Subject: [PATCH 013/336] feat: Add badges to admin --- i18n/en_US.yaml | 16 ++- ui/src/common/constants.ts | 3 + ui/src/common/interface.ts | 2 + .../Admin/Badges/components/Action/index.tsx | 51 ++++++++ ui/src/pages/Admin/Badges/index.tsx | 122 ++++++++++++++++++ ui/src/pages/Admin/index.tsx | 1 + ui/src/router/routes.ts | 4 + 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 ui/src/pages/Admin/Badges/components/Action/index.tsx create mode 100644 ui/src/pages/Admin/Badges/index.tsx diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 5cd06573..f50465c2 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1692,6 +1692,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: Flags settings: Settings general: General @@ -2117,7 +2118,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 - + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/ui/src/common/constants.ts b/ui/src/common/constants.ts index c846d4dd..d52f2b87 100644 --- a/ui/src/common/constants.ts +++ b/ui/src/common/constants.ts @@ -93,6 +93,9 @@ export const ADMIN_NAV_MENUS = [ { name: 'users', }, + { + name: 'badges', + }, { name: 'customize', children: [ diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index ff7c0902..41dc0fef 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -328,6 +328,8 @@ export type UserFilterBy = | 'suspended' | 'deleted'; +export type BadgeFilterBy = 'all' | 'active' | 'inactive'; + export type InstalledPluginsFilterBy = | 'all' | 'active' diff --git a/ui/src/pages/Admin/Badges/components/Action/index.tsx b/ui/src/pages/Admin/Badges/components/Action/index.tsx new file mode 100644 index 00000000..77601cbb --- /dev/null +++ b/ui/src/pages/Admin/Badges/components/Action/index.tsx @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Dropdown } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import { Icon } from '@/components'; + +interface Props { + badgeData; +} + +const UserOperation = ({ badgeData }: Props) => { + const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' }); + + console.log(badgeData); + + return ( + + + + + + + {t('active')} + {t('deactivate')} + + {t('show_logs')} + + + + ); +}; + +export default UserOperation; diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx new file mode 100644 index 00000000..28854012 --- /dev/null +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FC } from 'react'; +import { Form, Table, Stack } from 'react-bootstrap'; +import { useSearchParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; + +import { QueryGroup } from '@/components'; +import * as Type from '@/common/interface'; + +import Action from './components/Action'; + +const BadgeFilterKeys: Type.BadgeFilterBy[] = ['all', 'active', 'inactive']; + +// const bgMap = { +// normal: 'text-bg-success', +// suspended: 'text-bg-danger', +// deleted: 'text-bg-danger', +// inactive: 'text-bg-secondary', +// }; + +const Users: FC = () => { + const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' }); + + const [urlSearchParams, setUrlSearchParams] = useSearchParams(); + const curFilter = urlSearchParams.get('filter') || BadgeFilterKeys[0]; + const curQuery = urlSearchParams.get('query') || ''; + + const handleFilter = (e) => { + urlSearchParams.set('query', e.target.value); + urlSearchParams.delete('page'); + setUrlSearchParams(urlSearchParams); + }; + + return ( + <> +

{t('title')}

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
{t('name')}{t('group')}{t('awards')}{t('status')}{t('action')}
+ badge +
+
Nice Question
+
Question score of 10 or more.
+
+
Community Badges200Active
+ {/* {Number(data?.count) <= 0 && !isLoading && } */} + {/*
+ +
*/} + + ); +}; + +export default Users; diff --git a/ui/src/pages/Admin/index.tsx b/ui/src/pages/Admin/index.tsx index b527088f..5da0780d 100644 --- a/ui/src/pages/Admin/index.tsx +++ b/ui/src/pages/Admin/index.tsx @@ -37,6 +37,7 @@ const g10Paths = [ 'questions', 'answers', 'users', + 'badges', 'flags', 'installed-plugins', ]; diff --git a/ui/src/router/routes.ts b/ui/src/router/routes.ts index 5c420e36..bd4a0c79 100644 --- a/ui/src/router/routes.ts +++ b/ui/src/router/routes.ts @@ -400,6 +400,10 @@ const routes: RouteNode[] = [ path: ':slug_name', page: 'pages/Admin/Plugins/Config', }, + { + path: 'badges', + page: 'pages/Admin/Badges', + }, ], }, { From 027caa650e55da2e85999d80dbeb5ed54b9d1510 Mon Sep 17 00:00:00 2001 From: EkkoKo <65719025+EkkoKo@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:58:06 +0300 Subject: [PATCH 014/336] Makefile: Wraped with quotes the go location in go variable --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9cda2f5e..9dc8c983 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ DOCKER_CMD=docker GO_ENV=CGO_ENABLED=0 GO111MODULE=on Revision=$(shell git rev-parse --short HEAD 2>/dev/null || echo "") GO_FLAGS=-ldflags="-X github.com/apache/incubator-answer/cmd.Version=$(VERSION) -X 'github.com/apache/incubator-answer/cmd.Revision=$(Revision)' -X 'github.com/apache/incubator-answer/cmd.Time=`date +%s`' -extldflags -static" -GO=$(GO_ENV) $(shell which go) +GO=$(GO_ENV) "$(shell which go)" build: generate @$(GO) build $(GO_FLAGS) -o $(BIN) $(DIR_SRC) From d39c12f8f13c6a22509c77949a103b4ca20e0ecb Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 30 Jul 2024 10:47:12 +0800 Subject: [PATCH 015/336] docs(docs): remove the images about installation --- docs/img/install-database.png | Bin 13214 -> 0 bytes docs/img/install-site-info.png | Bin 43093 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/img/install-database.png delete mode 100644 docs/img/install-site-info.png diff --git a/docs/img/install-database.png b/docs/img/install-database.png deleted file mode 100644 index 09fbf36a18bb039cfaec997dd76fc6e4b9c12599..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13214 zcmcI~byOVBv+n`{0zpC`I0Sc>;O-D45M*(;#Vts%KycUK8c1LlSsa1|g1ZbJ90H4z z#RHG;@BZ`7d2-*CcTP>$r+d1qYO1DtS|(acLkSm~92*1z;i@RhYlA>&00@Md_7v^0 z1enm$dCXX7y?Lkb@bG{{B7dLUgZLlz4vxoWmS`DSr>3UJBHumM6c7?~@($wQ;U{`Y z?D^hbQ(Ld?d;8tp-=^jkYdgsO{r&Rt%7@_4`i3S2Wwo=jb4gi+qoX4`M>hdcnXK&G zx%q{)wY8bq*`1@i>)1WlMi1i8b0Thr)7Nh4g3`RF}$#-B(I>*FCcJv>$LHEe|tw~ zVOdRdY&*&PH;P5yX--q4(!|mVz56Bd!kE_~opd=M6wq7;7!3H$VW?;#@L!O;HU?EGPK>mecI;eE)1 zobCgo%)|2j*5Tnp$=8Rjf$61{hk@Y-9gBzOLJu>ubLrg`h@;c;;b!-$c(c+Fp=9f7 zVPPc@i04X0Ugn+e;=wcuE(nCvQ@Gl>cWvK=b}1bPB$Wtm+2e{B$|d|a!MH#%dk6Zb zJ;Gz2e&LMuMMbl^_S%+C6pTnB`2iVwL-IF8?enVj0?Maai`XxEb+W0S6usw`@IQZk z7ao6na1fWH^^}P6$8B4dL_z0mv8I1Y6k5$Rsp9TO_+dn_sC;&vC~dP#vWl z6;=Le2z%WuTm_T;=HLK?wrXyos;aBi;prqtvqWg?OhJ1D3cYc@l$C-pzqKht$W+x; z>hPve^4QX{6KttU=|wqN1gS*|Zp5B^J%R6F`8F ztPz<+!G-_A4Xj)>a;MY}C$<5Iin{PYwx3~@i>X0z55O#iz4A5=*KHeDntj@p>E9pAkl&li)PF}a8#cqUDwRy6dglV$V)1x& z&MQ8SU5qi4O&MKyly6IwP50B1V zM#v+@i|tMW;$}QNoGzngpmIgvNL%Siv>HAOv~R#T9wsbrD5q+E#iGtizQFlL_%|Za+|@-oqn%6UOo$W@q#mkx|fmJp^qoS z;n94YJ%fz+}?cOZo3f9qeK`tFPpJD$E%QuCWGDVB{~9?w12qAeUR# zd4SmR1hl6V9Qo6Q@-M5-(nr}b9b)e+^z*4 zkpM6RvE?wRZqEpo}@ z50ma`8Os?@W<~lQNm&Qi?|N)d#o&XC0VA#T324~V*a6z{^y?jYqRzF2!YkSyp_osi zP!D9pyLjPUDUa&Gi4)gj1fRS~+&g>dkLh9-kaC@A2=-$X(x_spYfP<=GaP{1lkXS! zVkMKyeGJ3*6$>93jD2DqS#)v-crV7^Gu(8AGJ6ZcK!Iv~q=Od_}O7KNy%b^11Ez zj+bu`MM>Yn-_g7*PeNTd1bN>0m@UO!vG(TSv@SRX} zsddvq$J&P@R(4-krcX%?bhd5+H~Vgu2{=u&J=tS74!x|C#(vScM(^7YZQ@W(#lfn* z#QcYX?KnG9f|e{dRE5VjoIwU*ac+Q*YbGIb1;u5V+%RK0G5V{eP)OQc>NVH+N%m7P zA{_csWH*v3iD1AG+T^!*6vfoBU^J;K_Eoe-if=H6WZQeXc!%77uWHB2$mq`E`x zLg$%XUITUQ@3$KaBE8$1LgBLXe&QW!uGznA31(UTO=N8W)eKSmOweyPpkOryPb7fj zLgn+)Y*^I_nxporSzT($MrjJa^I6f#Ur1t9QiH~TVJsW7r~qtqLz0PL$Uj|ykqJQ( zE0-;7jIQuSQF6-gJKiPAUN@Hmk`Oe*zd3k=S z#_&zL`;q7-#g99PH_YFwQuQHad+oc^TYm$oM_tNo@+jTQ;$em!xhnXa7Co&K=c$A zS?zU+oa)kg90>)(zdRO6&Agwsn{fEtjt5dJ-tTZ($-G6eIP9je#0g9%xQN(X#)^>s zORW|kcUp^MvQTf!uw|II7!w2%u$~V)a*Lj-xbRvLY20)ogYh>KCt7(BkBkawJpq%< zm4vPPo>Z*nt`-J2)tcP<^Ur^;1fI^w0iaJ|P!w!TFd7ja9D{|@8dpnrfV|KxNl<#7 z1`_f^=6|X%=6bOwjqy0?G*9Y8N_2QAL*^&Red;5qU=~XMZ7^@X!D<@gBPgnP*WNOe z+l?VsVR8pU$x&M2o7bGV!EM5NJ9Q8b4?IHjKS!N|{v&^h*Fa5y2~q?8;%Jn=MfB_f zHP5b*r}H7fkCWA#Hy&m=$TwB16mFlJAbk3^ftouuXn0;(gMlUhy`OVew=G|W&EFAZ zAR3-e%T5a$B6)t+4b^qfAPqUvfx=v4$2H{N1YM^zT_CXu9G(v$ByHgw5=XhAo6KgO7I!aG_^<3__1Z-5R8s4yNc%!=s=?JY z>VIBz>I7X@-3P;|?b=MPHsuHP|7j=;h9u+oKTFa{OhyWR80s)sinPF~c*yg9BJ0ok zyg2DqIF#9fRBq?7&$AH^$~_tZl1mlrSSZa4%@}ZT>g1G-Zke<0_Fj>{92s78=eFZk zn)DE8{m|ALlCigZp;*-(e0kzy<=qhsJgYK#@*;F$@N-yM^x#sMv7wWRzGUlBtH+_k zoC#=ZA#?ba-hOc;!&YrUoirl2Cq?ih1Da^IJDV8qQ>XdE{5|Mu8B6?b;pp7g`OFDP zPHn$wmOw#;?H;dAX#YU`7gp78r1fVMs-Irf3^Ibo2f?7>t;{!3DOBM*Gn}e=5;#34 z4!-a{BC<%guCmPpXq&CS=wQSv*!cM(M=4Z2G4InmyPitqJ@{C0Z_7!Vc2rQs+L$6R9`)Oo7$RSEEcp7y;(eNIp20b(#qG7ho0 z5)c4qdIzQV^kA__>1M#70i!Ivh4RY8pIMQgY6+20sWCp3IxxQ{Ywa26~%U!}< zYAL|XH1YFWY)M2pyevx9t#ziK;EGkCE7dYZno*@eQJkJk+96RHc--qHwn9Ci-Ik$K zR&90lvQJrUZWP z@N{&Aed$zxr)T!wW<`P?{K>A|`!3tKfMWD$A47e451s`5BE_ZHYdHu(F8w>z2@* zw31!1U`4@mf6Z5 z0O=`M9~4!aeHT$ojXC9H2T0gC*+ioHJ#$LF7AOtOYhV_?`LuJaLia+0gQ53`!wZaFBClIub7=pFc&=epQ)zGis~u;?~IU2P<-mpYP!kOs}fA zOB-lg03{GK%dx}>Q5yDli4iT7=3n760xwA)lYJ6X9wQ!Pu+0W1zS)CH&GdPU@|@q8 zCMRk!U0i77V%i3(c(Cu#cse0R{S{UuOWqtEnsoErkwrkuFX^3@2f%55!>`zU=uI-M zXZIvZ>R(|@nW=Q3CA~;h2SpQk1MX9LMQyLIsppqzv(kq@B&0C=ngh*6=EJkk{=)O= z$p$=Fx8fCPcLrV1HIuue!GUAt%Q#x&+wNBOe`z+)Dd5-S&_ur}nfpvJt za0@%Ci1lg0v73neAC`wMgt+JKMhb!+()ltTM;Bf;k1_u#A3inis+G(BGWbv@i^Df^ zqA|vw5zU#axTiB)CQ_j>0Dmn`Jfv_F*0V{(@7z@K9YXCrSBO6FJk2Re`wtCP&&eLE z-QR%mi(N`D-1>Skpi6~bSo1$|Xbyd?K4uM(fx{gjRvA7)657zwD zra8XH+=vzh31ai)+D{Uf8Qx3#x+ug(4edwlhziH64#c7^FwOIFjh(Y3AMRpxSRDj^ z|G?!OjzZdBfOkohU@k#uHQT82m8tQ5pFxr3?bq3Gwt76rT7qCL(I{t`QmW3?Ic>nnL*#T*uWdLjDgOgku2BkdIw)$H{B)=_ zpjvwcp=fY=Y2dwW(%p^p89fSl z`P&W%%vUrI#l4`oI!czX-}sYU=hkj$_VAQo`X>`&)TT9K+Tj>!N+9^nr1iyM@}Flw zu34U-ZGL=p_pHjV$f!NbR3z`KENaAp@yDjhjTT=xyZkimD;l@u_;DI;eMXV3 z%e@+(Pb=ac2$)4qSzFrMv!DqNGh~|SuQGp6Z&UWVHi?uXOY!b5WA9927c8KnP^vRc z$wI*KT(i`9Ny!^mc>nH)$Y+^(oCnA?j)XwfSFaQa@=eYpWR+c-GLRfu5xYsH7o!YQ zcNrANZx*oLzZCVQJ^Umgoj}ve6ks?cs>b(hm9GUYndO-yo@snb_jZ;6S=>Xfw$!iZU zQ@)@RRcQaj-olnCw)J)kZ*87rX+bPC^*V^i*@J}B%m{(v6rH)4^|o#-T#A-ij#;HL z2sY9!_?ag4+cATk%aA{TU=IWTb6y=|_z^=(e3zn|W4$!om9)w;rH%H#9Nw<&_`$Zwy0Ov;kIv$$^Um_u}1&-O%etTE-^yvTtj z?^(&AOWGBvzp%GnsR0Jam5|KMuT#JCl#lZBs(pYfx+=BzaO?vZ^Al*A`J;HD-e)3? zx#zPq5MjAg=pe!m!mAz!$B0=<-`q{F6?^J;rr7_q`w8k(RT2hJrpjRebr4&gz;|yO0c}8Mwj71~Lq%B;+@-B*-FY^E zf*sMQ=Y1(CE^t}V5TAi;n48U9FvDK{lb2~arNiq=LfkV8^HFatHRfVun2lKuw9@zX!b!7RF;=SWxz# zx@M05IO+O*?>2{<)?MH*@=LzGG^vCFQkZFC?Va^>@43ozg8Y33uXCUX(xmbClf?ON zt7&L0>Gr|ErFT{jNoQhaQyhQXA>~+hZC($UztK||5n`A{8rwWzv%)K?aue(nda+O1 zSL{#;E{|h8pC#E%y2lQQ{4-8T8bmw^>JkdXv6`%(g}&M?aQEb2&;Xe3s-h)9 zEbaiu;*SACH39o}Qnwe1K!E%<)K4K-Ft*XzE|2D$UKEwI<7y-{ku|E$mViVNP+bMB zc>r+)hi`yCx}aj2XJ2gF#l)Ezokv3wY`|aEoMw%dv&+iv(aa8B?)oGIsfez$ZsJdS z?0SoN+5z|+m6QXbR&%>m3ULaGzTj!e5K_N{H!S1R3^E9GyVfR)m(+wZVtehW4 z`pF3$~P#MMI? zCmF_{7*@i;Knrm_7cVich3#K*o-IZ+KXvh?2M&-xRN2obG%-IdZ!X>_tx_Z3DBGl* zf#56iTSOt7oJ1jCFIU@zLfBMZgLtWtTqwCzE-Bv2w*xk=0>q9&R>{w80XdMnZWBw= zJK~VdVCzN~jJ-d(rR?0t+u5Wlns3Y-Dc>o#n${a2KzT7iJ&m0zfOjCK*6WZ|IZF=g zA0s!G$!4qGiOSa~BX{8H92wQr6c7y>ce9Hp(lxN=iqls$X0uhKL4%{Qcd1K;261P^ z87PJT_9=oftDq{lO+3pEjQ|l}#Gfu=aiZ_AQ42-2t^Bnh}>ljUp;N zLz_<-_FPqQN#QwVtB9BP-fuJe<9y1NX$tMgzOY?>^dP^ij;-w@OU53KIxZB>PY2R$ zx!%hdcS`LMwl{WI$NgsjSg!l;hPP&vL}n>@@jKA-gx4t6ZtEN^OGDhB_C36rJx zQPEbE0CGr=KH2u%^|gP$^?DpqJaV~-tdm!(;Yr_nDOt`_Bk^ZD^Xbr5^B|S z5?Xfa#&ife`i<}@>%dKjD@UMX7Mi3`D%zkUf>n?zp$2FKUAmsX@ZvSq3?-q;+KVJA}ytq+~{`2 z%vahby~DipL)yLWBFYQWE2Kj3Q`nLglipRB!?{8bksTX9lpIQMXX;YMUUf@14cvh2 zDOD>vYFwA~ESJ3jVIdxj*fSy&=1Vv#lZg)h*kyn_#af7tFZ!DA_ymf5uJaFJ1ZT*v zO-p-P!gli-UZOy$?Op(MutIBt6&P zC_FEDmmzNV&E}PiEkxw2?S>-id3yrR|KpAS zyVtp^O&f2#n*Dl;B<4yuVypWTch;Lv5X2tv?VpPe?DgNYTkeUSZ-h4 z)c9gk>bl@$Hb@c{wV(RMY1!7P{sxxKl+ik@tB|&nIgHIJg~-qRqnV+1a}DQU=e5%I z1&RLmR{YDnE34f*aH`6NFka^o`+`Afa+2e-C2MaIv>(J(4zD<8FsUhWbG7yQzOAW%{&MM?@MP7;<7VD`#5tkgp>`3wy83hwa~hDFOI1`PBdy6-#(UfRDpuxTMr zxeorg+RiXkH5*tI#oZ(05QrW(NP}ze=RGN!%3>Ii8|^ck3%48Ab(9*@m86jee6lsw zG!UHV)JB*E#<}J$1*7<)9TudXZ?a?rA?c!k`EsWVOS2q8?8kDGMs6RCJ8h^pMa^h0 z07wotx%c3Z0LWpce>sOEesj6m$=L`!a-jutEr%+_Pl^sk-;oAzo#fr)!bn2wj$sX! znSd3DlQ#I4vP(ex+~uDN8GuwscW1FTVbpXd49U#HP-ctr-gt)QWyS5$eQR=R5Lv@fr!mkO$b*5#K%3Ybz3iHf9Y1|i?qPAk3SS4 z0n{VWaG42o?NDLck2`J?EJ@ZDpHrVyjgHt#4_ZAJmREQ`&oY&5$P-jB<}^m|MAuRn zs}ASmYb@;P?i#YB1zp&=WbPzJX9`&d=Y3%VVKZx!20{Ngii5NfSsKk}`ZuDz`#UzccS*4>;A2p{|(`2^#WBpm+iq&PpZN&h=bb zSxsoz95gVGpLIjMugpED=p0e}ESV4;{%0Rdxw>-SIIPTSjhEbSsB+@y(8Q7q3s#8D5+Qs;)%Kzc0u$B zBJr-AQ_=1j!xffY)aJ6N%^kOTJ)K=feAhP$4l6FNl@hAL78?QAQClCF0eBe9>`@rZ z9ha@+ml&hV7@9i&1u3!iMaA3C5*4W-cXbP0sQ^BiH7 z-#mF}4R5oWF+ZuXs}42%!1^qoO7#YfCCL&l2f;V;8Ys*|)iSjE=gAzLvu5~`OboAM zD%Q-^MZYjGdev}b;wr?qvR z6Q+*yz($8hrWFwtMgIA83E5$jtwk3}sa=e$E?)o?J>y_&#p$tv`YNmPb*0=zQ93h8eLu$qpqt>N6# zZ&rMRD(zpp4qF%+Nv9H#P{4*uebH5k+-E4`0LH>ELmj+qh8~?l`sptoR1jx7uWl&a z8Xy>-YS9f|BP3^Ats(*DuB67NN5^(MgqCD^A`FjOMmEr-wK-!e8P`5x9!(M{51zOU zJa$yOwKSsCcz}$4IqBb?r}~cZ9%H)c=7+{#fjbRN z|2jO^-crJ73MCg?o9Ok;`Z3BEJn{$`J`vMu4)M3dq2c8EW){eG5r*mDo8DZe7bS;P z#A@DF*+D6c2@QaM{`wnVf)|f|iviM+&(oevoJAk7rak(QIj&;6s3FKsXI9yGuA*De zIAG>>wt@dzn_T)bISO0o>2&sA+0G&7@T-?bI0qtYiYrUAoQUxi9$x+&l%9qiU)+wq zUav|ny*pz&&3!vn_Z4EfE2@IxqoL2mSHYRQ;ENhjK>&~&qePe+I#|dZt?$i)dLS4yg@DAuvxaW8m+3( zx?RD|I@G;;m%de$e%BZ5sMG82$zmAnLL5$opJEJlbe58KN3g=2iztK~q}>VZ1gS&t zEi-uSwej$~^@FdUWC|y_npnLD(sa3=WsgI%{KOvLp?Bb>3-TPs2iFR`XT$Y`6TNwy zuxAqm-|-8Z$(-t|0+I}*ST_blp2GsIO5$Sto~m*u-kkp2!Ai8Sf&bZ5;SRH7T>kL! zrOBKIYL!pCyS4+|`sMS$lkPZk^XtIN*Frr2R#hQO6}fS zPa4C_&<+Q`RvoX#cKm(x#WF45w{#;2-GJMh!f$^M-VJtD`RvQ;0HQ?9Mkn5zjQX!n z5%H>vc*7$o?7peo%*vhqCfMEH_LAmkQb?L|x?tiZ#ZQMs%~hd3x3MX5DnmI$mQ@{1l;L47w1xE`#0r2uIb_?7utEm zk7lwn(h3;e;IB5^m*O=Uu1I+e~;R^so?OUccY- z!Nys^@nEh?K`k}LZ+H<;#kt&R&0_c$1Jw>UWVjM!TyJ~+xdF_z#0tU}ZAuxi&(6nJshz>-93bx+bZtDzNhu4)o z;)*Ikm?5NjufOVVTRlOaJLN;#ZbaCzmm6JC*e5)61x(g-=|Xp$y{#jy8aWK1wkT@6 z*EAB8*|O_NP{xtBJ#l*k8>k!<^@ z##t68en|0B%6D$az#~{+&?%|uhek(~S11+@{lmX177aXdrFe`wCPyn^Bs&UBxTmP_ z0~-B8{@+Q9WdP>Pxz15xJ}&4`_lJ*QaQm<;4MXOeeI zEzSWI(-H%s9ZP(;bs9xEnpIDJZBP7pYuuI5sGwC3kERoh1Q%F#^9rt-&AKy#;B+s_Jq+yi=X!>uS{g;<11+Hni=Z4CY6m z*#1@B5|s7aSd8yUkHFI62J1V~=-jd+te({*q*a5~&PUU#BITAVm|Sga`*MrOmTeSz z14BX>`7l@gdA`~a>xHGB-{1$lKc3Pf>T|!t)QsrjN9RhL`l%hGLsj}zR$7c$Y@sD~ zzMEL6jmVv!2AAv&tyV8gm0UULdscW9`QGa6R!1&F-@ZD{7WLV!lPX`3hzR#(el0u$ zdpTDfpa@A#&woe8avLai%@z{#iGBSvDt46YuHUwE1$`E^b*f^?Whb&?xbOrVAW||p z-s*AzU)eCaA3yfT6^6Tqu~WO(iiAb}r50AvJGrbJm*nnFH_$VA5})eLj>VwLgkVS- z^k?g~1QSaP64xa>9^YHHf7UbkcK`@416jWT@FE0mVmC4MsFk9XjGe~T zXqg>mQ9o!HUh*E~?NhUO0ZfbWG!UFhWlb#U;vVRxyRF10sM%qKq@4NW!zM%KEl4w= z1bGF1?-(+DkO*WIAJ-dt?%;FXe^+vnr&*#QWzmheK>jr=98#Z*I zDs~)OtDtdOcOb;+H@WD{4++KrYPI+H&ys5>G${(8hviV6^6*d5;!o2vNDZY0Q3v zA*j4&_o*H?fv?=Ca@euN_h9=Jq(<-63W%i%Z8?=>01uJx5EDG6*@ZPi_5Nb!<}2Ct zr{MnSDSy0daRj*=t0KF@&e$yEkFc1Z)LBHc%g5Q1C5rxHXi2*xaSnZ@?_!K2-XGzt zk)O_+G~9{5x6V1$b^wA`)mGPPr0r_(USqng(I9cnnV6p-Ok*&Hl0oErlAz1$ZR;)6}QTkbM@=uyIvFhUx>|eq6 zOxIRjK!Sqr8O1+&KE7uU^R-s=;T9~|AA=Q91fOeTp*J%}V(Wf1qVWhOl6G`ht6l10 z6tc!8Jaleve`N8$^bm3Y&+Me0m@06xUS7SR2ai}t_yz1K4U+Fr1Q^-8VuTo2I_*|A zwcH?<71N>XQiJ3h1OEjw{*0^(;Xe7!f#^Rp?aDC`du>7bw3x=9;_o~SdP2BC_{X2$ zwA(@|f24mUL+%k%a^xE9AbA#+yL2GhKwSdH8V25|3OMrO5%?%*16+aRA?v0o%r?#@ zb2A{E*CzWJ=?!XjXgu?*euhA!%BejF!#}(pYzh!hS>kr_tSVp+k1W1cQ4==9=IL6p zO0EaH06QiijD42{aE{+dB?zZxZ2h9z78FAZDWrsB4E-P2-C{W!+2ihDh|E23c{N1) cpZXUOt4XkddA&E}UuQ-t3L5fNvgRNE2XLVHF8}}l diff --git a/docs/img/install-site-info.png b/docs/img/install-site-info.png deleted file mode 100644 index b8166caf426bca8f51a475b8c23da10617761ed1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43093 zcmce-1yG#NvnaZF2o?w$+zAc|Zo!=pH0VNbcV7q+T!On3f@^SDEVu;-5^RwLf-dZ0 zi(dY}^QvCeIq$u5?tSOps;|H4`o6B7neLhHneLfrO$|l7=dYdv002B?B{?ks01XTP zU@kmEd-_r=l~V!$poVIy>Bv7mK3-g0{5^e``n^KW{F)+CXLfeh(JKh>=5hZB_C)OB z8*+dD@K#v-^78WT?tW!;jg$8+5{bOIx!u^@+CMm)n*Hq&@MUvrySA?WOGMPw)%DTw zao^yGww~ed`Nj8IdR<-Mn7D-brRCZA#naO>Nf`xCAOG*w4Zguqf#LD7DcOnXc^1}o ztLqzkdw)-0r{QsFBO{}&ZS6k?hk&1~s%vWHmDNs8PQqf6MI_!qp}U#+rI9gl0b#Lc zXYlmg5*c~r)bz~r^YgOuiog5&)4ygMoL$?xdWS|QyZZ*~n%Z`D_kJ`rFE0I2R?~#T z5%mo}`uYZ(Ts=GkBl1fs$ERl8y?pcxjB6TO!9BhHfx&AK$mHZyaOjuZ{6Ylcys5oA zJ2yW%G1JA}du)871Ki)(+Nq|g{m}^M`$Qd;SYFdOGBMrwqbVypx3scu;@8~b@@i2@ z>9^9d!tYh_Uz7R<1~W3VXJ%(j%q*(vn?avL3{A{dH?}IOs%`9@TRMAEvI?zi9de4w zl2g)faq&i`SBObS6OvLOkd1<(;tlBE>EA2UbMp<&9jRGGdk4qcP-s*_dPirMouf;0 zOB-bS@AC4>8zHgc@|vF`<6HX|6}8PfN4I;hyMx1{!;>>FU(nU{6heCT_ia&W+OUex!#M-#Re>Y3WR3rADEY1DJJhGqP51Zl&>Q`xk1Nnz6}U7@ z)^Z;HpQ1}u7U^G#dE>UlPiIel6@Gyxt}uT{(flUufw1Q8n^ci0GJJ)L##;1xSo735 z2t!I1SS@;WAYnK{f%^6IZfIa&lk@Y`)F-fG=CVTy9)Rs8MRXKrzctL=?dz z=!j-n6Hmq$6lP#=-WRhY=FKLnT%xAB-l;^co=7$o|Lewe+fKin^mj+> z8Pes4Y#2_$A6R9NLvQLnd{2xE&k(5)eCwv@htY+D+zo39LoWB?#a5d!#q{WX=NWru z0AvUw_56c1Lo)nKM_!~)OC43{V|EmgqV45LEX&%Q>2K`TG*-ghPW6dJ%)k$0A0Gy2 z-hKe<8W6@ZCMSC3VFoqzyAf}6ql1?^!!p?Vc@wtpHX`>hiP+P*Fj}?SGCO}Npm*$) z>eYnJv~+xt_9_qi)WL+kS=1G+9FTHC9oj2Z_?dGzaBpodFK?7Yv`bsOKzq64aHkV7 zHG!yI$b+$xX%vUH~Fg^&?|4qe0?*)%CRLh@g{P~=M|-r&i<-QG57H2 z%uEkX?mok^Qe;FK5_9o;L--Ph2sX*R4i{bwBl()P;mp|OS!50P*8UZMC89-UV%G1A z+{)8b%g}&bT@>h)^={L};C-h?B_ahSjr3Eh&#P(u%Y3V1Y4tchVFF^{gIn`{(v-eUSD0V5) z%s=x9TrPUH3f4}(+whHhn)YX3Lf)Lr96%Jez6W^yWP(I!_&fk-#%-u0>41%H0734gO0`=2~03&hCieOjAoisyzKKWG#Pp-^!3t+@|Nc0|CKg53@`0CSS|m+Ioga zgB>)VG;i)?rQucfx`FwI+iluN3V5WYQ!7;Gz1jKKgt~KLiC+*J4Bq9*fbkZHTbfAC zmGQoX1Y4T%8@_DP+Zaj5;7f&tN4=gIJL8H1x>N2`S`Z}9R1O2`_j&J_-6E0a5b=! zqV2Y4Iz%*{Jx(IO2*VaEUyO|KocLiJ%Eu0z3FOm{{fnFr*R?ou)3RwoFNCf$E}zg2 z*=yZ+CcFe>yCm6y>5tDi9hBmx^gV|KX>Y4c9O4@=JCbmDuE=xx?G6SncbYxy{>2s3 zGe_^y&(L3N#t%UROx(nGgV#;=TN14hUI9|~=irC}8 zXM7bOs^YSI{41(*qzp+Ky-TTSfJv;aQgPo_f;jHt7o@wiOHFE< zTC#tyz?|}JJSDC>g5Ib2@O0JW@8BiMzx8ddxH-fe=j|&K@)CHrTFLBS@B3Fmi62|O zD%F(t@Oh6d@#l)YEna!y;m&3Jk8pFj3^RC-iazhyd4i`iU)#Ic0{iF((W`}si5wyq zs`e*Zol$@NGf(BxD>_HmW^OPobin1mZcwU3m8-D#th{p%QLs#9e%tC=o9VRv4a|)E zr<=TQngo+BG8HUUDDz+}FPo!rd}zC_PscIzL*FQuVU?-b5N&z<{JFKd6S;C2{~Jr+ z{vRpMrF%IHscUH{EADlAju~T-XO<#Jr&vXQoc_)lfA~Q1kE(es%^C&aQi^-Ac~K&y z>Abx1Hds@*d9SZ)d54`z`2L~MOt2G3vXS>*%4Y?xe$Bkq*ZPTPc<(2yN?1dwRQ0Ar z9AEaI{-;V9&W(65g{AC`k&)?VF0_dgKu~H9U*I&3Xatp<~%^lak>v@<|2^Sr~*y2Ff=9A*q7Y-c-S;<8BabAvvH+RphtC&}Htm7*|`Tr#|u zT+AgOhIB59n07Ya+?5Mp=xS!yX+3gI>fc)z;43}3YykTG=e2})QX}c$`cfXpeH^2k z{{K#NsFpfM@P)iIu?g!->>q`w#P=UDguPk5JlB+e{(11Ex1QhEXCs$}`zsb&GZg2) z`3ai#nYbV_!^-eVkb;Wkqj;ZF!FB`G;Wt6KWE+q?T1Xw!;uSn^^xgx-8{zhTR}5*I z;%694ooDU7mJd?`lbYGQp~yi5?w(xspJ-f(x9*A&edeL+Rpb}k75l;6i&C9Mi7@dn z3Px+QTFZnnTcF^ZK^yrXKMm3FH*+1Qd{FSE!J4Z7zn{a%yj!H*tGI392La@lxiL1% z=r}7iqT%Q`Gjr=NnYw0Ve~1Yfc_a7|pJ7SZS`uM1MTGe?+6%ve(Wu>_-Ahg{H|H67 z$&J{9>(C5}RuELaUn3tfp&W9S%3v9}^#6b?2<+W%xTZePrd06}6%!DS`E2$5GPdH> z$bV(_P*~*(K9#T_{^8dlxzDMol>8zvN(ua?I4#gWwpw^p|F|H>xq2q8jZy= z>~seD2h+Fk_=3z+omOSBFn)!=%8+=?D3OgD#2SDj>BVOrBIM9_!X||=rjO~V`pn*E zb?_Q#KK?&^9fot_hxTzzU(K|cT*+r z&T5Ca*2h8up&r`(we>2nGC4E!ecVzT%A#6+69%sXl}eVQF*a8gCDhls zU)S_Q$iN=q%y*agq|-?T0qF^9OUi_aXV}tc1w2`1ti;6WE`z~kAF(H|ywIFnI-xnX zy~9hF@H`nh$XC~_A62$1v@AQ97T3hXGKl*Ql!Bv}4A{5mmK>&^8+)B7dBecH&QCID z_RmL!%HaXv*XYbE$o>qMUwfZi6^@8ehRu;IjnCNPS`Y$gXgGY=NYMspklrT~M9s(a z+7dg11uTZ_kVY?7zbcf{%Sh1pxX1Rbrgao4mjjk#Hqddp8!&z?oYh1lJNh#axeGq- zqH)<1d$eEk9uUwjIN_Am9^Z3fD;rPqaG;4XG&4$HzfDxkzSwh+^=lF2hclyDjg9KR zR&#RBmkyAX!3BX|PH*r+1g;ds5Xa(h(6b$^*HVQ#G6)k^()ZG53F5FsJ&ZR9sMUr1 z&Y{E{hePy7NvuJtGX?#*Y_y0aV(vn5Y4P!pTYFAcTZI) z_Vjh#zofMLIREg>n=~CJY$v2v@2Lo8)a0D~^v1007_>K108@)g6??Eb3SHa8a)?*3 zunTR%kvLvQ<_A-7d@IGP&p4qAXZ>~@9LP$KDFsPDlVa<_9`(`jvPGW~P3woNYmSpH z*(-v*H>ePtsgWAsVd4>=+@`Ka`GQa`O-KHB1e*fW%*t}6z=wS<1h-pvYFz13 zkh|q8I7rZjK^$Vvo3e~szcNMVGit5`4wYvCav=}Mmp@E{3buX7=rf$Y>>8ox(CuQH#;^VDNg~0#U29!Y9ebV6((e_K&KNvjd3%%Z_imp#MjNtkBDJ{dSL?zkn2<5fPl|g} zZ(^Slo_r?(k)3^R77P7I_3D*qk0-dbSLI6CjeX+7BXarS9_R@bTTOC#UQK#k9oqV@ zYMvu&8C~IC*OZxA&!7Rjw;XndQ0J6%q4}XwL|!m_>9I({CS$~B*k@X2?G(O-Rpklo zd~TK1*qyF3p?0=UMAI6 z^K~}Y#SW?V zGybf^7w8I}V4_BDEgA4P(wW#JW#W|D{|vAr8Gy`IOo?p3)eqlXYvF@ce85y{Et)&mJl6spWvVH{yPtAzC)zPuz>44Pex)F)}!7B>qsJ;)`JZ_{lZ`|3Th)%}cc^D03uTlngcYXy8WJ#5ul zSrr`DAUu`9cR4Ico%pZS+_Rg<4(gB~P2kepe~7-&U+xE^KheDV^|*Na>^$s$Vx^~g zv^MGRQkrV$tl)a%bfW0?NCdf%781Y03#3+w9oaa7hH#C2n`-j`FL>>$p3}meP}weG-7Qdi zyRIKtfZ}Fgxkq}4$cC~?)9*KCHwAF{JS35cFIWVidlrxOQI~?JbDTlDRt%4--Tuh! za5DU&;V&qUat*o5pSC-^(&Ecs>kxY^Sxa;H{$>%TEA?kqum$|9x>F`q#|tdIe$ z1B3*ZyP`xL(I>vN3dCAoyEQ?sdz`-%&#enYpVsBk!Wn^5v&mAl>wFR9%%6Ap<-HKj zmbEpa|GXE+NK|g`_EkvQ0|Y^BigqfR3;X>7l@{|JbhX(~o3?>)?`{a~1;1d{;zW|7 zq*^n;C!q-ZUn6^qS`3GP-1rn)48Y3@2qNuO@cSYVf#J(Nh<*WzFdVL{f^*9ZNVoUz z>A-o^UEv0>b&3CR1*{SlGsQ4NB-iG5EriI%gu1-a@-e^PhAnfLAQKFFRazJ!x>%Wb z{y{|0&a&Eys^iEb3xM`P2cYovSR95Lyo=>uEg8$gnEqLEUI3@Y%#EWdweO9s1zmjC zZ(xLYcAGYo?z{=Eo>~O@Q1@2&@L&n+ERqz`FY^ITfFBqJQ|fTz7*5|(=hbENEjNfs zTnB(fjU2I%5rDr4xJlwh?QO9HI-DWUKcWmUf%5@%FsW{#r^Q@)rHeKT_WYE2+ipkf zS01b|TP#p2w@yNE!`Em--k`}y6aoWCT8U$r=|>T<)q$6*YKrZJ5&%yQ%Wh(AJUi-HFegk0-j(LCV>-0}cVei^k$wZ;z zv}rK>U#YgDz~el$rzwS;LSu}bO+L(mkphgOlDQHgAJ!aR(OUp zE7GPfojPs6Zvg4xY=5>!e8_v-t`7h$VsI1epe+&fQ;T zYMNcix)C*K2Bi_D%9L26kdypt903hz`gnBrC$6&ffg1Yj-ii!}`Pv)g_ub7Z;ci5? zflT3$I;YBaUwGR5jJKH0vG!;&URUECXy@p)VQ$!K?AHLJ+4Oug)BO*DSSp(dAA94X z)X-X2I9lXao~S$7xL!L=~8Mh=YDj3?e1;T@RM8423s^L zmszo~h=(&^yV}!X{CpR+*^q(3Ny97d{ETTs8lPN$w9)yKu-QeSx&BxC%Z^C(JG53r z4pLog#f_2~bLbw7k6wD;#MG5XVSDPN^7_As;R1S3yitoYp-KikRcheZH0~yor z>!u3enu=7@D|RpGcAd%#B6wg87O<52#OmOJ8G7q*kib^T{a52)QFY|%y@Ze6!Ipc4 z6c0T_|MdqIlaB}U%+Q=!P+G?eqvYKx9T_{Y3Um4s^69^h+|Dm|$W`!^AWhSeGw{_B z89mTG->UkDgIEv@NwX!4L-fJbwGmD+O*Jyo+WIGKQ=|FjGp5R{T%X&`x82`v`0^Dn zA&8`z=0P{w$f(T`S}c5WlJI~cxzf8(yK>?C_XX%1|B&J@qDAjhZ@`G1mfy(39=H<< zd5Vh@jv1&Kv4pYe!}9mO4_P=m^*FY;zX(dZ=o#@bvacl^6*}3)9c^s}sO7w`s(LA$ zq=^9ing6%{bX-L?k7+IoA=pbvE)F=W24{JwDZpf&*zCIJcRX+_9hq@K2uKpb972W! z_2|U+`x1U1$VDJYVaFwkgI7cyoj&KbE+566kRXM)bP!lKt`sE6m4BI&Hs%*#X@9vl zP*R=STZkSJLh|_9Q(0dU7^<~iyBw_qKGC!Q|5z0B){9^unAcr3a3q`_8krjT_HnaZ z3wy)|HRz=S3RQ|r6^_-}jxl*srL^#bs2Ob|o-y(ZU&>1hxa3fS{&+O?D8ONBAJe+q zHfX>XOsHW6L$QPcT7JH=cR+N|Mq(KBva5LZ?{*&dyWIeh_;sJ!c20|CjeIe0ts1}B z6slJim#CN^K{f|<)>8cyqxuU)bl?JY9R?|sRhw)HfobfzN4oHxYKd%g;EQ@R%A>@~ znJye+_7#lYV}deF$rJIZ>;ksyG4W;4GB$9%h15%IMe<*8fY$QE~^bCN)DDVH?ELK@< zMCfp3>dkWBvFXkMocad6Ouxz1x1&1#sgULCz*ie98+4cfl|VXTG`=A5#p+iLGhj5X z+Li9zr$5DYT&MrsZcJON^3uGi{H;5!@4snWsg^ZJ2h3`)nJ(c?B25~lo785ThabPR z!1BKr%ZqAgZxd$Xe-_Iyi{H(=M+;eN@(H2xwtld~Y@Z_O=k7 z@Oe{CVyqoC%Gva+=UOU(z2BoJQ##3LV@W4O;xjvs-tGjmrfuwat6TrBgL8lWWa~PS zaNiGS>__a6MDNLdk^a+@*75N8jo)WVj$n7d&cYd{oHGR5 zolT(Dd}{l@YFP{rBWYR$j$e@y-^sdv?at=fm0g4}d(HK^6*W9dKkzNDg6E zh*!l4o4H{GvK;vlGIlTVN)4Y4#zaEBmAu92H0Cwwzg)#|2=-Lk>MD zc?{px8KF*V{&rf(TBm}epe{~25=u3)0+OiGOwV;-NaxP*w`oAWlJ)4s?`>Lyu{e%q zi9or3aB`fE0=*SbsTmn5y(>Rh14Jp|@mb~5LIJd^l+s|u;M=p&nxw577NlU@0f&$d z5!@uqv>jVQs{qDE+$F?ZA&MnRdm9|>Xbjf7xslk&`n)5~bvy5sG|UUZ%6SMs%=|4^ zb`v{zNObTeB?4r@;s_q1BzyiDiOhfZnlV58J2Lx2X>yv2H!9rXlsEawragFlOsU*E zeTTaCj!zQE(M?dLr5nnec}DPahsN0DmcDI&dZ!b$i_8I6uLS8Fy%gOBisx4-DELds zXPpgoP)t+N0lPoD>N{>kM$mTeWN)Z7lzbxDkah$cRfXkza+DqoLc`6!!P=5J&A9JP zCC^%uDPrdLq7+W)W#WA~*~)bGQV>{TiJ-=08T4@KQU>#ts4&w(t}d%2l3`-vd6&Al z1`VVkYR2HsjqHzb?g{k!Kb$gE&l|weL+L;uF}tN)ZxaHlN}KV#uAjAkJn+mHFs(0WA-hCu2;)EyC}_xiA)g zt}N>MkW-PaET*F0*ieaga&7Tx7ahGM15Vre(wypu`_OQq4Q68RhX`O>eczmjlMqy{ z)o|{WgBI~OgQzo8N6JmFE35KdUOM$Af-0^SGYm`HkAC&f(f%Of>C{|b&ll^V=evo7 zDX?aD+85{cg%4QhTy9en645Z|~&-3q2NY0U~5s6^s02&;)#1AaqioJF^ zNP3G+X0ufb26D*iuD?28zj~xK9)!WWnO4H}NErio zcq0_YYLsj&nJ1O`zwiV8@3!`d|LKW}|C@mMa=(DNh&N&Dnqtb=#gHAHtcxAWf`KIH z>uVIOF@7HZjQ&~Vs?0Z6+vh-4Sy+AKVKY@IQD@(PM8VD#<hEyyktu_@+z;qB#8cv> zrWQ{pELXI_L@pnoISdB!e1;9He$LR)8FEX0VOd5i9VhMf<3tNtQIDPjD#;zeMl-tYp1F^g`Rg*`o#s0eVDM7VF zNxN#@FI*vG7$Q4=zq4D!H-FD}A+?UlhzXg1`qG0QX&oz1W;nQIKjw(%x;PC}?e(l2 z2DyY(!_zEdnIJ(}X4`X`+=(u{lb(3?$g*V)iQNE{6Pz86QBq~F_x7pnjm3=%G9ftU zLa&0w_%ao?iqBgY#;Dw83vZUmVlCT01&wQ79%~TXX@i?*!_3JF!Nnlv%_kwG08M;O z9YN0~eJFw~X>~(nzGkqD`wI!O5P4yN48&XvlgH zcJ}jKqlSbO4RCw|R%dS)oFrNlIF8C_juh3bZ6e`FQ$8e*;0Q=}FCt&+SVn=5=@aq9 zfN-?6??c}2gFb=->YX;T>s_YTQRd%)@878+Rkq}lU~ESi&YJmHh#KEm(zjfz^ru7l zZ-Zs%fVbGI>_FuXHaIm(<-#TD(#1|EZbA1Tp{q^)(a)dqL!!_g#dp81Sd0KY`uT{ha3re?ed)goLP`iG))d#4YXg4C!kv@-!!|g9{B=lOwtUa zi|IrAnS7tYVcY1IBz$W_B?$ROpqg%k^x6S9V361Z^GqL?= zXNBP^)Sqt~=i3787>X6O1%7VQ~4mzSdExP|Z>btNLz--caTH4LJSP3eC+Mt0iQ^XzMPO{y+ zD==GCc=w!;naXrG10;Q^o7e9Bawv#rm~8jL_{mgzIQD*H+zSN(d)`c}Ah<_-EYZGO zagGSV!=(~O$YTDZK?Po(?3UJWCJbErZ1m|m*ZSy`^Drs!8elMASZT`e&0D{DWkE&) zERG88uqBJAl(#GLoblGTR>`osG$Gz4$nDBKl-P#~T4l=5u1Oj6SbsgD8Eokw+>pNN|h^5$zk8WVj5u?Vd~d9tgXH7R5J@hlkfp zA2|9t2nhW3Hr?lJNitl@Muw=b_T6LIUz~P`cSvy<4Z3lY?Aw@Rz{J0uOO5o(9J*d- zYzx=YPKx8zvFP|5G%d~K9XcJTNVDbXzwJ5}mJh7T{yr6eyjK@2n*z+fckg)FQ%vuI zb<`^+e`CM{?M#`5Eo~FHnbldfX`ta&m=6pnLEZo@jWS@2U`7gR{kPBSYh2V&`aBf= zvIKBk<6Hh@AEj!U01y1Flc=Ra;ZB9b86P4nrGKoONX%F)Q@S^(62vsmQi3+KBPqr8Ir~`UZwxbb zJG~$2e9Ak{EE}HW+sy zJ|ZLNyQQRh(54lUh8KT>1fz>9E1RjR%l76Zs<#Bo3h0`d3ZV5izmmj){Fx3W)BaZH zWd$C6>lHnnOtU#|P?8!lAMJ6_6_)u*utze{%L!|MKboKsE+N5HZby)rWVJ2|GNH5D zecuZ^=+d$ls-=TaYz$E~Me5x?1sXMi-2`@u%CphfM%nsnUo8}sD}6p30ufMUtIR|sO{$eRs$`Wly10JQ!$Le#l)#ExGrcFrh2FN7 z({4+kPU==_^K8}Z$*E0;u{JucMAkibWdUO3f2s2vTQmtx+YO6d13+bjM$Ii3PVA+U z8ZeKtgi;z~&fA?Q7G2CSv>@Y)(G?ZXCn2lStk-Kn(k<3gQ$r}ch{8Y3+DI#xd?r}OvB^@l=48W66f zNe)9xZS{UI!+otHT)@DT;P6}FNM3OQ$Cs1s-sd?#6I7QS_ zdeNY6_x<9A@M~(~_zX&dgudTrw4uSJDB&!i!H%m1P-IA)$Z`R?6vTUrK1Z1M&&N0W zWfP16r4i!3bIIJBYDwTl93=SaJ#D}QfOx2MiMd{f^6lRZT$SvwH>0%6JGUghReJAh zdb)VuVju2W4DVYh&tcE0kHmPvYLM)@xv$QqFGGzWn=Xay&1-U4y<4spXCn1)p;Ap% zA4`0+kt;WK|5Ra$no85-K=Eb+r7jl#;Z}-dL)FzOr$`-)2AIl2lPY~WmOK;tV5BVm z*>49he@b$=ehli7Sbe<%kpiL<^{6-reYg|o-9P!buzgb6kOMH)sgkE#D;Gx*k-stJ zfl{t~=U(KuF3cV*zp10mN^Zgv8O1$@2P((5vItvS8l$FE8VzO;0I^Rb#DVdS+c~SL z<}S0u9InHv6?XoF1MQ1ZR8btWR~_6C&ZEpTzUrzI>1K4O;Sg?hM-_f=jotZ`GD}9O z@M)|i-caLHkb=}hhNnLh=E&_YWq5dg>$klHf{}8bv*XTz+0^ zmtBoAr;F=nyq8TEt+%P@kLlbQCu{DCaYv;@$50%T#(6HI;=Q&Yws8BaH(2}+reMd! z)!h9tx&Jxzqz>~u!^QpTjNISTt>@J*b1=`zBCKeo;BMglPjDMDzic0lxYC$Il6Ra- zs;^$iLqRBsJTFL*sOCxkzR*hn;UH0a-jzy&JAKWm$^~s*5@FSnbwq$i``=I7B>6u8 zoiW2#(43zq6y*X+71H3A#yiyJMm>il7j{vK;ODGqznOq5ay{=%x|gff!7WNz2p-om zdezwGvBegKoutr^96XEkG3#S^bJO$Qyah`xxWqTB^;p2_wmHX)<0{ig8W`4V6t2V$Dj6V2KXrnhb9?Ox+FZ5yHoavaTEt zwGp0T*fTPpotuSrYQWpB<9w3o(+D;|!nm8lI9YX{i_%5{?qmCAp<;|>zKXYtWlvx~I; zAz~It%8*X^yYdo0%~0fP``m#FsS8#3pewLtj3&9+QIDoX|H>TNXfT~E1pmW{3nW-B zQ~skrba#X)60O*L@2YpXDIA*z>r4E$9DH_`*`R=eUBhBwv%>)n38r)Zv=b1vL^{gPAjEP{uS=68)>!=+*XwJ{Ui7Vbh~yTRU&M%yJ4QO^ z9|cFX+OGWf(^r^+0l?8kuvfF9_lrNeP%Po8{@q*bhCn!JFIs!}l44_6YwZZ>FM%|r zTAF$mkwbST2z`@mBY{)O^HWKgS?k(8~PLP$ikyo~&=?xjNjwc;ai zdtcd%n_LOyij!!}Om~Uz;;qXg(B9RCOGGH0;nmwnVE$Ook!T?1o!uuOGirlz>&WWE@NJ<8A3OULzlesk|xh=KKesh$r;_bxPb2) zoJ_^YwEo5S%iyw*0EDJSwslijH3=5nLQ2;qYoF|5^T3Ag&o@Z)^AJSBwFl@AUjEZ@ z@;AY7ZR|%KyvEHn*et1J;qN}i*p?yLtnd7Yp~nRJQ)`pmA*Y) z@bLy?!o|hX;2T9taDTpIH)ZJSU zX-So}tr{nv6eNA&{H>9=6)l9=FMWK)pc?qWJ_>?~`7lX}#OB{fc8b5aJadS^A9YYM zhO)*&5M#T`!`=B_{_SPmk5go^EWS`o3g4)}#9Gqv%$Q+VGK?%)`q97A6U?HpE+OHS zIidetbGUn1DJkGxt(>5L__RKg{)P8(P}RKtcef~Tu2}5 zWgC~8R_7+$uss~j7Gv6Vnz%JKWzi`otDBfz*ChBbc_$EWl$H)#3EUaIWj>Uc-jZ9# zRJbZ2%awmR^fq=CQ~iz-PSkJ|@#&jEn3I^_fe!LEocwBYpG zce#rc6qkr7-B4dG43nRFWu>XdnoAZ(!+>QJimkLRhVj>kLF3!+QY>0hOUnO8n%UX8C&Y28^tjCUDvKOd5b`PhcNdx5TbzWR#lk`q-HhgcTl88LSJ zFHSb-rz=+2=$TYXT;^iXb^NjEE2M(>kgrQU6LKn-`~4!*0y89Q<+{VAo(1_ZdUaGq zHJ%Kc@RD+_e+n|EgXmSkiOj%}WFE^=vZr|SQ`Gr??KAD=$wryo)9t)#S$J$&tr5mc zR!b`uO4eGy0wLR~o%^{Sqexfa+jo?T^6tuoCzM3v_af(}Ok29@-5Ik01>FP7} zpaNA|75z4l_GJr>+``jcz5h*cui-9Z8T$<3b*P#)d6&5aCH(av$DdR0Me(DFC32lx zIv^+G^GN(fh3VNmKwR1^`3U!0_0d$KQSCfTlP zdK4Q(mudIN^wpFkj0IUs1 zCUY^2`uN_I^%%Xu0O;x4`y)}8@pi32`vvh3yTG$Nn;GcK;e(A_$r{WPIltOMB+-a<|)K?q^&1*jW zAQG2Pl?`N$9t`nN908^j!AODAs$tlJ8tzo{a5FFAw6SG84awT2%rqOf?nQ_t{ET3@gu^_bq)@PKa` zb5aYatEeY3IA6+xfx(%%N%%(d8o!P45bDtjfRntGx?83XYZ~FmDS$2T01SIDU#uKm zyqntY)~yYn1LZ~jxY%LIzV(h5|AZB+^>;kuynnpd~>OE}znZNX5tHB_w zb>R*+$c)OQY%nr8oMA)=my5o~5D!gYH)O~K?#1eAFH>hM@>v98(2O;a;YcD6K4~xD z&qi(hBn-&z8NDKZ=U1Ah)+*EwQUt6%bRzKs01K){IjZ9ZyQ-Jb48RH$hlFz|8JW;| zH@$unqX2|F7seKxE;;IuR)_Dg58GXl3=}gl16vj-!JPoMO8THzOJsibhI|cMXY$DO zLGceCh@GS+^vB*QH~rCIb%L9;D}ZT(@vz(PwzD{imBG%WryxGV-RKeG#6Xr1*2?m1 zM3EjV2d5hGsY_L`%xUi5^VB;-ME8+Qa+__H9R@6;YV_) z*6--h_6nvV!@u4m{TuSvLXh~< zSx@)r+;_67i9dj6LyCCXi;65fop1|s>flAU(IrWoO*$MCt*~!(#@NEs(?MJ1?}N<1 zvtP~vLy*aV#bf$+*tQJ`j1hC1D6bC-0#uD-i%UBRScat_b4ZnwG_rJY&tCzthBf7)!6?Sv$O_K<9s%P8fj1q zHl7|ab9Nr;`dcnalp*O{eAD<@pXExemfp1I>?a`uw0!g zZ}&Ft8|^J7$X3dqKi>;!s=UYzvV)B_vqM;se}e1onWnQrE1EnLmtxDwAlNxx=B!8E zNGr29kJ@rd3ms(qEZk3GF%&dSMajEA@|56RgyAACyKvyte}e5OaNzNvO#&u(c=3No z#%^Zhb^6&c#-j;8yafA>SrV1}QWz~y{G(k?F2GEbZu>Ta1$CG z(YaYS35P`bdcemeDOW^S981%mwYg8HNGi)>#3gZ0ApaXXtn~3kH_ZR<*Mh~g59qQo zZKd`*Wh9?lE()RzLG9vEwq!~;Ou_b56w=L~IB|TU|E9dOOL&UT?$EM!y`n0gV< zXtvlL=8ZYZIOX%|dP9}T8=EtF8#f^`(}g|BWfdILuYxXZ=^`EwpPlwWR z@bk^L)%aXIoV6sq|GRibSI?S(7b-u)QjAcU-xa>qSSy=j+VHRnjaevt6VIsIJ}CX5uIx$ zp^(WCWmnGfUd+%#JN1Lo4G+o|L(t2Iw|N!l%_3|+z z>D##lC6Da6-QEU8>&B@Lm$4){B+awsc@;W_z73Z&Vst0k5sRN}MS*#iTPf+;xSJ}- zU7G7LFEVJEHX(zaHF)-%aWUuu6@ukIu!PhV6Q6?>f>;~V8V5v5gdpvfi@vEd{7Jhp zldahUzTJ@**2cNR$9+31n7bLyq};)8Zg26k2#|;Fo=zQj#*;MpH7GB)Se-<*0X#>u zT~P%yl%~$iArg6YL_rQsfzf`}YuZg}QLGHuOZ-209ZFZE3@Zt9c)si#TG6!C|KRL_ zrV8Rq;4!eQpquE_<{%kO_0qK|Oy00Vj>qP{HzyW3evp>uy? z0iLRSZc2HV{HdZvM}d0QZJ6wjL0tk2n> zOAF;y2LZuzz8sjt%t5^ikI$Ru`4;@(?(XjHF2P*` z1RV$(+;t$3-~ocW1t+-sK!6~@32uXHut5hxvh)4Dt=ir9-qw5j-&WnJTh()KPj{d0 zp6=74cXsY+d9pI*KHei_N;iXm3fR@gtWLJXy&WpAqCex$Wc;dMPB=R#WFj)X%iW04a z8!2`_brl zQ-E*Jj#0@d>&dPm3S3|4!FBU+VO~7REM`oNK1^m8Vz9{Daebb*N69ATfg9T>WQ)}# z=nl3|iQ$(cFO<4m!aMD{;zS1)zcU}H@=XLEqwPT4Mu@|F5K3ZDfevYJc9P%g1Z?gc z5RyQJc2*icD~*pRglkMAYvyWU|5+tL>~PyYgog^_ZiDhB+avp?|a2<6s>Oxsq4fLfn~e zD^GH^@HfyOUd{>}@%Xd#88=JnZvY$$Ob2#1d#;EUcpBHte^(s|Qa)fJ< zIdiImaRfXbP!X3|^S!k8UKw}WXwufaU#Dg``1>!U(aw=n zUgZ066G8}od`&P>#&l<)w<4=D>)qs9@uiX?U+u%>iD>joZ-5=VdTo@#Z@T4C)M>KP#(P&-*oxK0hhaZ9}xB z+iTh8IkF9;XbEBH-1~Kjzo%v#Ai!dlO;UPdE>zcUPyxbt0LCDRzCq|so2(^*xj*8w z*$2OZo%8Ch|5=wIet zlHF`{;8GWeD1_t1aj`!#ngra~SH({(QzU~l_4Iu7zbf~G_#$X5bx@O(I0$99>Hw~B21s8gIFsKMZ)G&N z{nC;omEP7?pae|$+DQRoK|$*W5mJkObLT80x*kp>D#?GW*P?RFXPn(=g=)yiQo zq->@`2&q&++j3OicR|hegGs{G7~BK;&z7lR7%oeM)-!Vf@}aAtK3@?)RA~ai&cCJ* zMsMo@{=-at8a3BF?P2H785<{vtj8XTb&}W6i}2$)!ym!vQ>qwSEpb;~KNa8r2qp>l z?sXKmf3_J9L{D}hLAWp5qmi#zL=NPFH>Dmlk;mpBEfktzipSLz^d8~qUN&A}F4ITp zYgqbafn;Flv@g-w^F$a-b{t>gMmY!JN5ENf#~w_+Oqx|@C9@2HlL0@i zu!=AQy^UD6oa$bbthZ%5W|z-?uh6pAiMWu;pMN_J=Z1bJv`UJ-#de%7J7On;(nSD za1S=VIUC{-)CZJ4z!;qUYZi)jYh3@)-jj0`Hp)U{%R(;Hyn;hnZ zxEnDke~+K?_{#c^>SErKc?PHy3g$>SZ+zwD6Br>_Q|YeBXy1_d1C zoom7-)ov+S9_dB^_ts3c$%m3#dk;j5{0|=KbB&`H?kKrBii-%->mPPfigU$@HlIi-(RtE~Nm(OjIgbesQA^yGbBcqK zf9{II1d?vnrzZIMZU*Jxn;Q^OTmeZnsKGF{Op7v3IR;%_GS9rAn*MMpwZU*!u<>4f z3yD3Bfjb{-P7tjo>r_ehxo25g~ zQ$CIzgeV?@druv1LQj1`Z;~quxLjYw6Hh~7r0V`HkoNZ#mu|J~yQ$?ck-c}8FxkJD z)-yCr-mt=CCP3a)hiZ2t{WzAZqR+x86o$G_1z4B+`5~vVt~4(tm?s{v-Y3=f@q8YWtaC6ac~Ro5sRNPdfBNO<8n7Vk5&X`_P>lO+j2jy zHn-AkXvFpu#*n?8BqiwdpLK4^kKlYc|9TizwETPalX` z5ScHpnmnBjW1&tm5d>wm+sOt)=bGmc8$st;7_TPm1@j^P zeUKqC{{g~34N;7k}=*I)wSj;eyFN-C>N^M(B3kob-ZeK*{>)) zE~0bh(=!=Bov_@DKmce77RPN#UzW{8$m#?x|F|A2wxc|G z^t<_|U?%IFJv4Xj!#@GGZQ_Wmy$c8k)yi|yPf;ldvP5&=@ZabRh0(BIG;{HPJY5C& zKV8PSZHr^$@MHN7Uh$Rl&0dfhC$7sM@jh2$v_e5h?+VM^=_2IU z>bz}7O(*)`>m&Il&p&(B!IxcNc^66@bNOrf`DJx!LrgMxIqZkn3jmzqu#QSzJB2Iz zx#4D5n#z=t>!Lw(58xCJ){#!ACkfqi{o1)T-t$~k#)s-M@A|q@OUXxV>mrcvXGD`! zkIOc%Is|3%jlY5)!8h3=ndZ7~gvofBK^0$734R;wJ3zhX$s-=L>sdoozWCLJdo@=Lkv$_VN z<&f>lGjp5L#|~=iv3}}vouqR0C6iyRCj8fD;Sq-43fxkR&jxf(rNb{MFuIklMJnL3 z#(3flcOS__og2Dn>vJg!Jpb{oE;qQ|sP0o{I}KD|hLu)373^1&`XxK-?);i<<8|t^ z#tRZ|=tLtegE(aj7w5;A+9_jRQc2MtM$5B6WTUgw zv*A11N23|=S@kT#r{g>-K8FZ|KSq$#Bi4=x=v!AeKhE9hU^xAdYYfFWd!&*$#gI^? zNz8BiSUHrZM?XZ3jC)wdQ%89DQVuEndmQ4k+GLblAobnahb0q7Co(7S*GnG0m>IOs z=_J12q0NKm%<^3wVA^^2aFVt>A-H0f$OkF1wjnLBu3PBchn2*W+Yi`VGg z#%KQ$R>9Mg{KVeR45iQs!1Mt=DTtV=2o1*w#*nuAlz~B7{^Jkv18r^(o=-IV*dTj$fSkfMX)=&VfqB6s}n-NjqZtaUD_D zi>=;Qdzn2pHLG+w?$W^uf>QSuH^|bief>pXKRqK+raRE?CZ;vYcGVE$8&>#fI(K3G zhL(-|bl;R^YcT)-N)q(RDDz0JY9PWZb;$tlk+BYkYzLh7U|6i!p^ZPeU#X_ow18jk z5`qByvm_co(v}N?4hjOxRrMjlU#AArF7e)!KGxxT%%MRkJhYzAnqg@zqIDlLn|us# zKFHM~e#h1~DJ=x(n9=?&L8x+&dx zGRSg5+TA7+f9^BVN4wB>PW|jY7D#7jixIn1kAWENMkY?7h6wyUw;>Mzok!uLk%rf2 z@}GP;D(u3ae0yb(FZ$lkEt@0OCCKn8mI60x5r(j5^kumWZUMd_%S=PSFKT|_Ys;_$ zZ1id1d;s?LmwNm^ybQ($>FJI4}X7z5vL(CWnW?o7r=grtgh#J zF*)YiSdcZ*sAs&#D;Ef zqq@|q6W=QZg^vEAPaE)9y*H_3)(Tv&Tiq8+4Sg%R7P#wy>q@D8#(Jiy`Z-#)R7ffP z*%gpo(fS~2t^ouSrfrFe3doXi`8}uIm9`a>V;BqTY>^rS>4W^+7#u)nPsU9g?bn`B zX@Pz|7~_L`gL;Ja{0xZ++&?{?9f)MphwkI*GTZC$1Fx9M1sA~m4KLKp*+^?7)5e%i?PJE(w*iB zF9bxlS{B!O&jy(prwAPxMFSrXh@V(kgfUULRxmSDA%nFx1vt8XOa4Z^Hrv)+rTkQ& zc|=HP$&HRF=>HZZOX<(Bq7}(zEY+5uenQxE2W-%j&XQ$j_!I1XD&T!Gb(L26Gb+yG z#8vX@ueC-~F=^IjD&#|tAz4^A)<>f};)ArPBcgYg)*=BjTp5Jx_vhtQ-+3cPNp-4% zVT01pg6fsSk1v}OGWU{DOYD6q!_D`C=AB*qFkVz>fgd=AZ+t7j?(ZLS#GA2zie?F5 zc=Z?=0ERdM-@(H7tq%Vm-d4vSoMdqSj1tE5-)fD1!I$JYX zb;Ck4ZdcA$I^B%zt4cE3&v0=pUp>oXsVIxdZ^sNdJGDqjkUX+GPD<*_pA1lq!7Z#m z8)JGO04_>8QB(AnDuz3ceAQ8nPNl(-=#o`4Q;er8J905sOj-=fyL6=Cs2n4cTkR@Z zV*MbVuqU_k&9FUB1hbt3#>8Bxp_$j3%4kq`S7LPbYOW&wO%?6!>{}yl%=wSObzfAk zFJ4`tNVZ53If_;53#@%R@|hRuX-f9+_jhbZyJm*?=vjSg{US|Jim8g_4z9=J0Xtc zBQ+;7>#2DjJ}w8nIAWCRc@m#iQeCrbHEz9}0>XQS3XKV7xCIEp$)K z!|lZ~KfYgXq+Ocov!1CV2I<4MHV=nXlb^iLNz?IC+X@p3lt;ewrVLZ3vyV5}_LIpf zniIH*d=PZ=AF9(!Z^Ur()&qMeuYYWxl$u#6VuMWw3^^-O_&C^##S`XD?MtN)xuKdV zzQrq^yglsUYdX?9WIjuJHE)h*n6m9>RgRKdJ zJ!CTL>4q8dtS4C#`6}S)kg_%Ht+d*a6lasV6Uq^PiwsQkyVENSmOApB>uwA$&DPC@ zr?W+za?YQ6^=n9xQqFrODKr6-JY0GjNKnhvVO#cx96p+X&mgj5i^s5%b<%R|a^9so zUvN!ocr#Pn`pZoyS9F(HhA5J~37jfMGRM2hYH40^(#n3P4hsI&Xab;`~4vngg5v zB9ss6m@9o(X|yz)ORWQDxpm6h@YJ`c7)vVC?#ep$pHV;5jG6X?_QeSsPIsRyuFz_L zFK1n*a3iQ*+>`q=TB%!0$QfEcj6W2R6Wo+TJRfiR0B+Y!DChMsSEi#@p-51`7v#@% zJ$fa!4&(bF0+{FiA${y7^LzWvYk>-7xb_kvnYh1D;HVa7Yw+y^XzU^Qkl}^pIfT#b z0`d6MH-6~U_w#c{clf-DS#Lb`GL=CifplIab=Kmb(;{Zr(P6a~D#{}8WC+WQ9NSR@ zPfZfL)E{j8ZenXxz!(|};ON13Spa1bf9ac!%M^1-D?d@Pv!l(G@ULhqdi$5K-{A>Sp@S^gRjzd9T@mZZbMa!tN zkCoDNe*4GB4b)bhsy}a{M9J0;=cK>1>vZtb1BDh=?ECj6f5X5rP_3oi0`AaK#vS|H$BFSlD$;6Ow@T8|`6 z*Kmwv-+2W#nQDIdbsS_?)*gO2@?1UE@+h==^vg^DT?NM|$MeR^Ym}wDL40VR-NpJU8SX0LrhusLz*PDPk` zg5?|iuz}tNXf(`V3H~0@kB^h<@)$}S(@S3#YZ!T?+Pp^#ocscSG2Y+(rEO>4ot1P- znSG&=dPpdARHmS)%YKrzB;{HTOdM7+@0OK)moq&BOs`*O8D4TWXsQf)>824lENJ-b z*)$B|IG;U|QginX?U7;mI~G?OvUu+O%3zwO;dQ^X92>_DD5POcmO|sl_=&R!Fuh1v zQ0{#%t5Wn|7$Lz83tZ<8Wc2v|<%7clVS9DeNN<@)pN-E5WrP?4{L5=FUq{CFj+1Fl zX0cBdfzDL3`Sj!EV7s_CEE?BvxZcH7M{-dY#1w}mg)d7HV_+t7ZW?rPN zIqgjxsbzku8w*B8w0Ajkc?f{o(w<{>Yf+J-)4SPuD?+>2WqPiWRo)kyV zuTs;BfX#FfNF1?$wH}-)swCl0WjBagUNwILElU;{7z;rn&}_g!;hVre^Zpj(ny1rj z%SC`ZAVr!3*rr`;7nB8{vH|m;eC2<=jo4nEXstT-F*-q@`mhE;@6EK>vun-l`_3^j zNjJQB%w8Pm3kql=N}7C(Jk1?E6&l#oKK9_`t%N%?WIZ%T&`8m#T*wk&JqIn%FbLt?xDEW#@664F{wRidOLS9*&|sHfY7eHIzBwO(Ny-sIamaN1iOFGq3K9fPj?U8eKxcZJ z8LhJP5)j;3cMY=;JF+GLt{*0O?&%%`+i!gj6uiMugx-g9>?@^_Y@_{}Ja%B^tFnF8 zqxIXkHn&)NEoYdOq9qp6mGDmqw5#AB^4jwZ`JCIYfDwC-G5MRg{(Fh`lXU(U+351* z0BdVD6;y2BK_pE47-w!@*NZo5a?$z%b|9n1Kx4 z{}82@Q$bP3W~rA&O`;0;yY0-7eh)5c+0n#9!pYCCV$D-Qf5ArH_+paurjhs^EU@-# zKBy(D1SW&KI@E2iXkRLSLYN2LOEdKn=m;e#*;5C@(Whnw*&grhn*Ez>zQu|sp(tf_ zESFww`c!n7I4F4Hh))Ar*^<&e_(QxLzLXiqw>2XTdFP|^_x#;0M`00ddT5r7=0Ym1 z;5^ z-4&<=J^GF@r}O#f*(s8TF1k-4>3ICqf7*Y=8#8^Zc3ig&oy7q&v~w)8&lrq%d=R1p zT+@OA?^b(@E48gxH1-_8dB{$ z+mCbaD+&>nQ$;!*2JKk)51tXtB3dtp{2cPye=;vW?Kp=OdH4h5mFgJiknktc6eB=L zpNL8lx28K9EDBqTL5x8&#Droq>1taDr_9e^lqT#|O^lzLO-bAy$zcSZxv2k#5HT>7DZ<*}>sR}pM{ z3O1zc`yqzIqzOh$rl;UjQM|GnlPK8v@Z5$`d*=4=>6GK`@HpIu8PoO7CuKg&;)sgL zG{(mAATP3Ap&s@Q?FNVU-=x#^aas5`h>0Isfj?S7=&qGbPM1t3pSm-P5rn-z=Cd7( zU?>Ts0?#>T7J3!17+xhj!s^>+mVx>ETx;-#XLD`V2FF^=k7eExdt(g+PiT88EsLQp zkT;S}c6j8Qj7-gmAkUzUoA^fQOe}wK`Qvi^w%=D9y!Pw6aiIo=-oatYlKBNb%xT=h zGM822gd>aXECOWoWzxe9FKLNN5<--Uw==E=F5&Vu1EUBEpq2l90wuOQFmrjbjO$8x zV{q<%3iXkA_cEGRU(~=+xX!@N=L@!F{`sdE&OuhFJfLFB`m(rwfVHosxxzFfBrSX( zl3Ql>4SPK5462=GN**H#gdg~l=fOuQZb9bdTQ11#fgg;ND}%`?&FV9oUFt^k8O;z= zE6*k3!Ww_8gJ2NBSir(ez(-aHLn?0iC(_2*oW z071p5RYbcEH1V$#b+~Ar-9+!5B6tot@v%M2Xk9!6_SRr~xN>nUuOiuaIm8406VSHm9CBW50OGVG!cIK(U)NU=rYy>(t$r17Yozz(#Ub&w-D#OF}bmGCVezS}rl8JKREMr~_&z#MUwf zV(Lk`ZW5i2t`m^A1Pk|E3EpS&UGa_mdj`_rzcY#We~KgZzodz4S{+aUzgcJCoTdaaf~KnuXq4Q1(Z}(alav z81k~JSQ6U=zRwed8>(nT)cBQTo`Jf=B)>$@neY5w%ioJX`5Z z4LlR>Th`h9)bHGnw`{Lf;>Qdj&|yEhd;=cI&jNkSe1EzO6*aL+%P?5N080b?YPamLy ztH@ysQOemA;U0@h3QOKN7oEOpi8g({kt0g)wH<)mr9Xt#66wwAsvGh^;fxs6zh97r z2JxgW$AF>{q`m7W4RPO&AVp$t;{x%Vl&)_G>if#@A-p(OBWRZ+cGi%Ry)7~$rBAPj z$Z|e01IP};G95{B5RErde-A=Mvg9jo&d1@6SsxrKSUP4>thxpWCON5DR;)(!I1oO& z>;2Ts+p&WCO5_Lihji#bQa%`PzYFphhoPQ?DGUD0Y)}VJAFj(;pmIu%H&na~v?pmJ ziqO{KjF|tW)3@oXU_~ zb6>uHfN;px&zX4_(;I`Fqu61QRebS2xQJW!02&Iqr4Ze>=LV*MXeO4W>I2-5MBq(< z9b49cNuliE`GaZGJK9>OZ#MRxxJ-LYmBd%OQ$sA(i8SqsHOy1j`*hd(3g`bTBLMfa#cc&2=4bqc;HRpn0~1s1z8Y- zZ~y03GK4T9TGz-uXpJQ3iYB@d8h$H)n6^66Yb%L!5ZiT+qyUle8?-GTZD@f$n58o( zQDbB9sAnB~#+moAa$XX-C4NTDWI+%M-;TM1$bmQr=`||LCKi3CpCrV+c!llVZr`S# zJ#T~%Ts3la`@JVz9KwZ=9MU9%4=^+!+8$Z^CXR1M!hy7>s@gTl2`xKD72VLZth_P8 zD3&fnnum9jUZEdiMhv19oggDMBCO0sZ~67X(mhf+u6exlgS(7(HK)sw#d}>7JUmBY@0TXlvs-hlfBM^B<7niNz+93U>Q@7yfIW0vYn5?!nyrC)on`0Dyj zvlkz}K5-AY6n%Bkfr$Q!0{%@BEx$Ak-I)lZ$pD}a=n<1xA>r5w5go?>N%^Z7SQEZU z(D1H*Ocl~q1-ra`P?*cC#er=l@huc|Q9)&z`Q+ycOBw$0_wX~{iUu`s%bV6mgP4Gi zuNZ;k8eslRkPSC%@C`JoX&=jWoNOeOFM$O}t_cSHT6?95_=9D-~5aXQ@+XE9uK=+5U+MY@Zh)A94-uL(TLz zaNS2!!bE^Cvl2&26-dlgif^I-L54viM(N-Tv7I{uVcS$89W(mi>=#m&LOO2r0oV5! zZ==}xZ>^v>gGd-5i!n7ks*vV`Tu0L6n}AjKKAS11UxxRvzRX{HkW=60_4~@v<&3Y9 zrPT{jY85Nv#wL+tde;-nC$@}aC?Fr~b2DYw8l3%xzvgdmPi8AsauDt=-aN2)2*@=d zWEA?&3;7|+IHWx%i~nxw28Z9qgM@$4YO=$4XrT+Ag2Nvsi@;tK`g{p^A~Zlhc>V@3 zOXt%Q$HNRpB1iqh6rT1Sgm5|F(RVWb`Hfvg=fV1I_|IdC-(MYNyWimT1%cDl>ZlbW zB7*^(pJ2f_7;OlT3U(!(2YJ=Ynn_MffEq?B0NAefkq;8#6atV{Zjs&&VgU9n{1~Xm z&tZ3m{b}-e;KV_;A&%DdYQ!92F@GFY!TO1jN=(3_t<{_%mq%<)PVfOCP0|S+UEvCM z7^|`4263}sH9334-(uQOM`#gC2n6C%dm4zmjc=sQgtc2QjAJAablpfn2opFc6qrBf zPj&=0Thh|5f%?bD>`*5_EmF8}|Msn5FhXstbhH|6SC&VJse!lM!QXc!UVTI%Er_L?PL|%7>P)c=3FXwA$7b&Q%bVUHD`k zl*CIM5}sglV&u;4#7mno@B%4vqgc!%y}X5 zUo_#5d4r8uRdgF@$zbg{xiMDr_5aFBAuT7@@kV*H)To;CpWjE}rOQFTm{*%gfsSg4 zxIe9$%~7nz5F{&-3s9_%KFEZ}CfLxV`o!+1guoE<4iZb-((00ck+I@M4YBON6p$g9 z@oy&d#ij$-nI8EAeZ0;*F8M2QMFeW`I)upjSXp1rpqU|ElHpXo|La9L{*b~~3l2tw zzBuz0zgredzBD>Q%$@E=g@&G4$^W#xln1K@&CIsdBt^j0Nxuh+UL@Ni@KHr`Y@h<>>BSiMFg0fYT@-#nbh!)WWCP;#-1HA< zhIGU)Y?zxV1O(fQ_?&}#tz4n z{HHg%XJ0J7#b4UdxjcGf@*mlYqW5HTXXaEhTL-Re1DDJO`0 zS!A)fjT>fZx3u}-;D2N;P2qmzrFkF?mW;<{)gpdpH)|}7rl)_3I8b09CGQW(P%!KM zg9k1T^{_jel=~xHOAi*PwvumECr$Y#qK;FW(tzNq z)>hl@I+yPI!fL8mKQ@`wKJLdoll=QbR6OzGPE=v*IMu48F7bp#U~jnvercZ7S+M4!N7KB^_N9rFVBTyFRx%Y08d8?%GhvClIVD24*NT7a+!81;IAI`(N?3h zMo^jtnNo*bDVzTlfDL_eUs{S&ngsGeYKNYeLQAP!zwe_e+TGmk^5ODvMh->dmeZJ?Qrkp~J}R=ie0}^#Z=^DCiU`@(h*uB)CVl+g;BJmo z!IRmGwH3&)ynH*cNrW*_@Qb=*C{Y&Kcd|-5p4AE(lM231r`J@{g5x$_g#A49>hAX+ zNPhhEXrQSq>ha7%c~vBh`C)ah`D!od#ZUj~QJKfF$8H&cSD+ z(mU(z0*)k0uv(;b(N<2w-+E00w}D`uep;;=%N1AK_}#v)!|W&a@BVqMVD}-8_vL<% zZ~b4hhBQXoakt$g91AH|v*G+`-_2ujz)g1s!?Y#AC-bv(pl|Y+@iKzYf^)L{;9h#L zs-4KDgHUvUfuCgvL;epi)t35b1XX>}TgIT4BC9Xbq3dqh!54#W1-RcQ_PzcxN(U6U zi&TWlmbC?;G%alOcN#33cX7zb-+TTFiE2Onz7PdV+~$X&YK=OpRMj%oo?(PO^@k;-GYcSTmgQ){<{b@M$wcMT_&8lYvsuV04Pgx7Aa zbI%+$WM{mGB+3-DGf7LPQHvR}qknEvOW1Ip@_er?rG1D=WEOS4i&;|2orpNMT;o_A z9fo>;KY7G7&~B5ctQtDi7Y=Lj5v{9c)+d*(-+~9c7F{MS;UbyW*V<5KR6&n$vatK2 zu+7W(!BpuLpBm|){IH*3vgN+}Q2?%`-&3hUuIME8{`6!IM!BWY(b-A!*Sud|gPj~? zMUIVyV`;R%>S&?X-j7{50qx#cUH!%Qgv73_M(ym5WD+rt)a zm(($EEx2vL#>NGRI)5aMka!BGurv4OcOlwolQ(5r$6;r6LuFj-fW zE*y5P-Hm*^)p01Vua6b;jc-f{Nq~nK7sc~jdzp4C?H~4zuXe>7ZDQB_L$nj z{QZXHfCDIEM=~u8&>e?&EwgM4p{6H=jbol(Uk3n|qgpac<3&)deRD0PIKNS3^_lKe z&R!6hHFkuINiVLSgfd;)XzgWaAgLL1E}?>U62c~y5vUD|39oV|ULS^EAriSgqvLx- z`RW2bB|dgTI-V-cM)^MRX#-RN6#i4-Yfx+Zt|pEtx)*|Vc?pOn(W9`YqV|ut0Helh zqppRBirykDYhWUL^-l!}_GOuVOnVjXL8g%T9dqpXv9Ow2UCs=Yr6z2*+oE;-EoFTH zj$`|G!8ek3MDllRc^|2?6FZZ413;VkhpVdVoE& zyyHH+3){eQ%yo@@Jh%Tr?9Nc+TeYjIIrylb%f}i?OcH!J`z)V!z83AVwC;W@Hy~DM z=r{4x0v^fF>=lE|*dd^k5hw?us*sO)L;Z_Jy7#S0LhohLyEsvJ(_*Q#q^fIF<) z?EEua1t#kIyZg}rVFhh6GwTPnXD1D$mpg+@SP}|0kBL>?omkwJuNqEUzKB-z;~kQ? zzDaokKpayMlgNQaba*EVs35-I<~~WF@1uV(mw)SU_bD3*?>oLg^fPs=#s#JJ5DiLUOqjP4DUBU#sK`=}fEY^Q@*k^qbvh@A(& z)tBgA)Xj#WA85{ZNFD^CU@0(7gJf>rH4Q%3kNdCpEw1pOQ8+aHykOybjVI(PR82h} zDKJM6S*?v$JC!(xZynlaEH6-?wtZ9!Fk4xreGuf*CMGyLI$2Vd*qOs znEX(o%bq>WyesV%GDNCW_-+7IG0Hc3+g?*0CBRz)0+FU(;Xe3Mjf`iKMrz2$>ncE&AcKw zMEE_i-oLWEP1n!tS6Z`)E#WBwU>S6a83TQeN4F`Pq`-$;%lQtOnWr=JmEQJbH~KYt zO$ddu{Z#_%GTTeKy3ub`8asl=R>h!y$gb-EFz6&r6Nl3*FBT>?+iw> zzJ|$Uggcr_8HP#L?rGvywEKF*29fRQ?$prC61P+~FSyal=Jlm0F21H+W<`F%yVBm+ z{NA@d^CkLn?15`f=ctiNFlT8q3h4H(ue{wGY30=YZ&`L1D(N4nAg&^@TNg^KkC7x| z?1@E=BHKV4O#64iFoPCQ|htCXf6%`w;7kB55F0(^tA9x?$@&Yd{Pw)-X(k-9XSn!R$|Tz$5roRna69 zI{jZ$(7Jrbn5udbV>vO~owDw==)IVx*X9xo?NJt~!K?lyGn$XHxd%ECoy-9?F8VBE z7hSI#{OK4Kf4-^{FyxJ0JRqUM8t%k4k@s6t4}_kMQ=jmK4e;Z9$-a8-2S5a zGvKXYlyKq+MnpF(UAq)X3xTN#Le@O85MGND>u{}7ez?Y|#Krj&hgK#V#pl==l3l2c zu-_R=dx2HQ5}p)%9BmNtc7gj2q1G(R+yqF)-T@A!LlU38Ch0S-pS;AY4IiQB$g8R{ zDVUsTgz&ec`x@~C1?>jF^aYY7o+4?r~;nY~3U-|;2`RmzLe zCi1n}D`6si;XVG*u~lzj@(r?O0=}d1<66(^NCsV~g|um6-K)}i-zWA`J%SP5O2?hY zUQ*)A-Mol7J*up3A-*F_-o@uiKcPFvn;% z2Hl^$nfJ$8%Jv17@>CL0X)wBYmgCh4HzUNl)O2Bi?E%Kf;9n#)&g!@6&PD?w{^-Uh z3OLh*S;O!_u=&p*2ta~hTd)KSKNMq@!#lrzJKlg<`9=+0=i<-nMX9iZzDts;Uom#v zcBFlHoPrw@u0(43Zxs0^4U6m0kw<=l-l40wYb-vkw$HuI)!yQBOIicyloy({X^p_*T>X4%N^aq2b`MKa~Y^jNR zKA8rxOZEJn_gJyu7nwQ{pZ+TI=NWezCwHL3eZo?VzhmndtpmZec(S9XOiFfg)c+~SeXu&O_R{C2ya7eevrRp*2zO0zalx_pwYBdBAxkfgk4 zfXs*G%5vtA-K$KwQ(w9cAF^EYT735!cNI$FSqZzYc)EkNi3@zPDi1c-w8Ma@FrjVJ zs%BC=S{6lT_N-D*tL9CP)uNcfZQH&rH35?Xu4TeCoEZ%~!L}cKZg??hnQto34?aiL zqy?SbB!>1OhkzYMcccVOSQ(=ZrBK9lep;e!dNSvS6m7`{coxu9uTY8B7^0aws7{gQ zi{_0&pql`*f<%2PUJY4b=c8WV3wCgKy<*ucs3y{o0*Ij9!bFd=?v~r;b>N8z6aKqo zG}f^{SiRU0yvm15dE=@n^JvFtU=3d87xX~4?WfBV6PKR6%NjUCfmO`%H(;J~L)`jR zXT=CO_#sH*g8!qm?+%LM>$V*-5*5KA=VT)193*E!5D7z2keq}8W`-b=B}+y!D9IrR zLu^1m$w`u=K_q7x(hQ()e&2gluj;;AukLs6KV97??0vdV_vxy$*Io-r1q-q82q$J% zUfi2WmFHB=Il=vk5N4T?$)JqpwelEjib*)mN=-g zeW`LD4av2$2arYX**7H8k^R09#BB`s#|xVVme>f~x@D-dn-6eXxr0*hJ|v}VJ@+r< zoH#$bBcgms`=>~~FuTwwit8nOK%uOIlGatGWjkeeHd|w%Z3g4`Srj1q3j>s5L?667vvv_6t)zUp(2uPw0V#+8?Am6?Xa8x1k+d<@wK*dA!2soHQbA+ z6`?v~nSyLIbcb7lxKc`=^7u>ChfxC%_A6CbqzhK@7FHQX0Y>0T^g7dQ>#8K8L};jr>+$?x9)y&Oks0NC;2P&c{_8 zh*4CVdhhN`Uf2tdolN#JZAwFpZOY-{iVx7~S9sVWo~`h&g+7+%!LDv;6FYkI(F8Q= zmxh5_ByMQ0;z9UZw-)?%za;j62o>QR__g)zr=KoPea@_3Hk(&lKwWs7@4S$4U9a9G z%(e@9kxSz7kjxko37D8PLDtJ3*G)ur+}x6fPW}P7pEm2+!X~TOvjBA*Kib^zVH9cC z-H$aZATrk`0zad7MztY+b>Azr?<{7qb}IP`S9bl2b?q&cD<{J zavqI@QQ!*{Ap451=+>+l&;}RrlQC<#`;1E(DOkEPF0>bWV#qM+Wc+m!mhQR+-oOAF z&fJQB-)51(O+h5mo-aFX7xzGlo7j{$l2fqsn9!H#P8{iX!8a1Ns^%;C~*%|i2(Nb0uMl(oZrGz`RnLwY3RK!8l#R zwgu4(vdTLI;H$h%>8ewxj!G|_0Q=P*)ic`)epb2jdqEZ8=>gBPfJ*glYa2)|I*;A{|cdn3%+-r|Af8%-rS2lpo-@B z?v5Tj_QW-8ME7vGltUNRM~DU5hOr0f>ql=ypJuEFq&sEpb)s={sNcskA?b$BZ4aQ6 z`a`ES=XChI5ZFvpk>J~3-u)+G(fZ4A0@5<0D_rlG9dnGvxrir!u(Q^`5@IBzj?)Yu z;McPgnW5}g)dRysm{OCI$IRZtke}88Q_^M2)$|+K`L5o&dCrxpiPW_R^iYF`o;?M+s$5x%y;=p4C9y`lIZ ze11mTHA>gI8(wDgoG~}ei;ibD?ZzI@<^v3yO8tj|LMjW){%PT>nCUQ7aU)w-B`>m< zZ;gm^wG5TCILcPn^}4=u7?r0+F>kC1Sz8EuT*N@@w`RD$gNV;#Si{b6vKe@2H??r} z&K2TGA}bqmgT<9asZ;KbkfQAFp@*wR!-g8emkUR+WmQQ5N6o`>2ltVcBK-Cq?ZHJ#XS3xsmoBj-4WMXd(2Bho4938-wrH_GHC96KT?Bl=8 z*#s|`L8;U5nj00?yT^{mq^ll6-F?fPq`1BptNg~k({dEcjO$)+J06RoE%JkDY>&)A zD;x1}wn2qwU3VGsh?)!Ej-48RtJ%N4L739v}?eX;mVg3bKp6r5-@3IEfqA z)PjfL^1Q?01UC%2EJtSf?D@yk+k92y2}}%1H50<#Py{;+mwJQOfKiL#ly6%p#-yX> z7;0^DP`rewFz>dDjCG7fE{%?3OB7_=(eN~b5>JRW_Zi-?cJHkx$U4?Mr*!HV?oU;x z^sO46?WM2p9>QG=Y)!4-7&c|G>1f9e{NiOK^ge;T#f_=yN{vj{uC*UpdOXG5TJgLuIL+OMU3#x-0FrCQn!% z>4%2;PL*8j4K#uz+9GCbljB7FIr(f>aacLm{4?T}>~~g$ZpV^%gd0=x@@>p>sc$O! zxBH|B(ukn-E7Rg$rivNVZ0;>nu4kCQ(ldciT^X;L)Jj` z;lm+!IuHY-uU-=XsE5)k>Lgy%(@iu2Ed$}K;$)L=p2jpDpAsgC86dLHe-Q3G;_-R8 zAxSXwF9TlSETh=|-OV5EAQ8XVE3TP=%+cv!3lxDF*i79?x*xqjiaT@F@>ulkG}?ZK z6>^`u?JuC2W<)`k_+%*|RmrCcyyC+Tam3SMCc6Oew)WWz_Pr(tf-^Zh!>Q{OjN;on zpOW11*$%sqMWb%k)8~b+nuz9h*DggnEsyE5FYLhC0U?<gLh4g|oE| zlYaMJT3`wPzW#UgD$yJPqbmYFe2Kr54beRkDshB20ts)|m9BcklIpyTV0E_bOM-B9)IjhE(mW2)H!SuUa50-f20@!dzBqBv%% z!wh8zT0h~B*4gcojp|8S%ko+#ZtVBdMhcQ#iGU)z3E}ZujC3YCF_he`;MLn51W+~O zEbmJrm4f9AGosB5xgwGkTzu3>?Ot!87t>8SXMfPu1LH+p{#oz=?ddh8Oc9EYfLy+` z}1t(Uf7wmQ>1Q}sI9)nDAFG3oC-x$cLB;)GrtSiXlj|d_En*HX7%)TE7&mXs>>DmGHr2Gn-jQC0zb>{0^ zVh_0Lw)BKJTOS3fOf|QMQk73~m(%vsP7&v)&ylnb?smzFdf4e}*zxG1O;_rlbVC!< zv6Uq|)sxa>!zBi(;@y2F+=X65sp3EW*wcp1aXJ|!ut3bL~h%}rlj3j}FN1*oT9MOd_*P|I*9P+5tnMV0ZeBerif z^HdTor+ds6y^K6*ypET6c*+5pT1GrWXrR^Y$Op=u9i3QG^Yyzl2y~`X&(t16uW;s^ zE$8!{QO`?HMvmP9g1#)ceo^xi+;YVqT^e4~A2Hms*+?&ur}hX765it53Vq_8fS7wX zc{a<$kd{7WZJd|eYhZX_rx%@i8%A>8^SKn27{Jm_6?^hq%(gw=-FVG}cRhYWx zH5(alszDgI#QkkG9VRn{!s0;3u5WX9D`~$ZPGvIZvu1$21(01OSX_o#NY!9yI`P;= zQ@E9jUz$u1g`Gwd94Yqnq~?BIiN)K`fMN`lS4WyNZ(XnotZCds2T{;`?x%8O!tbjR z_mSl76o&arDo%5;m4fVksTYHHJ5K?Kh`W{So{kVlS{nXs z0!I_BSj@6=OU>5jz#4HFqeDR5(%-Hz3~bg=pNRFoRh*y+3umv^+_?mc!nz*qx~cB4 ztfk8TW+Y%ULVtCS3E?wJLXnMnIVS=??MO}ycC;KQWD9pAgY-xgO1%WtqF(SwA>u*4 zB>wBhjU;`b08rlgKr-FJhYbDvIA+H{rA zWU_~0#^rWy9X+9yd{&LDZz53`$r-t%Vk10YMf7x2>{t=<^Zq!cG2qln{hkaIkuzl^ z%$=0|+{0BX3cIwbh(AM99rbTJYs<2?Y&0JzAoNOoGmiMjZqk8nxMGK>i`{JAGyBaV z{6Y|VcI=~ZYrh!74m@}d6~<2X^}5pmd6XfKKo}Mm6~Qot>MJ1{xZ!niqQGw$eL}6- zzt#4p_ru|U``#=;K*6D*>;&#H1GO%Quk{Pjhr>oJ&K4&$N^`Ym%%VhmUf#L)pj^0x zMuBvk*Cf^8uP0ae68R|p5U zhH2pu@zkB~nGIg%z9}Q~)h0HXL;0mIQqAs6W>z#pNx}vJ<;y>1xno+pFw(-H<97zq zo4YJD=Ei8sl^kB@_HOAwB?(-Jg2Sw|2;VgYRV*%;CYXH+%D~9s$K4RV$Hx3Q1_)mM zc$Y-8z_v4b&EC-jk*$B9%vvGzE~njRz`sy`_+>tRh9frtxdo{Xr>aE~M-LW+GCO|J zblPJXhf9Ua-M**=Hkr#3gbo z7kAwESaZ8g=g)$6wnN>`3Sw4H{R2r>Aay&0a14JzCodMYct!*=E*}N z&yig1A@x0+SeuIHl$QlTv+J<6OPLi>`xKO-Q6VVo@cEtT%p4Uj9(i`v8AG!$OoOi* zVIj}qL6-}}IyMt`MzGjO!;Sa!vB_MSmVjQnfv|91sHRS};w9oR?5j?2O`OH42Pk3T z&yZc@iGf7e$mMUQ=%aY)(SB85oH#CkKq1B6^5P+`oYeSv><_x5Em`4{Mgr?G(j1zH z)m|F}aS1C#-Gd*bcnu{#BKKvzIm(1j`)CW)h19ud1fQW3>GWAU%Mb5ndDqgnhIo`$ z38qqQywN)yvr;bcVz(ZueSm*+i@bKs83(}uPAt|&4LYJnUvG(nCL0zMJX|^gTJ^9pa(OmE;vrVW!co@x=V-GzhDQ0-M z;Wzi?mTU22-k$oKNq~Lzs;<&cVW>keiR2UO?F*|WlxLjzii~*;M~HBp5%RH>4aRb)`v7LmgVVpE@l-T)IJ!$DJW2>SrDAmGfCVp3w&MDuYr%=7hV^=`R| zv|GIeNPF7)wl0PL1M}zHB=|oi|NI}7as})$HrjKN_k3jTCMRQ=+z|oPJTt`CsMI1& zN^~Q;Be`0P$is=j;f*!gZ3D3VDGp_QJRrI+RhS+xR*v5s!(R-vy0EUIsDDijfH$U3 z>)rur!oyoP_2lr3nBsl){8+V=h0C9ukSq=G(C!+g-xS?MMAE??1;2H^aDg;rmE9a^(DJnjSFn2{-Y{W8n~kacV$Temfgd?~{j}AFfI; ze)GBdgiNhZBc@p$W9&Du-4 zmwGxju)x2`*wfO4Gl`l!g^WX(j^4uWzBG86MEZqh(|)DTCy(@77YF%izk(vtv0_d23Ota(ASx02E$`T&1De#4K(&*zMB=E z+m+}8f8qIp9?g@rtWni_PStW_kq@mr+D1|#29dZEiQJQC={uJzhvqNlufU?)bGbvv zU1)$K@EfGH8@?MdYu@h|?)Lgn;2Fp>Et6}c2Yh`OuGqPmM3_z=m@jSYVt*_a;zgu5 zwwu!j)e(!uL$!93HFo!i(ZA}PKrE%!m6Bv=_OLB5P{JA@puY^-VnC~mM|g6=!5>4v zK;x~uiP0r%q+uS{LGrp6LQZ7E7H%DHbbzt` z7ofwSnkSBnX(h={D^<*(Rz85Iw-JHLMh+LHd5{?t)|kzne;-3Y0`kEXpOMgDy<^^|&EQgGdS}S(ZjIh}})G5ax^h0`iA<@-b2do1E zxxyU03zW%~m?v$Z#T$TppKmp@N+}x|0)(c{R}j{T!YCSiViW$2P*>8-)A&@HH zd=E1+w|bf7Wu^Q?B8_clX@h(#3%>eNM=a0F9YduHM{jJxAnqNSISraZ>N(+Fj9&Y- zE4jw|PWwAWPry2cf^aa3X!A0>onQn7+Ao}Voxd!(rR2;@c_Y^kU5h<2n2Q|_(e_zKHR9VWUW;9YL@Fj5{h{Zn%w9y=E z!0Z#noYZ;kd|o7XvB67~J*3q9-I0i}n)wDC_W#mueWaxI*oJ@1@92qA>d9J5(IAP` z3Mzb~@Z#sV4B*>SXaY|%TXFmS*r#`BtV-Yz!q-CKVh&WA9I+A1nYt_q>hht&wMnp> zSV9k0NQ(_x5Ew1MF7t74x<$AYLk)rO8Y~U#wE$~=+QZ(Sy{i-mRRK>SQ`T3DvwVY9 z813ck;15qjYi_J>f{t4;R0wdjz&v4J-P3H#<~Se?c4gQ$?G#!qZn8u@=s$L&gOG(D zkOom{NLxsI6@*D}K&B_))3(^pCZ)8&Z8(^@QXi@R6GqG+r-T0XW^`qe;6l@bpscu~bh0-&Jr?XY@4?r9FQ)Rs`L_QWKGD6{-s3tfDn(6!kPc_Dhs& z9Nb=AQUjL65S}PuNKE$d$ zJC6LkM(HvDo=g=k<%4MNa$s#Ky$NT3!e;~TtPtnd(QLH!!UzmkU9lp^7AH z!!3TxUj*$K>bOh$mpW?&w`Ik;AfM;u0R!FMuc6t5y+l|NW!c#TSB2hZ(AEW#@gbi7 zWPEsCwEtTXvhab3?w>fQ>R$+oXPkED-wAI18*NFnLhse@3om#5<4Z@w@X;qVyVw5< DY$>gM From 98a2de61f1a52a05547bfad48fd1c5a0c26434d4 Mon Sep 17 00:00:00 2001 From: Sonui Date: Wed, 31 Jul 2024 12:49:00 +0800 Subject: [PATCH 016/336] fix: Update Test_emailRepo_VerifyCode to handle additional parameters This commit updates the `Test_emailRepo_VerifyCode` function in the `email_repo_test.go` file. It adds support for additional parameters in the `SetCode` function call, specifically the `user_id` and `skip_validation_latest_code` parameters. This change ensures that the `VerifyCode` function can properly handle the updated code format. --- internal/repo/repo_test/email_repo_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/repo/repo_test/email_repo_test.go b/internal/repo/repo_test/email_repo_test.go index f9f43372..62d1ccb8 100644 --- a/internal/repo/repo_test/email_repo_test.go +++ b/internal/repo/repo_test/email_repo_test.go @@ -30,8 +30,8 @@ import ( func Test_emailRepo_VerifyCode(t *testing.T) { emailRepo := export.NewEmailRepo(testDataSource) - code, content := "1111", "test" - err := emailRepo.SetCode(context.TODO(), code, content, time.Minute) + code, content := "1111", "{\"source_type\":\"\",\"e_mail\":\"\",\"user_id\":\"1\",\"skip_validation_latest_code\":false}" + err := emailRepo.SetCode(context.TODO(), "1", code, content, time.Minute) assert.NoError(t, err) verifyContent, err := emailRepo.VerifyCode(context.TODO(), code) From 2167a8243c5660d68ac504cae03d6bfd1d6fb842 Mon Sep 17 00:00:00 2001 From: Sonui Date: Thu, 1 Aug 2024 23:53:55 +0800 Subject: [PATCH 017/336] fix: set last answer ID to zero if no answers --- internal/service/question_common/question.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index fce3761e..b9f2fd53 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -145,6 +145,15 @@ func (qs *QuestionCommon) UpdateAnswerCount(ctx context.Context, questionID stri if err != nil { return err } + if count == 0 { + err = qs.questionRepo.UpdateLastAnswer(ctx, &entity.Question{ + ID: questionID, + LastAnswerID: "0", + }) + if err != nil { + return err + } + } return qs.questionRepo.UpdateAnswerCount(ctx, questionID, int(count)) } From 8762f5b751a99da9e525b2f1c4625a5472813c4e Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 2 Aug 2024 00:01:01 +0800 Subject: [PATCH 018/336] typo: GetCss swagger annotation content --- internal/controller_admin/siteinfo_controller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/controller_admin/siteinfo_controller.go b/internal/controller_admin/siteinfo_controller.go index 623ab5f7..6429d671 100644 --- a/internal/controller_admin/siteinfo_controller.go +++ b/internal/controller_admin/siteinfo_controller.go @@ -188,12 +188,12 @@ func (sc *SiteInfoController) GetRobots(ctx *gin.Context) { ctx.String(http.StatusOK, resp.Robots) } -// GetRobots get site robots information -// @Summary get site robots information -// @Description get site robots information +// GetCss get site custom CSS +// @Summary get site custom CSS +// @Description get site custom CSS // @Tags site -// @Produce json -// @Success 200 {string} txt "" +// @Produce text/css +// @Success 200 {string} css "" // @Router /custom.css [get] func (sc *SiteInfoController) GetCss(ctx *gin.Context) { resp, err := sc.siteInfoService.GetSiteCustomCssHTML(ctx) From 5afa01ba8982ac91bac6e4d7ed399bd7e4fb98c8 Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 2 Aug 2024 09:33:48 +0800 Subject: [PATCH 019/336] perf: optimize search for unanswered questions using answer_count --- internal/repo/question/question_repo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 5a683af7..83a84157 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -385,7 +385,7 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, case "score": session.OrderBy("question.pin desc,question.vote_count DESC, question.view_count DESC") case "unanswered": - session.Where("question.last_answer_id = 0") + session.Where("question.answer_count = 0") session.OrderBy("question.pin desc,question.created_at DESC") } From 11fb3aafd879c001cc98d11214406140a02d0daf Mon Sep 17 00:00:00 2001 From: EkkoKo <65719025+EkkoKo@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:58:06 +0300 Subject: [PATCH 020/336] Makefile: Wraped with quotes the go location in go variable --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9cda2f5e..9dc8c983 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ DOCKER_CMD=docker GO_ENV=CGO_ENABLED=0 GO111MODULE=on Revision=$(shell git rev-parse --short HEAD 2>/dev/null || echo "") GO_FLAGS=-ldflags="-X github.com/apache/incubator-answer/cmd.Version=$(VERSION) -X 'github.com/apache/incubator-answer/cmd.Revision=$(Revision)' -X 'github.com/apache/incubator-answer/cmd.Time=`date +%s`' -extldflags -static" -GO=$(GO_ENV) $(shell which go) +GO=$(GO_ENV) "$(shell which go)" build: generate @$(GO) build $(GO_FLAGS) -o $(BIN) $(DIR_SRC) From c3a17046c6c3be1cec16ba49d07d9f7742b7260f Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 6 Aug 2024 16:43:13 +0800 Subject: [PATCH 021/336] fix: gavatar use sha256 for hash --- ui/package.json | 2 +- ui/pnpm-lock.yaml | 30 +++++-------------- ui/src/pages/Users/Settings/Profile/index.tsx | 4 +-- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/ui/package.json b/ui/package.json index 19e66981..8a087428 100644 --- a/ui/package.json +++ b/ui/package.json @@ -31,9 +31,9 @@ "diff": "^5.1.0", "front-matter": "^4.0.2", "i18next": "^21.9.0", + "js-sha256": "0.11.0", "lodash": "^4.17.21", "marked": "^4.0.19", - "md5": "^2.3.0", "next-share": "^0.18.1", "qrcode": "^1.5.1", "qs": "^6.11.0", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index b855bfa0..77bbee2d 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -53,15 +53,15 @@ importers: i18next: specifier: ^21.9.0 version: 21.9.2 + js-sha256: + specifier: 0.11.0 + version: 0.11.0 lodash: specifier: ^4.17.21 version: 4.17.21 marked: specifier: ^4.0.19 version: 4.1.0 - md5: - specifier: ^2.3.0 - version: 2.3.0 next-share: specifier: ^0.18.1 version: 0.18.1(react-dom@18.2.0)(react-scripts@5.0.1)(react@18.2.0) @@ -4642,10 +4642,6 @@ packages: resolution: {integrity: sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==} engines: {node: '>=12.20'} - /charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - dev: false - /check-types@11.1.2: resolution: {integrity: sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==} @@ -4977,10 +4973,6 @@ packages: shebang-command: 2.0.0 which: 2.0.2 - /crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - dev: false - /crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} @@ -7207,10 +7199,6 @@ packages: call-bind: 1.0.5 has-tostringtag: 1.0.0 - /is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - dev: false - /is-callable@1.2.6: resolution: {integrity: sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==} engines: {node: '>= 0.4'} @@ -8017,6 +8005,10 @@ packages: - ts-node - utf-8-validate + /js-sha256@0.11.0: + resolution: {integrity: sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q==} + dev: false + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -8362,14 +8354,6 @@ packages: hasBin: true dev: false - /md5@2.3.0: - resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} - dependencies: - charenc: 0.0.2 - crypt: 0.0.2 - is-buffer: 1.1.6 - dev: false - /mdn-data@2.0.14: resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} diff --git a/ui/src/pages/Users/Settings/Profile/index.tsx b/ui/src/pages/Users/Settings/Profile/index.tsx index ab2ee0f1..9af28ce6 100644 --- a/ui/src/pages/Users/Settings/Profile/index.tsx +++ b/ui/src/pages/Users/Settings/Profile/index.tsx @@ -21,7 +21,7 @@ import React, { FormEvent, useState, useEffect } from 'react'; import { Form, Button, Stack, ButtonGroup } from 'react-bootstrap'; import { Trans, useTranslation } from 'react-i18next'; -import MD5 from 'md5'; +import { sha256 } from 'js-sha256'; import type { FormDataType } from '@/common/interface'; import { UploadImg, Avatar, Icon, ImgViewer } from '@/components'; @@ -273,7 +273,7 @@ const Index: React.FC = () => { setFormData({ ...formData }); if (res.e_mail) { const str = res.e_mail.toLowerCase().trim(); - const hash = MD5(str); + const hash = sha256(str); setMailHash(hash); } }); From f0b585974709d4adc4364d533419c5fa45a83cd4 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Mon, 5 Aug 2024 17:03:23 +0800 Subject: [PATCH 022/336] feat: Add Open Search support --- internal/controller/template_controller.go | 8 +++++ .../controller/template_render/question.go | 22 ++++++++++++++ internal/router/template_router.go | 2 ++ ui/template/header.html | 1 + ui/template/opensearch.xml | 29 +++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 ui/template/opensearch.xml diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index a7d69ebc..09f5bffc 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -562,6 +562,14 @@ func (tc *TemplateController) html(ctx *gin.Context, code int, tpl string, siteI ctx.HTML(code, tpl, data) } +func (tc *TemplateController) OpenSearch(ctx *gin.Context) { + if tc.checkPrivateMode(ctx) { + tc.Page404(ctx) + return + } + tc.templateRenderController.OpenSearch(ctx) +} + func (tc *TemplateController) Sitemap(ctx *gin.Context) { if tc.checkPrivateMode(ctx) { tc.Page404(ctx) diff --git a/internal/controller/template_render/question.go b/internal/controller/template_render/question.go index a65c3083..83d08dc7 100644 --- a/internal/controller/template_render/question.go +++ b/internal/controller/template_render/question.go @@ -89,6 +89,28 @@ func (t *TemplateRenderController) Sitemap(ctx *gin.Context) { ) } +func (t *TemplateRenderController) OpenSearch(ctx *gin.Context) { + general, err := t.siteInfoService.GetSiteGeneral(ctx) + if err != nil { + log.Error("get site general failed:", err) + return + } + + favicon := "favicon.ico" + branding, err := t.siteInfoService.GetSiteBranding(ctx) + if err == nil { + favicon = branding.Favicon + } + + ctx.Header("Content-Type", "application/xml") + ctx.HTML( + http.StatusOK, "opensearch.xml", gin.H{ + "general": general, + "favicon": favicon, + }, + ) +} + func (t *TemplateRenderController) SitemapPage(ctx *gin.Context, page int) error { general, err := t.siteInfoService.GetSiteGeneral(ctx) if err != nil { diff --git a/internal/router/template_router.go b/internal/router/template_router.go index 01e8b307..195030f9 100644 --- a/internal/router/template_router.go +++ b/internal/router/template_router.go @@ -60,6 +60,8 @@ func (a *TemplateRouter) RegisterTemplateRouter(r *gin.RouterGroup, baseURLPath seoNoAuth.GET("/404", a.templateController.Page404) + seoNoAuth.GET("/opensearch.xml", a.templateController.OpenSearch) + seo := r.Group(baseURLPath) seo.Use(a.authUserMiddleware.CheckPrivateMode()) seo.GET("/", a.templateController.Index) diff --git a/ui/template/header.html b/ui/template/header.html index 6eff7340..653f9a28 100644 --- a/ui/template/header.html +++ b/ui/template/header.html @@ -33,6 +33,7 @@ + + + {{$.general.Name}} + {{if $.general.Description}} + {{$.general.Description}} + {{end}} + UTF-8 + {{$.favicon}} + + From 264f927433f8153cea3566ae7c981e2947d6e1ab Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Tue, 6 Aug 2024 15:39:55 +0800 Subject: [PATCH 023/336] fix: branding favicon might be empty --- internal/controller/template_render/question.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/controller/template_render/question.go b/internal/controller/template_render/question.go index 83d08dc7..b9753618 100644 --- a/internal/controller/template_render/question.go +++ b/internal/controller/template_render/question.go @@ -96,9 +96,9 @@ func (t *TemplateRenderController) OpenSearch(ctx *gin.Context) { return } - favicon := "favicon.ico" + favicon := general.SiteUrl + "/favicon.ico" branding, err := t.siteInfoService.GetSiteBranding(ctx) - if err == nil { + if err == nil && len(branding.Favicon) > 0 { favicon = branding.Favicon } From ea43edc864e718eb22e49e4e6576b958ab071d85 Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 7 Aug 2024 16:35:22 +0800 Subject: [PATCH 024/336] feat(badge): define func and add badge's list --- cmd/wire_gen.go | 11 +- docs/docs.go | 137 ++++++++++++++++- docs/swagger.json | 139 +++++++++++++++++- docs/swagger.yaml | 89 ++++++++++- internal/controller/badge_controller.go | 52 +++++++ internal/controller/controller.go | 1 + internal/entity/badge.go | 58 -------- .../{badge_award.go => badge_award_entity.go} | 10 ++ internal/entity/badge_entity.go | 60 ++++++++ .../{badge_group.go => badge_group_entity.go} | 0 internal/repo/badge/badge_repo.go | 76 ++++++++++ internal/repo/badge_award/badge_award_repo.go | 106 +++++++++++++ internal/repo/badge_group/badge_group_repo.go | 50 +++++++ internal/repo/provider.go | 6 + internal/router/answer_api_router.go | 6 + internal/schema/badge.go | 34 +++++ internal/service/badge/badge_service.go | 112 ++++++++++++++ .../badge_award/badge_award_service.go | 64 ++++++++ .../badge_group/badge_group_service.go | 40 +++++ internal/service/provider.go | 6 + 20 files changed, 975 insertions(+), 82 deletions(-) create mode 100644 internal/controller/badge_controller.go delete mode 100644 internal/entity/badge.go rename internal/entity/{badge_award.go => badge_award_entity.go} (88%) create mode 100644 internal/entity/badge_entity.go rename internal/entity/{badge_group.go => badge_group_entity.go} (100%) create mode 100644 internal/repo/badge/badge_repo.go create mode 100644 internal/repo/badge_award/badge_award_repo.go create mode 100644 internal/repo/badge_group/badge_group_repo.go create mode 100644 internal/schema/badge.go create mode 100644 internal/service/badge/badge_service.go create mode 100644 internal/service/badge_award/badge_award_service.go create mode 100644 internal/service/badge_group/badge_group_service.go diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 4928a122..c20aa2cf 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -40,6 +40,9 @@ import ( "github.com/apache/incubator-answer/internal/repo/activity_common" "github.com/apache/incubator-answer/internal/repo/answer" "github.com/apache/incubator-answer/internal/repo/auth" + "github.com/apache/incubator-answer/internal/repo/badge" + "github.com/apache/incubator-answer/internal/repo/badge_award" + "github.com/apache/incubator-answer/internal/repo/badge_group" "github.com/apache/incubator-answer/internal/repo/captcha" "github.com/apache/incubator-answer/internal/repo/collection" "github.com/apache/incubator-answer/internal/repo/comment" @@ -71,6 +74,7 @@ import ( "github.com/apache/incubator-answer/internal/service/activity_queue" "github.com/apache/incubator-answer/internal/service/answer_common" auth2 "github.com/apache/incubator-answer/internal/service/auth" + badge2 "github.com/apache/incubator-answer/internal/service/badge" collection2 "github.com/apache/incubator-answer/internal/service/collection" "github.com/apache/incubator-answer/internal/service/collection_common" comment2 "github.com/apache/incubator-answer/internal/service/comment" @@ -253,7 +257,12 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, reviewController := controller.NewReviewController(reviewService, rankService, captchaService) metaService := meta2.NewMetaService(metaCommonService, userCommon, answerRepo, questionRepo) metaController := controller.NewMetaController(metaService) - answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController) + badgeRepo := badge.NewBadgeRepo(dataData, uniqueIDRepo) + badgeGroupRepo := badge_group.NewBadgeGroupRepo(dataData, uniqueIDRepo) + badgeAwardRepo := badge_award.NewBadgeAwardRepo(dataData, uniqueIDRepo) + badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo) + badgeController := controller.NewBadgeController(badgeService) + answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController) swaggerRouter := router.NewSwaggerRouter(swaggerConf) uiRouter := router.NewUIRouter(controllerSiteInfoController, siteInfoCommonService) authUserMiddleware := middleware.NewAuthUserMiddleware(authService, siteInfoCommonService) diff --git a/docs/docs.go b/docs/docs.go index cf1264d1..6fc76693 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2239,6 +2239,49 @@ const docTemplate = `{ } } }, + "/answer/api/v1/badges": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "list all badges group by group", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "list all badges group by group", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetBadgeListResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/collection/switch": { "post": { "security": [ @@ -4410,7 +4453,7 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetTagResp" + "$ref": "#/definitions/schema.GetTagBasicResp" } } } @@ -5380,7 +5423,7 @@ const docTemplate = `{ }, "/answer/api/v1/tags": { "get": { - "description": "get tags list", + "description": "get tags list by slug name", "produces": [ "application/json" ], @@ -5404,7 +5447,22 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handler.RespBody" + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetTagBasicResp" + } + } + } + } + ] } } } @@ -7327,6 +7385,26 @@ const docTemplate = `{ } } }, + "schema.BadgeListInfo": { + "type": "object", + "properties": { + "award_count": { + "type": "integer" + }, + "earned": { + "type": "boolean" + }, + "icon": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "schema.CloseQuestionReq": { "type": "object", "required": [ @@ -7578,6 +7656,20 @@ const docTemplate = `{ } } }, + "schema.GetBadgeListResp": { + "type": "object", + "properties": { + "badges": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.BadgeListInfo" + } + }, + "group_name": { + "type": "string" + } + } + }, "schema.GetCommentPersonalWithPageResp": { "type": "object", "properties": { @@ -8242,6 +8334,23 @@ const docTemplate = `{ } } }, + "schema.GetTagBasicResp": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "recommend": { + "type": "boolean" + }, + "reserved": { + "type": "boolean" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.GetTagPageResp": { "type": "object", "properties": { @@ -9819,7 +9928,7 @@ const docTemplate = `{ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9828,7 +9937,7 @@ const docTemplate = `{ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9842,7 +9951,7 @@ const docTemplate = `{ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9851,7 +9960,7 @@ const docTemplate = `{ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9859,6 +9968,20 @@ const docTemplate = `{ } } }, + "schema.SiteWriteTag": { + "type": "object", + "required": [ + "slug_name" + ], + "properties": { + "display_name": { + "type": "string" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.TagItem": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 1e93d2b0..45936363 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2209,6 +2209,49 @@ } } }, + "/answer/api/v1/badges": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "list all badges group by group", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "list all badges group by group", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetBadgeListResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/collection/switch": { "post": { "security": [ @@ -4380,7 +4423,7 @@ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetTagResp" + "$ref": "#/definitions/schema.GetTagBasicResp" } } } @@ -5350,7 +5393,7 @@ }, "/answer/api/v1/tags": { "get": { - "description": "get tags list", + "description": "get tags list by slug name", "produces": [ "application/json" ], @@ -5374,7 +5417,22 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handler.RespBody" + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetTagBasicResp" + } + } + } + } + ] } } } @@ -7297,6 +7355,26 @@ } } }, + "schema.BadgeListInfo": { + "type": "object", + "properties": { + "award_count": { + "type": "integer" + }, + "earned": { + "type": "boolean" + }, + "icon": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "schema.CloseQuestionReq": { "type": "object", "required": [ @@ -7548,6 +7626,20 @@ } } }, + "schema.GetBadgeListResp": { + "type": "object", + "properties": { + "badges": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.BadgeListInfo" + } + }, + "group_name": { + "type": "string" + } + } + }, "schema.GetCommentPersonalWithPageResp": { "type": "object", "properties": { @@ -8212,6 +8304,23 @@ } } }, + "schema.GetTagBasicResp": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "recommend": { + "type": "boolean" + }, + "reserved": { + "type": "boolean" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.GetTagPageResp": { "type": "object", "properties": { @@ -8809,7 +8918,7 @@ "enum": [ "newest", "active", - "frequent", + "hot", "score", "unanswered" ] @@ -9789,7 +9898,7 @@ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9798,7 +9907,7 @@ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9812,7 +9921,7 @@ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9821,7 +9930,7 @@ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9829,6 +9938,20 @@ } } }, + "schema.SiteWriteTag": { + "type": "object", + "required": [ + "slug_name" + ], + "properties": { + "display_name": { + "type": "string" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.TagItem": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 93f8116a..c91c987e 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -342,6 +342,19 @@ definitions: maxLength: 100 type: string type: object + schema.BadgeListInfo: + properties: + award_count: + type: integer + earned: + type: boolean + icon: + type: string + id: + type: string + name: + type: string + type: object schema.CloseQuestionReq: properties: close_msg: @@ -513,6 +526,15 @@ definitions: description: if user is followed object will be true,otherwise false type: boolean type: object + schema.GetBadgeListResp: + properties: + badges: + items: + $ref: '#/definitions/schema.BadgeListInfo' + type: array + group_name: + type: string + type: object schema.GetCommentPersonalWithPageResp: properties: answer_id: @@ -983,6 +1005,17 @@ definitions: terms_of_service_parsed_text: type: string type: object + schema.GetTagBasicResp: + properties: + display_name: + type: string + recommend: + type: boolean + reserved: + type: boolean + slug_name: + type: string + type: object schema.GetTagPageResp: properties: created_at: @@ -1401,7 +1434,7 @@ definitions: enum: - newest - active - - frequent + - hot - score - unanswered type: string @@ -2071,13 +2104,13 @@ definitions: properties: recommend_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array required_tag: type: boolean reserved_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array restrict_answer: type: boolean @@ -2086,17 +2119,26 @@ definitions: properties: recommend_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array required_tag: type: boolean reserved_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array restrict_answer: type: boolean type: object + schema.SiteWriteTag: + properties: + display_name: + type: string + slug_name: + type: string + required: + - slug_name + type: object schema.TagItem: properties: display_name: @@ -4063,6 +4105,30 @@ paths: summary: recover answer tags: - Answer + /answer/api/v1/badges: + get: + consumes: + - application/json + description: list all badges group by group + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetBadgeListResp' + type: array + type: object + security: + - ApiKeyAuth: [] + summary: list all badges group by group + tags: + - api-badge /answer/api/v1/collection/switch: post: consumes: @@ -5382,7 +5448,7 @@ paths: - properties: data: items: - $ref: '#/definitions/schema.GetTagResp' + $ref: '#/definitions/schema.GetTagBasicResp' type: array type: object security: @@ -5965,7 +6031,7 @@ paths: - Tag /answer/api/v1/tags: get: - description: get tags list + description: get tags list by slug name parameters: - collectionFormat: csv description: string collection @@ -5980,7 +6046,14 @@ paths: "200": description: OK schema: - $ref: '#/definitions/handler.RespBody' + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetTagBasicResp' + type: array + type: object summary: get tags list tags: - Tag diff --git a/internal/controller/badge_controller.go b/internal/controller/badge_controller.go new file mode 100644 index 00000000..ebc534ce --- /dev/null +++ b/internal/controller/badge_controller.go @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package controller + +import ( + "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/middleware" + "github.com/apache/incubator-answer/internal/service/badge" + "github.com/gin-gonic/gin" +) + +type BadgeController struct { + badgeService *badge.BadgeService +} + +func NewBadgeController(badgeService *badge.BadgeService) *BadgeController { + return &BadgeController{ + badgeService: badgeService, + } +} + +// GetBadgeList list all badges +// @Summary list all badges group by group +// @Description list all badges group by group +// @Tags api-badge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Success 200 {object} handler.RespBody{data=[]schema.GetBadgeListResp} +// @Router /answer/api/v1/badges [get] +func (b *BadgeController) GetBadgeList(ctx *gin.Context) { + userID := middleware.GetLoginUserIDFromContext(ctx) + resp, err := b.badgeService.ListByGroup(ctx, userID) + handler.HandleResponse(ctx, err, resp) +} diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 9eb64c58..8fad918a 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -51,4 +51,5 @@ var ProviderSetController = wire.NewSet( NewCaptchaController, NewMetaController, NewEmbedController, + NewBadgeController, ) diff --git a/internal/entity/badge.go b/internal/entity/badge.go deleted file mode 100644 index 976bb47d..00000000 --- a/internal/entity/badge.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package entity - -import "time" - -const ( - BadgeStatusActive = 1 - BadgeStatusDeleted = 10 - BadgeStatusInactive = 11 - - BadgeLevelBronze = 1 - BadgeLevelSilver = 2 - BadgeLevelGold = 3 - - BadgeSingleAward = 1 - BadgeMultiAward = 2 -) - -// Badge badge -type Badge struct { - ID string `json:"id" xorm:"id"` - CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` - UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` - Name string `json:"name" xorm:"not null default '' VARCHAR(256) name"` - Icon string `json:"icon" xorm:"not null default '' VARCHAR(1024) icon"` - AwardCount int64 `json:"award_count" xorm:"not null default 0 INT(11) award_count"` - Description string `json:"description" xorm:"not null default '' MEDIUMTEXT description"` - Status int8 `json:"status" xorm:"not null default 1 INT(11) status"` - BadgeGroupId int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` - Level int64 `json:"level" xorm:"not null default 1 TINYINT(4) level"` - Single int8 `json:"single" xorm:"not null default 1 TINYINT(4) single"` - Collect string `json:"collect" xorm:"not null default '' VARCHAR(64) collect"` - Handler string `json:"handler" xorm:"not null default '' VARCHAR(64) handler"` - Param string `json:"param" xorm:"not null default '' VARCHAR(128) param"` -} - -// TableName badge table name -func (Badge) TableName() string { - return "badge" -} diff --git a/internal/entity/badge_award.go b/internal/entity/badge_award_entity.go similarity index 88% rename from internal/entity/badge_award.go rename to internal/entity/badge_award_entity.go index 235d369c..a852f6bd 100644 --- a/internal/entity/badge_award.go +++ b/internal/entity/badge_award_entity.go @@ -37,3 +37,13 @@ type BadgeAward struct { func (BadgeAward) TableName() string { return "badge_award" } + +type BadgeEarnedCount struct { + BadgeID string `xorm:"badge_id"` + EarnedCount int `xorm:"earned_count"` +} + +// TableName badge_award table name +func (BadgeEarnedCount) TableName() string { + return "badge_award" +} diff --git a/internal/entity/badge_entity.go b/internal/entity/badge_entity.go new file mode 100644 index 00000000..da6cd4dd --- /dev/null +++ b/internal/entity/badge_entity.go @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package entity + +import "time" + +type BadgeLevel int + +const ( + BadgeStatusActive = 1 + BadgeStatusDeleted = 10 + BadgeStatusInactive = 11 + + BadgeLevelBronze BadgeLevel = 1 + BadgeLevelSilver BadgeLevel = 2 + BadgeLevelGold BadgeLevel = 3 + + BadgeSingleAward = 1 + BadgeMultiAward = 2 +) + +// Badge badge +type Badge struct { + ID string `json:"id" xorm:"id"` + CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` + UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` + Name string `json:"name" xorm:"not null default '' VARCHAR(256) name"` + Icon string `json:"icon" xorm:"not null default '' VARCHAR(1024) icon"` + AwardCount int `json:"award_count" xorm:"not null default 0 INT(11) award_count"` + Description string `json:"description" xorm:"not null default '' MEDIUMTEXT description"` + Status int8 `json:"status" xorm:"not null default 1 INT(11) status"` + BadgeGroupId int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` + Level BadgeLevel `json:"level" xorm:"not null default 1 TINYINT(4) level"` + Single int8 `json:"single" xorm:"not null default 1 TINYINT(4) single"` + Collect string `json:"collect" xorm:"not null default '' VARCHAR(64) collect"` + Handler string `json:"handler" xorm:"not null default '' VARCHAR(64) handler"` + Param string `json:"param" xorm:"not null default '' VARCHAR(128) param"` +} + +// TableName badge table name +func (Badge) TableName() string { + return "badge" +} diff --git a/internal/entity/badge_group.go b/internal/entity/badge_group_entity.go similarity index 100% rename from internal/entity/badge_group.go rename to internal/entity/badge_group_entity.go diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go new file mode 100644 index 00000000..b4cd72f1 --- /dev/null +++ b/internal/repo/badge/badge_repo.go @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge + +import ( + "context" + "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/service/badge" + "github.com/apache/incubator-answer/internal/service/unique" +) + +type badgeRepo struct { + data *data.Data + uniqueIDRepo unique.UniqueIDRepo +} + +// NewBadgeRepo creates a new badge repository +func NewBadgeRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge.BadgeRepo { + return &badgeRepo{ + data: data, + uniqueIDRepo: uniqueIDRepo, + } +} + +// ListByLevel returns a list of badges by level +func (r *badgeRepo) ListByLevel(ctx context.Context, level entity.BadgeLevel) (badges []*entity.Badge, err error) { + badges = make([]*entity.Badge, 0) + err = r.data.DB.Context(ctx).Where("level = ?", level).Find(&badges) + return +} + +// ListByGroup returns a list of badges by group +func (r *badgeRepo) ListByGroup(ctx context.Context, groupID int64) (badges []*entity.Badge, err error) { + badges = make([]*entity.Badge, 0) + err = r.data.DB.Context(ctx).Where("group_id = ?", groupID).Find(&badges) + return +} + +// ListByLevelAndGroup returns a list of badges by level and group +func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) (badges []*entity.Badge, err error) { + badges = make([]*entity.Badge, 0) + err = r.data.DB.Context(ctx).Where("level = ? AND group_id = ?", level, groupID).Find(&badges) + return +} + +// ListActivated returns a list of activated badges +func (r *badgeRepo) ListActivated(ctx context.Context) (badges []*entity.Badge, err error) { + badges = make([]*entity.Badge, 0) + err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusActive).Find(&badges) + return +} + +// ListInactivated returns a list of inactivated badges +func (r *badgeRepo) ListInactivated(ctx context.Context) (badges []*entity.Badge, err error) { + badges = make([]*entity.Badge, 0) + err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusInactive).Find(&badges) + return +} diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go new file mode 100644 index 00000000..b6f0e95e --- /dev/null +++ b/internal/repo/badge_award/badge_award_repo.go @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge_award + +import ( + "context" + "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/service/badge_award" + "github.com/apache/incubator-answer/internal/service/unique" + "time" +) + +type badgeAwardRepo struct { + data *data.Data + uniqueIDRepo unique.UniqueIDRepo +} + +func NewBadgeAwardRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge_award.BadgeAwardRepo { + return &badgeAwardRepo{ + data: data, + uniqueIDRepo: uniqueIDRepo, + } +} + +func (r *badgeAwardRepo) Award(ctx context.Context, badgeID string, userID string, objectID string, force bool, createdAt time.Time) { + return +} +func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, objectID string) (isAward bool) { + return +} +func (r *badgeAwardRepo) CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) { + return +} +func (r *badgeAwardRepo) CountByUserId(ctx context.Context, userID string) (awardCount int64) { + return +} +func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) { + return +} +func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, objectID string) (awardCount int64) { + return +} +func (r *badgeAwardRepo) CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID string) (awardCount int64) { + return +} +func (r *badgeAwardRepo) CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, objectID string, badgeID string) (awardCount int64) { + return +} +func (r *badgeAwardRepo) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) { + err = r.data.DB.Context(ctx).Select("badge_id, count(`id`) AS earned_count").Where("user_id = ?", userID).GroupBy("badge_id").Find(&earnedCounts) + return +} +func (r *badgeAwardRepo) ListAllByUserId(ctx context.Context, userID string) (badgeAwards []*entity.BadgeAward) { + return +} +func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs []int64, page int64, pageSize int64, filterUserID int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []int64, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListPagedLatest(ctx context.Context, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int64, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + return +} +func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward) { + return +} +func (r *badgeAwardRepo) GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, objectID string) (badgeAward *entity.BadgeAward) { + return +} diff --git a/internal/repo/badge_group/badge_group_repo.go b/internal/repo/badge_group/badge_group_repo.go new file mode 100644 index 00000000..7dfe90fc --- /dev/null +++ b/internal/repo/badge_group/badge_group_repo.go @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge_group + +import ( + "context" + "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/service/badge_group" + "github.com/apache/incubator-answer/internal/service/unique" +) + +type badgeGroupRepo struct { + data *data.Data + uniqueIDRepo unique.UniqueIDRepo +} + +func NewBadgeGroupRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge_group.BadgeGroupRepo { + return &badgeGroupRepo{ + data: data, + uniqueIDRepo: uniqueIDRepo, + } +} + +func (r *badgeGroupRepo) ListGroups(ctx context.Context) (groups []*entity.BadgeGroup, err error) { + groups = make([]*entity.BadgeGroup, 0) + err = r.data.DB.Context(ctx).Find(&groups) + return +} + +func (r *badgeGroupRepo) AddGroup(ctx context.Context, group *entity.BadgeGroup) (err error) { + return +} diff --git a/internal/repo/provider.go b/internal/repo/provider.go index 3a517120..ee309e02 100644 --- a/internal/repo/provider.go +++ b/internal/repo/provider.go @@ -25,6 +25,9 @@ import ( "github.com/apache/incubator-answer/internal/repo/activity_common" "github.com/apache/incubator-answer/internal/repo/answer" "github.com/apache/incubator-answer/internal/repo/auth" + "github.com/apache/incubator-answer/internal/repo/badge" + "github.com/apache/incubator-answer/internal/repo/badge_award" + "github.com/apache/incubator-answer/internal/repo/badge_group" "github.com/apache/incubator-answer/internal/repo/captcha" "github.com/apache/incubator-answer/internal/repo/collection" "github.com/apache/incubator-answer/internal/repo/comment" @@ -100,4 +103,7 @@ var ProviderSetRepo = wire.NewSet( limit.NewRateLimitRepo, plugin_config.NewPluginUserConfigRepo, review.NewReviewRepo, + badge.NewBadgeRepo, + badge_group.NewBadgeGroupRepo, + badge_award.NewBadgeAwardRepo, ) diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index 32854186..dadf2a85 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -55,6 +55,7 @@ type AnswerAPIRouter struct { userPluginController *controller.UserPluginController reviewController *controller.ReviewController metaController *controller.MetaController + badgeController *controller.BadgeController } func NewAnswerAPIRouter( @@ -86,6 +87,7 @@ func NewAnswerAPIRouter( userPluginController *controller.UserPluginController, reviewController *controller.ReviewController, metaController *controller.MetaController, + badgeController *controller.BadgeController, ) *AnswerAPIRouter { return &AnswerAPIRouter{ langController: langController, @@ -116,6 +118,7 @@ func NewAnswerAPIRouter( userPluginController: userPluginController, reviewController: reviewController, metaController: metaController, + badgeController: badgeController, } } @@ -187,6 +190,9 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) { // reaction r.GET("/meta/reaction", a.metaController.GetReaction) + + // badges + r.GET("/badges", a.badgeController.GetBadgeList) } func (a *AnswerAPIRouter) RegisterAuthUserWithAnyStatusAnswerAPIRouter(r *gin.RouterGroup) { diff --git a/internal/schema/badge.go b/internal/schema/badge.go new file mode 100644 index 00000000..c52a235b --- /dev/null +++ b/internal/schema/badge.go @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package schema + +// BadgeListInfo get badge list response +type BadgeListInfo struct { + ID string `json:"id" ` + Name string `json:"name" ` + Icon string `json:"icon" ` + AwardCount int `json:"award_count" ` + Earned bool `json:"earned" ` +} + +type GetBadgeListResp struct { + Badges []*BadgeListInfo `json:"badges" ` + GroupName string `json:"group_name" ` +} diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go new file mode 100644 index 00000000..1109b444 --- /dev/null +++ b/internal/service/badge/badge_service.go @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge + +import ( + "context" + "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/badge_award" + "github.com/apache/incubator-answer/internal/service/badge_group" + "github.com/apache/incubator-answer/pkg/converter" +) + +type BadgeRepo interface { + ListByLevel(ctx context.Context, level entity.BadgeLevel) ([]*entity.Badge, error) + ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error) + ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) ([]*entity.Badge, error) + ListActivated(ctx context.Context) ([]*entity.Badge, error) + ListInactivated(ctx context.Context) ([]*entity.Badge, error) +} + +type BadgeService struct { + badgeRepo BadgeRepo + badgeGroupRepo badge_group.BadgeGroupRepo + badgeAwardRepo badge_award.BadgeAwardRepo +} + +func NewBadgeService( + badgeRepo BadgeRepo, + badgeGroupRepo badge_group.BadgeGroupRepo, + badgeAwardRepo badge_award.BadgeAwardRepo) *BadgeService { + return &BadgeService{ + badgeRepo: badgeRepo, + badgeGroupRepo: badgeGroupRepo, + badgeAwardRepo: badgeAwardRepo, + } +} + +func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []*schema.GetBadgeListResp, err error) { + var ( + groups []*entity.BadgeGroup + badges []*entity.Badge + earnedCounts []*entity.BadgeEarnedCount + + groupMap = make(map[int64]string, 0) + badgesMap = make(map[int64][]*schema.BadgeListInfo, 0) + ) + resp = make([]*schema.GetBadgeListResp, 0) + + groups, err = b.badgeGroupRepo.ListGroups(ctx) + if err != nil { + return + } + badges, err = b.badgeRepo.ListActivated(ctx) + if err != nil { + return + } + earnedCounts, err = b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, userID) + + for _, group := range groups { + groupMap[converter.StringToInt64(group.ID)] = group.Name + } + + for _, badge := range badges { + // check is earned + earned := false + if len(earnedCounts) > 0 { + for _, earnedCount := range earnedCounts { + if badge.ID == earnedCount.BadgeID { + earned = true + break + } + } + } + + badgesMap[badge.BadgeGroupId] = append(badgesMap[badge.BadgeGroupId], &schema.BadgeListInfo{ + ID: badge.ID, + Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), + Icon: badge.Icon, + AwardCount: badge.AwardCount, + Earned: earned, + }) + } + + for _, group := range groups { + resp = append(resp, &schema.GetBadgeListResp{ + GroupName: group.Name, + Badges: badgesMap[converter.StringToInt64(group.ID)], + }) + } + + return +} diff --git a/internal/service/badge_award/badge_award_service.go b/internal/service/badge_award/badge_award_service.go new file mode 100644 index 00000000..8f84453e --- /dev/null +++ b/internal/service/badge_award/badge_award_service.go @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge_award + +import ( + "context" + "github.com/apache/incubator-answer/internal/entity" + "time" +) + +type BadgeAwardRepo interface { + Award(ctx context.Context, badgeID string, userID string, objectID string, force bool, createdAt time.Time) + CheckIsAward(ctx context.Context, badgeID string, userID string, objectID string) bool + + CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) + CountByUserId(ctx context.Context, userID string) (awardCount int64) + CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) + CountByObjectId(ctx context.Context, objectID string) (awardCount int64) + CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID string) int64 + CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, objectID string, badgeID string) (awardCount int64) + + SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) + + ListAllByUserId(ctx context.Context, userID string) (badgeAwards []*entity.BadgeAward) + ListPagedByBadgeId(ctx context.Context, badgeID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + ListTagPagedByBadgeId(ctx context.Context, badgeIDs []int64, page int64, pageSize int64, filterUserID int64) (badgeAwards []*entity.BadgeAward, total int64) + ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []int64, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + ListPagedLatest(ctx context.Context, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int64) (badgeAwards []*entity.BadgeAward, total int64) + ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int64, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + + GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward) + GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, objectID string) (badgeAward *entity.BadgeAward) +} + +type BadgeAwardService struct { + badgeAwardRepo BadgeAwardRepo +} + +func NewBadgeAwardService(badgeAwardRepo BadgeAwardRepo) *BadgeAwardService { + return &BadgeAwardService{ + badgeAwardRepo: badgeAwardRepo, + } +} diff --git a/internal/service/badge_group/badge_group_service.go b/internal/service/badge_group/badge_group_service.go new file mode 100644 index 00000000..c78f3e4f --- /dev/null +++ b/internal/service/badge_group/badge_group_service.go @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge_group + +import ( + "context" + "github.com/apache/incubator-answer/internal/entity" +) + +type BadgeGroupRepo interface { + ListGroups(ctx context.Context) (groups []*entity.BadgeGroup, err error) + AddGroup(ctx context.Context, group *entity.BadgeGroup) (err error) +} + +type BadgeGroupService struct { + badgeGroupRepo BadgeGroupRepo +} + +func NewBadgeGroupService(badgeGroupRepo BadgeGroupRepo) *BadgeGroupService { + return &BadgeGroupService{ + badgeGroupRepo: badgeGroupRepo, + } +} diff --git a/internal/service/provider.go b/internal/service/provider.go index e82d9316..38832923 100644 --- a/internal/service/provider.go +++ b/internal/service/provider.go @@ -26,6 +26,9 @@ import ( "github.com/apache/incubator-answer/internal/service/activity_queue" answercommon "github.com/apache/incubator-answer/internal/service/answer_common" "github.com/apache/incubator-answer/internal/service/auth" + "github.com/apache/incubator-answer/internal/service/badge" + "github.com/apache/incubator-answer/internal/service/badge_award" + "github.com/apache/incubator-answer/internal/service/badge_group" "github.com/apache/incubator-answer/internal/service/collection" collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" "github.com/apache/incubator-answer/internal/service/comment" @@ -117,4 +120,7 @@ var ProviderSetService = wire.NewSet( notice_queue.NewNewQuestionNotificationQueueService, review.NewReviewService, meta.NewMetaService, + badge.NewBadgeService, + badge_award.NewBadgeAwardService, + badge_group.NewBadgeGroupService, ) From 23b6b11f9ea5f78c33902525d74509eca635992e Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 7 Aug 2024 17:13:32 +0800 Subject: [PATCH 025/336] feat(badge): badge init add icon --- internal/migrations/v22.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index b0016671..de15cea6 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -40,7 +40,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.autobiographer.name", - Icon: "", + Icon: "person-badge-fill", AwardCount: 0, Description: "badge.default_badges.autobiographer.desc", Status: entity.BadgeStatusActive, @@ -55,7 +55,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.editor.name", - Icon: "", + Icon: "pencil-fill", AwardCount: 0, Description: "badge.default_badges.editor.desc", Status: entity.BadgeStatusActive, @@ -70,7 +70,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.first_flag.name", - Icon: "", + Icon: "flag-fill", AwardCount: 0, Description: "badge.default_badges.first_flag.desc", Status: entity.BadgeStatusActive, @@ -85,7 +85,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.first_upvote.name", - Icon: "", + Icon: "hand-thumbs-up-fill", AwardCount: 0, Description: "badge.default_badges.first_upvote.desc", Status: entity.BadgeStatusActive, @@ -100,7 +100,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.first_reaction.name", - Icon: "", + Icon: "emoji-smile-fill", AwardCount: 0, Description: "badge.default_badges.first_reaction.desc", Status: entity.BadgeStatusActive, @@ -115,7 +115,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.first_share.name", - Icon: "", + Icon: "share-fill", AwardCount: 0, Description: "badge.default_badges.first_share.desc", Status: entity.BadgeStatusActive, @@ -130,7 +130,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.scholar.name", - Icon: "", + Icon: "check-circle-fill", AwardCount: 0, Description: "badge.default_badges.scholar.desc", Status: entity.BadgeStatusActive, @@ -145,7 +145,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.solved.name", - Icon: "", + Icon: "check-square-fill", AwardCount: 0, Description: "badge.default_badges.solved.desc", Status: entity.BadgeStatusActive, @@ -160,7 +160,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.nice_answer.name", - Icon: "", + Icon: "chat-square-text-fill", AwardCount: 0, Description: "badge.default_badges.nice_answer.desc", Status: entity.BadgeStatusActive, @@ -175,7 +175,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.good_answer.name", - Icon: "", + Icon: "chat-square-text-fill", AwardCount: 0, Description: "badge.default_badges.good_answer.desc", Status: entity.BadgeStatusActive, @@ -190,7 +190,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.great_answer.name", - Icon: "", + Icon: "chat-square-text-fill", AwardCount: 0, Description: "badge.default_badges.great_answer.desc", Status: entity.BadgeStatusActive, @@ -205,7 +205,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.nice_question.name", - Icon: "", + Icon: "question-circle-fill", AwardCount: 0, Description: "badge.default_badges.nice_question.desc", Status: entity.BadgeStatusActive, @@ -220,7 +220,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.good_question.name", - Icon: "", + Icon: "question-circle-fill", AwardCount: 0, Description: "badge.default_badges.good_question.desc", Status: entity.BadgeStatusActive, @@ -235,7 +235,7 @@ var ( CreatedAt: time.Now(), UpdatedAt: time.Now(), Name: "badge.default_badges.great_question.name", - Icon: "", + Icon: "question-circle-fill", AwardCount: 0, Description: "badge.default_badges.great_question.desc", Status: entity.BadgeStatusActive, From 2e626660e671b39d06324139341b5e326d4c7d9d Mon Sep 17 00:00:00 2001 From: "James Roller, Jr." Date: Mon, 5 Aug 2024 20:10:12 -0700 Subject: [PATCH 026/336] add pvc dataSource - allow for restoring a volumeSnapshot --- charts/templates/pvc.yaml | 8 +++++++- charts/values.yaml | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/charts/templates/pvc.yaml b/charts/templates/pvc.yaml index 5dfab8fc..640fb9fe 100644 --- a/charts/templates/pvc.yaml +++ b/charts/templates/pvc.yaml @@ -20,7 +20,7 @@ kind: PersistentVolumeClaim apiVersion: v1 metadata: name: {{ include "answer.fullname" . }}-claim - {{- with .Values.persistence.annotations }} + {{- with .Values.persistence.annotations }} annotations: {{ toYaml . | indent 4 }} {{- end }} @@ -39,4 +39,10 @@ spec: resources: requests: storage: {{ .Values.persistence.size | quote }} + {{- with .Values.persistence.dataSource }} + dataSource: + name: {{ .name }} + kind: {{ .kind | default "VolumeSnapshot" }} + apiGroup: {{ .apiGroup | default "snapshot.storage.k8s.io" }} + {{- end }} {{- end }} \ No newline at end of file diff --git a/charts/values.yaml b/charts/values.yaml index 8bb36c46..d932db84 100644 --- a/charts/values.yaml +++ b/charts/values.yaml @@ -68,7 +68,7 @@ env: # Configure extra containers extraContainers: [] - # - name: cloudsql-proxy + # - name: cloudsql-proxy # image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.1.2 # command: # - /cloud-sql-proxy @@ -91,6 +91,12 @@ persistence: accessMode: ReadWriteOnce size: 5Gi annotations: {} + # To restore a PVC from a VolumeSnapshot, set the dataSource; + # the kind and apiGroup are optional and default to the shown values + dataSource: {} + # name: my-volume-snapshot + # kind: VolumeSnapshot + # apiGroup: snapshot.storage.k8s.io imagePullSecrets: [] nameOverride: "" From 07e4f549b13216f76a69a897fb73d2a8fcd55de4 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 8 Aug 2024 16:19:47 +0800 Subject: [PATCH 027/336] feat(badge): add event for the badge --- cmd/wire_gen.go | 18 ++-- internal/base/constant/event.go | 75 ++++++++++++++++ internal/controller/template_controller.go | 16 ++++ internal/repo/badge/badge_event_handler.go | 57 ++++++++++++ internal/repo/badge/badge_rule.go | 95 ++++++++++++++++++++ internal/repo/badge/event_rule_mapping.go | 47 ++++++++++ internal/repo/badge/rule.go | 43 +++++++++ internal/schema/event_schema.go | 70 +++++++++++++++ internal/service/comment/comment_service.go | 19 +++- internal/service/content/answer_service.go | 13 +++ internal/service/content/question_service.go | 10 +++ internal/service/content/user_service.go | 8 ++ internal/service/content/vote_service.go | 31 +++++++ internal/service/event_queue/event_queue.go | 69 ++++++++++++++ internal/service/meta/meta_service.go | 22 ++++- internal/service/provider.go | 2 + internal/service/report/report_service.go | 30 ++++++- 17 files changed, 611 insertions(+), 14 deletions(-) create mode 100644 internal/base/constant/event.go create mode 100644 internal/repo/badge/badge_event_handler.go create mode 100644 internal/repo/badge/badge_rule.go create mode 100644 internal/repo/badge/event_rule_mapping.go create mode 100644 internal/repo/badge/rule.go create mode 100644 internal/schema/event_schema.go create mode 100644 internal/service/event_queue/event_queue.go diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 4928a122..c6cdc021 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -78,6 +78,7 @@ import ( config2 "github.com/apache/incubator-answer/internal/service/config" "github.com/apache/incubator-answer/internal/service/content" "github.com/apache/incubator-answer/internal/service/dashboard" + "github.com/apache/incubator-answer/internal/service/event_queue" export2 "github.com/apache/incubator-answer/internal/service/export" "github.com/apache/incubator-answer/internal/service/follow" meta2 "github.com/apache/incubator-answer/internal/service/meta" @@ -172,7 +173,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, metaRepo := meta.NewMetaRepo(dataData) metaCommonService := metacommon.NewMetaCommonService(metaRepo) questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaCommonService, configService, activityQueueService, revisionRepo, dataData) - userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon) + eventQueueService := event_queue.NewEventQueueService() + userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon, eventQueueService) captchaRepo := captcha.NewCaptchaRepo(dataData) captchaService := action.NewCaptchaService(captchaRepo) userController := controller.NewUserController(authService, userService, captchaService, emailService, siteInfoCommonService, userNotificationConfigService) @@ -181,7 +183,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, objService := object_info.NewObjService(answerRepo, questionRepo, commentCommonRepo, tagCommonRepo, tagCommonService) notificationQueueService := notice_queue.NewNotificationQueueService() externalNotificationQueueService := notice_queue.NewNewQuestionNotificationQueueService() - commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo, emailService, userRepo, notificationQueueService, externalNotificationQueueService, activityQueueService) + commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo, emailService, userRepo, notificationQueueService, externalNotificationQueueService, activityQueueService, eventQueueService) rolePowerRelRepo := role.NewRolePowerRelRepo(dataData) rolePowerRelService := role2.NewRolePowerRelService(rolePowerRelRepo, userRoleRelService) rankService := rank2.NewRankService(userCommon, userRankRepo, objService, userRoleRelService, rolePowerRelService, configService) @@ -194,13 +196,13 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, externalNotificationService := notification.NewExternalNotificationService(dataData, userNotificationConfigRepo, followRepo, emailService, userRepo, externalNotificationQueueService, userExternalLoginRepo, siteInfoCommonService) reviewRepo := review.NewReviewRepo(dataData) reviewService := review2.NewReviewService(reviewRepo, objService, userCommon, userRepo, questionRepo, answerRepo, userRoleRelService, externalNotificationQueueService, tagCommonService, questionCommon, notificationQueueService, siteInfoCommonService) - questionService := content.NewQuestionService(questionRepo, answerRepo, tagCommonService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService) - answerService := content.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService, reviewService) + questionService := content.NewQuestionService(questionRepo, answerRepo, tagCommonService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService, eventQueueService) + answerService := content.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService, reviewService, eventQueueService) reportHandle := report_handle.NewReportHandle(questionService, answerService, commentService) - reportService := report2.NewReportService(reportRepo, objService, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService) + reportService := report2.NewReportService(reportRepo, objService, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService, eventQueueService) reportController := controller.NewReportController(reportService, rankService, captchaService) contentVoteRepo := activity.NewVoteRepo(dataData, activityRepo, userRankRepo, notificationQueueService) - voteService := content.NewVoteService(contentVoteRepo, configService, questionRepo, answerRepo, commentCommonRepo, objService) + voteService := content.NewVoteService(contentVoteRepo, configService, questionRepo, answerRepo, commentCommonRepo, objService, eventQueueService) voteController := controller.NewVoteController(voteService, rankService, captchaService) tagService := tag2.NewTagService(tagRepo, tagCommonService, revisionService, followRepo, siteInfoCommonService, activityQueueService) tagController := controller.NewTagController(tagService, tagCommonService, rankService) @@ -251,7 +253,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, permissionController := controller.NewPermissionController(rankService) userPluginController := controller.NewUserPluginController(pluginCommonService) reviewController := controller.NewReviewController(reviewService, rankService, captchaService) - metaService := meta2.NewMetaService(metaCommonService, userCommon, answerRepo, questionRepo) + metaService := meta2.NewMetaService(metaCommonService, userCommon, answerRepo, questionRepo, eventQueueService) metaController := controller.NewMetaController(metaService) answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController) swaggerRouter := router.NewSwaggerRouter(swaggerConf) @@ -260,7 +262,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, avatarMiddleware := middleware.NewAvatarMiddleware(serviceConf, uploaderService) shortIDMiddleware := middleware.NewShortIDMiddleware(siteInfoCommonService) templateRenderController := templaterender.NewTemplateRenderController(questionService, userService, tagService, answerService, commentService, siteInfoCommonService, questionRepo) - templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService) + templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService, eventQueueService, userService) templateRouter := router.NewTemplateRouter(templateController, templateRenderController, siteInfoController, authUserMiddleware) connectorController := controller.NewConnectorController(siteInfoCommonService, emailService, userExternalLoginService) userCenterLoginService := user_external_login2.NewUserCenterLoginService(userRepo, userCommon, userExternalLoginRepo, userActiveActivityRepo, siteInfoCommonService) diff --git a/internal/base/constant/event.go b/internal/base/constant/event.go new file mode 100644 index 00000000..f7fd8412 --- /dev/null +++ b/internal/base/constant/event.go @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package constant + +// EventType event type. It is used to define the type of event. Such as object.action +type EventType string + +// event object +const ( + eventQuestion = "question" + eventAnswer = "answer" + eventComment = "comment" + eventUser = "user" +) + +// event action +const ( + eventCreate = "create" + eventUpdate = "update" + eventDelete = "delete" + eventVote = "vote" + eventAccept = "accept" // only question have the accept event + eventShare = "share" // the object share link has been clicked + eventFlag = "flag" + eventReact = "react" +) + +const ( + EventUserUpdate EventType = eventUser + "." + eventUpdate + EventUserShare EventType = eventUser + "." + eventShare +) + +const ( + EventQuestionCreate EventType = eventQuestion + "." + eventCreate + EventQuestionUpdate EventType = eventQuestion + "." + eventUpdate + EventQuestionDelete EventType = eventQuestion + "." + eventDelete + EventQuestionVote EventType = eventQuestion + "." + eventVote + EventQuestionAccept EventType = eventQuestion + "." + eventAccept + EventQuestionFlag EventType = eventQuestion + "." + eventFlag + EventQuestionReact EventType = eventQuestion + "." + eventReact +) + +const ( + EventAnswerCreate EventType = eventAnswer + "." + eventCreate + EventAnswerUpdate EventType = eventAnswer + "." + eventUpdate + EventAnswerDelete EventType = eventAnswer + "." + eventDelete + EventAnswerVote EventType = eventAnswer + "." + eventVote + EventAnswerFlag EventType = eventAnswer + "." + eventFlag + EventAnswerReact EventType = eventAnswer + "." + eventReact +) + +const ( + EventCommentCreate EventType = eventComment + "." + eventCreate + EventCommentUpdate EventType = eventComment + "." + eventUpdate + EventCommentDelete EventType = eventComment + "." + eventDelete + EventCommentVote EventType = eventComment + "." + eventVote + EventCommentFlag EventType = eventComment + "." + eventFlag +) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 09f5bffc..a786f646 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -22,6 +22,8 @@ package controller import ( "encoding/json" "fmt" + "github.com/apache/incubator-answer/internal/service/content" + "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/apache/incubator-answer/plugin" "html/template" "net/http" @@ -54,12 +56,16 @@ type TemplateController struct { cssPath string templateRenderController *templaterender.TemplateRenderController siteInfoService siteinfo_common.SiteInfoCommonService + eventQueueService event_queue.EventQueueService + userService *content.UserService } // NewTemplateController new controller func NewTemplateController( templateRenderController *templaterender.TemplateRenderController, siteInfoService siteinfo_common.SiteInfoCommonService, + eventQueueService event_queue.EventQueueService, + userService *content.UserService, ) *TemplateController { script, css := GetStyle() return &TemplateController{ @@ -67,6 +73,8 @@ func NewTemplateController( cssPath: css, templateRenderController: templateRenderController, siteInfoService: siteInfoService, + eventQueueService: eventQueueService, + userService: userService, } } func GetStyle() (script []string, css string) { @@ -271,6 +279,7 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { id := ctx.Param("id") title := ctx.Param("title") answerid := ctx.Param("answerid") + shareUsername := ctx.Query("share") if checker.IsQuestionsIgnorePath(id) { // if id == "ask" { file, err := ui.Build.ReadFile("build/index.html") @@ -291,6 +300,13 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { tc.Page404(ctx) return } + if len(shareUsername) > 0 { + userInfo, err := tc.userService.GetOtherUserInfoByUsername( + ctx, &schema.GetOtherUserInfoByUsernameReq{Username: shareUsername}) + if err == nil { + tc.eventQueueService.Send(ctx, schema.NewEvent(constant.EventUserShare, userInfo.ID)) + } + } encodeTitle := htmltext.UrlTitle(detail.Title) if encodeTitle == title { correctTitle = true diff --git a/internal/repo/badge/badge_event_handler.go b/internal/repo/badge/badge_event_handler.go new file mode 100644 index 00000000..242778ec --- /dev/null +++ b/internal/repo/badge/badge_event_handler.go @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge + +import ( + "context" + "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/segmentfault/pacman/log" + + "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/schema" +) + +type BadgeEventService struct { + data *data.Data + eventQueueService event_queue.EventQueueService +} + +func NewBadgeEventService( + data *data.Data, + eventQueueService event_queue.EventQueueService, +) *BadgeEventService { + n := &BadgeEventService{ + data: data, + eventQueueService: eventQueueService, + } + eventQueueService.RegisterHandler(n.Handler) + return n +} + +func (ns *BadgeEventService) Handler(ctx context.Context, msg *schema.EventMsg) error { + log.Debugf("received badge event %+v", msg) + // TODO: Check if badge already exists + + // TODO: Check rule + + // TODO: Distribute badge + + return nil +} diff --git a/internal/repo/badge/badge_rule.go b/internal/repo/badge/badge_rule.go new file mode 100644 index 00000000..3ae0b7b4 --- /dev/null +++ b/internal/repo/badge/badge_rule.go @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge + +import ( + "context" + "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/base/reason" + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/service/unique" + "github.com/segmentfault/pacman/errors" +) + +// BadgeRuleRepo collection repository +type BadgeRuleRepo struct { + data *data.Data + uniqueIDRepo unique.UniqueIDRepo +} + +// FilledPersonalProfile filled personal profile +func (br *BadgeRuleRepo) FilledPersonalProfile(ctx context.Context, userID string) (reach bool, err error) { + bean := &entity.User{ID: userID} + exist, err := br.data.DB.Context(ctx).Get(bean) + if err != nil { + return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + if !exist { + return false, nil + } + if len(bean.Bio) > 0 { + return true, nil + } + return false, nil +} + +// FirstPostEdit first post edit +func (br *BadgeRuleRepo) FirstPostEdit(ctx context.Context, userID string, objectID string) { + +} + +// FirstFlaggedPost first flagged post. +func (br *BadgeRuleRepo) FirstFlaggedPost(ctx context.Context, userID string, reportID string) { +} + +// FirstVotedPost first voted post +func (br *BadgeRuleRepo) FirstVotedPost(ctx context.Context) { + +} + +// FirstReactedPost first reacted post +func (br *BadgeRuleRepo) FirstReactedPost(ctx context.Context) { + +} + +// FirstSharedPost first shared post +func (br *BadgeRuleRepo) FirstSharedPost(ctx context.Context) { + +} + +// AskQuestionAcceptAnswer ask question accept answer +func (br *BadgeRuleRepo) AskQuestionAcceptAnswer(ctx context.Context) { + +} + +// AnswerAccepted answer accepted +func (br *BadgeRuleRepo) AnswerAccepted(ctx context.Context) { + +} + +// ReachAnswerScore reach answer score +func (br *BadgeRuleRepo) ReachAnswerScore(ctx context.Context) { + +} + +// ReachQuestionScore reach question score +func (br *BadgeRuleRepo) ReachQuestionScore(ctx context.Context) { + +} diff --git a/internal/repo/badge/event_rule_mapping.go b/internal/repo/badge/event_rule_mapping.go new file mode 100644 index 00000000..8f01fdef --- /dev/null +++ b/internal/repo/badge/event_rule_mapping.go @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge + +import "github.com/apache/incubator-answer/internal/base/constant" + +var ( + EventRuleMapping = map[constant.EventType][]string{ + constant.EventUserUpdate: {FilledPersonalProfile}, + constant.EventUserShare: {FirstSharedPost}, + constant.EventQuestionCreate: {""}, + constant.EventQuestionUpdate: {FirstPostEdit}, + constant.EventQuestionDelete: {""}, + constant.EventQuestionVote: {FirstVotedPost, ReachQuestionScore}, + constant.EventQuestionAccept: {AskQuestionAcceptAnswer, AnswerAccepted}, + constant.EventQuestionFlag: {FirstFlaggedPost}, + constant.EventQuestionReact: {FirstReactedPost}, + constant.EventAnswerCreate: {""}, + constant.EventAnswerUpdate: {FirstPostEdit}, + constant.EventAnswerDelete: {""}, + constant.EventAnswerVote: {FirstVotedPost, ReachAnswerScore}, + constant.EventAnswerFlag: {FirstFlaggedPost}, + constant.EventAnswerReact: {FirstReactedPost}, + constant.EventCommentCreate: {""}, + constant.EventCommentUpdate: {""}, + constant.EventCommentDelete: {""}, + constant.EventCommentVote: {FirstVotedPost}, + constant.EventCommentFlag: {FirstFlaggedPost}, + } +) diff --git a/internal/repo/badge/rule.go b/internal/repo/badge/rule.go new file mode 100644 index 00000000..635b30da --- /dev/null +++ b/internal/repo/badge/rule.go @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge + +const ( + // FilledPersonalProfile filled personal profile + FilledPersonalProfile = "filled_personal_profile" + // FirstPostEdit first post edit + FirstPostEdit = "first_post_edit" + // FirstFlaggedPost first flagged post. + FirstFlaggedPost = "first_flagged_post" + // FirstVotedPost first voted post + FirstVotedPost = "first_voted_post" + // FirstReactedPost first reacted post + FirstReactedPost = "first_reacted_post" + // FirstSharedPost first shared post + FirstSharedPost = "first_shared_post" + // AskQuestionAcceptAnswer ask question accept answer + AskQuestionAcceptAnswer = "ask_question_accept_answer" + // AnswerAccepted answer accepted + AnswerAccepted = "answer_accepted" + // ReachAnswerScore reach answer score + ReachAnswerScore = "reach_answer_score" + // ReachQuestionScore reach question score + ReachQuestionScore = "reach_question_score" +) diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go new file mode 100644 index 00000000..01f80fbb --- /dev/null +++ b/internal/schema/event_schema.go @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package schema + +import "github.com/apache/incubator-answer/internal/base/constant" + +// EventMsg event message +type EventMsg struct { + EventType constant.EventType + UserID string + + QuestionID string + QuestionUserID string + + AnswerID string + AnswerUserID string + + CommentID string + CommentUserID string + + ExtraInfo map[string]string +} + +func NewEvent(e constant.EventType, userID string) *EventMsg { + return &EventMsg{ + UserID: userID, + EventType: e, + ExtraInfo: make(map[string]string), + } +} + +func (e *EventMsg) QID(questionID, userID string) *EventMsg { + e.QuestionID = questionID + e.QuestionUserID = userID + return e +} + +func (e *EventMsg) AID(answerID, userID string) *EventMsg { + e.AnswerID = answerID + e.AnswerUserID = userID + return e +} + +func (e *EventMsg) CID(comment, userID string) *EventMsg { + e.CommentID = comment + e.CommentUserID = userID + return e +} + +func (e *EventMsg) AddExtra(key, value string) *EventMsg { + e.ExtraInfo[key] = value + return e +} diff --git a/internal/service/comment/comment_service.go b/internal/service/comment/comment_service.go index 9f2c45f1..75d30f9d 100644 --- a/internal/service/comment/comment_service.go +++ b/internal/service/comment/comment_service.go @@ -21,6 +21,7 @@ package comment import ( "context" + "github.com/apache/incubator-answer/internal/service/event_queue" "time" "github.com/apache/incubator-answer/internal/base/constant" @@ -86,6 +87,7 @@ type CommentService struct { notificationQueueService notice_queue.NotificationQueueService externalNotificationQueueService notice_queue.ExternalNotificationQueueService activityQueueService activity_queue.ActivityQueueService + eventQueueService event_queue.EventQueueService } // NewCommentService new comment service @@ -100,6 +102,7 @@ func NewCommentService( notificationQueueService notice_queue.NotificationQueueService, externalNotificationQueueService notice_queue.ExternalNotificationQueueService, activityQueueService activity_queue.ActivityQueueService, + eventQueueService event_queue.EventQueueService, ) *CommentService { return &CommentService{ commentRepo: commentRepo, @@ -112,6 +115,7 @@ func NewCommentService( notificationQueueService: notificationQueueService, externalNotificationQueueService: externalNotificationQueueService, activityQueueService: activityQueueService, + eventQueueService: eventQueueService, } } @@ -184,13 +188,19 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment OriginalObjectID: req.ObjectID, ActivityTypeKey: constant.ActQuestionCommented, } + var event *schema.EventMsg switch objInfo.ObjectType { case constant.QuestionObjectType: activityMsg.ActivityTypeKey = constant.ActQuestionCommented + event = schema.NewEvent(constant.EventCommentCreate, req.UserID). + CID(comment.ID, comment.UserID).QID(objInfo.QuestionID, objInfo.ObjectCreatorUserID) case constant.AnswerObjectType: activityMsg.ActivityTypeKey = constant.ActAnswerCommented + event = schema.NewEvent(constant.EventCommentCreate, req.UserID). + CID(comment.ID, comment.UserID).AID(objInfo.AnswerID, objInfo.ObjectCreatorUserID) } cs.activityQueueService.Send(ctx, activityMsg) + cs.eventQueueService.Send(ctx, event) return resp, nil } @@ -241,7 +251,12 @@ func (cs *CommentService) addCommentNotification( // RemoveComment delete comment func (cs *CommentService) RemoveComment(ctx context.Context, req *schema.RemoveCommentReq) (err error) { - return cs.commentRepo.RemoveComment(ctx, req.CommentID) + err = cs.commentRepo.RemoveComment(ctx, req.CommentID) + if err != nil { + return err + } + cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentDelete, req.UserID).CID(req.CommentID, req.UserID)) + return nil } // UpdateComment update comment @@ -273,6 +288,8 @@ func (cs *CommentService) UpdateComment(ctx context.Context, req *schema.UpdateC OriginalText: req.OriginalText, ParsedText: req.ParsedText, } + cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentUpdate, req.UserID). + CID(old.ID, old.UserID)) return resp, nil } diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index f8feda8a..5674a79b 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -22,6 +22,7 @@ package content import ( "context" "encoding/json" + "github.com/apache/incubator-answer/internal/service/event_queue" "time" "github.com/apache/incubator-answer/internal/base/constant" @@ -67,6 +68,7 @@ type AnswerService struct { externalNotificationQueueService notice_queue.ExternalNotificationQueueService activityQueueService activity_queue.ActivityQueueService reviewService *review.ReviewService + eventQueueService event_queue.EventQueueService } func NewAnswerService( @@ -86,6 +88,7 @@ func NewAnswerService( externalNotificationQueueService notice_queue.ExternalNotificationQueueService, activityQueueService activity_queue.ActivityQueueService, reviewService *review.ReviewService, + eventQueueService event_queue.EventQueueService, ) *AnswerService { return &AnswerService{ answerRepo: answerRepo, @@ -104,6 +107,7 @@ func NewAnswerService( externalNotificationQueueService: externalNotificationQueueService, activityQueueService: activityQueueService, reviewService: reviewService, + eventQueueService: eventQueueService, } } @@ -175,6 +179,8 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns OriginalObjectID: answerInfo.ID, ActivityTypeKey: constant.ActAnswerDeleted, }) + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerDelete, req.UserID). + AID(answerInfo.ID, answerInfo.UserID)) return } @@ -295,6 +301,8 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) ( OriginalObjectID: questionInfo.ID, ActivityTypeKey: constant.ActQuestionAnswered, }) + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerCreate, req.UserID). + AID(insertData.ID, insertData.UserID)) return insertData.ID, nil } @@ -383,6 +391,8 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq ActivityTypeKey: constant.ActAnswerEdited, RevisionID: revisionID, }) + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerUpdate, req.UserID). + AID(insertData.ID, insertData.UserID)) } return insertData.ID, nil @@ -436,6 +446,9 @@ func (as *AnswerService) AcceptAnswer(ctx context.Context, req *schema.AcceptAns oldAnswerInfo.ID = uid.DeShortID(oldAnswerInfo.ID) } + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionAccept, req.UserID). + QID(questionInfo.ID, questionInfo.UserID).AID(req.AnswerID, req.UserID)) + as.updateAnswerRank(ctx, req.UserID, questionInfo, acceptedAnswerInfo, oldAnswerInfo) return nil } diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index 6d8b37ba..dfb778ea 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -23,6 +23,7 @@ import ( "encoding/json" "fmt" answercommon "github.com/apache/incubator-answer/internal/service/answer_common" + "github.com/apache/incubator-answer/internal/service/event_queue" "strings" "time" @@ -84,6 +85,7 @@ type QuestionService struct { newQuestionNotificationService *notification.ExternalNotificationService reviewService *review.ReviewService configService *config.ConfigService + eventQueueService event_queue.EventQueueService } func NewQuestionService( @@ -106,6 +108,7 @@ func NewQuestionService( newQuestionNotificationService *notification.ExternalNotificationService, reviewService *review.ReviewService, configService *config.ConfigService, + eventQueueService event_queue.EventQueueService, ) *QuestionService { return &QuestionService{ questionRepo: questionRepo, @@ -127,6 +130,7 @@ func NewQuestionService( newQuestionNotificationService: newQuestionNotificationService, reviewService: reviewService, configService: configService, + eventQueueService: eventQueueService, } } @@ -385,6 +389,8 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question qs.externalNotificationQueueService.Send(ctx, schema.CreateNewQuestionNotificationMsg(question.ID, question.Title, question.UserID, tags)) } + qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionCreate, req.UserID). + QID(question.ID, question.UserID)) questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, req.QuestionPermission) return @@ -546,6 +552,8 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov OriginalObjectID: questionInfo.ID, ActivityTypeKey: constant.ActQuestionDeleted, }) + qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionDelete, req.UserID). + QID(questionInfo.ID, questionInfo.UserID)) return nil } @@ -937,6 +945,8 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest RevisionID: revisionID, OriginalObjectID: question.ID, }) + qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionUpdate, req.UserID). + QID(question.ID, question.UserID)) } questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, req.QuestionPermission) diff --git a/internal/service/content/user_service.go b/internal/service/content/user_service.go index 11f3bb63..2a6122ae 100644 --- a/internal/service/content/user_service.go +++ b/internal/service/content/user_service.go @@ -23,6 +23,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/apache/incubator-answer/internal/service/event_queue" "time" "github.com/apache/incubator-answer/internal/base/constant" @@ -65,6 +66,7 @@ type UserService struct { userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo userNotificationConfigService *user_notification_config.UserNotificationConfigService questionService *questioncommon.QuestionCommon + eventQueueService event_queue.EventQueueService } func NewUserService(userRepo usercommon.UserRepo, @@ -79,6 +81,7 @@ func NewUserService(userRepo usercommon.UserRepo, userNotificationConfigRepo user_notification_config.UserNotificationConfigRepo, userNotificationConfigService *user_notification_config.UserNotificationConfigService, questionService *questioncommon.QuestionCommon, + eventQueueService event_queue.EventQueueService, ) *UserService { return &UserService{ userCommonService: userCommonService, @@ -93,6 +96,7 @@ func NewUserService(userRepo usercommon.UserRepo, userNotificationConfigRepo: userNotificationConfigRepo, userNotificationConfigService: userNotificationConfigService, questionService: questionService, + eventQueueService: eventQueueService, } } @@ -352,6 +356,10 @@ func (us *UserService) UpdateInfo(ctx context.Context, req *schema.UpdateInfoReq cond := us.formatUserInfoForUpdateInfo(oldUserInfo, req, siteUsers) err = us.userRepo.UpdateInfo(ctx, cond) + if err != nil { + return nil, err + } + us.eventQueueService.Send(ctx, schema.NewEvent(constant.EventUserUpdate, req.UserID)) return nil, err } diff --git a/internal/service/content/vote_service.go b/internal/service/content/vote_service.go index bfb403c9..c83011a9 100644 --- a/internal/service/content/vote_service.go +++ b/internal/service/content/vote_service.go @@ -21,6 +21,8 @@ package content import ( "context" + "fmt" + "github.com/apache/incubator-answer/internal/service/event_queue" "strings" "github.com/apache/incubator-answer/internal/service/activity_common" @@ -62,6 +64,7 @@ type VoteService struct { commentCommonRepo comment_common.CommentCommonRepo objectService *object_info.ObjService activityRepo activity_common.ActivityRepo + eventQueueService event_queue.EventQueueService } func NewVoteService( @@ -71,6 +74,7 @@ func NewVoteService( answerRepo answercommon.AnswerRepo, commentCommonRepo comment_common.CommentCommonRepo, objectService *object_info.ObjService, + eventQueueService event_queue.EventQueueService, ) *VoteService { return &VoteService{ voteRepo: voteRepo, @@ -79,6 +83,7 @@ func NewVoteService( answerRepo: answerRepo, commentCommonRepo: commentCommonRepo, objectService: objectService, + eventQueueService: eventQueueService, } } @@ -112,6 +117,9 @@ func (vs *VoteService) VoteUp(ctx context.Context, req *schema.VoteReq) (resp *s return nil, err } err = vs.voteRepo.Vote(ctx, voteUpOperationInfo) + if err != nil { + return nil, err + } } if err != nil { return nil, err @@ -125,6 +133,7 @@ func (vs *VoteService) VoteUp(ctx context.Context, req *schema.VoteReq) (resp *s resp.Votes = resp.UpVotes - resp.DownVotes if !req.IsCancel { resp.VoteStatus = constant.ActVoteUp + vs.sendEvent(ctx, req, objectInfo, resp) } return resp, nil } @@ -173,6 +182,7 @@ func (vs *VoteService) VoteDown(ctx context.Context, req *schema.VoteReq) (resp resp.Votes = resp.UpVotes - resp.DownVotes if !req.IsCancel { resp.VoteStatus = constant.ActVoteDown + vs.sendEvent(ctx, req, objectInfo, resp) } return resp, nil } @@ -289,3 +299,24 @@ func (vs *VoteService) getActivities(ctx context.Context, op *schema.VoteOperati } return activities } + +func (vs *VoteService) sendEvent(ctx context.Context, + req *schema.VoteReq, objectInfo *schema.SimpleObjectInfo, resp *schema.VoteResp) { + var event *schema.EventMsg + switch objectInfo.ObjectType { + case constant.QuestionObjectType: + event = schema.NewEvent(constant.EventQuestionVote, req.UserID). + QID(objectInfo.QuestionID, objectInfo.ObjectCreatorUserID) + case constant.AnswerObjectType: + event = schema.NewEvent(constant.EventAnswerVote, req.UserID). + AID(objectInfo.AnswerID, objectInfo.ObjectCreatorUserID) + case constant.CommentObjectType: + event = schema.NewEvent(constant.EventCommentVote, req.UserID). + CID(objectInfo.CommentID, objectInfo.ObjectCreatorUserID) + default: + return + } + event.AddExtra("vote_up_amount", fmt.Sprintf("%d", resp.UpVotes)) + event.AddExtra("vote_down_amount", fmt.Sprintf("%d", resp.DownVotes)) + vs.eventQueueService.Send(ctx, event) +} diff --git a/internal/service/event_queue/event_queue.go b/internal/service/event_queue/event_queue.go new file mode 100644 index 00000000..b89a3ccc --- /dev/null +++ b/internal/service/event_queue/event_queue.go @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package event_queue + +import ( + "context" + + "github.com/apache/incubator-answer/internal/schema" + "github.com/segmentfault/pacman/log" +) + +type EventQueueService interface { + Send(ctx context.Context, msg *schema.EventMsg) + RegisterHandler(handler func(ctx context.Context, msg *schema.EventMsg) error) +} + +type eventQueueService struct { + Queue chan *schema.EventMsg + Handler func(ctx context.Context, msg *schema.EventMsg) error +} + +func (ns *eventQueueService) Send(ctx context.Context, msg *schema.EventMsg) { + ns.Queue <- msg +} + +func (ns *eventQueueService) RegisterHandler( + handler func(ctx context.Context, msg *schema.EventMsg) error) { + ns.Handler = handler +} + +func (ns *eventQueueService) working() { + go func() { + for msg := range ns.Queue { + log.Debugf("received badge %+v", msg) + if ns.Handler == nil { + log.Warnf("no handler for badge") + continue + } + if err := ns.Handler(context.Background(), msg); err != nil { + log.Error(err) + } + } + }() +} + +// NewEventQueueService create a new badge queue service +func NewEventQueueService() EventQueueService { + ns := &eventQueueService{} + ns.Queue = make(chan *schema.EventMsg, 128) + ns.working() + return ns +} diff --git a/internal/service/meta/meta_service.go b/internal/service/meta/meta_service.go index 1026b173..778c6ca6 100644 --- a/internal/service/meta/meta_service.go +++ b/internal/service/meta/meta_service.go @@ -23,6 +23,7 @@ import ( "context" "encoding/json" "errors" + "github.com/apache/incubator-answer/internal/service/event_queue" "strconv" "strings" @@ -46,14 +47,22 @@ type MetaService struct { userCommon *usercommon.UserCommon questionRepo questioncommon.QuestionRepo answerRepo answercommon.AnswerRepo + eventQueueService event_queue.EventQueueService } -func NewMetaService(metaCommonService *metacommon.MetaCommonService, userCommon *usercommon.UserCommon, answerRepo answercommon.AnswerRepo, questionRepo questioncommon.QuestionRepo) *MetaService { +func NewMetaService( + metaCommonService *metacommon.MetaCommonService, + userCommon *usercommon.UserCommon, + answerRepo answercommon.AnswerRepo, + questionRepo questioncommon.QuestionRepo, + eventQueueService event_queue.EventQueueService, +) *MetaService { return &MetaService{ metaCommonService: metaCommonService, questionRepo: questionRepo, userCommon: userCommon, answerRepo: answerRepo, + eventQueueService: eventQueueService, } } @@ -86,22 +95,27 @@ func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.Upda if err != nil { return nil, err } + var event *schema.EventMsg if objectType == constant.AnswerObjectType { - _, exist, err := ms.answerRepo.GetAnswer(ctx, req.ObjectID) + answerInfo, exist, err := ms.answerRepo.GetAnswer(ctx, req.ObjectID) if err != nil { return nil, err } if !exist { return nil, myErrors.BadRequest(reason.AnswerNotFound) } + event = schema.NewEvent(constant.EventAnswerReact, req.UserID). + AID(answerInfo.ID, answerInfo.UserID) } else if objectType == constant.QuestionObjectType { - _, exist, err := ms.questionRepo.GetQuestion(ctx, req.ObjectID) + questionInfo, exist, err := ms.questionRepo.GetQuestion(ctx, req.ObjectID) if err != nil { return nil, err } if !exist { return nil, myErrors.BadRequest(reason.QuestionNotFound) } + event = schema.NewEvent(constant.EventQuestionReact, req.UserID). + QID(questionInfo.ID, questionInfo.UserID) } else { return nil, myErrors.BadRequest(reason.ObjectNotFound) } @@ -138,7 +152,7 @@ func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.Upda if err != nil { return nil, err } - + ms.eventQueueService.Send(ctx, event) return resp, nil } diff --git a/internal/service/provider.go b/internal/service/provider.go index e82d9316..a22a6ea9 100644 --- a/internal/service/provider.go +++ b/internal/service/provider.go @@ -33,6 +33,7 @@ import ( "github.com/apache/incubator-answer/internal/service/config" "github.com/apache/incubator-answer/internal/service/content" "github.com/apache/incubator-answer/internal/service/dashboard" + "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/apache/incubator-answer/internal/service/export" "github.com/apache/incubator-answer/internal/service/follow" "github.com/apache/incubator-answer/internal/service/meta" @@ -117,4 +118,5 @@ var ProviderSetService = wire.NewSet( notice_queue.NewNewQuestionNotificationQueueService, review.NewReviewService, meta.NewMetaService, + event_queue.NewEventQueueService, ) diff --git a/internal/service/report/report_service.go b/internal/service/report/report_service.go index 7f060a39..218423e1 100644 --- a/internal/service/report/report_service.go +++ b/internal/service/report/report_service.go @@ -21,6 +21,7 @@ package report import ( "encoding/json" + "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/base/handler" @@ -55,6 +56,7 @@ type ReportService struct { commentCommonRepo comment_common.CommentCommonRepo reportHandle *report_handle.ReportHandle configService *config.ConfigService + eventQueueService event_queue.EventQueueService } // NewReportService new report service @@ -67,6 +69,7 @@ func NewReportService( commentCommonRepo comment_common.CommentCommonRepo, reportHandle *report_handle.ReportHandle, configService *config.ConfigService, + eventQueueService event_queue.EventQueueService, ) *ReportService { return &ReportService{ reportRepo: reportRepo, @@ -77,6 +80,7 @@ func NewReportService( commentCommonRepo: commentCommonRepo, reportHandle: reportHandle, configService: configService, + eventQueueService: eventQueueService, } } @@ -112,7 +116,12 @@ func (rs *ReportService) AddReport(ctx context.Context, req *schema.AddReportReq Content: req.Content, Status: entity.ReportStatusPending, } - return rs.reportRepo.AddReport(ctx, report) + err = rs.reportRepo.AddReport(ctx, report) + if err != nil { + return err + } + rs.sendEvent(ctx, report, objInfo) + return nil } // GetUnreviewedReportPostPage get unreviewed report post page @@ -218,3 +227,22 @@ func (rs *ReportService) ReviewReport(ctx context.Context, req *schema.ReviewRep return rs.reportRepo.UpdateStatus(ctx, report.ID, entity.ReportStatusCompleted) } + +func (rs *ReportService) sendEvent(ctx context.Context, + report *entity.Report, objectInfo *schema.SimpleObjectInfo) { + var event *schema.EventMsg + switch objectInfo.ObjectType { + case constant.QuestionObjectType: + event = schema.NewEvent(constant.EventQuestionFlag, report.UserID). + QID(objectInfo.QuestionID, objectInfo.ObjectCreatorUserID) + case constant.AnswerObjectType: + event = schema.NewEvent(constant.EventAnswerFlag, report.UserID). + AID(objectInfo.AnswerID, objectInfo.ObjectCreatorUserID) + case constant.CommentObjectType: + event = schema.NewEvent(constant.EventCommentFlag, report.UserID). + CID(objectInfo.CommentID, objectInfo.ObjectCreatorUserID) + default: + return + } + rs.eventQueueService.Send(ctx, event) +} From 797ea9b9187847fde3dad778fd8c1715b0b5cd33 Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 8 Aug 2024 16:41:17 +0800 Subject: [PATCH 028/336] feat(badge): badge info && badge award list --- cmd/wire_gen.go | 4 +- docs/docs.go | 156 ++++++++++++++++++ docs/swagger.json | 156 ++++++++++++++++++ docs/swagger.yaml | 96 +++++++++++ i18n/en_US.yaml | 3 + internal/base/reason/reason.go | 1 + internal/controller/badge_controller.go | 61 ++++++- internal/entity/badge_award_entity.go | 8 +- internal/repo/badge/badge_repo.go | 6 + internal/repo/badge_award/badge_award_repo.go | 33 +++- internal/router/answer_api_router.go | 2 + internal/schema/badge.go | 34 ---- internal/schema/badge_schema.go | 70 ++++++++ internal/service/badge/badge_service.go | 52 +++++- .../badge_award/badge_award_service.go | 102 ++++++++++-- 15 files changed, 718 insertions(+), 66 deletions(-) delete mode 100644 internal/schema/badge.go create mode 100644 internal/schema/badge_schema.go diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index c20aa2cf..30b3b65c 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -75,6 +75,7 @@ import ( "github.com/apache/incubator-answer/internal/service/answer_common" auth2 "github.com/apache/incubator-answer/internal/service/auth" badge2 "github.com/apache/incubator-answer/internal/service/badge" + badge_award2 "github.com/apache/incubator-answer/internal/service/badge_award" collection2 "github.com/apache/incubator-answer/internal/service/collection" "github.com/apache/incubator-answer/internal/service/collection_common" comment2 "github.com/apache/incubator-answer/internal/service/comment" @@ -261,7 +262,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, badgeGroupRepo := badge_group.NewBadgeGroupRepo(dataData, uniqueIDRepo) badgeAwardRepo := badge_award.NewBadgeAwardRepo(dataData, uniqueIDRepo) badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo) - badgeController := controller.NewBadgeController(badgeService) + badgeAwardService := badge_award2.NewBadgeAwardService(badgeAwardRepo, userCommon, objService, questionRepo, answerRepo) + badgeController := controller.NewBadgeController(badgeService, badgeAwardService) answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController) swaggerRouter := router.NewSwaggerRouter(swaggerConf) uiRouter := router.NewUIRouter(controllerSiteInfoController, siteInfoCommonService) diff --git a/docs/docs.go b/docs/docs.go index 6fc76693..bda5a17b 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2239,6 +2239,117 @@ const docTemplate = `{ } } }, + "/answer/api/v1/badge": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get badge info", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get badge info", + "parameters": [ + { + "type": "string", + "default": "string", + "description": "id", + "name": "id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/schema.GetBadgeInfoResp" + } + } + } + ] + } + } + } + } + }, + "/answer/api/v1/badge/awards/page": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get badge award list", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get badge award list", + "parameters": [ + { + "type": "integer", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "badge id", + "name": "badge_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/schema.GetBadgeInfoResp" + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/badges": { "get": { "security": [ @@ -6942,6 +7053,19 @@ const docTemplate = `{ } } }, + "entity.BadgeLevel": { + "type": "integer", + "enum": [ + 1, + 2, + 3 + ], + "x-enum-varnames": [ + "BadgeLevelBronze", + "BadgeLevelSilver", + "BadgeLevelGold" + ] + }, "handler.RespBody": { "type": "object", "properties": { @@ -7400,6 +7524,9 @@ const docTemplate = `{ "id": { "type": "string" }, + "level": { + "$ref": "#/definitions/entity.BadgeLevel" + }, "name": { "type": "string" } @@ -7656,6 +7783,35 @@ const docTemplate = `{ } } }, + "schema.GetBadgeInfoResp": { + "type": "object", + "properties": { + "award_count": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "earned_count": { + "type": "integer" + }, + "icon": { + "type": "string" + }, + "id": { + "type": "string" + }, + "is_single": { + "type": "boolean" + }, + "level": { + "$ref": "#/definitions/entity.BadgeLevel" + }, + "name": { + "type": "string" + } + } + }, "schema.GetBadgeListResp": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 45936363..5ea50e6b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2209,6 +2209,117 @@ } } }, + "/answer/api/v1/badge": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get badge info", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get badge info", + "parameters": [ + { + "type": "string", + "default": "string", + "description": "id", + "name": "id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/schema.GetBadgeInfoResp" + } + } + } + ] + } + } + } + } + }, + "/answer/api/v1/badge/awards/page": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get badge award list", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get badge award list", + "parameters": [ + { + "type": "integer", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "badge id", + "name": "badge_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/schema.GetBadgeInfoResp" + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/badges": { "get": { "security": [ @@ -6912,6 +7023,19 @@ } } }, + "entity.BadgeLevel": { + "type": "integer", + "enum": [ + 1, + 2, + 3 + ], + "x-enum-varnames": [ + "BadgeLevelBronze", + "BadgeLevelSilver", + "BadgeLevelGold" + ] + }, "handler.RespBody": { "type": "object", "properties": { @@ -7370,6 +7494,9 @@ "id": { "type": "string" }, + "level": { + "$ref": "#/definitions/entity.BadgeLevel" + }, "name": { "type": "string" } @@ -7626,6 +7753,35 @@ } } }, + "schema.GetBadgeInfoResp": { + "type": "object", + "properties": { + "award_count": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "earned_count": { + "type": "integer" + }, + "icon": { + "type": "string" + }, + "id": { + "type": "string" + }, + "is_single": { + "type": "boolean" + }, + "level": { + "$ref": "#/definitions/entity.BadgeLevel" + }, + "name": { + "type": "string" + } + } + }, "schema.GetBadgeListResp": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c91c987e..ca11b20f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -32,6 +32,16 @@ definitions: minimum: 1 type: integer type: object + entity.BadgeLevel: + enum: + - 1 + - 2 + - 3 + type: integer + x-enum-varnames: + - BadgeLevelBronze + - BadgeLevelSilver + - BadgeLevelGold handler.RespBody: properties: code: @@ -352,6 +362,8 @@ definitions: type: string id: type: string + level: + $ref: '#/definitions/entity.BadgeLevel' name: type: string type: object @@ -526,6 +538,25 @@ definitions: description: if user is followed object will be true,otherwise false type: boolean type: object + schema.GetBadgeInfoResp: + properties: + award_count: + type: integer + description: + type: string + earned_count: + type: integer + icon: + type: string + id: + type: string + is_single: + type: boolean + level: + $ref: '#/definitions/entity.BadgeLevel' + name: + type: string + type: object schema.GetBadgeListResp: properties: badges: @@ -4105,6 +4136,71 @@ paths: summary: recover answer tags: - Answer + /answer/api/v1/badge: + get: + consumes: + - application/json + description: get badge info + parameters: + - default: string + description: id + in: query + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + $ref: '#/definitions/schema.GetBadgeInfoResp' + type: object + security: + - ApiKeyAuth: [] + summary: get badge info + tags: + - api-badge + /answer/api/v1/badge/awards/page: + get: + consumes: + - application/json + description: get badge award list + parameters: + - description: page + in: query + name: page + type: integer + - description: page size + in: query + name: page_size + type: integer + - description: badge id + in: query + name: badge_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + $ref: '#/definitions/schema.GetBadgeInfoResp' + type: object + security: + - ApiKeyAuth: [] + summary: get badge award list + tags: + - api-badge /answer/api/v1/badges: get: consumes: diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index f50465c2..0d7f2ecf 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -312,6 +312,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go index 66ef1bed..a6168690 100644 --- a/internal/base/reason/reason.go +++ b/internal/base/reason/reason.go @@ -106,6 +106,7 @@ const ( AddBulkUsersAmountError = "error.user.add_bulk_users_amount_error" InvalidURLError = "error.common.invalid_url" MetaObjectNotFound = "error.meta.object_not_found" + BadgeObjectNotFound = "error.badge.object_not_found" ) // user external login reasons diff --git a/internal/controller/badge_controller.go b/internal/controller/badge_controller.go index ebc534ce..c26d9205 100644 --- a/internal/controller/badge_controller.go +++ b/internal/controller/badge_controller.go @@ -22,17 +22,25 @@ package controller import ( "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/middleware" + "github.com/apache/incubator-answer/internal/base/pager" + "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/badge" + "github.com/apache/incubator-answer/internal/service/badge_award" + "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" ) type BadgeController struct { - badgeService *badge.BadgeService + badgeService *badge.BadgeService + badgeAwardService *badge_award.BadgeAwardService } -func NewBadgeController(badgeService *badge.BadgeService) *BadgeController { +func NewBadgeController( + badgeService *badge.BadgeService, + badgeAwardService *badge_award.BadgeAwardService) *BadgeController { return &BadgeController{ - badgeService: badgeService, + badgeService: badgeService, + badgeAwardService: badgeAwardService, } } @@ -50,3 +58,50 @@ func (b *BadgeController) GetBadgeList(ctx *gin.Context) { resp, err := b.badgeService.ListByGroup(ctx, userID) handler.HandleResponse(ctx, err, resp) } + +// GetBadgeInfo get badge info +// @Summary get badge info +// @Description get badge info +// @Tags api-badge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param id query string true "id" default(string) +// @Success 200 {object} handler.RespBody{data=schema.GetBadgeInfoResp} +// @Router /answer/api/v1/badge [get] +func (b *BadgeController) GetBadgeInfo(ctx *gin.Context) { + id := ctx.Query("id") + id = uid.DeShortID(id) + + userID := middleware.GetLoginUserIDFromContext(ctx) + resp, err := b.badgeService.GetBadgeInfo(ctx, id, userID) + handler.HandleResponse(ctx, err, resp) +} + +// GetBadgeAwardList get badge award list +// @Summary get badge award list +// @Description get badge award list +// @Tags api-badge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param page query int false "page" +// @Param page_size query int false "page size" +// @Param badge_id query string true "badge id" +// @Success 200 {object} handler.RespBody{data=schema.GetBadgeInfoResp} +// @Router /answer/api/v1/badge/awards/page [get] +func (b *BadgeController) GetBadgeAwardList(ctx *gin.Context) { + req := &schema.GetBadgeAwardWithPageReq{} + if handler.BindAndCheck(ctx, req) { + return + } + req.BadgeID = uid.DeShortID(req.BadgeID) + req.UserID = middleware.GetLoginUserIDFromContext(ctx) + + resp, total, err := b.badgeAwardService.GetBadgeAwardList(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) +} diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index a852f6bd..a26fd8de 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -26,10 +26,10 @@ type BadgeAward struct { ID string `json:"id" xorm:"id"` CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` - UserId int64 `json:"user_id" xorm:"not null index BIGINT(20) user_id"` - BadgeId int64 `json:"badge_id" xorm:"not null index BIGINT(20) badge_id"` - ObjectId int64 `json:"object_id" xorm:"not null index BIGINT(20) object_id"` - BadgeGroupId int8 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` + UserID string `json:"user_id" xorm:"not null index BIGINT(20) user_id"` + BadgeID string `json:"badge_id" xorm:"not null index BIGINT(20) badge_id"` + ObjectID string `json:"object_id" xorm:"not null index BIGINT(20) object_id"` + BadgeGroupID int8 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index TINYINT(1) s_badge_deleted"` } diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index b4cd72f1..7651f95b 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -40,6 +40,12 @@ func NewBadgeRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge.Badge } } +func (r badgeRepo) GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) { + badge = &entity.Badge{} + exists, err = r.data.DB.Context(ctx).Where("id = ?", id).Get(badge) + return +} + // ListByLevel returns a list of badges by level func (r *badgeRepo) ListByLevel(ctx context.Context, level entity.BadgeLevel) (badges []*entity.Badge, err error) { badges = make([]*entity.Badge, 0) diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index b6f0e95e..0a460347 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -22,9 +22,12 @@ package badge_award import ( "context" "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/base/pager" + "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/service/badge_award" "github.com/apache/incubator-answer/internal/service/unique" + "github.com/segmentfault/pacman/errors" "time" ) @@ -53,6 +56,10 @@ func (r *badgeAwardRepo) CountByUserId(ctx context.Context, userID string) (awar return } func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) { + awardCount, err := r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ?", userID, badgeID).Count(&entity.BadgeAward{}) + if err != nil { + return 0 + } return } func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, objectID string) (awardCount int64) { @@ -71,31 +78,39 @@ func (r *badgeAwardRepo) SumUserEarnedGroupByBadgeID(ctx context.Context, userID func (r *badgeAwardRepo) ListAllByUserId(ctx context.Context, userID string) (badgeAwards []*entity.BadgeAward) { return } -func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { + +// ListPagedByBadgeId list badge awards by badge id +func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error) { + session := r.data.DB.Context(ctx) + session.Where("badge_id = ?", badgeID) + total, err = pager.Help(page, pageSize, &badgeAwardList, &entity.Question{}, session) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } -func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs []int64, page int64, pageSize int64, filterUserID int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []int64, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListPagedLatest(ctx context.Context, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListPagedLatest(ctx context.Context, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int64, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) { +func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward) { diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index dadf2a85..c7d4c38e 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -192,6 +192,8 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) { r.GET("/meta/reaction", a.metaController.GetReaction) // badges + r.GET("/badge", a.badgeController.GetBadgeInfo) + r.GET("/badge/awards/page", a.badgeController.GetBadgeAwardList) r.GET("/badges", a.badgeController.GetBadgeList) } diff --git a/internal/schema/badge.go b/internal/schema/badge.go deleted file mode 100644 index c52a235b..00000000 --- a/internal/schema/badge.go +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package schema - -// BadgeListInfo get badge list response -type BadgeListInfo struct { - ID string `json:"id" ` - Name string `json:"name" ` - Icon string `json:"icon" ` - AwardCount int `json:"award_count" ` - Earned bool `json:"earned" ` -} - -type GetBadgeListResp struct { - Badges []*BadgeListInfo `json:"badges" ` - GroupName string `json:"group_name" ` -} diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go new file mode 100644 index 00000000..06d92ecc --- /dev/null +++ b/internal/schema/badge_schema.go @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package schema + +import "github.com/apache/incubator-answer/internal/entity" + +// BadgeListInfo get badge list response +type BadgeListInfo struct { + ID string `json:"id" ` + Name string `json:"name" ` + Icon string `json:"icon" ` + AwardCount int `json:"award_count" ` + Earned bool `json:"earned" ` + Level entity.BadgeLevel `json:"level" ` +} + +type GetBadgeListResp struct { + Badges []*BadgeListInfo `json:"badges" ` + GroupName string `json:"group_name" ` +} + +type GetBadgeInfoResp struct { + ID string `json:"id" ` + Name string `json:"name" ` + Description string `json:"description" ` + Icon string `json:"icon" ` + AwardCount int `json:"award_count" ` + EarnedCount int64 `json:"earned_count" ` + IsSingle bool `json:"is_single" ` + Level entity.BadgeLevel `json:"level" ` +} + +type GetBadgeAwardWithPageReq struct { + // page + Page int `validate:"omitempty,min=1" form:"page"` + // page size + PageSize int `validate:"omitempty,min=1" form:"page_size"` + // badge id + BadgeID string `validate:"required" form:"badge_id"` + // user id + UserID string `json:"-"` +} + +type GetBadgeAwardWithPageResp struct { + CreatedAt int64 `json:"created_at"` + ObjectID string `json:"object_id"` + QuestionID string `json:"question_id"` + AnswerID string `json:"answer_id"` + CommentID string `json:"comment_id"` + ObjectType string `json:"object_type" enums:"question,answer,comment"` + UrlTitle string `json:"url_title"` + AuthorUserInfo UserBasicInfo `json:"author_user_info"` +} diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 1109b444..94ba5b64 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -22,15 +22,20 @@ package badge import ( "context" "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/base/translator" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/badge_award" "github.com/apache/incubator-answer/internal/service/badge_group" "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/incubator-answer/pkg/uid" + "github.com/gin-gonic/gin" + "github.com/segmentfault/pacman/errors" ) type BadgeRepo interface { + GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) ListByLevel(ctx context.Context, level entity.BadgeLevel) ([]*entity.Badge, error) ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) ([]*entity.Badge, error) @@ -55,6 +60,7 @@ func NewBadgeService( } } +// ListByGroup list all badges group by group func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []*schema.GetBadgeListResp, err error) { var ( groups []*entity.BadgeGroup @@ -74,7 +80,13 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* if err != nil { return } - earnedCounts, err = b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, userID) + + if len(userID) > 0 { + earnedCounts, err = b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, userID) + if err != nil { + return + } + } for _, group := range groups { groupMap[converter.StringToInt64(group.ID)] = group.Name @@ -93,11 +105,12 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* } badgesMap[badge.BadgeGroupId] = append(badgesMap[badge.BadgeGroupId], &schema.BadgeListInfo{ - ID: badge.ID, + ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), Icon: badge.Icon, AwardCount: badge.AwardCount, Earned: earned, + Level: badge.Level, }) } @@ -110,3 +123,38 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* return } + +// GetBadgeInfo get badge info +func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) (info *schema.GetBadgeInfoResp, err error) { + var ( + badge *entity.Badge + earnedTotal int64 = 0 + exists = false + ) + + badge, exists, err = b.badgeRepo.GetByID(ctx, id) + if err != nil { + return + } + + if !exists || badge.Status == entity.BadgeStatusInactive { + err = errors.BadRequest(reason.BadgeObjectNotFound) + return + } + + if len(userID) > 0 { + earnedTotal = b.badgeAwardRepo.CountByUserIdAndBadgeId(ctx, userID, badge.ID) + } + + info = &schema.GetBadgeInfoResp{ + ID: uid.EnShortID(badge.ID), + Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), + Description: translator.Tr(handler.GetLangByCtx(ctx), badge.Description), + Icon: badge.Icon, + AwardCount: badge.AwardCount, + EarnedCount: earnedTotal, + IsSingle: badge.Single == entity.BadgeSingleAward, + Level: badge.Level, + } + return +} diff --git a/internal/service/badge_award/badge_award_service.go b/internal/service/badge_award/badge_award_service.go index 8f84453e..b8e96545 100644 --- a/internal/service/badge_award/badge_award_service.go +++ b/internal/service/badge_award/badge_award_service.go @@ -21,7 +21,17 @@ package badge_award import ( "context" + "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/schema" + answercommon "github.com/apache/incubator-answer/internal/service/answer_common" + "github.com/apache/incubator-answer/internal/service/object_info" + questioncommon "github.com/apache/incubator-answer/internal/service/question_common" + usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/incubator-answer/pkg/htmltext" + "github.com/jinzhu/copier" + "github.com/segmentfault/pacman/errors" + "github.com/segmentfault/pacman/log" "time" ) @@ -33,32 +43,98 @@ type BadgeAwardRepo interface { CountByUserId(ctx context.Context, userID string) (awardCount int64) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) CountByObjectId(ctx context.Context, objectID string) (awardCount int64) - CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID string) int64 + CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID string) (awardCount int64) CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, objectID string, badgeID string) (awardCount int64) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) ListAllByUserId(ctx context.Context, userID string) (badgeAwards []*entity.BadgeAward) - ListPagedByBadgeId(ctx context.Context, badgeID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) - ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) - ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) - ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) - ListTagPagedByBadgeId(ctx context.Context, badgeIDs []int64, page int64, pageSize int64, filterUserID int64) (badgeAwards []*entity.BadgeAward, total int64) - ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []int64, userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) - ListPagedLatest(ctx context.Context, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) - ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int64) (badgeAwards []*entity.BadgeAward, total int64) - ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int64, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) + ListPagedByBadgeId(ctx context.Context, badgeID string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error) + ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListPagedLatest(ctx context.Context, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward) GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, objectID string) (badgeAward *entity.BadgeAward) } type BadgeAwardService struct { - badgeAwardRepo BadgeAwardRepo + badgeAwardRepo BadgeAwardRepo + userCommon *usercommon.UserCommon + objectInfoService *object_info.ObjService + questionRepo questioncommon.QuestionRepo + answerRepo answercommon.AnswerRepo } -func NewBadgeAwardService(badgeAwardRepo BadgeAwardRepo) *BadgeAwardService { +func NewBadgeAwardService( + badgeAwardRepo BadgeAwardRepo, + userCommon *usercommon.UserCommon, + objectInfoService *object_info.ObjService, + questionRepo questioncommon.QuestionRepo, + answerRepo answercommon.AnswerRepo, +) *BadgeAwardService { return &BadgeAwardService{ - badgeAwardRepo: badgeAwardRepo, + badgeAwardRepo: badgeAwardRepo, + userCommon: userCommon, + objectInfoService: objectInfoService, + questionRepo: questionRepo, + answerRepo: answerRepo, } } + +// GetBadgeAwardList get badge award list +func (b *BadgeAwardService) GetBadgeAwardList( + ctx context.Context, req *schema.GetBadgeAwardWithPageReq, +) (resp []*schema.GetBadgeAwardWithPageResp, total int64, err error) { + var ( + badgeAwardList []*entity.BadgeAward + ) + + badgeAwardList, total, err = b.badgeAwardRepo.ListPagedByBadgeId(ctx, req.BadgeID, req.Page, req.PageSize) + if err != nil { + return + } + + resp = make([]*schema.GetBadgeAwardWithPageResp, 0, len(badgeAwardList)) + + for i, badgeAward := range badgeAwardList { + objInfo, e := b.objectInfoService.GetInfo(ctx, badgeAward.ObjectID) + if e != nil { + err = e + return + } + if objInfo.IsDeleted() { + err = errors.BadRequest(reason.NewObjectAlreadyDeleted) + return + } + + row := &schema.GetBadgeAwardWithPageResp{ + CreatedAt: badgeAward.CreatedAt.Unix(), + ObjectID: badgeAward.ObjectID, + QuestionID: objInfo.QuestionID, + AnswerID: objInfo.AnswerID, + CommentID: objInfo.CommentID, + ObjectType: objInfo.ObjectType, + UrlTitle: htmltext.UrlTitle(objInfo.Title), + AuthorUserInfo: schema.UserBasicInfo{}, + } + + // get user info + userInfo, exists, e := b.userCommon.GetUserBasicInfoByID(ctx, badgeAward.UserID) + if e != nil { + log.Errorf("user not found by id: %s, err: %v", badgeAward.UserID, e) + } + if exists { + _ = copier.Copy(&row.AuthorUserInfo, userInfo) + } + + resp[i] = row + } + + return +} From 9b0de85ed4f5d9b77506b4698cc87850baf89691 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 8 Aug 2024 18:09:27 +0800 Subject: [PATCH 029/336] feat(badge): add badge event handler --- cmd/wire_gen.go | 4 +- internal/repo/badge/badge_event_rule.go | 216 ++++++++++++++++++ internal/repo/badge/badge_repo.go | 31 ++- internal/repo/badge/badge_rule.go | 95 -------- internal/repo/badge/event_rule_mapping.go | 47 ---- internal/repo/badge/rule.go | 43 ---- internal/repo/provider.go | 1 + internal/schema/event_schema.go | 10 + .../badge/badge_event_handler.go | 34 ++- internal/service/badge/badge_service.go | 19 +- internal/service/provider.go | 1 + 11 files changed, 304 insertions(+), 197 deletions(-) create mode 100644 internal/repo/badge/badge_event_rule.go delete mode 100644 internal/repo/badge/badge_rule.go delete mode 100644 internal/repo/badge/event_rule_mapping.go delete mode 100644 internal/repo/badge/rule.go rename internal/{repo => service}/badge/badge_event_handler.go (60%) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 24cdb163..f49ef20e 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -263,7 +263,9 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, badgeRepo := badge.NewBadgeRepo(dataData, uniqueIDRepo) badgeGroupRepo := badge_group.NewBadgeGroupRepo(dataData, uniqueIDRepo) badgeAwardRepo := badge_award.NewBadgeAwardRepo(dataData, uniqueIDRepo) - badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo) + eventRuleRepo := badge.NewEventRuleRepo(dataData) + badgeEventService := badge2.NewBadgeEventService(dataData, eventQueueService, badgeRepo, eventRuleRepo) + badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) badgeAwardService := badge_award2.NewBadgeAwardService(badgeAwardRepo, userCommon, objService, questionRepo, answerRepo) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController) diff --git a/internal/repo/badge/badge_event_rule.go b/internal/repo/badge/badge_event_rule.go new file mode 100644 index 00000000..8f940720 --- /dev/null +++ b/internal/repo/badge/badge_event_rule.go @@ -0,0 +1,216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package badge + +import ( + "context" + "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/base/reason" + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/badge" + "github.com/segmentfault/pacman/errors" + "github.com/segmentfault/pacman/log" +) + +// eventRuleRepo event rule repo +type eventRuleRepo struct { + data *data.Data + EventRuleMapping map[constant.EventType][]badge.EventRuleHandler +} + +// NewEventRuleRepo creates a new badge repository +func NewEventRuleRepo(data *data.Data) badge.EventRuleRepo { + b := &eventRuleRepo{ + data: data, + } + b.EventRuleMapping = map[constant.EventType][]badge.EventRuleHandler{ + constant.EventUserUpdate: {b.FirstUpdateUserProfile}, + constant.EventUserShare: {b.FirstSharedPost}, + constant.EventQuestionCreate: nil, + constant.EventQuestionUpdate: {b.FirstPostEdit}, + constant.EventQuestionDelete: nil, + constant.EventQuestionVote: {b.FirstVotedPost, b.ReachQuestionVote}, + constant.EventQuestionAccept: {b.FirstAcceptAnswer, b.ReachAnswerAcceptedAmount}, + constant.EventQuestionFlag: {b.FirstFlaggedPost}, + constant.EventQuestionReact: {b.FirstReactedPost}, + constant.EventAnswerCreate: nil, + constant.EventAnswerUpdate: {b.FirstPostEdit}, + constant.EventAnswerDelete: nil, + constant.EventAnswerVote: {b.FirstVotedPost, b.ReachAnswerVote}, + constant.EventAnswerFlag: {b.FirstFlaggedPost}, + constant.EventAnswerReact: {b.FirstReactedPost}, + constant.EventCommentCreate: nil, + constant.EventCommentUpdate: nil, + constant.EventCommentDelete: nil, + constant.EventCommentVote: {b.FirstVotedPost}, + constant.EventCommentFlag: {b.FirstFlaggedPost}, + } + return b +} + +// HandleEventWithRule handle event with rule +func (br *eventRuleRepo) HandleEventWithRule(ctx context.Context, msg *schema.EventMsg) ( + awards []*entity.BadgeAward) { + handlers := br.EventRuleMapping[msg.EventType] + for _, h := range handlers { + t, err := h(ctx, msg) + if err != nil { + log.Errorf("error handling badge event %+v: %v", msg, err) + } else { + awards = append(awards, t...) + } + } + return awards +} + +// FirstUpdateUserProfile first update user profile +func (br *eventRuleRepo) FirstUpdateUserProfile(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "FirstUpdateUserProfile") + if b == nil { + return nil, nil + } + bean := &entity.User{ID: event.UserID} + exist, err := br.data.DB.Context(ctx).Get(bean) + if err != nil { + return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + if !exist { + return nil, nil + } + if len(bean.Bio) > 0 { + return append(awards, br.createBadgeAward(event.UserID, b.ID, "")), nil + } + return nil, nil +} + +// FirstPostEdit first post edit +func (br *eventRuleRepo) FirstPostEdit(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "FirstPostEdit") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// FirstFlaggedPost first flagged post. +func (br *eventRuleRepo) FirstFlaggedPost(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "FirstFlaggedPost") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// FirstVotedPost first voted post +func (br *eventRuleRepo) FirstVotedPost(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "FirstVotedPost") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// FirstReactedPost first reacted post +func (br *eventRuleRepo) FirstReactedPost(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "FirstReactedPost") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// FirstSharedPost first shared post +func (br *eventRuleRepo) FirstSharedPost(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "FirstSharedPost") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// FirstAcceptAnswer user first accept answer +func (br *eventRuleRepo) FirstAcceptAnswer(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "FirstAcceptAnswer") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// ReachAnswerAcceptedAmount reach answer accepted amount +func (br *eventRuleRepo) ReachAnswerAcceptedAmount(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "ReachAnswerAcceptedAmount") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// ReachAnswerVote reach answer vote +func (br *eventRuleRepo) ReachAnswerVote(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "ReachAnswerVote") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +// ReachQuestionVote reach question vote +func (br *eventRuleRepo) ReachQuestionVote(ctx context.Context, + event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { + b := br.getBadgeByHandler(ctx, "ReachQuestionVote") + if b == nil { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil +} + +func (br *eventRuleRepo) getBadgeByHandler(ctx context.Context, handler string) (b *entity.Badge) { + b = &entity.Badge{Handler: handler} + exist, err := br.data.DB.Context(ctx).Get(b) + if err != nil { + log.Errorf("error getting badge by handler %s: %v", handler, err) + return nil + } + if !exist { + log.Errorf("badge not found by handler %s", handler) + return nil + } + return b +} + +func (br *eventRuleRepo) createBadgeAward(userID, badgeID, objectID string) (awards *entity.BadgeAward) { + return &entity.BadgeAward{ + UserID: userID, + BadgeID: badgeID, + ObjectID: objectID, + } +} diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index 7651f95b..5030f0da 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -22,9 +22,11 @@ package badge import ( "context" "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/unique" + "github.com/segmentfault/pacman/errors" ) type badgeRepo struct { @@ -40,9 +42,21 @@ func NewBadgeRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge.Badge } } -func (r badgeRepo) GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) { +func (r *badgeRepo) GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) { badge = &entity.Badge{} exists, err = r.data.DB.Context(ctx).Where("id = ?", id).Get(badge) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + +func (r *badgeRepo) GetByIDs(ctx context.Context, ids []string) (badges []*entity.Badge, err error) { + badges = make([]*entity.Badge, 0) + err = r.data.DB.Context(ctx).In("id", ids).Find(&badges) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } @@ -50,6 +64,9 @@ func (r badgeRepo) GetByID(ctx context.Context, id string) (badge *entity.Badge, func (r *badgeRepo) ListByLevel(ctx context.Context, level entity.BadgeLevel) (badges []*entity.Badge, err error) { badges = make([]*entity.Badge, 0) err = r.data.DB.Context(ctx).Where("level = ?", level).Find(&badges) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } @@ -57,6 +74,9 @@ func (r *badgeRepo) ListByLevel(ctx context.Context, level entity.BadgeLevel) (b func (r *badgeRepo) ListByGroup(ctx context.Context, groupID int64) (badges []*entity.Badge, err error) { badges = make([]*entity.Badge, 0) err = r.data.DB.Context(ctx).Where("group_id = ?", groupID).Find(&badges) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } @@ -64,6 +84,9 @@ func (r *badgeRepo) ListByGroup(ctx context.Context, groupID int64) (badges []*e func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) (badges []*entity.Badge, err error) { badges = make([]*entity.Badge, 0) err = r.data.DB.Context(ctx).Where("level = ? AND group_id = ?", level, groupID).Find(&badges) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } @@ -71,6 +94,9 @@ func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level entity.BadgeL func (r *badgeRepo) ListActivated(ctx context.Context) (badges []*entity.Badge, err error) { badges = make([]*entity.Badge, 0) err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusActive).Find(&badges) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } @@ -78,5 +104,8 @@ func (r *badgeRepo) ListActivated(ctx context.Context) (badges []*entity.Badge, func (r *badgeRepo) ListInactivated(ctx context.Context) (badges []*entity.Badge, err error) { badges = make([]*entity.Badge, 0) err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusInactive).Find(&badges) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } diff --git a/internal/repo/badge/badge_rule.go b/internal/repo/badge/badge_rule.go deleted file mode 100644 index 3ae0b7b4..00000000 --- a/internal/repo/badge/badge_rule.go +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package badge - -import ( - "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/segmentfault/pacman/errors" -) - -// BadgeRuleRepo collection repository -type BadgeRuleRepo struct { - data *data.Data - uniqueIDRepo unique.UniqueIDRepo -} - -// FilledPersonalProfile filled personal profile -func (br *BadgeRuleRepo) FilledPersonalProfile(ctx context.Context, userID string) (reach bool, err error) { - bean := &entity.User{ID: userID} - exist, err := br.data.DB.Context(ctx).Get(bean) - if err != nil { - return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - } - if !exist { - return false, nil - } - if len(bean.Bio) > 0 { - return true, nil - } - return false, nil -} - -// FirstPostEdit first post edit -func (br *BadgeRuleRepo) FirstPostEdit(ctx context.Context, userID string, objectID string) { - -} - -// FirstFlaggedPost first flagged post. -func (br *BadgeRuleRepo) FirstFlaggedPost(ctx context.Context, userID string, reportID string) { -} - -// FirstVotedPost first voted post -func (br *BadgeRuleRepo) FirstVotedPost(ctx context.Context) { - -} - -// FirstReactedPost first reacted post -func (br *BadgeRuleRepo) FirstReactedPost(ctx context.Context) { - -} - -// FirstSharedPost first shared post -func (br *BadgeRuleRepo) FirstSharedPost(ctx context.Context) { - -} - -// AskQuestionAcceptAnswer ask question accept answer -func (br *BadgeRuleRepo) AskQuestionAcceptAnswer(ctx context.Context) { - -} - -// AnswerAccepted answer accepted -func (br *BadgeRuleRepo) AnswerAccepted(ctx context.Context) { - -} - -// ReachAnswerScore reach answer score -func (br *BadgeRuleRepo) ReachAnswerScore(ctx context.Context) { - -} - -// ReachQuestionScore reach question score -func (br *BadgeRuleRepo) ReachQuestionScore(ctx context.Context) { - -} diff --git a/internal/repo/badge/event_rule_mapping.go b/internal/repo/badge/event_rule_mapping.go deleted file mode 100644 index 8f01fdef..00000000 --- a/internal/repo/badge/event_rule_mapping.go +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package badge - -import "github.com/apache/incubator-answer/internal/base/constant" - -var ( - EventRuleMapping = map[constant.EventType][]string{ - constant.EventUserUpdate: {FilledPersonalProfile}, - constant.EventUserShare: {FirstSharedPost}, - constant.EventQuestionCreate: {""}, - constant.EventQuestionUpdate: {FirstPostEdit}, - constant.EventQuestionDelete: {""}, - constant.EventQuestionVote: {FirstVotedPost, ReachQuestionScore}, - constant.EventQuestionAccept: {AskQuestionAcceptAnswer, AnswerAccepted}, - constant.EventQuestionFlag: {FirstFlaggedPost}, - constant.EventQuestionReact: {FirstReactedPost}, - constant.EventAnswerCreate: {""}, - constant.EventAnswerUpdate: {FirstPostEdit}, - constant.EventAnswerDelete: {""}, - constant.EventAnswerVote: {FirstVotedPost, ReachAnswerScore}, - constant.EventAnswerFlag: {FirstFlaggedPost}, - constant.EventAnswerReact: {FirstReactedPost}, - constant.EventCommentCreate: {""}, - constant.EventCommentUpdate: {""}, - constant.EventCommentDelete: {""}, - constant.EventCommentVote: {FirstVotedPost}, - constant.EventCommentFlag: {FirstFlaggedPost}, - } -) diff --git a/internal/repo/badge/rule.go b/internal/repo/badge/rule.go deleted file mode 100644 index 635b30da..00000000 --- a/internal/repo/badge/rule.go +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package badge - -const ( - // FilledPersonalProfile filled personal profile - FilledPersonalProfile = "filled_personal_profile" - // FirstPostEdit first post edit - FirstPostEdit = "first_post_edit" - // FirstFlaggedPost first flagged post. - FirstFlaggedPost = "first_flagged_post" - // FirstVotedPost first voted post - FirstVotedPost = "first_voted_post" - // FirstReactedPost first reacted post - FirstReactedPost = "first_reacted_post" - // FirstSharedPost first shared post - FirstSharedPost = "first_shared_post" - // AskQuestionAcceptAnswer ask question accept answer - AskQuestionAcceptAnswer = "ask_question_accept_answer" - // AnswerAccepted answer accepted - AnswerAccepted = "answer_accepted" - // ReachAnswerScore reach answer score - ReachAnswerScore = "reach_answer_score" - // ReachQuestionScore reach question score - ReachQuestionScore = "reach_question_score" -) diff --git a/internal/repo/provider.go b/internal/repo/provider.go index ee309e02..7f222a42 100644 --- a/internal/repo/provider.go +++ b/internal/repo/provider.go @@ -104,6 +104,7 @@ var ProviderSetRepo = wire.NewSet( plugin_config.NewPluginUserConfigRepo, review.NewReviewRepo, badge.NewBadgeRepo, + badge.NewEventRuleRepo, badge_group.NewBadgeGroupRepo, badge_award.NewBadgeAwardRepo, ) diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go index 01f80fbb..17be9627 100644 --- a/internal/schema/event_schema.go +++ b/internal/schema/event_schema.go @@ -68,3 +68,13 @@ func (e *EventMsg) AddExtra(key, value string) *EventMsg { e.ExtraInfo[key] = value return e } + +func (e *EventMsg) GetObjectID() string { + if len(e.CommentID) > 0 { + return e.CommentID + } + if len(e.AnswerID) > 0 { + return e.AnswerID + } + return e.QuestionID +} diff --git a/internal/repo/badge/badge_event_handler.go b/internal/service/badge/badge_event_handler.go similarity index 60% rename from internal/repo/badge/badge_event_handler.go rename to internal/service/badge/badge_event_handler.go index 242778ec..587ee77d 100644 --- a/internal/repo/badge/badge_event_handler.go +++ b/internal/service/badge/badge_event_handler.go @@ -21,6 +21,8 @@ package badge import ( "context" + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/service/badge_award" "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/segmentfault/pacman/log" @@ -31,15 +33,28 @@ import ( type BadgeEventService struct { data *data.Data eventQueueService event_queue.EventQueueService + badgeAwardRepo badge_award.BadgeAwardRepo + badgeRepo BadgeRepo + eventRuleRepo EventRuleRepo +} + +type EventRuleHandler func(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) + +type EventRuleRepo interface { + HandleEventWithRule(ctx context.Context, msg *schema.EventMsg) (awards []*entity.BadgeAward) } func NewBadgeEventService( data *data.Data, eventQueueService event_queue.EventQueueService, + badgeRepo BadgeRepo, + eventRuleRepo EventRuleRepo, ) *BadgeEventService { n := &BadgeEventService{ data: data, eventQueueService: eventQueueService, + badgeRepo: badgeRepo, + eventRuleRepo: eventRuleRepo, } eventQueueService.RegisterHandler(n.Handler) return n @@ -47,11 +62,24 @@ func NewBadgeEventService( func (ns *BadgeEventService) Handler(ctx context.Context, msg *schema.EventMsg) error { log.Debugf("received badge event %+v", msg) - // TODO: Check if badge already exists - // TODO: Check rule + awards := ns.eventRuleRepo.HandleEventWithRule(ctx, msg) + if len(awards) == 0 { + return nil + } - // TODO: Distribute badge + badgeIDs := make([]string, 0) + for _, award := range awards { + badgeIDs = append(badgeIDs, award.BadgeID) + } + badges, err := ns.badgeRepo.GetByIDs(ctx, badgeIDs) + if err != nil { + log.Errorf("error getting badges %+v: %v", badgeIDs, err) + return err + } + + // TODO: award badges to user + log.Debugf("awarding badges %+v to user", badges) return nil } diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 94ba5b64..16087f9c 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -36,6 +36,7 @@ import ( type BadgeRepo interface { GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) + GetByIDs(ctx context.Context, ids []string) (badges []*entity.Badge, err error) ListByLevel(ctx context.Context, level entity.BadgeLevel) ([]*entity.Badge, error) ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) ([]*entity.Badge, error) @@ -44,19 +45,23 @@ type BadgeRepo interface { } type BadgeService struct { - badgeRepo BadgeRepo - badgeGroupRepo badge_group.BadgeGroupRepo - badgeAwardRepo badge_award.BadgeAwardRepo + badgeRepo BadgeRepo + badgeGroupRepo badge_group.BadgeGroupRepo + badgeAwardRepo badge_award.BadgeAwardRepo + badgeEventService *BadgeEventService } func NewBadgeService( badgeRepo BadgeRepo, badgeGroupRepo badge_group.BadgeGroupRepo, - badgeAwardRepo badge_award.BadgeAwardRepo) *BadgeService { + badgeAwardRepo badge_award.BadgeAwardRepo, + badgeEventService *BadgeEventService, +) *BadgeService { return &BadgeService{ - badgeRepo: badgeRepo, - badgeGroupRepo: badgeGroupRepo, - badgeAwardRepo: badgeAwardRepo, + badgeRepo: badgeRepo, + badgeGroupRepo: badgeGroupRepo, + badgeAwardRepo: badgeAwardRepo, + badgeEventService: badgeEventService, } } diff --git a/internal/service/provider.go b/internal/service/provider.go index bf1528b8..7a6b1340 100644 --- a/internal/service/provider.go +++ b/internal/service/provider.go @@ -123,6 +123,7 @@ var ProviderSetService = wire.NewSet( meta.NewMetaService, event_queue.NewEventQueueService, badge.NewBadgeService, + badge.NewBadgeEventService, badge_award.NewBadgeAwardService, badge_group.NewBadgeGroupService, ) From 49ba98c6fc1c130ade00af9fddd62bc76aa471e0 Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 8 Aug 2024 18:16:08 +0800 Subject: [PATCH 030/336] feat(badge): change badge_award entity --- internal/entity/badge_award_entity.go | 2 +- .../badge_award/badge_award_service.go | 36 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index a26fd8de..26369394 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -28,7 +28,7 @@ type BadgeAward struct { UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` UserID string `json:"user_id" xorm:"not null index BIGINT(20) user_id"` BadgeID string `json:"badge_id" xorm:"not null index BIGINT(20) badge_id"` - ObjectID string `json:"object_id" xorm:"not null index BIGINT(20) object_id"` + AwardKey string `json:"award_key" xorm:"not null index VARCHAR(64) award_key"` BadgeGroupID int8 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index TINYINT(1) s_badge_deleted"` } diff --git a/internal/service/badge_award/badge_award_service.go b/internal/service/badge_award/badge_award_service.go index b8e96545..7eb218fd 100644 --- a/internal/service/badge_award/badge_award_service.go +++ b/internal/service/badge_award/badge_award_service.go @@ -21,16 +21,13 @@ package badge_award import ( "context" - "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" answercommon "github.com/apache/incubator-answer/internal/service/answer_common" "github.com/apache/incubator-answer/internal/service/object_info" questioncommon "github.com/apache/incubator-answer/internal/service/question_common" usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/htmltext" "github.com/jinzhu/copier" - "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "time" ) @@ -103,24 +100,29 @@ func (b *BadgeAwardService) GetBadgeAwardList( resp = make([]*schema.GetBadgeAwardWithPageResp, 0, len(badgeAwardList)) for i, badgeAward := range badgeAwardList { - objInfo, e := b.objectInfoService.GetInfo(ctx, badgeAward.ObjectID) - if e != nil { - err = e - return - } - if objInfo.IsDeleted() { - err = errors.BadRequest(reason.NewObjectAlreadyDeleted) - return + var ( + objectID, questionID, answerID, commentID, objectType, urlTitle string + ) + + // if exist object info + objInfo, e := b.objectInfoService.GetInfo(ctx, badgeAward.AwardKey) + if e == nil && !objInfo.IsDeleted() { + objectID = objInfo.ObjectID + questionID = objInfo.QuestionID + answerID = objInfo.AnswerID + commentID = objInfo.CommentID + objectType = objInfo.ObjectType + urlTitle = objInfo.Title } row := &schema.GetBadgeAwardWithPageResp{ CreatedAt: badgeAward.CreatedAt.Unix(), - ObjectID: badgeAward.ObjectID, - QuestionID: objInfo.QuestionID, - AnswerID: objInfo.AnswerID, - CommentID: objInfo.CommentID, - ObjectType: objInfo.ObjectType, - UrlTitle: htmltext.UrlTitle(objInfo.Title), + ObjectID: objectID, + QuestionID: questionID, + AnswerID: answerID, + CommentID: commentID, + ObjectType: objectType, + UrlTitle: urlTitle, AuthorUserInfo: schema.UserBasicInfo{}, } From 122ac657f14f4806956ed0e70bc518d175efa57b Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 8 Aug 2024 18:17:41 +0800 Subject: [PATCH 031/336] feat(badge): change badge_award check --- internal/repo/badge_award/badge_award_repo.go | 4 ++-- internal/service/badge_award/badge_award_service.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 0a460347..85d3ceac 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -43,10 +43,10 @@ func NewBadgeAwardRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge_ } } -func (r *badgeAwardRepo) Award(ctx context.Context, badgeID string, userID string, objectID string, force bool, createdAt time.Time) { +func (r *badgeAwardRepo) Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) { return } -func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, objectID string) (isAward bool) { +func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string) (isAward bool) { return } func (r *badgeAwardRepo) CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) { diff --git a/internal/service/badge_award/badge_award_service.go b/internal/service/badge_award/badge_award_service.go index 7eb218fd..d94258b4 100644 --- a/internal/service/badge_award/badge_award_service.go +++ b/internal/service/badge_award/badge_award_service.go @@ -33,8 +33,8 @@ import ( ) type BadgeAwardRepo interface { - Award(ctx context.Context, badgeID string, userID string, objectID string, force bool, createdAt time.Time) - CheckIsAward(ctx context.Context, badgeID string, userID string, objectID string) bool + Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) + CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string) bool CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) CountByUserId(ctx context.Context, userID string) (awardCount int64) From 203062dd985e0f4909cfde3cd7a69a0965b86ff4 Mon Sep 17 00:00:00 2001 From: kumfo Date: Fri, 9 Aug 2024 10:33:03 +0800 Subject: [PATCH 032/336] feat(badge): badge award --- internal/entity/badge_award_entity.go | 2 +- internal/entity/badge_entity.go | 2 +- internal/migrations/v22.go | 28 +++---- internal/repo/badge/badge_repo.go | 6 ++ internal/repo/badge_award/badge_award_repo.go | 51 +++++++++--- internal/service/badge/badge_service.go | 5 +- .../badge_award/badge_award_service.go | 77 +++++++++++++++---- 7 files changed, 127 insertions(+), 44 deletions(-) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 26369394..310c85a7 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -29,7 +29,7 @@ type BadgeAward struct { UserID string `json:"user_id" xorm:"not null index BIGINT(20) user_id"` BadgeID string `json:"badge_id" xorm:"not null index BIGINT(20) badge_id"` AwardKey string `json:"award_key" xorm:"not null index VARCHAR(64) award_key"` - BadgeGroupID int8 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` + BadgeGroupID int64 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index TINYINT(1) s_badge_deleted"` } diff --git a/internal/entity/badge_entity.go b/internal/entity/badge_entity.go index da6cd4dd..d2c426fa 100644 --- a/internal/entity/badge_entity.go +++ b/internal/entity/badge_entity.go @@ -46,7 +46,7 @@ type Badge struct { AwardCount int `json:"award_count" xorm:"not null default 0 INT(11) award_count"` Description string `json:"description" xorm:"not null default '' MEDIUMTEXT description"` Status int8 `json:"status" xorm:"not null default 1 INT(11) status"` - BadgeGroupId int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` + BadgeGroupID int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` Level BadgeLevel `json:"level" xorm:"not null default 1 TINYINT(4) level"` Single int8 `json:"single" xorm:"not null default 1 TINYINT(4) single"` Collect string `json:"collect" xorm:"not null default '' VARCHAR(64) collect"` diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index de15cea6..19ec1ce0 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -44,7 +44,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.autobiographer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -59,7 +59,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.editor.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "question", @@ -74,7 +74,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_flag.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -89,7 +89,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_upvote.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -104,7 +104,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_reaction.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -119,7 +119,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_share.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -134,7 +134,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.scholar.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -149,7 +149,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.solved.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 2, + BadgeGroupID: 2, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -164,7 +164,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.nice_answer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelBronze, Single: entity.BadgeMultiAward, Collect: "", @@ -179,7 +179,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.good_answer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelSilver, Single: entity.BadgeMultiAward, Collect: "", @@ -194,7 +194,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.great_answer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelGold, Single: entity.BadgeMultiAward, Collect: "", @@ -209,7 +209,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.nice_question.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelBronze, Single: entity.BadgeMultiAward, Collect: "", @@ -224,7 +224,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.good_question.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelSilver, Single: entity.BadgeSingleAward, Collect: "", @@ -239,7 +239,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.great_question.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelGold, Single: entity.BadgeMultiAward, Collect: "", diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index 5030f0da..d4d2f992 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -109,3 +109,9 @@ func (r *badgeRepo) ListInactivated(ctx context.Context) (badges []*entity.Badge } return } + +// UpdateAwardCount updates the award count of a badge +func (r *badgeRepo) UpdateAwardCount(ctx context.Context, id string, count int64) (err error) { + _, err = r.data.DB.Context(ctx).Where("id = ?", id).Incr("award_count", count).Update(&entity.Badge{}) + return +} diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 85d3ceac..92807d1d 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -28,7 +28,6 @@ import ( "github.com/apache/incubator-answer/internal/service/badge_award" "github.com/apache/incubator-answer/internal/service/unique" "github.com/segmentfault/pacman/errors" - "time" ) type badgeAwardRepo struct { @@ -43,10 +42,36 @@ func NewBadgeAwardRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge_ } } -func (r *badgeAwardRepo) Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) { +func (r *badgeAwardRepo) Add(ctx context.Context, badgeAward *entity.BadgeAward) (err error) { + badgeAward.ID, err = r.uniqueIDRepo.GenUniqueIDStr(ctx, entity.BadgeAward{}.TableName()) + if err != nil { + return + } + _, err = r.data.DB.Context(ctx).Insert(badgeAward) return } -func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string) (isAward bool) { +func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) (isAward bool) { + isAward = false + if singleOrMulti == entity.BadgeSingleAward { + _, exists, err := r.GetByUserIdAndBadgeId(ctx, userID, badgeID) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + return + } + if exists { + return true + } + } else { + _, exists, err := r.GetByUserIdAndBadgeIdAndObjectId(ctx, userID, badgeID, awardKey) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + return + } + if exists { + return true + } + } + return } func (r *badgeAwardRepo) CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) { @@ -62,13 +87,13 @@ func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID str } return } -func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, objectID string) (awardCount int64) { +func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, awardKey string) (awardCount int64) { return } -func (r *badgeAwardRepo) CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID string) (awardCount int64) { +func (r *badgeAwardRepo) CountByObjectIdAndBadgeId(ctx context.Context, awardKey string, badgeID string) (awardCount int64) { return } -func (r *badgeAwardRepo) CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, objectID string, badgeID string) (awardCount int64) { +func (r *badgeAwardRepo) CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, awardKey string, badgeID string) (awardCount int64) { return } func (r *badgeAwardRepo) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) { @@ -92,10 +117,10 @@ func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID string, func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { +func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, awardKey string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { +func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, awardKey string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) { @@ -113,9 +138,15 @@ func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID str func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } -func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward) { + +// GetByUserIdAndBadgeId get badge award by user id and badge id +func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) { + exists, err = r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ? AND is_badge_deleted = 0", userID, badgeID).Get(&badgeAward) return } -func (r *badgeAwardRepo) GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, objectID string) (badgeAward *entity.BadgeAward) { + +// GetByUserIdAndBadgeIdAndObjectId get badge award by user id, badge id and object id +func (r *badgeAwardRepo) GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) { + exists, err = r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ? AND award_key = ? AND is_badge_deleted = 0", userID, badgeID, awardKey).Get(&badgeAward) return } diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 16087f9c..faf97b11 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -37,11 +37,14 @@ import ( type BadgeRepo interface { GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) GetByIDs(ctx context.Context, ids []string) (badges []*entity.Badge, err error) + ListByLevel(ctx context.Context, level entity.BadgeLevel) ([]*entity.Badge, error) ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) ([]*entity.Badge, error) ListActivated(ctx context.Context) ([]*entity.Badge, error) ListInactivated(ctx context.Context) ([]*entity.Badge, error) + + UpdateAwardCount(ctx context.Context, id string, count int64) error } type BadgeService struct { @@ -109,7 +112,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* } } - badgesMap[badge.BadgeGroupId] = append(badgesMap[badge.BadgeGroupId], &schema.BadgeListInfo{ + badgesMap[badge.BadgeGroupID] = append(badgesMap[badge.BadgeGroupID], &schema.BadgeListInfo{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), Icon: badge.Icon, diff --git a/internal/service/badge_award/badge_award_service.go b/internal/service/badge_award/badge_award_service.go index d94258b4..2c7c5ffa 100644 --- a/internal/service/badge_award/badge_award_service.go +++ b/internal/service/badge_award/badge_award_service.go @@ -21,66 +21,64 @@ package badge_award import ( "context" + "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" + "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/object_info" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" usercommon "github.com/apache/incubator-answer/internal/service/user_common" "github.com/jinzhu/copier" + "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "time" ) type BadgeAwardRepo interface { - Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) - CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string) bool + Add(ctx context.Context, badgeAward *entity.BadgeAward) (err error) + CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) bool CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) CountByUserId(ctx context.Context, userID string) (awardCount int64) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) - CountByObjectId(ctx context.Context, objectID string) (awardCount int64) - CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID string) (awardCount int64) - CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, objectID string, badgeID string) (awardCount int64) + CountByObjectId(ctx context.Context, awardKey string) (awardCount int64) + CountByObjectIdAndBadgeId(ctx context.Context, awardKey string, badgeID string) (awardCount int64) + CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, awardKey string, badgeID string) (awardCount int64) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) ListAllByUserId(ctx context.Context, userID string) (badgeAwards []*entity.BadgeAward) ListPagedByBadgeId(ctx context.Context, badgeID string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListPagedByObjectId(ctx context.Context, badgeID string, objectID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, objectID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListPagedByObjectId(ctx context.Context, badgeID string, awardKey string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, awardKey string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) ListPagedLatest(ctx context.Context, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err error) ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) - GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward) - GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, objectID string) (badgeAward *entity.BadgeAward) + GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) + GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) } type BadgeAwardService struct { badgeAwardRepo BadgeAwardRepo + badgeRepo badge.BadgeRepo userCommon *usercommon.UserCommon objectInfoService *object_info.ObjService - questionRepo questioncommon.QuestionRepo - answerRepo answercommon.AnswerRepo } func NewBadgeAwardService( badgeAwardRepo BadgeAwardRepo, + badgeRepo badge.BadgeRepo, userCommon *usercommon.UserCommon, objectInfoService *object_info.ObjService, - questionRepo questioncommon.QuestionRepo, - answerRepo answercommon.AnswerRepo, ) *BadgeAwardService { return &BadgeAwardService{ badgeAwardRepo: badgeAwardRepo, + badgeRepo: badgeRepo, userCommon: userCommon, objectInfoService: objectInfoService, - questionRepo: questionRepo, - answerRepo: answerRepo, } } @@ -140,3 +138,48 @@ func (b *BadgeAwardService) GetBadgeAwardList( return } + +// Award award badge +func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) (err error) { + var ( + badgeData *entity.Badge + exists, awarded bool + ) + + badgeData, exists, err = b.badgeRepo.GetByID(ctx, badgeID) + if err != nil { + return + } + + if !exists || badgeData.Status == entity.BadgeStatusInactive { + err = errors.BadRequest(reason.BadgeObjectNotFound) + return + } + + awarded = b.badgeAwardRepo.CheckIsAward(ctx, badgeID, userID, awardKey, badgeData.Single) + if !force && awarded { + return + } + + if createdAt.IsZero() { + createdAt = time.Now() + } + + err = b.badgeAwardRepo.Add(ctx, &entity.BadgeAward{ + CreatedAt: createdAt, + UpdatedAt: createdAt, + UserID: userID, + BadgeID: badgeID, + AwardKey: awardKey, + BadgeGroupID: badgeData.BadgeGroupID, + IsBadgeDeleted: 0, + }) + if err != nil { + return + } + + // increment badge award count + err = b.badgeRepo.UpdateAwardCount(ctx, badgeID, 1) + + return +} From c2531f9b07243dce326cbf5cf89d9fba23ade976 Mon Sep 17 00:00:00 2001 From: kumfo Date: Fri, 9 Aug 2024 11:33:24 +0800 Subject: [PATCH 033/336] chore(badge): change project code struct --- cmd/wire_gen.go | 3 +-- docs/docs.go | 6 +++--- docs/swagger.json | 6 +++--- docs/swagger.yaml | 6 +++--- internal/controller/badge_controller.go | 5 ++--- internal/repo/badge/badge_event_rule.go | 2 +- internal/repo/badge_award/badge_award_repo.go | 4 ++-- internal/repo/badge_group/badge_group_repo.go | 4 ++-- .../{badge_award => badge}/badge_award_service.go | 11 +++++------ internal/service/badge/badge_event_handler.go | 3 +-- .../{badge_group => badge}/badge_group_service.go | 2 +- internal/service/badge/badge_service.go | 12 +++++------- internal/service/provider.go | 6 ++---- 13 files changed, 31 insertions(+), 39 deletions(-) rename internal/service/{badge_award => badge}/badge_award_service.go (96%) rename internal/service/{badge_group => badge}/badge_group_service.go (98%) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index f49ef20e..309af935 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -75,7 +75,6 @@ import ( "github.com/apache/incubator-answer/internal/service/answer_common" auth2 "github.com/apache/incubator-answer/internal/service/auth" badge2 "github.com/apache/incubator-answer/internal/service/badge" - badge_award2 "github.com/apache/incubator-answer/internal/service/badge_award" collection2 "github.com/apache/incubator-answer/internal/service/collection" "github.com/apache/incubator-answer/internal/service/collection_common" comment2 "github.com/apache/incubator-answer/internal/service/comment" @@ -266,7 +265,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, eventRuleRepo := badge.NewEventRuleRepo(dataData) badgeEventService := badge2.NewBadgeEventService(dataData, eventQueueService, badgeRepo, eventRuleRepo) badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) - badgeAwardService := badge_award2.NewBadgeAwardService(badgeAwardRepo, userCommon, objService, questionRepo, answerRepo) + badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController) swaggerRouter := router.NewSwaggerRouter(swaggerConf) diff --git a/docs/docs.go b/docs/docs.go index bda5a17b..e1946590 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -6740,14 +6740,14 @@ const docTemplate = `{ }, "/custom.css": { "get": { - "description": "get site robots information", + "description": "get site custom CSS", "produces": [ - "application/json" + "text/css" ], "tags": [ "site" ], - "summary": "get site robots information", + "summary": "get site custom CSS", "responses": { "200": { "description": "OK", diff --git a/docs/swagger.json b/docs/swagger.json index 5ea50e6b..0a3bf6c7 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -6710,14 +6710,14 @@ }, "/custom.css": { "get": { - "description": "get site robots information", + "description": "get site custom CSS", "produces": [ - "application/json" + "text/css" ], "tags": [ "site" ], - "summary": "get site robots information", + "summary": "get site custom CSS", "responses": { "200": { "description": "OK", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ca11b20f..777445b3 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -6846,15 +6846,15 @@ paths: - Activity /custom.css: get: - description: get site robots information + description: get site custom CSS produces: - - application/json + - text/css responses: "200": description: OK schema: type: string - summary: get site robots information + summary: get site custom CSS tags: - site /installation/base-info: diff --git a/internal/controller/badge_controller.go b/internal/controller/badge_controller.go index c26d9205..d7ecc3fa 100644 --- a/internal/controller/badge_controller.go +++ b/internal/controller/badge_controller.go @@ -25,19 +25,18 @@ import ( "github.com/apache/incubator-answer/internal/base/pager" "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/internal/service/badge_award" "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" ) type BadgeController struct { badgeService *badge.BadgeService - badgeAwardService *badge_award.BadgeAwardService + badgeAwardService *badge.BadgeAwardService } func NewBadgeController( badgeService *badge.BadgeService, - badgeAwardService *badge_award.BadgeAwardService) *BadgeController { + badgeAwardService *badge.BadgeAwardService) *BadgeController { return &BadgeController{ badgeService: badgeService, badgeAwardService: badgeAwardService, diff --git a/internal/repo/badge/badge_event_rule.go b/internal/repo/badge/badge_event_rule.go index 8f940720..d6c0d826 100644 --- a/internal/repo/badge/badge_event_rule.go +++ b/internal/repo/badge/badge_event_rule.go @@ -211,6 +211,6 @@ func (br *eventRuleRepo) createBadgeAward(userID, badgeID, objectID string) (awa return &entity.BadgeAward{ UserID: userID, BadgeID: badgeID, - ObjectID: objectID, + AwardKey: objectID, } } diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 92807d1d..8860a5b1 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -25,7 +25,7 @@ import ( "github.com/apache/incubator-answer/internal/base/pager" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/badge_award" + "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/unique" "github.com/segmentfault/pacman/errors" ) @@ -35,7 +35,7 @@ type badgeAwardRepo struct { uniqueIDRepo unique.UniqueIDRepo } -func NewBadgeAwardRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge_award.BadgeAwardRepo { +func NewBadgeAwardRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge.BadgeAwardRepo { return &badgeAwardRepo{ data: data, uniqueIDRepo: uniqueIDRepo, diff --git a/internal/repo/badge_group/badge_group_repo.go b/internal/repo/badge_group/badge_group_repo.go index 7dfe90fc..63f438b9 100644 --- a/internal/repo/badge_group/badge_group_repo.go +++ b/internal/repo/badge_group/badge_group_repo.go @@ -23,7 +23,7 @@ import ( "context" "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/badge_group" + "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/unique" ) @@ -32,7 +32,7 @@ type badgeGroupRepo struct { uniqueIDRepo unique.UniqueIDRepo } -func NewBadgeGroupRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge_group.BadgeGroupRepo { +func NewBadgeGroupRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge.BadgeGroupRepo { return &badgeGroupRepo{ data: data, uniqueIDRepo: uniqueIDRepo, diff --git a/internal/service/badge_award/badge_award_service.go b/internal/service/badge/badge_award_service.go similarity index 96% rename from internal/service/badge_award/badge_award_service.go rename to internal/service/badge/badge_award_service.go index 2c7c5ffa..229b09a5 100644 --- a/internal/service/badge_award/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -17,14 +17,13 @@ * under the License. */ -package badge_award +package badge import ( "context" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/object_info" usercommon "github.com/apache/incubator-answer/internal/service/user_common" "github.com/jinzhu/copier" @@ -62,15 +61,15 @@ type BadgeAwardRepo interface { } type BadgeAwardService struct { - badgeAwardRepo BadgeAwardRepo - badgeRepo badge.BadgeRepo - userCommon *usercommon.UserCommon + badgeAwardRepo BadgeAwardRepo + badgeRepo BadgeRepo + userCommon *usercommon.UserCommon objectInfoService *object_info.ObjService } func NewBadgeAwardService( badgeAwardRepo BadgeAwardRepo, - badgeRepo badge.BadgeRepo, + badgeRepo BadgeRepo, userCommon *usercommon.UserCommon, objectInfoService *object_info.ObjService, ) *BadgeAwardService { diff --git a/internal/service/badge/badge_event_handler.go b/internal/service/badge/badge_event_handler.go index 587ee77d..d6758baf 100644 --- a/internal/service/badge/badge_event_handler.go +++ b/internal/service/badge/badge_event_handler.go @@ -22,7 +22,6 @@ package badge import ( "context" "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/badge_award" "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/segmentfault/pacman/log" @@ -33,7 +32,7 @@ import ( type BadgeEventService struct { data *data.Data eventQueueService event_queue.EventQueueService - badgeAwardRepo badge_award.BadgeAwardRepo + badgeAwardRepo BadgeAwardRepo badgeRepo BadgeRepo eventRuleRepo EventRuleRepo } diff --git a/internal/service/badge_group/badge_group_service.go b/internal/service/badge/badge_group_service.go similarity index 98% rename from internal/service/badge_group/badge_group_service.go rename to internal/service/badge/badge_group_service.go index c78f3e4f..16dd74ee 100644 --- a/internal/service/badge_group/badge_group_service.go +++ b/internal/service/badge/badge_group_service.go @@ -17,7 +17,7 @@ * under the License. */ -package badge_group +package badge import ( "context" diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index faf97b11..366dd338 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -26,8 +26,6 @@ import ( "github.com/apache/incubator-answer/internal/base/translator" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/badge_award" - "github.com/apache/incubator-answer/internal/service/badge_group" "github.com/apache/incubator-answer/pkg/converter" "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" @@ -48,16 +46,16 @@ type BadgeRepo interface { } type BadgeService struct { - badgeRepo BadgeRepo - badgeGroupRepo badge_group.BadgeGroupRepo - badgeAwardRepo badge_award.BadgeAwardRepo + badgeRepo BadgeRepo + badgeGroupRepo BadgeGroupRepo + badgeAwardRepo BadgeAwardRepo badgeEventService *BadgeEventService } func NewBadgeService( badgeRepo BadgeRepo, - badgeGroupRepo badge_group.BadgeGroupRepo, - badgeAwardRepo badge_award.BadgeAwardRepo, + badgeGroupRepo BadgeGroupRepo, + badgeAwardRepo BadgeAwardRepo, badgeEventService *BadgeEventService, ) *BadgeService { return &BadgeService{ diff --git a/internal/service/provider.go b/internal/service/provider.go index 7a6b1340..12e0db79 100644 --- a/internal/service/provider.go +++ b/internal/service/provider.go @@ -27,8 +27,6 @@ import ( answercommon "github.com/apache/incubator-answer/internal/service/answer_common" "github.com/apache/incubator-answer/internal/service/auth" "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/internal/service/badge_award" - "github.com/apache/incubator-answer/internal/service/badge_group" "github.com/apache/incubator-answer/internal/service/collection" collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" "github.com/apache/incubator-answer/internal/service/comment" @@ -124,6 +122,6 @@ var ProviderSetService = wire.NewSet( event_queue.NewEventQueueService, badge.NewBadgeService, badge.NewBadgeEventService, - badge_award.NewBadgeAwardService, - badge_group.NewBadgeGroupService, + badge.NewBadgeAwardService, + badge.NewBadgeGroupService, ) From 5293f4f3eaf397ad67bca83bfc5806aac62e1cc3 Mon Sep 17 00:00:00 2001 From: kumfo Date: Fri, 9 Aug 2024 15:00:46 +0800 Subject: [PATCH 034/336] feat(badge): user's badge award list --- docs/docs.go | 72 +++++++++++++++++++ docs/swagger.json | 72 +++++++++++++++++++ docs/swagger.yaml | 43 +++++++++++ internal/controller/badge_controller.go | 25 +++++++ internal/entity/badge_award_entity.go | 2 +- internal/router/answer_api_router.go | 1 + internal/schema/badge_schema.go | 12 ++++ internal/service/badge/badge_award_service.go | 69 +++++++++++++++++- internal/service/badge/badge_service.go | 8 +-- 9 files changed, 296 insertions(+), 8 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index e1946590..79e23a85 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2350,6 +2350,58 @@ const docTemplate = `{ } } }, + "/answer/api/v1/badge/user/awards": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get user badge award list", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get user badge award list", + "parameters": [ + { + "type": "integer", + "description": "user id", + "name": "user_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetUserBadgeAwardListResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/badges": { "get": { "security": [ @@ -8734,6 +8786,26 @@ const docTemplate = `{ } } }, + "schema.GetUserBadgeAwardListResp": { + "type": "object", + "properties": { + "earned_count": { + "type": "integer" + }, + "icon": { + "type": "string" + }, + "id": { + "type": "string" + }, + "level": { + "$ref": "#/definitions/entity.BadgeLevel" + }, + "name": { + "type": "string" + } + } + }, "schema.GetUserNotificationConfigResp": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 0a3bf6c7..07aabfea 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2320,6 +2320,58 @@ } } }, + "/answer/api/v1/badge/user/awards": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get user badge award list", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get user badge award list", + "parameters": [ + { + "type": "integer", + "description": "user id", + "name": "user_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetUserBadgeAwardListResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/badges": { "get": { "security": [ @@ -8704,6 +8756,26 @@ } } }, + "schema.GetUserBadgeAwardListResp": { + "type": "object", + "properties": { + "earned_count": { + "type": "integer" + }, + "icon": { + "type": "string" + }, + "id": { + "type": "string" + }, + "level": { + "$ref": "#/definitions/entity.BadgeLevel" + }, + "name": { + "type": "string" + } + } + }, "schema.GetUserNotificationConfigResp": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 777445b3..c8c5a560 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1203,6 +1203,19 @@ definitions: activation_url: type: string type: object + schema.GetUserBadgeAwardListResp: + properties: + earned_count: + type: integer + icon: + type: string + id: + type: string + level: + $ref: '#/definitions/entity.BadgeLevel' + name: + type: string + type: object schema.GetUserNotificationConfigResp: properties: all_new_question: @@ -4201,6 +4214,36 @@ paths: summary: get badge award list tags: - api-badge + /answer/api/v1/badge/user/awards: + get: + consumes: + - application/json + description: get user badge award list + parameters: + - description: user id + in: query + name: user_id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetUserBadgeAwardListResp' + type: array + type: object + security: + - ApiKeyAuth: [] + summary: get user badge award list + tags: + - api-badge /answer/api/v1/badges: get: consumes: diff --git a/internal/controller/badge_controller.go b/internal/controller/badge_controller.go index d7ecc3fa..7eb42da0 100644 --- a/internal/controller/badge_controller.go +++ b/internal/controller/badge_controller.go @@ -104,3 +104,28 @@ func (b *BadgeController) GetBadgeAwardList(ctx *gin.Context) { } handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) } + +// GetBadgeAwardListByUsername get user badge award list +// @Summary get user badge award list +// @Description get user badge award list +// @Tags api-badge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param user_id query int true "user id" +// @Success 200 {object} handler.RespBody{data=[]schema.GetUserBadgeAwardListResp} +// @Router /answer/api/v1/badge/user/awards [get] +func (b *BadgeController) GetBadgeAwardListByUsername(ctx *gin.Context) { + req := &schema.GetUserBadgeAwardListReq{} + if handler.BindAndCheck(ctx, req) { + return + } + + resp, total, err := b.badgeAwardService.GetUserBadgeAwardList(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + + handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) +} diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 310c85a7..17649734 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -40,7 +40,7 @@ func (BadgeAward) TableName() string { type BadgeEarnedCount struct { BadgeID string `xorm:"badge_id"` - EarnedCount int `xorm:"earned_count"` + EarnedCount int64 `xorm:"earned_count"` } // TableName badge_award table name diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index c7d4c38e..63dec5fa 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -194,6 +194,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) { // badges r.GET("/badge", a.badgeController.GetBadgeInfo) r.GET("/badge/awards/page", a.badgeController.GetBadgeAwardList) + r.GET("/badge/user/awards", a.badgeController.GetBadgeAwardListByUsername) r.GET("/badges", a.badgeController.GetBadgeList) } diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index 06d92ecc..0555a99b 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -68,3 +68,15 @@ type GetBadgeAwardWithPageResp struct { UrlTitle string `json:"url_title"` AuthorUserInfo UserBasicInfo `json:"author_user_info"` } + +type GetUserBadgeAwardListReq struct { + Username string `validate:"omitempty,gt=0,lte=100" form:"username"` + UserID string `json:"-"` +} +type GetUserBadgeAwardListResp struct { + ID string `json:"id" ` + Name string `json:"name" ` + Icon string `json:"icon" ` + EarnedCount int64 `json:"earned_count" ` + Level entity.BadgeLevel `json:"level" ` +} diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index 229b09a5..c13c5658 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -21,11 +21,14 @@ package badge import ( "context" + "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/reason" + "github.com/apache/incubator-answer/internal/base/translator" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/object_info" usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" @@ -61,9 +64,9 @@ type BadgeAwardRepo interface { } type BadgeAwardService struct { - badgeAwardRepo BadgeAwardRepo - badgeRepo BadgeRepo - userCommon *usercommon.UserCommon + badgeAwardRepo BadgeAwardRepo + badgeRepo BadgeRepo + userCommon *usercommon.UserCommon objectInfoService *object_info.ObjService } @@ -182,3 +185,63 @@ func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID st return } + +// GetUserBadgeAwardList get user badge award list +func (b *BadgeAwardService) GetUserBadgeAwardList( + ctx *gin.Context, + req *schema.GetUserBadgeAwardListReq, +) ( + resp []*schema.GetUserBadgeAwardListResp, + total int64, + err error, +) { + var ( + earnedCounts []*entity.BadgeEarnedCount + userInfo *schema.UserBasicInfo + exist bool + ) + + // validate user exists or not + if len(req.Username) > 0 { + userInfo, exist, err = b.userCommon.GetUserBasicInfoByUserName(ctx, req.Username) + if err != nil { + return + } + if !exist { + err = errors.BadRequest(reason.UserNotFound) + return + } + req.UserID = userInfo.ID + } + if len(req.UserID) == 0 { + err = errors.BadRequest(reason.UserNotFound) + return + } + + earnedCounts, err = b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, req.UserID) + if err != nil { + return + } + total = int64(len(earnedCounts)) + resp = make([]*schema.GetUserBadgeAwardListResp, 0, total) + + for i, earnedCount := range earnedCounts { + badge, exists, e := b.badgeRepo.GetByID(ctx, earnedCount.BadgeID) + if e != nil { + err = e + return + } + if !exists { + continue + } + resp[i] = &schema.GetUserBadgeAwardListResp{ + ID: badge.ID, + Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), + Icon: badge.Icon, + EarnedCount: earnedCount.EarnedCount, + Level: badge.Level, + } + } + + return +} diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 366dd338..32a54a8d 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -46,9 +46,9 @@ type BadgeRepo interface { } type BadgeService struct { - badgeRepo BadgeRepo - badgeGroupRepo BadgeGroupRepo - badgeAwardRepo BadgeAwardRepo + badgeRepo BadgeRepo + badgeGroupRepo BadgeGroupRepo + badgeAwardRepo BadgeAwardRepo badgeEventService *BadgeEventService } @@ -103,7 +103,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* earned := false if len(earnedCounts) > 0 { for _, earnedCount := range earnedCounts { - if badge.ID == earnedCount.BadgeID { + if badge.ID == earnedCount.BadgeID && earnedCount.EarnedCount > 0 { earned = true break } From 61db21e0d376a22a3b1e32a32a3d1578eb1106d4 Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 12 Aug 2024 15:33:04 +0800 Subject: [PATCH 035/336] feat(badge): fixed user's badge award list and add recent user badges --- docs/docs.go | 103 +++++++++++++++- docs/swagger.json | 103 +++++++++++++++- docs/swagger.yaml | 70 ++++++++++- internal/controller/badge_controller.go | 35 +++++- internal/entity/badge_award_entity.go | 21 +++- internal/repo/badge_award/badge_award_repo.go | 25 +++- internal/router/answer_api_router.go | 3 +- internal/schema/badge_schema.go | 95 ++++++++++----- internal/service/badge/badge_award_service.go | 113 ++++++++++++++---- 9 files changed, 492 insertions(+), 76 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 79e23a85..ecc62169 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2326,6 +2326,12 @@ const docTemplate = `{ "name": "badge_id", "in": "query", "required": true + }, + { + "type": "string", + "description": "only list the award by username", + "name": "username", + "in": "query" } ], "responses": { @@ -2370,9 +2376,61 @@ const docTemplate = `{ "summary": "get user badge award list", "parameters": [ { - "type": "integer", - "description": "user id", - "name": "user_id", + "type": "string", + "description": "user name", + "name": "username", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetUserBadgeAwardListResp" + } + } + } + } + ] + } + } + } + } + }, + "/answer/api/v1/badge/user/awards/recent": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get user badge award list", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get user badge award list", + "parameters": [ + { + "type": "string", + "description": "user name", + "name": "username", "in": "query", "required": true } @@ -7565,21 +7623,31 @@ const docTemplate = `{ "type": "object", "properties": { "award_count": { + "description": "badge award count", "type": "integer" }, "earned": { + "description": "badge earned count", "type": "boolean" }, "icon": { + "description": "badge icon", "type": "string" }, "id": { + "description": "badge id", "type": "string" }, "level": { - "$ref": "#/definitions/entity.BadgeLevel" + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] }, "name": { + "description": "badge name", "type": "string" } } @@ -7839,27 +7907,39 @@ const docTemplate = `{ "type": "object", "properties": { "award_count": { + "description": "badge award count", "type": "integer" }, "description": { + "description": "badge description", "type": "string" }, "earned_count": { + "description": "badge earned count", "type": "integer" }, "icon": { + "description": "badge icon", "type": "string" }, "id": { + "description": "badge id", "type": "string" }, "is_single": { + "description": "badge is single or multiple", "type": "boolean" }, "level": { - "$ref": "#/definitions/entity.BadgeLevel" + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] }, "name": { + "description": "badge name", "type": "string" } } @@ -7868,12 +7948,14 @@ const docTemplate = `{ "type": "object", "properties": { "badges": { + "description": "badge list info", "type": "array", "items": { "$ref": "#/definitions/schema.BadgeListInfo" } }, "group_name": { + "description": "badge group name", "type": "string" } } @@ -8790,18 +8872,27 @@ const docTemplate = `{ "type": "object", "properties": { "earned_count": { + "description": "badge award count", "type": "integer" }, "icon": { + "description": "badge icon", "type": "string" }, "id": { + "description": "badge id", "type": "string" }, "level": { - "$ref": "#/definitions/entity.BadgeLevel" + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] }, "name": { + "description": "badge name", "type": "string" } } diff --git a/docs/swagger.json b/docs/swagger.json index 07aabfea..1412f179 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2296,6 +2296,12 @@ "name": "badge_id", "in": "query", "required": true + }, + { + "type": "string", + "description": "only list the award by username", + "name": "username", + "in": "query" } ], "responses": { @@ -2340,9 +2346,61 @@ "summary": "get user badge award list", "parameters": [ { - "type": "integer", - "description": "user id", - "name": "user_id", + "type": "string", + "description": "user name", + "name": "username", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetUserBadgeAwardListResp" + } + } + } + } + ] + } + } + } + } + }, + "/answer/api/v1/badge/user/awards/recent": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get user badge award list", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "api-badge" + ], + "summary": "get user badge award list", + "parameters": [ + { + "type": "string", + "description": "user name", + "name": "username", "in": "query", "required": true } @@ -7535,21 +7593,31 @@ "type": "object", "properties": { "award_count": { + "description": "badge award count", "type": "integer" }, "earned": { + "description": "badge earned count", "type": "boolean" }, "icon": { + "description": "badge icon", "type": "string" }, "id": { + "description": "badge id", "type": "string" }, "level": { - "$ref": "#/definitions/entity.BadgeLevel" + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] }, "name": { + "description": "badge name", "type": "string" } } @@ -7809,27 +7877,39 @@ "type": "object", "properties": { "award_count": { + "description": "badge award count", "type": "integer" }, "description": { + "description": "badge description", "type": "string" }, "earned_count": { + "description": "badge earned count", "type": "integer" }, "icon": { + "description": "badge icon", "type": "string" }, "id": { + "description": "badge id", "type": "string" }, "is_single": { + "description": "badge is single or multiple", "type": "boolean" }, "level": { - "$ref": "#/definitions/entity.BadgeLevel" + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] }, "name": { + "description": "badge name", "type": "string" } } @@ -7838,12 +7918,14 @@ "type": "object", "properties": { "badges": { + "description": "badge list info", "type": "array", "items": { "$ref": "#/definitions/schema.BadgeListInfo" } }, "group_name": { + "description": "badge group name", "type": "string" } } @@ -8760,18 +8842,27 @@ "type": "object", "properties": { "earned_count": { + "description": "badge award count", "type": "integer" }, "icon": { + "description": "badge icon", "type": "string" }, "id": { + "description": "badge id", "type": "string" }, "level": { - "$ref": "#/definitions/entity.BadgeLevel" + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] }, "name": { + "description": "badge name", "type": "string" } } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c8c5a560..e2fc6682 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -355,16 +355,23 @@ definitions: schema.BadgeListInfo: properties: award_count: + description: badge award count type: integer earned: + description: badge earned count type: boolean icon: + description: badge icon type: string id: + description: badge id type: string level: - $ref: '#/definitions/entity.BadgeLevel' + allOf: + - $ref: '#/definitions/entity.BadgeLevel' + description: badge level name: + description: badge name type: string type: object schema.CloseQuestionReq: @@ -541,29 +548,40 @@ definitions: schema.GetBadgeInfoResp: properties: award_count: + description: badge award count type: integer description: + description: badge description type: string earned_count: + description: badge earned count type: integer icon: + description: badge icon type: string id: + description: badge id type: string is_single: + description: badge is single or multiple type: boolean level: - $ref: '#/definitions/entity.BadgeLevel' + allOf: + - $ref: '#/definitions/entity.BadgeLevel' + description: badge level name: + description: badge name type: string type: object schema.GetBadgeListResp: properties: badges: + description: badge list info items: $ref: '#/definitions/schema.BadgeListInfo' type: array group_name: + description: badge group name type: string type: object schema.GetCommentPersonalWithPageResp: @@ -1206,14 +1224,20 @@ definitions: schema.GetUserBadgeAwardListResp: properties: earned_count: + description: badge award count type: integer icon: + description: badge icon type: string id: + description: badge id type: string level: - $ref: '#/definitions/entity.BadgeLevel' + allOf: + - $ref: '#/definitions/entity.BadgeLevel' + description: badge level name: + description: badge name type: string type: object schema.GetUserNotificationConfigResp: @@ -4197,6 +4221,10 @@ paths: name: badge_id required: true type: string + - description: only list the award by username + in: query + name: username + type: string produces: - application/json responses: @@ -4220,11 +4248,41 @@ paths: - application/json description: get user badge award list parameters: - - description: user id + - description: user name in: query - name: user_id + name: username required: true - type: integer + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetUserBadgeAwardListResp' + type: array + type: object + security: + - ApiKeyAuth: [] + summary: get user badge award list + tags: + - api-badge + /answer/api/v1/badge/user/awards/recent: + get: + consumes: + - application/json + description: get user badge award list + parameters: + - description: user name + in: query + name: username + required: true + type: string produces: - application/json responses: diff --git a/internal/controller/badge_controller.go b/internal/controller/badge_controller.go index 7eb42da0..65b59407 100644 --- a/internal/controller/badge_controller.go +++ b/internal/controller/badge_controller.go @@ -87,6 +87,7 @@ func (b *BadgeController) GetBadgeInfo(ctx *gin.Context) { // @Param page query int false "page" // @Param page_size query int false "page size" // @Param badge_id query string true "badge id" +// @Param username query string false "only list the award by username" // @Success 200 {object} handler.RespBody{data=schema.GetBadgeInfoResp} // @Router /answer/api/v1/badge/awards/page [get] func (b *BadgeController) GetBadgeAwardList(ctx *gin.Context) { @@ -95,7 +96,6 @@ func (b *BadgeController) GetBadgeAwardList(ctx *gin.Context) { return } req.BadgeID = uid.DeShortID(req.BadgeID) - req.UserID = middleware.GetLoginUserIDFromContext(ctx) resp, total, err := b.badgeAwardService.GetBadgeAwardList(ctx, req) if err != nil { @@ -105,17 +105,17 @@ func (b *BadgeController) GetBadgeAwardList(ctx *gin.Context) { handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) } -// GetBadgeAwardListByUsername get user badge award list +// GetAllBadgeAwardListByUsername get user badge award list // @Summary get user badge award list // @Description get user badge award list // @Tags api-badge // @Accept json // @Produce json // @Security ApiKeyAuth -// @Param user_id query int true "user id" +// @Param username query string true "user name" // @Success 200 {object} handler.RespBody{data=[]schema.GetUserBadgeAwardListResp} // @Router /answer/api/v1/badge/user/awards [get] -func (b *BadgeController) GetBadgeAwardListByUsername(ctx *gin.Context) { +func (b *BadgeController) GetAllBadgeAwardListByUsername(ctx *gin.Context) { req := &schema.GetUserBadgeAwardListReq{} if handler.BindAndCheck(ctx, req) { return @@ -129,3 +129,30 @@ func (b *BadgeController) GetBadgeAwardListByUsername(ctx *gin.Context) { handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) } + +// GetRecentBadgeAwardListByUsername get user badge award list +// @Summary get user badge award list +// @Description get user badge award list +// @Tags api-badge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param username query string true "user name" +// @Success 200 {object} handler.RespBody{data=[]schema.GetUserBadgeAwardListResp} +// @Router /answer/api/v1/badge/user/awards/recent [get] +func (b *BadgeController) GetRecentBadgeAwardListByUsername(ctx *gin.Context) { + req := &schema.GetUserBadgeAwardListReq{} + if handler.BindAndCheck(ctx, req) { + return + } + + req.Limit = 10 + + resp, total, err := b.badgeAwardService.GetUserRecentBadgeAwardList(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + + handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) +} diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 17649734..1d421623 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -21,6 +21,11 @@ package entity import "time" +const ( + IsBadgeNotDeleted = 0 + IsBadgeDeleted = 1 +) + // BadgeAward badge_award type BadgeAward struct { ID string `json:"id" xorm:"id"` @@ -30,7 +35,7 @@ type BadgeAward struct { BadgeID string `json:"badge_id" xorm:"not null index BIGINT(20) badge_id"` AwardKey string `json:"award_key" xorm:"not null index VARCHAR(64) award_key"` BadgeGroupID int64 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` - IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index TINYINT(1) s_badge_deleted"` + IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index TINYINT(1) is_badge_deleted"` } // TableName badge_award table name @@ -47,3 +52,17 @@ type BadgeEarnedCount struct { func (BadgeEarnedCount) TableName() string { return "badge_award" } + +type BadgeAwardRecent struct { + Created time.Time `xorm:"created"` + UserID string `xorm:"user_id"` + BadgeID string `xorm:"badge_id"` + AwardKey string `xorm:"award_key"` + EarnedCount int64 `xorm:"earned_count"` + IsBadgeDeleted int8 `xorm:"is_badge_deleted"` +} + +// TableName badge_award table name +func (BadgeAwardRecent) TableName() string { + return "badge_award" +} diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 8860a5b1..5a5d56cd 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -108,13 +108,21 @@ func (r *badgeAwardRepo) ListAllByUserId(ctx context.Context, userID string) (ba func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error) { session := r.data.DB.Context(ctx) session.Where("badge_id = ?", badgeID) - total, err = pager.Help(page, pageSize, &badgeAwardList, &entity.Question{}, session) + total, err = pager.Help(page, pageSize, &badgeAwardList, &entity.BadgeAward{}, session) if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } return } -func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { + +// ListPagedByBadgeIdAndUserId list badge awards by badge id and user id +func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error) { + session := r.data.DB.Context(ctx) + session.Where("badge_id = ? AND user_id = ?", badgeID, userID) + total, err = pager.Help(page, pageSize, &badgeAwardList, &entity.Question{}, session) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, awardKey string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { @@ -132,6 +140,19 @@ func (r *badgeAwardRepo) ListTagPagedByBadgeIdAndUserId(ctx context.Context, bad func (r *badgeAwardRepo) ListPagedLatest(ctx context.Context, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } + +// ListNewestEarned list newest earned badge awards +func (r *badgeAwardRepo) ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) { + badgeAwards = make([]*entity.BadgeAwardRecent, 0) + err = r.data.DB.Context(ctx). + Select("user_id, badge_id, max(created_at) created,count(*) earned_count"). + Where("user_id = ? AND is_badge_deleted = ? ", userID, entity.IsBadgeNotDeleted). + GroupBy("badge_id"). + OrderBy("created desc"). + Limit(limit).Find(&badgeAwards) + return +} + func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index 63dec5fa..f343d7d1 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -194,7 +194,8 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) { // badges r.GET("/badge", a.badgeController.GetBadgeInfo) r.GET("/badge/awards/page", a.badgeController.GetBadgeAwardList) - r.GET("/badge/user/awards", a.badgeController.GetBadgeAwardListByUsername) + r.GET("/badge/user/awards/recent", a.badgeController.GetRecentBadgeAwardListByUsername) + r.GET("/badge/user/awards", a.badgeController.GetAllBadgeAwardListByUsername) r.GET("/badges", a.badgeController.GetBadgeList) } diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index 0555a99b..cae2aa66 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -23,28 +23,44 @@ import "github.com/apache/incubator-answer/internal/entity" // BadgeListInfo get badge list response type BadgeListInfo struct { - ID string `json:"id" ` - Name string `json:"name" ` - Icon string `json:"icon" ` - AwardCount int `json:"award_count" ` - Earned bool `json:"earned" ` - Level entity.BadgeLevel `json:"level" ` + // badge id + ID string `json:"id" ` + // badge name + Name string `json:"name" ` + // badge icon + Icon string `json:"icon" ` + // badge award count + AwardCount int `json:"award_count" ` + // badge earned count + Earned bool `json:"earned" ` + // badge level + Level entity.BadgeLevel `json:"level" ` } type GetBadgeListResp struct { - Badges []*BadgeListInfo `json:"badges" ` - GroupName string `json:"group_name" ` + // badge list info + Badges []*BadgeListInfo `json:"badges" ` + // badge group name + GroupName string `json:"group_name" ` } type GetBadgeInfoResp struct { - ID string `json:"id" ` - Name string `json:"name" ` - Description string `json:"description" ` - Icon string `json:"icon" ` - AwardCount int `json:"award_count" ` - EarnedCount int64 `json:"earned_count" ` - IsSingle bool `json:"is_single" ` - Level entity.BadgeLevel `json:"level" ` + // badge id + ID string `json:"id" ` + // badge name + Name string `json:"name" ` + // badge description + Description string `json:"description" ` + // badge icon + Icon string `json:"icon" ` + // badge award count + AwardCount int `json:"award_count" ` + // badge earned count + EarnedCount int64 `json:"earned_count" ` + // badge is single or multiple + IsSingle bool `json:"is_single" ` + // badge level + Level entity.BadgeLevel `json:"level" ` } type GetBadgeAwardWithPageReq struct { @@ -54,29 +70,48 @@ type GetBadgeAwardWithPageReq struct { PageSize int `validate:"omitempty,min=1" form:"page_size"` // badge id BadgeID string `validate:"required" form:"badge_id"` + // username + Username string `validate:"omitempty,gt=0,lte=100" form:"username"` // user id UserID string `json:"-"` } type GetBadgeAwardWithPageResp struct { - CreatedAt int64 `json:"created_at"` - ObjectID string `json:"object_id"` - QuestionID string `json:"question_id"` - AnswerID string `json:"answer_id"` - CommentID string `json:"comment_id"` - ObjectType string `json:"object_type" enums:"question,answer,comment"` - UrlTitle string `json:"url_title"` + // created time + CreatedAt int64 `json:"created_at"` + // object id + ObjectID string `json:"object_id"` + // question id + QuestionID string `json:"question_id"` + // answer id + AnswerID string `json:"answer_id"` + // comment id + CommentID string `json:"comment_id"` + // object type + ObjectType string `json:"object_type" enums:"question,answer,comment"` + // url title + UrlTitle string `json:"url_title"` + // author user info AuthorUserInfo UserBasicInfo `json:"author_user_info"` } type GetUserBadgeAwardListReq struct { - Username string `validate:"omitempty,gt=0,lte=100" form:"username"` - UserID string `json:"-"` + // username + Username string `validate:"required,gt=0,lte=100" form:"username"` + // user id + UserID string `json:"-"` + Limit int `json:"-"` } + type GetUserBadgeAwardListResp struct { - ID string `json:"id" ` - Name string `json:"name" ` - Icon string `json:"icon" ` - EarnedCount int64 `json:"earned_count" ` - Level entity.BadgeLevel `json:"level" ` + // badge id + ID string `json:"id" ` + // badge name + Name string `json:"name" ` + // badge icon + Icon string `json:"icon" ` + // badge award count + EarnedCount int64 `json:"earned_count" ` + // badge level + Level entity.BadgeLevel `json:"level" ` } diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index c13c5658..0ad299ba 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -28,6 +28,7 @@ import ( "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/object_info" usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" @@ -56,6 +57,7 @@ type BadgeAwardRepo interface { ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) ListPagedLatest(ctx context.Context, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err error) ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) @@ -86,13 +88,20 @@ func NewBadgeAwardService( // GetBadgeAwardList get badge award list func (b *BadgeAwardService) GetBadgeAwardList( - ctx context.Context, req *schema.GetBadgeAwardWithPageReq, + ctx context.Context, + req *schema.GetBadgeAwardWithPageReq, ) (resp []*schema.GetBadgeAwardWithPageResp, total int64, err error) { var ( badgeAwardList []*entity.BadgeAward ) - badgeAwardList, total, err = b.badgeAwardRepo.ListPagedByBadgeId(ctx, req.BadgeID, req.Page, req.PageSize) + req.UserID, err = b.validateUserByUsername(ctx, req.Username) + if err != nil { + badgeAwardList, total, err = b.badgeAwardRepo.ListPagedByBadgeId(ctx, req.BadgeID, req.Page, req.PageSize) + } else { + badgeAwardList, total, err = b.badgeAwardRepo.ListPagedByBadgeIdAndUserId(ctx, req.BadgeID, req.UserID, req.Page, req.PageSize) + } + if err != nil { return } @@ -197,24 +206,10 @@ func (b *BadgeAwardService) GetUserBadgeAwardList( ) { var ( earnedCounts []*entity.BadgeEarnedCount - userInfo *schema.UserBasicInfo - exist bool ) - // validate user exists or not - if len(req.Username) > 0 { - userInfo, exist, err = b.userCommon.GetUserBasicInfoByUserName(ctx, req.Username) - if err != nil { - return - } - if !exist { - err = errors.BadRequest(reason.UserNotFound) - return - } - req.UserID = userInfo.ID - } - if len(req.UserID) == 0 { - err = errors.BadRequest(reason.UserNotFound) + req.UserID, err = b.validateUserByUsername(ctx, req.Username) + if err != nil { return } @@ -223,7 +218,7 @@ func (b *BadgeAwardService) GetUserBadgeAwardList( return } total = int64(len(earnedCounts)) - resp = make([]*schema.GetUserBadgeAwardListResp, 0, total) + resp = make([]*schema.GetUserBadgeAwardListResp, total) for i, earnedCount := range earnedCounts { badge, exists, e := b.badgeRepo.GetByID(ctx, earnedCount.BadgeID) @@ -235,7 +230,7 @@ func (b *BadgeAwardService) GetUserBadgeAwardList( continue } resp[i] = &schema.GetUserBadgeAwardListResp{ - ID: badge.ID, + ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), Icon: badge.Icon, EarnedCount: earnedCount.EarnedCount, @@ -245,3 +240,81 @@ func (b *BadgeAwardService) GetUserBadgeAwardList( return } + +// GetUserRecentBadgeAwardList get user badge award list +func (b *BadgeAwardService) GetUserRecentBadgeAwardList( + ctx *gin.Context, + req *schema.GetUserBadgeAwardListReq, +) ( + resp []*schema.GetUserBadgeAwardListResp, + total int64, + err error, +) { + var ( + earnedCounts []*entity.BadgeAwardRecent + ) + + req.UserID, err = b.validateUserByUsername(ctx, req.Username) + if err != nil { + return + } + + earnedCounts, err = b.badgeAwardRepo.ListNewestEarned(ctx, req.UserID, req.Limit) + if err != nil { + return + } + + total = int64(len(earnedCounts)) + resp = make([]*schema.GetUserBadgeAwardListResp, total) + + for i, earnedCount := range earnedCounts { + badge, exists, e := b.badgeRepo.GetByID(ctx, earnedCount.BadgeID) + if e != nil { + err = e + return + } + if !exists { + continue + } + resp[i] = &schema.GetUserBadgeAwardListResp{ + ID: uid.EnShortID(badge.ID), + Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), + Icon: badge.Icon, + EarnedCount: earnedCount.EarnedCount, + Level: badge.Level, + } + } + + return +} + +// validate user + +type userReq struct { + UserID string + Username string +} + +func (b *BadgeAwardService) validateUserByUsername(ctx context.Context, userName string) (userID string, err error) { + var ( + userInfo *schema.UserBasicInfo + exist bool + ) + // validate user exists or not + if len(userName) > 0 { + userInfo, exist, err = b.userCommon.GetUserBasicInfoByUserName(ctx, userName) + if err != nil { + return + } + if !exist { + err = errors.BadRequest(reason.UserNotFound) + return + } + userID = userInfo.ID + } + if len(userID) == 0 { + err = errors.BadRequest(reason.UserNotFound) + return + } + return +} From 5c04bceca74847e7b0406d1a0a96b13b19d2f346 Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 12 Aug 2024 16:01:20 +0800 Subject: [PATCH 036/336] feat(badge): fixed badge detail --- internal/service/badge/badge_award_service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index 0ad299ba..96a9743f 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -106,7 +106,7 @@ func (b *BadgeAwardService) GetBadgeAwardList( return } - resp = make([]*schema.GetBadgeAwardWithPageResp, 0, len(badgeAwardList)) + resp = make([]*schema.GetBadgeAwardWithPageResp, len(badgeAwardList)) for i, badgeAward := range badgeAwardList { var ( From 98d93b1f98b4c4d44492f1a2f4fd0b350fc6d2fb Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 12 Aug 2024 16:34:16 +0800 Subject: [PATCH 037/336] feat(badge): add badge checking rule --- internal/entity/badge_entity.go | 43 +++++++++------ internal/migrations/init.go | 2 +- internal/migrations/v22.go | 2 +- internal/repo/badge/badge_event_rule.go | 55 +++++++++++++++++-- internal/schema/event_schema.go | 7 +++ internal/service/badge/badge_event_handler.go | 2 - 6 files changed, 87 insertions(+), 24 deletions(-) diff --git a/internal/entity/badge_entity.go b/internal/entity/badge_entity.go index d2c426fa..96babcb9 100644 --- a/internal/entity/badge_entity.go +++ b/internal/entity/badge_entity.go @@ -19,7 +19,10 @@ package entity -import "time" +import ( + "github.com/tidwall/gjson" + "time" +) type BadgeLevel int @@ -38,23 +41,31 @@ const ( // Badge badge type Badge struct { - ID string `json:"id" xorm:"id"` - CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` - UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` - Name string `json:"name" xorm:"not null default '' VARCHAR(256) name"` - Icon string `json:"icon" xorm:"not null default '' VARCHAR(1024) icon"` - AwardCount int `json:"award_count" xorm:"not null default 0 INT(11) award_count"` - Description string `json:"description" xorm:"not null default '' MEDIUMTEXT description"` - Status int8 `json:"status" xorm:"not null default 1 INT(11) status"` - BadgeGroupID int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` - Level BadgeLevel `json:"level" xorm:"not null default 1 TINYINT(4) level"` - Single int8 `json:"single" xorm:"not null default 1 TINYINT(4) single"` - Collect string `json:"collect" xorm:"not null default '' VARCHAR(64) collect"` - Handler string `json:"handler" xorm:"not null default '' VARCHAR(64) handler"` - Param string `json:"param" xorm:"not null default '' VARCHAR(128) param"` + ID string `xorm:"not null pk autoincr BIGINT(20) id"` + CreatedAt time.Time `xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` + UpdatedAt time.Time `xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` + Name string `xorm:"not null default '' VARCHAR(256) name"` + Icon string `xorm:"not null default '' VARCHAR(1024) icon"` + AwardCount int `xorm:"not null default 0 INT(11) award_count"` + Description string `xorm:"not null default '' MEDIUMTEXT description"` + Status int8 `xorm:"not null default 1 INT(11) status"` + BadgeGroupID int64 `xorm:"not null default 0 BIGINT(20) badge_group_id"` + Level BadgeLevel `xorm:"not null default 1 TINYINT(4) level"` + Single int8 `xorm:"not null default 1 TINYINT(4) single"` + Collect string `xorm:"not null default '' VARCHAR(64) collect"` + Handler string `xorm:"not null default '' VARCHAR(64) handler"` + Param string `xorm:"not null default '' TEXT param"` } // TableName badge table name -func (Badge) TableName() string { +func (b *Badge) TableName() string { return "badge" } + +func (b *Badge) GetIntParam(key string) int64 { + return gjson.Get(b.Param, key).Int() +} + +func (b *Badge) GetStringParam(key string) string { + return gjson.Get(b.Param, key).String() +} diff --git a/internal/migrations/init.go b/internal/migrations/init.go index 40e9a91a..0b4d1ce3 100644 --- a/internal/migrations/init.go +++ b/internal/migrations/init.go @@ -136,7 +136,7 @@ func (m *Mentor) initBadge() { } for _, badge := range defaultBadgeTable { - badge.ID, m.err = uniqueIDRepo.GenUniqueIDStr(m.ctx, entity.Badge{}.TableName()) + badge.ID, m.err = uniqueIDRepo.GenUniqueIDStr(m.ctx, new(entity.Badge).TableName()) if m.err != nil { return } diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index 19ec1ce0..f5793d4a 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -273,7 +273,7 @@ func addBadges(ctx context.Context, x *xorm.Engine) (err error) { return } for _, badge := range defaultBadgeTable { - badge.ID, err = uniqueIDRepo.GenUniqueIDStr(ctx, entity.Badge{}.TableName()) + badge.ID, err = uniqueIDRepo.GenUniqueIDStr(ctx, new(entity.Badge).TableName()) if err != nil { return } diff --git a/internal/repo/badge/badge_event_rule.go b/internal/repo/badge/badge_event_rule.go index d6c0d826..41d56686 100644 --- a/internal/repo/badge/badge_event_rule.go +++ b/internal/repo/badge/badge_event_rule.go @@ -29,6 +29,7 @@ import ( "github.com/apache/incubator-answer/internal/service/badge" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" + "strconv" ) // eventRuleRepo event rule repo @@ -170,6 +171,26 @@ func (br *eventRuleRepo) ReachAnswerAcceptedAmount(ctx context.Context, if b == nil { return nil, nil } + if len(event.AnswerUserID) == 0 { + return nil, nil + } + + // count user's accepted answer amount + amount, err := br.data.DB.Context(ctx).Count(&entity.Answer{ + UserID: event.AnswerUserID, + Accepted: schema.AnswerAcceptedEnable, + Status: entity.AnswerStatusAvailable, + }) + if err != nil { + return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + + // get badge requirement + requirement := b.GetIntParam("amount") + if requirement == 0 || amount < requirement { + return nil, nil + } + return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil } @@ -180,7 +201,20 @@ func (br *eventRuleRepo) ReachAnswerVote(ctx context.Context, if b == nil { return nil, nil } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + + // get vote amount + amount, _ := strconv.Atoi(event.GetExtra("vote_up_amount")) + if amount == 0 { + return nil, nil + } + + // get badge requirement + requirement := b.GetIntParam("amount") + if requirement == 0 || int64(amount) < requirement { + return nil, nil + } + + return append(awards, br.createBadgeAward(event.AnswerUserID, b.ID, event.AnswerID)), nil } // ReachQuestionVote reach question vote @@ -190,7 +224,20 @@ func (br *eventRuleRepo) ReachQuestionVote(ctx context.Context, if b == nil { return nil, nil } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + + // get vote amount + amount, _ := strconv.Atoi(event.GetExtra("vote_up_amount")) + if amount == 0 { + return nil, nil + } + + // get badge requirement + requirement := b.GetIntParam("amount") + if requirement == 0 || int64(amount) < requirement { + return nil, nil + } + + return append(awards, br.createBadgeAward(event.QuestionUserID, b.ID, event.QuestionID)), nil } func (br *eventRuleRepo) getBadgeByHandler(ctx context.Context, handler string) (b *entity.Badge) { @@ -207,10 +254,10 @@ func (br *eventRuleRepo) getBadgeByHandler(ctx context.Context, handler string) return b } -func (br *eventRuleRepo) createBadgeAward(userID, badgeID, objectID string) (awards *entity.BadgeAward) { +func (br *eventRuleRepo) createBadgeAward(userID, badgeID, awardKey string) (awards *entity.BadgeAward) { return &entity.BadgeAward{ UserID: userID, BadgeID: badgeID, - AwardKey: objectID, + AwardKey: awardKey, } } diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go index 17be9627..fd8e06dd 100644 --- a/internal/schema/event_schema.go +++ b/internal/schema/event_schema.go @@ -69,6 +69,13 @@ func (e *EventMsg) AddExtra(key, value string) *EventMsg { return e } +func (e *EventMsg) GetExtra(key string) string { + if v, ok := e.ExtraInfo[key]; ok { + return v + } + return "" +} + func (e *EventMsg) GetObjectID() string { if len(e.CommentID) > 0 { return e.CommentID diff --git a/internal/service/badge/badge_event_handler.go b/internal/service/badge/badge_event_handler.go index d6758baf..09331197 100644 --- a/internal/service/badge/badge_event_handler.go +++ b/internal/service/badge/badge_event_handler.go @@ -60,8 +60,6 @@ func NewBadgeEventService( } func (ns *BadgeEventService) Handler(ctx context.Context, msg *schema.EventMsg) error { - log.Debugf("received badge event %+v", msg) - awards := ns.eventRuleRepo.HandleEventWithRule(ctx, msg) if len(awards) == 0 { return nil From 811d6de69d6329deef2be5e516fe5848244079ac Mon Sep 17 00:00:00 2001 From: Fen Date: Tue, 13 Aug 2024 10:29:55 +0800 Subject: [PATCH 038/336] docs: enable wiki --- .asf.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.asf.yaml b/.asf.yaml index a8baeb21..7505cd7f 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -30,7 +30,7 @@ github: - q-and-a - hacktoberfest features: - wiki: false + wiki: true issues: true projects: true discussions: false From 290f63f2a14a542803e7190ccf0153324c1f1a77 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 13 Aug 2024 10:40:55 +0800 Subject: [PATCH 039/336] feat(badge): add comment for event schema --- internal/schema/event_schema.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go index fd8e06dd..a507f269 100644 --- a/internal/schema/event_schema.go +++ b/internal/schema/event_schema.go @@ -38,6 +38,7 @@ type EventMsg struct { ExtraInfo map[string]string } +// NewEvent create a new event func NewEvent(e constant.EventType, userID string) *EventMsg { return &EventMsg{ UserID: userID, @@ -46,29 +47,34 @@ func NewEvent(e constant.EventType, userID string) *EventMsg { } } +// QID get question id func (e *EventMsg) QID(questionID, userID string) *EventMsg { e.QuestionID = questionID e.QuestionUserID = userID return e } +// AID get answer id func (e *EventMsg) AID(answerID, userID string) *EventMsg { e.AnswerID = answerID e.AnswerUserID = userID return e } +// CID get comment id func (e *EventMsg) CID(comment, userID string) *EventMsg { e.CommentID = comment e.CommentUserID = userID return e } +// AddExtra add extra info func (e *EventMsg) AddExtra(key, value string) *EventMsg { e.ExtraInfo[key] = value return e } +// GetExtra get extra info func (e *EventMsg) GetExtra(key string) string { if v, ok := e.ExtraInfo[key]; ok { return v @@ -76,6 +82,7 @@ func (e *EventMsg) GetExtra(key string) string { return "" } +// GetObjectID get object id func (e *EventMsg) GetObjectID() string { if len(e.CommentID) > 0 { return e.CommentID From bb40366f001fa183387a4d2a6d2676d866cb218e Mon Sep 17 00:00:00 2001 From: kumfo Date: Tue, 13 Aug 2024 16:12:34 +0800 Subject: [PATCH 040/336] feat(badge): badge manage and user center's badge list --- cmd/wire_gen.go | 3 +- docs/docs.go | 188 ++++++++++++++++++ docs/swagger.json | 188 ++++++++++++++++++ docs/swagger.yaml | 118 +++++++++++ i18n/en_US.yaml | 12 ++ internal/base/reason/reason.go | 1 + internal/controller_admin/badge_controller.go | 85 ++++++++ internal/controller_admin/controller.go | 1 + internal/entity/badge_award_entity.go | 2 +- internal/entity/badge_entity.go | 2 +- internal/migrations/v22.go | 6 +- internal/repo/badge/badge_repo.go | 64 +++++- internal/router/answer_api_router.go | 7 + internal/schema/badge_schema.go | 54 +++++ internal/service/badge/badge_service.go | 93 ++++++++- 15 files changed, 807 insertions(+), 17 deletions(-) create mode 100644 internal/controller_admin/badge_controller.go diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 309af935..d4034b6b 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -267,7 +267,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) - answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController) + controller_adminBadgeController := controller_admin.NewBadgeController(badgeService) + answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController, controller_adminBadgeController) swaggerRouter := router.NewSwaggerRouter(swaggerConf) uiRouter := router.NewUIRouter(controllerSiteInfoController, siteInfoCommonService) authUserMiddleware := middleware.NewAuthUserMiddleware(authService, siteInfoCommonService) diff --git a/docs/docs.go b/docs/docs.go index ecc62169..eaa7133a 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -154,6 +154,113 @@ const docTemplate = `{ } } }, + "/answer/admin/api/badge/status": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update badge status", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "update badge status", + "parameters": [ + { + "description": "UpdateBadgeStatusReq", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.UpdateBadgeStatusReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, + "/answer/admin/api/badges": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "list all badges by page", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "list all badges by page", + "parameters": [ + { + "type": "integer", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size", + "name": "page_size", + "in": "query" + }, + { + "enum": [ + "", + "active", + "inactive" + ], + "type": "string", + "description": "badge status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetBadgeListPagedResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/admin/api/dashboard": { "get": { "security": [ @@ -7652,6 +7759,17 @@ const docTemplate = `{ } } }, + "schema.BadgeStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ], + "x-enum-varnames": [ + "BadgeStatusActive", + "BadgeStatusInactive" + ] + }, "schema.CloseQuestionReq": { "type": "object", "required": [ @@ -7944,6 +8062,55 @@ const docTemplate = `{ } } }, + "schema.GetBadgeListPagedResp": { + "type": "object", + "properties": { + "award_count": { + "description": "badge award count", + "type": "integer" + }, + "description": { + "description": "badge description", + "type": "string" + }, + "earned": { + "description": "badge earned count", + "type": "boolean" + }, + "group_name": { + "description": "badge group name", + "type": "string" + }, + "icon": { + "description": "badge icon", + "type": "string" + }, + "id": { + "description": "badge id", + "type": "string" + }, + "level": { + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] + }, + "name": { + "description": "badge name", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.GetBadgeListResp": { "type": "object", "properties": { @@ -10446,6 +10613,27 @@ const docTemplate = `{ } } }, + "schema.UpdateBadgeStatusReq": { + "type": "object", + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "description": "badge id", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.UpdateCommentReq": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 1412f179..116a3a6a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -124,6 +124,113 @@ } } }, + "/answer/admin/api/badge/status": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update badge status", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "update badge status", + "parameters": [ + { + "description": "UpdateBadgeStatusReq", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.UpdateBadgeStatusReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, + "/answer/admin/api/badges": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "list all badges by page", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "list all badges by page", + "parameters": [ + { + "type": "integer", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size", + "name": "page_size", + "in": "query" + }, + { + "enum": [ + "", + "active", + "inactive" + ], + "type": "string", + "description": "badge status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetBadgeListPagedResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/admin/api/dashboard": { "get": { "security": [ @@ -7622,6 +7729,17 @@ } } }, + "schema.BadgeStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ], + "x-enum-varnames": [ + "BadgeStatusActive", + "BadgeStatusInactive" + ] + }, "schema.CloseQuestionReq": { "type": "object", "required": [ @@ -7914,6 +8032,55 @@ } } }, + "schema.GetBadgeListPagedResp": { + "type": "object", + "properties": { + "award_count": { + "description": "badge award count", + "type": "integer" + }, + "description": { + "description": "badge description", + "type": "string" + }, + "earned": { + "description": "badge earned count", + "type": "boolean" + }, + "group_name": { + "description": "badge group name", + "type": "string" + }, + "icon": { + "description": "badge icon", + "type": "string" + }, + "id": { + "description": "badge id", + "type": "string" + }, + "level": { + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] + }, + "name": { + "description": "badge name", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.GetBadgeListResp": { "type": "object", "properties": { @@ -10416,6 +10583,27 @@ } } }, + "schema.UpdateBadgeStatusReq": { + "type": "object", + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "description": "badge id", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.UpdateCommentReq": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e2fc6682..116b5932 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -374,6 +374,14 @@ definitions: description: badge name type: string type: object + schema.BadgeStatus: + enum: + - active + - inactive + type: string + x-enum-varnames: + - BadgeStatusActive + - BadgeStatusInactive schema.CloseQuestionReq: properties: close_msg: @@ -573,6 +581,38 @@ definitions: description: badge name type: string type: object + schema.GetBadgeListPagedResp: + properties: + award_count: + description: badge award count + type: integer + description: + description: badge description + type: string + earned: + description: badge earned count + type: boolean + group_name: + description: badge group name + type: string + icon: + description: badge icon + type: string + id: + description: badge id + type: string + level: + allOf: + - $ref: '#/definitions/entity.BadgeLevel' + description: badge level + name: + description: badge name + type: string + status: + allOf: + - $ref: '#/definitions/schema.BadgeStatus' + description: badge status + type: object schema.GetBadgeListResp: properties: badges: @@ -2307,6 +2347,19 @@ definitions: url_title: type: string type: object + schema.UpdateBadgeStatusReq: + properties: + id: + description: badge id + type: string + status: + allOf: + - $ref: '#/definitions/schema.BadgeStatus' + description: badge status + required: + - id + - status + type: object schema.UpdateCommentReq: properties: captcha_code: @@ -2924,6 +2977,71 @@ paths: summary: update answer status tags: - admin + /answer/admin/api/badge/status: + put: + consumes: + - application/json + description: update badge status + parameters: + - description: UpdateBadgeStatusReq + in: body + name: data + required: true + schema: + $ref: '#/definitions/schema.UpdateBadgeStatusReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.RespBody' + security: + - ApiKeyAuth: [] + summary: update badge status + tags: + - AdminBadge + /answer/admin/api/badges: + get: + consumes: + - application/json + description: list all badges by page + parameters: + - description: page + in: query + name: page + type: integer + - description: page size + in: query + name: page_size + type: integer + - description: badge status + enum: + - "" + - active + - inactive + in: query + name: status + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetBadgeListPagedResp' + type: array + type: object + security: + - ApiKeyAuth: [] + summary: list all badges by page + tags: + - AdminBadge /answer/admin/api/dashboard: get: consumes: diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 0d7f2ecf..071644f4 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -146,6 +146,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -776,6 +778,16 @@ backend: other: Famous Link desc: other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go index a6168690..24d7ab5f 100644 --- a/internal/base/reason/reason.go +++ b/internal/base/reason/reason.go @@ -107,6 +107,7 @@ const ( InvalidURLError = "error.common.invalid_url" MetaObjectNotFound = "error.meta.object_not_found" BadgeObjectNotFound = "error.badge.object_not_found" + StatusInvalid = "error.common.status_invalid" ) // user external login reasons diff --git a/internal/controller_admin/badge_controller.go b/internal/controller_admin/badge_controller.go new file mode 100644 index 00000000..8842592f --- /dev/null +++ b/internal/controller_admin/badge_controller.go @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package controller_admin + +import ( + "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/pager" + "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/badge" + "github.com/gin-gonic/gin" +) + +type BadgeController struct { + badgeService *badge.BadgeService +} + +func NewBadgeController(badgeService *badge.BadgeService) *BadgeController { + return &BadgeController{ + badgeService: badgeService, + } +} + +// GetBadgeList list all badges by page +// @Summary list all badges by page +// @Description list all badges by page +// @Tags AdminBadge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param page query int false "page" +// @Param page_size query int false "page size" +// @Param status query string false "badge status" Enums(, active, inactive) +// @Success 200 {object} handler.RespBody{data=[]schema.GetBadgeListPagedResp} +// @Router /answer/admin/api/badges [get] +func (b *BadgeController) GetBadgeList(ctx *gin.Context) { + req := &schema.GetBadgeListPagedReq{} + if handler.BindAndCheck(ctx, req) { + return + } + + resp, total, err := b.badgeService.ListPaged(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + + handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) +} + +// UpdateBadgeStatus update badge status +// @Summary update badge status +// @Description update badge status +// @Tags AdminBadge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param data body schema.UpdateBadgeStatusReq true "UpdateBadgeStatusReq" +// @Success 200 {object} handler.RespBody +// @Router /answer/admin/api/badge/status [put] +func (b *BadgeController) UpdateBadgeStatus(ctx *gin.Context) { + req := &schema.UpdateBadgeStatusReq{} + if handler.BindAndCheck(ctx, req) { + return + } + + err := b.badgeService.UpdateStatus(ctx, req) + handler.HandleResponse(ctx, err, nil) +} diff --git a/internal/controller_admin/controller.go b/internal/controller_admin/controller.go index de87d105..ebf32cbf 100644 --- a/internal/controller_admin/controller.go +++ b/internal/controller_admin/controller.go @@ -28,4 +28,5 @@ var ProviderSetController = wire.NewSet( NewSiteInfoController, NewRoleController, NewPluginController, + NewBadgeController, ) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 1d421623..0eb30227 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -28,7 +28,7 @@ const ( // BadgeAward badge_award type BadgeAward struct { - ID string `json:"id" xorm:"id"` + ID string `xorm:"not null pk BIGINT(20) id"` CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` UserID string `json:"user_id" xorm:"not null index BIGINT(20) user_id"` diff --git a/internal/entity/badge_entity.go b/internal/entity/badge_entity.go index 96babcb9..5177c93c 100644 --- a/internal/entity/badge_entity.go +++ b/internal/entity/badge_entity.go @@ -41,7 +41,7 @@ const ( // Badge badge type Badge struct { - ID string `xorm:"not null pk autoincr BIGINT(20) id"` + ID string `xorm:"not null pk BIGINT(20) id"` CreatedAt time.Time `xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` UpdatedAt time.Time `xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` Name string `xorm:"not null default '' VARCHAR(256) name"` diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index f5793d4a..d3d81d84 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -30,9 +30,9 @@ import ( var ( defaultBadgeGroupTable = []*entity.BadgeGroup{ - {ID: "1", Name: "Getting Started"}, - {ID: "2", Name: "Community"}, - {ID: "3", Name: "Posting"}, + {ID: "1", Name: "badge.default_badge_groups.getting_started.name"}, + {ID: "2", Name: "badge.default_badge_groups.community.name"}, + {ID: "3", Name: "badge.default_badge_groups.posting.name"}, } defaultBadgeTable = []*entity.Badge{ diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index d4d2f992..ebdb0425 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -22,11 +22,13 @@ package badge import ( "context" "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/base/pager" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/unique" "github.com/segmentfault/pacman/errors" + "xorm.io/xorm" ) type badgeRepo struct { @@ -90,10 +92,29 @@ func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level entity.BadgeL return } -// ListActivated returns a list of activated badges -func (r *badgeRepo) ListActivated(ctx context.Context) (badges []*entity.Badge, err error) { +// ListPaged returns a list of activated badges +func (r *badgeRepo) ListPaged(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { badges = make([]*entity.Badge, 0) - err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusActive).Find(&badges) + session := r.data.DB.Context(ctx).Where("status <> ?", entity.BadgeStatusDeleted) + total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + +// ListActivated returns a list of activated badges +func (r *badgeRepo) ListActivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { + badges = make([]*entity.Badge, 0) + total = 0 + + session := r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusActive) + if page == 0 || pageSize == 0 { + err = session.Find(&badges) + } else { + total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + } + if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -101,9 +122,17 @@ func (r *badgeRepo) ListActivated(ctx context.Context) (badges []*entity.Badge, } // ListInactivated returns a list of inactivated badges -func (r *badgeRepo) ListInactivated(ctx context.Context) (badges []*entity.Badge, err error) { +func (r *badgeRepo) ListInactivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { badges = make([]*entity.Badge, 0) - err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusInactive).Find(&badges) + total = 0 + + session := r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusInactive) + if page == 0 || pageSize == 0 { + err = session.Find(&badges) + } else { + total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + } + if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -115,3 +144,28 @@ func (r *badgeRepo) UpdateAwardCount(ctx context.Context, id string, count int64 _, err = r.data.DB.Context(ctx).Where("id = ?", id).Incr("award_count", count).Update(&entity.Badge{}) return } + +// UpdateStatus updates the award count of a badge +func (r *badgeRepo) UpdateStatus(ctx context.Context, id string, status int8) (err error) { + _, err = r.data.DB.Transaction(func(session *xorm.Session) (result any, err error) { + _, err = session.ID(id).Update(&entity.Badge{ + Status: status, + }) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(session.Rollback()).WithStack() + return + } + if status >= entity.BadgeStatusDeleted { + _, err = session.Where("badge_id = ?", id).Cols("is_badge_deleted").Update(&entity.BadgeAward{ + IsBadgeDeleted: entity.IsBadgeDeleted, + }) + } else { + _, err = session.Where("badge_id = ?", id).Cols("is_badge_deleted").Update(&entity.BadgeAward{ + IsBadgeDeleted: entity.IsBadgeNotDeleted, + }) + } + return + }) + + return +} diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index f343d7d1..b4ec3bdc 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -56,6 +56,7 @@ type AnswerAPIRouter struct { reviewController *controller.ReviewController metaController *controller.MetaController badgeController *controller.BadgeController + adminBadgeController *controller_admin.BadgeController } func NewAnswerAPIRouter( @@ -88,6 +89,7 @@ func NewAnswerAPIRouter( reviewController *controller.ReviewController, metaController *controller.MetaController, badgeController *controller.BadgeController, + adminBadgeController *controller_admin.BadgeController, ) *AnswerAPIRouter { return &AnswerAPIRouter{ langController: langController, @@ -119,6 +121,7 @@ func NewAnswerAPIRouter( reviewController: reviewController, metaController: metaController, badgeController: badgeController, + adminBadgeController: adminBadgeController, } } @@ -369,4 +372,8 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) { r.PUT("/plugin/status", a.pluginController.UpdatePluginStatus) r.GET("/plugin/config", a.pluginController.GetPluginConfig) r.PUT("/plugin/config", a.pluginController.UpdatePluginConfig) + + // badge + r.GET("/badges", a.adminBadgeController.GetBadgeList) + r.PUT("/badge/status", a.adminBadgeController.UpdateBadgeStatus) } diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index cae2aa66..39a2e2ae 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -21,6 +21,23 @@ package schema import "github.com/apache/incubator-answer/internal/entity" +const ( + BadgeStatusActive BadgeStatus = "active" + BadgeStatusInactive BadgeStatus = "inactive" +) + +type BadgeStatus string + +var BadgeStatusMap = map[int8]BadgeStatus{ + entity.BadgeStatusActive: BadgeStatusActive, + entity.BadgeStatusInactive: BadgeStatusInactive, +} + +var BadgeStatusEMap = map[BadgeStatus]int8{ + BadgeStatusActive: entity.BadgeStatusActive, + BadgeStatusInactive: entity.BadgeStatusInactive, +} + // BadgeListInfo get badge list response type BadgeListInfo struct { // badge id @@ -44,6 +61,43 @@ type GetBadgeListResp struct { GroupName string `json:"group_name" ` } +type UpdateBadgeStatusReq struct { + // badge id + ID string `validate:"required" json:"id"` + // badge status + Status BadgeStatus `validate:"required" json:"status"` +} + +type GetBadgeListPagedReq struct { + // page + Page int `validate:"omitempty,min=1" form:"page"` + // page size + PageSize int `validate:"omitempty,min=1" form:"page_size"` + // badge status + Status BadgeStatus `validate:"omitempty" form:"status"` +} + +type GetBadgeListPagedResp struct { + // badge id + ID string `json:"id" ` + // badge name + Name string `json:"name" ` + // badge description + Description string `json:"description" ` + // badge icon + Icon string `json:"icon" ` + // badge award count + AwardCount int `json:"award_count" ` + // badge earned count + Earned bool `json:"earned" ` + // badge level + Level entity.BadgeLevel `json:"level" ` + // badge group name + GroupName string `json:"group_name" ` + // badge status + Status BadgeStatus `json:"status"` +} + type GetBadgeInfoResp struct { // badge id ID string `json:"id" ` diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 32a54a8d..7daab796 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -39,10 +39,12 @@ type BadgeRepo interface { ListByLevel(ctx context.Context, level entity.BadgeLevel) ([]*entity.Badge, error) ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) ([]*entity.Badge, error) - ListActivated(ctx context.Context) ([]*entity.Badge, error) - ListInactivated(ctx context.Context) ([]*entity.Badge, error) + ListPaged(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) + ListActivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) + ListInactivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) - UpdateAwardCount(ctx context.Context, id string, count int64) error + UpdateAwardCount(ctx context.Context, id string, count int64) (err error) + UpdateStatus(ctx context.Context, id string, status int8) (err error) } type BadgeService struct { @@ -82,7 +84,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* if err != nil { return } - badges, err = b.badgeRepo.ListActivated(ctx) + badges, _, err = b.badgeRepo.ListActivated(ctx, 0, 0) if err != nil { return } @@ -95,7 +97,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* } for _, group := range groups { - groupMap[converter.StringToInt64(group.ID)] = group.Name + groupMap[converter.StringToInt64(group.ID)] = translator.Tr(handler.GetLangByCtx(ctx), group.Name) } for _, badge := range badges { @@ -122,7 +124,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* for _, group := range groups { resp = append(resp, &schema.GetBadgeListResp{ - GroupName: group.Name, + GroupName: translator.Tr(handler.GetLangByCtx(ctx), group.Name), Badges: badgesMap[converter.StringToInt64(group.ID)], }) } @@ -130,6 +132,53 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* return } +// ListPaged list all badges by page +func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPagedReq) (resp []*schema.GetBadgeListPagedResp, total int64, err error) { + var ( + groups []*entity.BadgeGroup + badges []*entity.Badge + groupMap = make(map[int64]string, 0) + ) + + switch req.Status { + case schema.BadgeStatusActive: + badges, total, err = b.badgeRepo.ListActivated(ctx, req.Page, req.PageSize) + case schema.BadgeStatusInactive: + badges, total, err = b.badgeRepo.ListInactivated(ctx, req.Page, req.PageSize) + default: + badges, total, err = b.badgeRepo.ListPaged(ctx, req.Page, req.PageSize) + } + + if err != nil { + return + } + + // find all group and build group map + groups, err = b.badgeGroupRepo.ListGroups(ctx) + if err != nil { + return + } + for _, group := range groups { + groupMap[converter.StringToInt64(group.ID)] = translator.Tr(handler.GetLangByCtx(ctx), group.Name) + } + + resp = make([]*schema.GetBadgeListPagedResp, len(badges)) + + for i, badge := range badges { + resp[i] = &schema.GetBadgeListPagedResp{ + ID: uid.EnShortID(badge.ID), + Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), + Description: translator.Tr(handler.GetLangByCtx(ctx), badge.Description), + Icon: badge.Icon, + AwardCount: badge.AwardCount, + Level: badge.Level, + GroupName: groupMap[badge.BadgeGroupID], + Status: schema.BadgeStatusMap[badge.Status], + } + } + return +} + // GetBadgeInfo get badge info func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) (info *schema.GetBadgeInfoResp, err error) { var ( @@ -164,3 +213,35 @@ func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) } return } + +// UpdateStatus update badge status +func (b *BadgeService) UpdateStatus(ctx *gin.Context, req *schema.UpdateBadgeStatusReq) (err error) { + var ( + badge *entity.Badge + exists bool + ) + req.ID = uid.DeShortID(req.ID) + + badge, exists, err = b.badgeRepo.GetByID(ctx, req.ID) + if err != nil { + return + } + if !exists { + err = errors.BadRequest(reason.BadgeObjectNotFound) + return + } + + status, ok := schema.BadgeStatusEMap[req.Status] + // check duplicate action + if badge.Status == status { + return + } + + if !ok { + err = errors.BadRequest(reason.StatusInvalid) + return + } + + err = b.badgeRepo.UpdateStatus(ctx, req.ID, status) + return +} From cf327f59dcd621a914893b01100075549cea0a1b Mon Sep 17 00:00:00 2001 From: kumfo Date: Tue, 13 Aug 2024 17:50:10 +0800 Subject: [PATCH 041/336] feat(badge): badge manage add badge search --- docs/docs.go | 25 ++------ docs/swagger.json | 6 ++ docs/swagger.yaml | 4 ++ internal/controller_admin/badge_controller.go | 1 + internal/repo/badge/badge_repo.go | 9 ++- internal/schema/badge_schema.go | 2 + internal/service/badge/badge_service.go | 61 ++++++++++++++++--- 7 files changed, 78 insertions(+), 30 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index eaa7133a..7fef400f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,22 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - // Package docs Code generated by swaggo/swag. DO NOT EDIT package docs @@ -234,6 +215,12 @@ const docTemplate = `{ "description": "badge status", "name": "status", "in": "query" + }, + { + "type": "string", + "description": "search param", + "name": "q", + "in": "query" } ], "responses": { diff --git a/docs/swagger.json b/docs/swagger.json index 116a3a6a..234d2f13 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -204,6 +204,12 @@ "description": "badge status", "name": "status", "in": "query" + }, + { + "type": "string", + "description": "search param", + "name": "q", + "in": "query" } ], "responses": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 116b5932..1a5979e6 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -3023,6 +3023,10 @@ paths: in: query name: status type: string + - description: search param + in: query + name: q + type: string produces: - application/json responses: diff --git a/internal/controller_admin/badge_controller.go b/internal/controller_admin/badge_controller.go index 8842592f..4a44f176 100644 --- a/internal/controller_admin/badge_controller.go +++ b/internal/controller_admin/badge_controller.go @@ -47,6 +47,7 @@ func NewBadgeController(badgeService *badge.BadgeService) *BadgeController { // @Param page query int false "page" // @Param page_size query int false "page size" // @Param status query string false "badge status" Enums(, active, inactive) +// @Param q query string false "search param" // @Success 200 {object} handler.RespBody{data=[]schema.GetBadgeListPagedResp} // @Router /answer/admin/api/badges [get] func (b *BadgeController) GetBadgeList(ctx *gin.Context) { diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index ebdb0425..8537e389 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -95,8 +95,15 @@ func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level entity.BadgeL // ListPaged returns a list of activated badges func (r *badgeRepo) ListPaged(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { badges = make([]*entity.Badge, 0) + total = 0 + session := r.data.DB.Context(ctx).Where("status <> ?", entity.BadgeStatusDeleted) - total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + if page == 0 || pageSize == 0 { + err = session.Find(&badges) + } else { + total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + } + if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index 39a2e2ae..088193ad 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -75,6 +75,8 @@ type GetBadgeListPagedReq struct { PageSize int `validate:"omitempty,min=1" form:"page_size"` // badge status Status BadgeStatus `validate:"omitempty" form:"status"` + // query condition + Query string `validate:"omitempty" form:"q"` } type GetBadgeListPagedResp struct { diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 7daab796..c9f3797a 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -30,6 +30,7 @@ import ( "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" + "strings" ) type BadgeRepo interface { @@ -137,20 +138,44 @@ func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPa var ( groups []*entity.BadgeGroup badges []*entity.Badge + badge *entity.Badge + exists bool groupMap = make(map[int64]string, 0) ) - switch req.Status { - case schema.BadgeStatusActive: - badges, total, err = b.badgeRepo.ListActivated(ctx, req.Page, req.PageSize) - case schema.BadgeStatusInactive: - badges, total, err = b.badgeRepo.ListInactivated(ctx, req.Page, req.PageSize) - default: - badges, total, err = b.badgeRepo.ListPaged(ctx, req.Page, req.PageSize) - } + total = 0 - if err != nil { - return + if len(req.Query) > 0 { + isID := strings.Index(req.Query, "badge:") + if isID != 0 { + badges, err = b.searchByName(ctx, req.Query) + if err != nil { + return + } + } else { + req.Query = strings.TrimSpace(strings.TrimLeft(req.Query, "badge:")) + id := uid.DeShortID(req.Query) + if len(id) == 0 { + return + } + badge, exists, err = b.badgeRepo.GetByID(ctx, id) + if err != nil || !exists { + return + } + badges = append(badges, badge) + } + } else { + switch req.Status { + case schema.BadgeStatusActive: + badges, total, err = b.badgeRepo.ListActivated(ctx, req.Page, req.PageSize) + case schema.BadgeStatusInactive: + badges, total, err = b.badgeRepo.ListInactivated(ctx, req.Page, req.PageSize) + default: + badges, total, err = b.badgeRepo.ListPaged(ctx, req.Page, req.PageSize) + } + if err != nil { + return + } } // find all group and build group map @@ -179,6 +204,22 @@ func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPa return } +// searchByName +func (b *BadgeService) searchByName(ctx context.Context, name string) (result []*entity.Badge, err error) { + var badges []*entity.Badge + name = strings.ToLower(name) + result = make([]*entity.Badge, 0) + + badges, _, err = b.badgeRepo.ListPaged(ctx, 0, 0) + for _, badge := range badges { + tn := strings.ToLower(translator.Tr(handler.GetLangByCtx(ctx), badge.Name)) + if strings.Contains(tn, name) { + result = append(result, badge) + } + } + return +} + // GetBadgeInfo get badge info func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) (info *schema.GetBadgeInfoResp, err error) { var ( From b0c76757cc4c85d6cf35180d3fc51b200058f5ee Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 14 Aug 2024 10:05:10 +0800 Subject: [PATCH 042/336] feat(badge): badge search with page --- internal/service/badge/badge_service.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index c9f3797a..acb68cff 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -152,6 +152,19 @@ func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPa if err != nil { return } + // paged result + count := len(badges) + total = int64(count) + start := (req.Page - 1) * req.PageSize + end := req.Page * req.PageSize + if start >= count { + start = count + end = count + } + if end > count { + end = count + } + badges = badges[start:end] } else { req.Query = strings.TrimSpace(strings.TrimLeft(req.Query, "badge:")) id := uid.DeShortID(req.Query) From bede0adbf783a840fdeefec8afeb61e1e71cb864 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 14 Aug 2024 10:37:37 +0800 Subject: [PATCH 043/336] feat(badge): award badge for user --- cmd/wire_gen.go | 4 +- docs/docs.go | 19 ++++ internal/entity/badge_award_entity.go | 16 +-- internal/repo/badge/badge_event_rule.go | 2 +- internal/repo/badge_award/badge_award_repo.go | 102 ++++++++++++------ internal/service/badge/badge_award_service.go | 49 +++------ internal/service/badge/badge_event_handler.go | 34 +++--- 7 files changed, 137 insertions(+), 89 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index d4034b6b..9acd76ee 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -263,9 +263,9 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, badgeGroupRepo := badge_group.NewBadgeGroupRepo(dataData, uniqueIDRepo) badgeAwardRepo := badge_award.NewBadgeAwardRepo(dataData, uniqueIDRepo) eventRuleRepo := badge.NewEventRuleRepo(dataData) - badgeEventService := badge2.NewBadgeEventService(dataData, eventQueueService, badgeRepo, eventRuleRepo) - badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService) + badgeEventService := badge2.NewBadgeEventService(dataData, eventQueueService, badgeRepo, eventRuleRepo, badgeAwardService) + badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) controller_adminBadgeController := controller_admin.NewBadgeController(badgeService) answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController, controller_adminBadgeController) diff --git a/docs/docs.go b/docs/docs.go index 7fef400f..cfefe0ed 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Package docs Code generated by swaggo/swag. DO NOT EDIT package docs diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 0eb30227..5ba475cd 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -24,18 +24,20 @@ import "time" const ( IsBadgeNotDeleted = 0 IsBadgeDeleted = 1 + + BadgeOnceAwardKey = "0" ) // BadgeAward badge_award type BadgeAward struct { ID string `xorm:"not null pk BIGINT(20) id"` - CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` - UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` - UserID string `json:"user_id" xorm:"not null index BIGINT(20) user_id"` - BadgeID string `json:"badge_id" xorm:"not null index BIGINT(20) badge_id"` - AwardKey string `json:"award_key" xorm:"not null index VARCHAR(64) award_key"` - BadgeGroupID int64 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` - IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index TINYINT(1) is_badge_deleted"` + CreatedAt time.Time `xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` + UpdatedAt time.Time `xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` + UserID string `xorm:"not null index BIGINT(20) user_id"` + BadgeID string `xorm:"not null index BIGINT(20) badge_id"` + AwardKey string `xorm:"not null index VARCHAR(64) award_key"` + BadgeGroupID int64 `xorm:"not null index BIGINT(20) badge_group_id"` + IsBadgeDeleted int8 `xorm:"not null TINYINT(1) is_badge_deleted"` } // TableName badge_award table name diff --git a/internal/repo/badge/badge_event_rule.go b/internal/repo/badge/badge_event_rule.go index 41d56686..f912c2bb 100644 --- a/internal/repo/badge/badge_event_rule.go +++ b/internal/repo/badge/badge_event_rule.go @@ -99,7 +99,7 @@ func (br *eventRuleRepo) FirstUpdateUserProfile(ctx context.Context, return nil, nil } if len(bean.Bio) > 0 { - return append(awards, br.createBadgeAward(event.UserID, b.ID, "")), nil + return append(awards, br.createBadgeAward(event.UserID, b.ID, entity.BadgeOnceAwardKey)), nil } return nil, nil } diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 5a5d56cd..058fa864 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -21,6 +21,7 @@ package badge_award import ( "context" + "fmt" "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/base/pager" "github.com/apache/incubator-answer/internal/base/reason" @@ -28,6 +29,7 @@ import ( "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/unique" "github.com/segmentfault/pacman/errors" + "xorm.io/xorm" ) type badgeAwardRepo struct { @@ -42,38 +44,62 @@ func NewBadgeAwardRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge. } } -func (r *badgeAwardRepo) Add(ctx context.Context, badgeAward *entity.BadgeAward) (err error) { +// AwardBadgeForUser award badge for user +func (r *badgeAwardRepo) AwardBadgeForUser(ctx context.Context, badgeAward *entity.BadgeAward) (err error) { badgeAward.ID, err = r.uniqueIDRepo.GenUniqueIDStr(ctx, entity.BadgeAward{}.TableName()) if err != nil { - return - } - _, err = r.data.DB.Context(ctx).Insert(badgeAward) - return -} -func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) (isAward bool) { - isAward = false - if singleOrMulti == entity.BadgeSingleAward { - _, exists, err := r.GetByUserIdAndBadgeId(ctx, userID, badgeID) - if err != nil { - err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - return - } - if exists { - return true - } - } else { - _, exists, err := r.GetByUserIdAndBadgeIdAndObjectId(ctx, userID, badgeID, awardKey) - if err != nil { - err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - return - } - if exists { - return true - } + return err } - return + _, err = r.data.DB.Transaction(func(session *xorm.Session) (result any, err error) { + session = session.Context(ctx) + + badgeInfo := &entity.Badge{} + exist, err := session.ID(badgeAward.BadgeID).ForUpdate().Get(badgeInfo) + if err != nil { + return nil, err + } + if !exist { + return nil, fmt.Errorf("badge not exist") + } + + old := &entity.BadgeAward{} + exist, err = session.Where("user_id = ? AND badge_id = ? AND award_key = ? AND is_badge_deleted = 0", + badgeAward.UserID, badgeAward.BadgeID, badgeAward.AwardKey).Get(old) + if err != nil { + return nil, err + } + if exist { + return nil, fmt.Errorf("badge already awarded") + } + + _, err = session.Insert(badgeAward) + if err != nil { + return nil, err + } + + return session.ID(badgeInfo.ID).Incr("award_count", 1).Update(&entity.Badge{}) + }) + if err != nil { + return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return nil } + +// CheckIsAward check this badge is awarded for this user or not +func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID, userID, awardKey string, singleOrMulti int8) ( + isAward bool, err error) { + if singleOrMulti == entity.BadgeSingleAward { + _, isAward, err = r.GetByUserIdAndBadgeId(ctx, userID, badgeID) + } else { + _, isAward, err = r.GetByUserIdAndBadgeIdAndAwardKey(ctx, userID, badgeID, awardKey) + } + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return isAward, err +} + func (r *badgeAwardRepo) CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) { return } @@ -161,13 +187,25 @@ func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context, userID } // GetByUserIdAndBadgeId get badge award by user id and badge id -func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) { - exists, err = r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ? AND is_badge_deleted = 0", userID, badgeID).Get(&badgeAward) +func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) ( + badgeAward *entity.BadgeAward, exists bool, err error) { + badgeAward = &entity.BadgeAward{} + exists, err = r.data.DB.Context(ctx). + Where("user_id = ? AND badge_id = ? AND is_badge_deleted = 0", userID, badgeID).Get(badgeAward) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } -// GetByUserIdAndBadgeIdAndObjectId get badge award by user id, badge id and object id -func (r *badgeAwardRepo) GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) { - exists, err = r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ? AND award_key = ? AND is_badge_deleted = 0", userID, badgeID, awardKey).Get(&badgeAward) +// GetByUserIdAndBadgeIdAndAwardKey get badge award by user id and badge id and award key +func (r *badgeAwardRepo) GetByUserIdAndBadgeIdAndAwardKey(ctx context.Context, userID string, badgeID string, awardKey string) ( + badgeAward *entity.BadgeAward, exists bool, err error) { + badgeAward = &entity.BadgeAward{} + exists, err = r.data.DB.Context(ctx). + Where("user_id = ? AND badge_id = ? AND award_key = ? AND is_badge_deleted = 0", userID, badgeID, awardKey).Get(badgeAward) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } return } diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index 96a9743f..3883de61 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -33,12 +33,11 @@ import ( "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" - "time" ) type BadgeAwardRepo interface { - Add(ctx context.Context, badgeAward *entity.BadgeAward) (err error) - CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) bool + CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) (isAward bool, err error) + AwardBadgeForUser(ctx context.Context, badgeAward *entity.BadgeAward) (err error) CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) CountByUserId(ctx context.Context, userID string) (awardCount int64) @@ -62,7 +61,7 @@ type BadgeAwardRepo interface { ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) - GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) + GetByUserIdAndBadgeIdAndAwardKey(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) } type BadgeAwardService struct { @@ -151,48 +150,32 @@ func (b *BadgeAwardService) GetBadgeAwardList( } // Award award badge -func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) (err error) { - var ( - badgeData *entity.Badge - exists, awarded bool - ) - - badgeData, exists, err = b.badgeRepo.GetByID(ctx, badgeID) +func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID string, awardKey string) (err error) { + badgeData, exists, err := b.badgeRepo.GetByID(ctx, badgeID) if err != nil { - return + return err } if !exists || badgeData.Status == entity.BadgeStatusInactive { - err = errors.BadRequest(reason.BadgeObjectNotFound) - return + return errors.BadRequest(reason.BadgeObjectNotFound) } - awarded = b.badgeAwardRepo.CheckIsAward(ctx, badgeID, userID, awardKey, badgeData.Single) - if !force && awarded { - return + alreadyAwarded, err := b.badgeAwardRepo.CheckIsAward(ctx, badgeID, userID, awardKey, badgeData.Single) + if err != nil { + return err + } + if alreadyAwarded { + return nil } - if createdAt.IsZero() { - createdAt = time.Now() - } - - err = b.badgeAwardRepo.Add(ctx, &entity.BadgeAward{ - CreatedAt: createdAt, - UpdatedAt: createdAt, + badgeAward := &entity.BadgeAward{ UserID: userID, BadgeID: badgeID, AwardKey: awardKey, BadgeGroupID: badgeData.BadgeGroupID, - IsBadgeDeleted: 0, - }) - if err != nil { - return + IsBadgeDeleted: entity.IsBadgeNotDeleted, } - - // increment badge award count - err = b.badgeRepo.UpdateAwardCount(ctx, badgeID, 1) - - return + return b.badgeAwardRepo.AwardBadgeForUser(ctx, badgeAward) } // GetUserBadgeAwardList get user badge award list diff --git a/internal/service/badge/badge_event_handler.go b/internal/service/badge/badge_event_handler.go index 09331197..f990260b 100644 --- a/internal/service/badge/badge_event_handler.go +++ b/internal/service/badge/badge_event_handler.go @@ -21,12 +21,11 @@ package badge import ( "context" + "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/segmentfault/pacman/log" - - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/schema" ) type BadgeEventService struct { @@ -35,6 +34,7 @@ type BadgeEventService struct { badgeAwardRepo BadgeAwardRepo badgeRepo BadgeRepo eventRuleRepo EventRuleRepo + badgeAwardService *BadgeAwardService } type EventRuleHandler func(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) @@ -48,12 +48,14 @@ func NewBadgeEventService( eventQueueService event_queue.EventQueueService, badgeRepo BadgeRepo, eventRuleRepo EventRuleRepo, + badgeAwardService *BadgeAwardService, ) *BadgeEventService { n := &BadgeEventService{ data: data, eventQueueService: eventQueueService, badgeRepo: badgeRepo, eventRuleRepo: eventRuleRepo, + badgeAwardService: badgeAwardService, } eventQueueService.RegisterHandler(n.Handler) return n @@ -65,18 +67,22 @@ func (ns *BadgeEventService) Handler(ctx context.Context, msg *schema.EventMsg) return nil } - badgeIDs := make([]string, 0) + //badgeIDs := make([]string, 0) + //for _, award := range awards { + // badgeIDs = append(badgeIDs, award.BadgeID) + //} + // + //badges, err := ns.badgeRepo.GetByIDs(ctx, badgeIDs) + //if err != nil { + // log.Errorf("error getting badges %+v: %v", badgeIDs, err) + // return err + //} + for _, award := range awards { - badgeIDs = append(badgeIDs, award.BadgeID) + err := ns.badgeAwardService.Award(ctx, award.BadgeID, award.UserID, award.AwardKey) + if err != nil { + log.Debugf("error awarding badge %s: %v", award.BadgeID, err) + } } - - badges, err := ns.badgeRepo.GetByIDs(ctx, badgeIDs) - if err != nil { - log.Errorf("error getting badges %+v: %v", badgeIDs, err) - return err - } - - // TODO: award badges to user - log.Debugf("awarding badges %+v to user", badges) return nil } From 46ab8a20fe94a43c72e637415990f2591b76bb28 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 14 Aug 2024 10:58:39 +0800 Subject: [PATCH 044/336] chore(badge): remove unused comment --- internal/service/badge/badge_event_handler.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/internal/service/badge/badge_event_handler.go b/internal/service/badge/badge_event_handler.go index f990260b..8a92f08b 100644 --- a/internal/service/badge/badge_event_handler.go +++ b/internal/service/badge/badge_event_handler.go @@ -67,17 +67,6 @@ func (ns *BadgeEventService) Handler(ctx context.Context, msg *schema.EventMsg) return nil } - //badgeIDs := make([]string, 0) - //for _, award := range awards { - // badgeIDs = append(badgeIDs, award.BadgeID) - //} - // - //badges, err := ns.badgeRepo.GetByIDs(ctx, badgeIDs) - //if err != nil { - // log.Errorf("error getting badges %+v: %v", badgeIDs, err) - // return err - //} - for _, award := range awards { err := ns.badgeAwardService.Award(ctx, award.BadgeID, award.UserID, award.AwardKey) if err != nil { From f0c433cc026d001f920411a1a6e1f144620ee924 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 14 Aug 2024 12:31:03 +0800 Subject: [PATCH 045/336] fix(badge): fix badge init data --- internal/entity/badge_entity.go | 8 +- internal/migrations/init.go | 20 ++ internal/migrations/init_data.go | 156 ++++++++++++ internal/migrations/v22.go | 270 +++------------------ internal/repo/badge/badge_event_rule.go | 155 ++++++------ internal/service/content/answer_service.go | 6 +- 6 files changed, 286 insertions(+), 329 deletions(-) diff --git a/internal/entity/badge_entity.go b/internal/entity/badge_entity.go index 5177c93c..a370e275 100644 --- a/internal/entity/badge_entity.go +++ b/internal/entity/badge_entity.go @@ -47,14 +47,14 @@ type Badge struct { Name string `xorm:"not null default '' VARCHAR(256) name"` Icon string `xorm:"not null default '' VARCHAR(1024) icon"` AwardCount int `xorm:"not null default 0 INT(11) award_count"` - Description string `xorm:"not null default '' MEDIUMTEXT description"` + Description string `xorm:"not null MEDIUMTEXT description"` Status int8 `xorm:"not null default 1 INT(11) status"` BadgeGroupID int64 `xorm:"not null default 0 BIGINT(20) badge_group_id"` Level BadgeLevel `xorm:"not null default 1 TINYINT(4) level"` Single int8 `xorm:"not null default 1 TINYINT(4) single"` - Collect string `xorm:"not null default '' VARCHAR(64) collect"` - Handler string `xorm:"not null default '' VARCHAR(64) handler"` - Param string `xorm:"not null default '' TEXT param"` + Collect string `xorm:"not null default '' VARCHAR(128) collect"` + Handler string `xorm:"not null default '' VARCHAR(128) handler"` + Param string `xorm:"not null TEXT param"` } // TableName badge table name diff --git a/internal/migrations/init.go b/internal/migrations/init.go index 0b4d1ce3..b74e3688 100644 --- a/internal/migrations/init.go +++ b/internal/migrations/init.go @@ -80,6 +80,7 @@ func (m *Mentor) InitDB() error { m.do("init site info privilege rank", m.initSiteInfoPrivilegeRank) m.do("init site info write", m.initSiteInfoWrite) m.do("init default content", m.initDefaultContent) + m.do("init default badges", m.initDefaultBadges) return m.err } @@ -432,3 +433,22 @@ func (m *Mentor) initDefaultContent() { return } } + +func (m *Mentor) initDefaultBadges() { + uniqueIDRepo := unique.NewUniqueIDRepo(&data.Data{DB: m.engine}) + + _, m.err = m.engine.Context(m.ctx).Insert(defaultBadgeGroupTable) + if m.err != nil { + return + } + for _, badge := range defaultBadgeTable { + badge.ID, m.err = uniqueIDRepo.GenUniqueIDStr(m.ctx, new(entity.Badge).TableName()) + if m.err != nil { + return + } + if _, m.err = m.engine.Context(m.ctx).Insert(badge); m.err != nil { + return + } + } + return +} diff --git a/internal/migrations/init_data.go b/internal/migrations/init_data.go index f9a09f52..50a5651b 100644 --- a/internal/migrations/init_data.go +++ b/internal/migrations/init_data.go @@ -347,4 +347,160 @@ var ( {ID: 129, Key: "rank.question.undeleted", Value: `-1`}, {ID: 130, Key: "rank.tag.undeleted", Value: `-1`}, } + + defaultBadgeGroupTable = []*entity.BadgeGroup{ + {ID: "1", Name: "badge.default_badge_groups.getting_started.name"}, + {ID: "2", Name: "badge.default_badge_groups.community.name"}, + {ID: "3", Name: "badge.default_badge_groups.posting.name"}, + } + + defaultBadgeTable = []*entity.Badge{ + { + Name: "badge.default_badges.autobiographer.name", + Icon: "person-badge-fill", + Description: "badge.default_badges.autobiographer.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "FirstUpdateUserProfile", + }, + { + Name: "badge.default_badges.editor.name", + Icon: "pencil-fill", + Description: "badge.default_badges.editor.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "FirstPostEdit", + }, + { + Name: "badge.default_badges.first_flag.name", + Icon: "flag-fill", + Description: "badge.default_badges.first_flag.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "FirstFlaggedPost", + }, + { + Name: "badge.default_badges.first_upvote.name", + Icon: "hand-thumbs-up-fill", + Description: "badge.default_badges.first_upvote.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "FirstVotedPost", + }, + { + Name: "badge.default_badges.first_reaction.name", + Icon: "emoji-smile-fill", + Description: "badge.default_badges.first_reaction.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "FirstReactedPost", + }, + { + Name: "badge.default_badges.first_share.name", + Icon: "share-fill", + Description: "badge.default_badges.first_share.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "FirstSharedPost", + }, + { + Name: "badge.default_badges.scholar.name", + Icon: "check-circle-fill", + Description: "badge.default_badges.scholar.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 1, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "FirstAcceptAnswer", + }, + { + Name: "badge.default_badges.solved.name", + Icon: "check-square-fill", + Description: "badge.default_badges.solved.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 2, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeSingleAward, + Handler: "ReachAnswerAcceptedAmount", + Param: `{"amount":"1"}`, + }, + { + Name: "badge.default_badges.nice_answer.name", + Icon: "chat-square-text-fill", + Description: "badge.default_badges.nice_answer.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeMultiAward, + Handler: "ReachAnswerVote", + Param: `{"amount":"10"}`, + }, + { + Name: "badge.default_badges.good_answer.name", + Icon: "chat-square-text-fill", + Description: "badge.default_badges.good_answer.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 3, + Level: entity.BadgeLevelSilver, + Single: entity.BadgeMultiAward, + Handler: "ReachAnswerVote", + Param: `{"amount":"25"}`, + }, + { + Name: "badge.default_badges.great_answer.name", + Icon: "chat-square-text-fill", + Description: "badge.default_badges.great_answer.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 3, + Level: entity.BadgeLevelGold, + Single: entity.BadgeMultiAward, + Handler: "ReachAnswerVote", + Param: `{"amount":"50"}`, + }, + { + Name: "badge.default_badges.nice_question.name", + Icon: "question-circle-fill", + Description: "badge.default_badges.nice_question.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 3, + Level: entity.BadgeLevelBronze, + Single: entity.BadgeMultiAward, + Handler: "ReachQuestionVote", + Param: `{"amount":"10"}`, + }, + { + Name: "badge.default_badges.good_question.name", + Icon: "question-circle-fill", + Description: "badge.default_badges.good_question.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 3, + Level: entity.BadgeLevelSilver, + Single: entity.BadgeMultiAward, + Handler: "ReachQuestionVote", + Param: `{"amount":"25"}`, + }, + { + Name: "badge.default_badges.great_question.name", + Icon: "question-circle-fill", + Description: "badge.default_badges.great_question.desc", + Status: entity.BadgeStatusActive, + BadgeGroupID: 3, + Level: entity.BadgeLevelGold, + Single: entity.BadgeMultiAward, + Handler: "ReachQuestionVote", + Param: `{"amount":"50"}`, + }, + } ) diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index d3d81d84..ab7185e3 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -21,265 +21,51 @@ package migrations import ( "context" + "fmt" "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/repo/unique" - "time" "xorm.io/xorm" ) -var ( - defaultBadgeGroupTable = []*entity.BadgeGroup{ - {ID: "1", Name: "badge.default_badge_groups.getting_started.name"}, - {ID: "2", Name: "badge.default_badge_groups.community.name"}, - {ID: "3", Name: "badge.default_badge_groups.posting.name"}, - } - - defaultBadgeTable = []*entity.Badge{ - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.autobiographer.name", - Icon: "person-badge-fill", - AwardCount: 0, - Description: "badge.default_badges.autobiographer.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 1, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.editor.name", - Icon: "pencil-fill", - AwardCount: 0, - Description: "badge.default_badges.editor.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 1, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "question", - Handler: "FirstQuestion", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.first_flag.name", - Icon: "flag-fill", - AwardCount: 0, - Description: "badge.default_badges.first_flag.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 1, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.first_upvote.name", - Icon: "hand-thumbs-up-fill", - AwardCount: 0, - Description: "badge.default_badges.first_upvote.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 1, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.first_reaction.name", - Icon: "emoji-smile-fill", - AwardCount: 0, - Description: "badge.default_badges.first_reaction.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 1, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.first_share.name", - Icon: "share-fill", - AwardCount: 0, - Description: "badge.default_badges.first_share.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 1, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.scholar.name", - Icon: "check-circle-fill", - AwardCount: 0, - Description: "badge.default_badges.scholar.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 1, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.solved.name", - Icon: "check-square-fill", - AwardCount: 0, - Description: "badge.default_badges.solved.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 2, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.nice_answer.name", - Icon: "chat-square-text-fill", - AwardCount: 0, - Description: "badge.default_badges.nice_answer.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 3, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeMultiAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.good_answer.name", - Icon: "chat-square-text-fill", - AwardCount: 0, - Description: "badge.default_badges.good_answer.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 3, - Level: entity.BadgeLevelSilver, - Single: entity.BadgeMultiAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.great_answer.name", - Icon: "chat-square-text-fill", - AwardCount: 0, - Description: "badge.default_badges.great_answer.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 3, - Level: entity.BadgeLevelGold, - Single: entity.BadgeMultiAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.nice_question.name", - Icon: "question-circle-fill", - AwardCount: 0, - Description: "badge.default_badges.nice_question.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 3, - Level: entity.BadgeLevelBronze, - Single: entity.BadgeMultiAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.good_question.name", - Icon: "question-circle-fill", - AwardCount: 0, - Description: "badge.default_badges.good_question.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 3, - Level: entity.BadgeLevelSilver, - Single: entity.BadgeSingleAward, - Collect: "", - Handler: "", - Param: "", - }, - { - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - Name: "badge.default_badges.great_question.name", - Icon: "question-circle-fill", - AwardCount: 0, - Description: "badge.default_badges.great_question.desc", - Status: entity.BadgeStatusActive, - BadgeGroupID: 3, - Level: entity.BadgeLevelGold, - Single: entity.BadgeMultiAward, - Collect: "", - Handler: "", - Param: "", - }, - } -) - func addBadges(ctx context.Context, x *xorm.Engine) (err error) { uniqueIDRepo := unique.NewUniqueIDRepo(&data.Data{DB: x}) - // create table - err = x.Context(ctx).Sync(new(entity.Badge)) + + err = x.Context(ctx).Sync(new(entity.Badge), new(entity.BadgeGroup), new(entity.BadgeAward)) if err != nil { - return + return fmt.Errorf("sync table failed: %w", err) } - err = x.Context(ctx).Sync(new(entity.BadgeGroup)) - if err != nil { - return + for _, badgeGroup := range defaultBadgeGroupTable { + exist, err := x.Context(ctx).Get(&entity.BadgeGroup{ID: badgeGroup.ID}) + if err != nil { + return err + } + if exist { + _, err = x.Context(ctx).ID(badgeGroup.ID).Update(badgeGroup) + } else { + _, err = x.Context(ctx).Insert(badgeGroup) + } + if err != nil { + return fmt.Errorf("insert badge group failed: %w", err) + } } - err = x.Context(ctx).Sync(new(entity.BadgeAward)) - if err != nil { - return - } - - // insert default data - _, err = x.Context(ctx).Insert(defaultBadgeGroupTable) - if err != nil { - return - } for _, badge := range defaultBadgeTable { + exist, err := x.Context(ctx).Get(&entity.Badge{Name: badge.Name}) + if err != nil { + return err + } + if exist { + continue + } badge.ID, err = uniqueIDRepo.GenUniqueIDStr(ctx, new(entity.Badge).TableName()) if err != nil { - return + return err } - _, err = x.Context(ctx).Insert(badge) - if err != nil { - return + + if _, err := x.Context(ctx).Insert(badge); err != nil { + return err } } return diff --git a/internal/repo/badge/badge_event_rule.go b/internal/repo/badge/badge_event_rule.go index f912c2bb..f107203e 100644 --- a/internal/repo/badge/badge_event_rule.go +++ b/internal/repo/badge/badge_event_rule.go @@ -86,91 +86,87 @@ func (br *eventRuleRepo) HandleEventWithRule(ctx context.Context, msg *schema.Ev // FirstUpdateUserProfile first update user profile func (br *eventRuleRepo) FirstUpdateUserProfile(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "FirstUpdateUserProfile") - if b == nil { - return nil, nil + badges := br.getBadgesByHandler(ctx, "FirstUpdateUserProfile") + for _, b := range badges { + bean := &entity.User{ID: event.UserID} + exist, err := br.data.DB.Context(ctx).Get(bean) + if err != nil { + return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + if !exist { + continue + } + if len(bean.Bio) > 0 { + awards = append(awards, br.createBadgeAward(event.UserID, "", b)) + } } - bean := &entity.User{ID: event.UserID} - exist, err := br.data.DB.Context(ctx).Get(bean) - if err != nil { - return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - } - if !exist { - return nil, nil - } - if len(bean.Bio) > 0 { - return append(awards, br.createBadgeAward(event.UserID, b.ID, entity.BadgeOnceAwardKey)), nil - } - return nil, nil + return awards, nil } // FirstPostEdit first post edit func (br *eventRuleRepo) FirstPostEdit(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "FirstPostEdit") - if b == nil { - return nil, nil + badges := br.getBadgesByHandler(ctx, "FirstPostEdit") + for _, b := range badges { + awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + return awards, nil } // FirstFlaggedPost first flagged post. func (br *eventRuleRepo) FirstFlaggedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "FirstFlaggedPost") - if b == nil { - return nil, nil + badges := br.getBadgesByHandler(ctx, "FirstFlaggedPost") + for _, b := range badges { + awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + return awards, nil } // FirstVotedPost first voted post func (br *eventRuleRepo) FirstVotedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "FirstVotedPost") - if b == nil { - return nil, nil + badges := br.getBadgesByHandler(ctx, "FirstVotedPost") + for _, b := range badges { + awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + return awards, nil } // FirstReactedPost first reacted post func (br *eventRuleRepo) FirstReactedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "FirstReactedPost") - if b == nil { - return nil, nil + badges := br.getBadgesByHandler(ctx, "FirstReactedPost") + for _, b := range badges { + awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + return awards, nil } // FirstSharedPost first shared post func (br *eventRuleRepo) FirstSharedPost(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "FirstSharedPost") - if b == nil { - return nil, nil + badges := br.getBadgesByHandler(ctx, "FirstSharedPost") + for _, b := range badges { + awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + return awards, nil } // FirstAcceptAnswer user first accept answer func (br *eventRuleRepo) FirstAcceptAnswer(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "FirstAcceptAnswer") - if b == nil { - return nil, nil + badges := br.getBadgesByHandler(ctx, "FirstAcceptAnswer") + for _, b := range badges { + awards = append(awards, br.createBadgeAward(event.UserID, event.GetObjectID(), b)) } - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + return awards, nil } // ReachAnswerAcceptedAmount reach answer accepted amount func (br *eventRuleRepo) ReachAnswerAcceptedAmount(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "ReachAnswerAcceptedAmount") - if b == nil { - return nil, nil - } + badges := br.getBadgesByHandler(ctx, "ReachAnswerAcceptedAmount") if len(event.AnswerUserID) == 0 { return nil, nil } @@ -185,79 +181,76 @@ func (br *eventRuleRepo) ReachAnswerAcceptedAmount(ctx context.Context, return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } - // get badge requirement - requirement := b.GetIntParam("amount") - if requirement == 0 || amount < requirement { - return nil, nil + for _, b := range badges { + // get badge requirement + requirement := b.GetIntParam("amount") + if requirement == 0 || amount < requirement { + continue + } + awards = append(awards, br.createBadgeAward(event.AnswerUserID, event.AnswerID, b)) } - - return append(awards, br.createBadgeAward(event.UserID, b.ID, event.GetObjectID())), nil + return awards, nil } // ReachAnswerVote reach answer vote func (br *eventRuleRepo) ReachAnswerVote(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "ReachAnswerVote") - if b == nil { - return nil, nil - } - + badges := br.getBadgesByHandler(ctx, "ReachAnswerVote") // get vote amount amount, _ := strconv.Atoi(event.GetExtra("vote_up_amount")) if amount == 0 { return nil, nil } - // get badge requirement - requirement := b.GetIntParam("amount") - if requirement == 0 || int64(amount) < requirement { - return nil, nil + for _, b := range badges { + // get badge requirement + requirement := b.GetIntParam("amount") + if requirement == 0 || int64(amount) < requirement { + continue + } + awards = append(awards, br.createBadgeAward(event.AnswerUserID, event.AnswerID, b)) } - - return append(awards, br.createBadgeAward(event.AnswerUserID, b.ID, event.AnswerID)), nil + return awards, nil } // ReachQuestionVote reach question vote func (br *eventRuleRepo) ReachQuestionVote(ctx context.Context, event *schema.EventMsg) (awards []*entity.BadgeAward, err error) { - b := br.getBadgeByHandler(ctx, "ReachQuestionVote") - if b == nil { - return nil, nil - } - + badges := br.getBadgesByHandler(ctx, "ReachQuestionVote") // get vote amount amount, _ := strconv.Atoi(event.GetExtra("vote_up_amount")) if amount == 0 { return nil, nil } - // get badge requirement - requirement := b.GetIntParam("amount") - if requirement == 0 || int64(amount) < requirement { - return nil, nil + for _, b := range badges { + // get badge requirement + requirement := b.GetIntParam("amount") + if requirement == 0 || int64(amount) < requirement { + continue + } + awards = append(awards, br.createBadgeAward(event.QuestionUserID, event.QuestionID, b)) } - - return append(awards, br.createBadgeAward(event.QuestionUserID, b.ID, event.QuestionID)), nil + return awards, nil } -func (br *eventRuleRepo) getBadgeByHandler(ctx context.Context, handler string) (b *entity.Badge) { - b = &entity.Badge{Handler: handler} - exist, err := br.data.DB.Context(ctx).Get(b) +func (br *eventRuleRepo) getBadgesByHandler(ctx context.Context, handler string) (badges []*entity.Badge) { + badges = make([]*entity.Badge, 0) + err := br.data.DB.Context(ctx).Where("handler = ?", handler).Find(&badges) if err != nil { log.Errorf("error getting badge by handler %s: %v", handler, err) return nil } - if !exist { - log.Errorf("badge not found by handler %s", handler) - return nil - } - return b + return badges } -func (br *eventRuleRepo) createBadgeAward(userID, badgeID, awardKey string) (awards *entity.BadgeAward) { +func (br *eventRuleRepo) createBadgeAward(userID, awardKey string, badge *entity.Badge) (awards *entity.BadgeAward) { + if badge.Single == entity.BadgeSingleAward { + awardKey = entity.BadgeOnceAwardKey + } return &entity.BadgeAward{ UserID: userID, - BadgeID: badgeID, + BadgeID: badge.ID, AwardKey: awardKey, } } diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index 5674a79b..496f7546 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -446,8 +446,10 @@ func (as *AnswerService) AcceptAnswer(ctx context.Context, req *schema.AcceptAns oldAnswerInfo.ID = uid.DeShortID(oldAnswerInfo.ID) } - as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionAccept, req.UserID). - QID(questionInfo.ID, questionInfo.UserID).AID(req.AnswerID, req.UserID)) + if acceptedAnswerInfo != nil { + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionAccept, req.UserID). + QID(questionInfo.ID, questionInfo.UserID).AID(acceptedAnswerInfo.ID, acceptedAnswerInfo.UserID)) + } as.updateAnswerRank(ctx, req.UserID, questionInfo, acceptedAnswerInfo, oldAnswerInfo) return nil From 7d040f07dd8faf244eab2695036f69342e7e3b01 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 15 Aug 2024 18:34:13 +0800 Subject: [PATCH 046/336] feat(badge): add badge notification --- cmd/wire_gen.go | 6 +- i18n/en_US.yaml | 2 + internal/base/constant/cache_key.go | 2 + internal/base/constant/notification.go | 8 ++ .../controller/notification_controller.go | 6 +- .../repo/notification/notification_repo.go | 6 +- internal/schema/badge_schema.go | 18 ++++ internal/schema/notification_schema.go | 76 ++++++++++++- internal/service/badge/badge_award_service.go | 85 +++++++++------ .../notification/notification_service.go | 100 ++++++++++++------ .../notification_common/notification.go | 89 +++++++++++++--- internal/service/object_info/object_info.go | 1 - 12 files changed, 301 insertions(+), 98 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 9acd76ee..cc245aea 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -238,7 +238,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, controllerSiteInfoController := controller.NewSiteInfoController(siteInfoCommonService) notificationRepo := notification2.NewNotificationRepo(dataData) notificationCommon := notificationcommon.NewNotificationCommon(dataData, notificationRepo, userCommon, activityRepo, followRepo, objService, notificationQueueService, userExternalLoginRepo, siteInfoCommonService) - notificationService := notification.NewNotificationService(dataData, notificationRepo, notificationCommon, revisionService, userRepo, reportRepo, reviewService) + badgeRepo := badge.NewBadgeRepo(dataData, uniqueIDRepo) + notificationService := notification.NewNotificationService(dataData, notificationRepo, notificationCommon, revisionService, userRepo, reportRepo, reviewService, badgeRepo) notificationController := controller.NewNotificationController(notificationService, rankService) dashboardService := dashboard.NewDashboardService(questionRepo, answerRepo, commentCommonRepo, voteRepo, userRepo, reportRepo, configService, siteInfoCommonService, serviceConf, reviewService, revisionRepo, dataData) dashboardController := controller.NewDashboardController(dashboardService) @@ -259,11 +260,10 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, reviewController := controller.NewReviewController(reviewService, rankService, captchaService) metaService := meta2.NewMetaService(metaCommonService, userCommon, answerRepo, questionRepo, eventQueueService) metaController := controller.NewMetaController(metaService) - badgeRepo := badge.NewBadgeRepo(dataData, uniqueIDRepo) badgeGroupRepo := badge_group.NewBadgeGroupRepo(dataData, uniqueIDRepo) badgeAwardRepo := badge_award.NewBadgeAwardRepo(dataData, uniqueIDRepo) eventRuleRepo := badge.NewEventRuleRepo(dataData) - badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService) + badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService, notificationQueueService) badgeEventService := badge2.NewBadgeEventService(dataData, eventQueueService, badgeRepo, eventRuleRepo, badgeAwardService) badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 071644f4..4de69658 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -465,6 +465,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: diff --git a/internal/base/constant/cache_key.go b/internal/base/constant/cache_key.go index 4135b53c..987798d1 100644 --- a/internal/base/constant/cache_key.go +++ b/internal/base/constant/cache_key.go @@ -50,4 +50,6 @@ const ( NewQuestionNotificationLimitMax = 50 RateLimitCacheKeyPrefix = "answer:rate-limit:" RateLimitCacheTime = 5 * time.Minute + RedDotCacheKey = "answer:red-dot:%s:%s" + RedDotCacheTime = 30 * 24 * time.Hour ) diff --git a/internal/base/constant/notification.go b/internal/base/constant/notification.go index ceebe7de..9a7762d8 100644 --- a/internal/base/constant/notification.go +++ b/internal/base/constant/notification.go @@ -56,6 +56,8 @@ const ( NotificationYourCommentWasDeleted = "notification.action.your_comment_was_deleted" // NotificationInvitedYouToAnswer invited you to answer NotificationInvitedYouToAnswer = "notification.action.invited_you_to_answer" + // NotificationEarnedBadge earned badge + NotificationEarnedBadge = "notification.action.earned_badge" ) type NotificationChannelKey string @@ -71,6 +73,12 @@ const ( EmailChannel NotificationChannelKey = "email" ) +const ( + NotificationTypeInbox = "inbox" + NotificationTypeAchievement = "achievement" + NotificationTypeBadgeAchievement = "badge" +) + var ( NotificationMsgTypeMapping = map[string]int{ NotificationUpdateQuestion: 1, diff --git a/internal/controller/notification_controller.go b/internal/controller/notification_controller.go index 15796b9c..952c262e 100644 --- a/internal/controller/notification_controller.go +++ b/internal/controller/notification_controller.go @@ -105,8 +105,8 @@ func (nc *NotificationController) ClearRedDot(ctx *gin.Context) { req.CanReviewAnswer = canList[1] req.CanReviewTag = canList[2] - RedDot, err := nc.notificationService.ClearRedDot(ctx, req) - handler.HandleResponse(ctx, err, RedDot) + resp, err := nc.notificationService.ClearRedDot(ctx, req) + handler.HandleResponse(ctx, err, resp) } // ClearUnRead @@ -125,7 +125,7 @@ func (nc *NotificationController) ClearUnRead(ctx *gin.Context) { return } userID := middleware.GetLoginUserIDFromContext(ctx) - err := nc.notificationService.ClearUnRead(ctx, userID, req.TypeStr) + err := nc.notificationService.ClearUnRead(ctx, userID, req.NotificationType) handler.HandleResponse(ctx, err, gin.H{}) } diff --git a/internal/repo/notification/notification_repo.go b/internal/repo/notification/notification_repo.go index 6b4f0040..bd325ef2 100644 --- a/internal/repo/notification/notification_repo.go +++ b/internal/repo/notification/notification_repo.go @@ -69,7 +69,7 @@ func (nr *notificationRepo) UpdateNotificationContent(ctx context.Context, notif func (nr *notificationRepo) ClearUnRead(ctx context.Context, userID string, notificationType int) (err error) { info := &entity.Notification{} info.IsRead = schema.NotificationRead - _, err = nr.data.DB.Context(ctx).Where("user_id =?", userID).And("type =?", notificationType).Cols("is_read").Update(info) + _, err = nr.data.DB.Context(ctx).Where("user_id = ?", userID).And("type = ?", notificationType).Cols("is_read").Update(info) if err != nil { return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -79,7 +79,7 @@ func (nr *notificationRepo) ClearUnRead(ctx context.Context, userID string, noti func (nr *notificationRepo) ClearIDUnRead(ctx context.Context, userID string, id string) (err error) { info := &entity.Notification{} info.IsRead = schema.NotificationRead - _, err = nr.data.DB.Context(ctx).Where("user_id =?", userID).And("id =?", id).Cols("is_read").Update(info) + _, err = nr.data.DB.Context(ctx).Where("user_id = ?", userID).And("id = ?", id).Cols("is_read").Update(info) if err != nil { return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -98,7 +98,7 @@ func (nr *notificationRepo) GetById(ctx context.Context, id string) (*entity.Not func (nr *notificationRepo) GetByUserIdObjectIdTypeId(ctx context.Context, userID, objectID string, notificationType int) (*entity.Notification, bool, error) { info := &entity.Notification{} - exist, err := nr.data.DB.Context(ctx).Where("user_id = ? ", userID).And("object_id = ?", objectID).And("type = ?", notificationType).Get(info) + exist, err := nr.data.DB.Context(ctx).Where("user_id = ?", userID).And("object_id = ?", objectID).And("type = ?", notificationType).Get(info) if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() return info, false, err diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index 088193ad..efbcd37a 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -171,3 +171,21 @@ type GetUserBadgeAwardListResp struct { // badge level Level entity.BadgeLevel `json:"level" ` } + +// GetBadgeByIDResp get badge by id response +type GetBadgeByIDResp struct { + // badge id + ID string `json:"id" ` + // badge name + Name string `json:"name" ` + // badge description + Description string `json:"description" ` + // badge icon + Icon string `json:"icon" ` + // badge award count + AwardCount int `json:"award_count" ` + // badge is single or multiple + IsSingle bool `json:"is_single" ` + // badge level + Level entity.BadgeLevel `json:"level" ` +} diff --git a/internal/schema/notification_schema.go b/internal/schema/notification_schema.go index 4e0e9316..8d4b694e 100644 --- a/internal/schema/notification_schema.go +++ b/internal/schema/notification_schema.go @@ -19,6 +19,12 @@ package schema +import ( + "encoding/json" + "github.com/apache/incubator-answer/internal/entity" + "sort" +) + const ( NotificationTypeInbox = 1 NotificationTypeAchievement = 2 @@ -95,10 +101,70 @@ type ObjectInfo struct { } type RedDot struct { - Inbox int64 `json:"inbox"` - Achievement int64 `json:"achievement"` - Revision int64 `json:"revision"` - CanRevision bool `json:"can_revision"` + Inbox int64 `json:"inbox"` + Achievement int64 `json:"achievement"` + Revision int64 `json:"revision"` + CanRevision bool `json:"can_revision"` + BadgeAward *RedDotBadgeAward `json:"badge_award"` +} + +type RedDotBadgeAward struct { + NotificationID string `json:"notification_id"` + BadgeID string `json:"badge_id"` + Name string `json:"name"` + Icon string `json:"icon"` + Level entity.BadgeLevel `json:"level"` +} + +type RedDotBadgeAwardCache struct { + BadgeAwardList map[string]*RedDotBadgeAward `json:"badge_award_list"` +} + +// NewRedDotBadgeAwardCache new red dot badge award cache +func NewRedDotBadgeAwardCache() *RedDotBadgeAwardCache { + return &RedDotBadgeAwardCache{ + BadgeAwardList: make(map[string]*RedDotBadgeAward), + } +} + +// GetBadgeAward get badge award +func (r *RedDotBadgeAwardCache) GetBadgeAward() *RedDotBadgeAward { + if len(r.BadgeAwardList) == 0 { + return nil + } + var ids []string + for _, v := range r.BadgeAwardList { + ids = append(ids, v.NotificationID) + } + sort.Strings(ids) + return r.BadgeAwardList[ids[0]] +} + +// FromJSON from json +func (r *RedDotBadgeAwardCache) FromJSON(data string) { + _ = json.Unmarshal([]byte(data), r) +} + +// ToJSON to json +func (r *RedDotBadgeAwardCache) ToJSON() string { + data, _ := json.Marshal(r) + return string(data) +} + +// AddBadgeAward add badge award +func (r *RedDotBadgeAwardCache) AddBadgeAward(badgeAward *RedDotBadgeAward) { + if r.BadgeAwardList == nil { + r.BadgeAwardList = make(map[string]*RedDotBadgeAward) + } + r.BadgeAwardList[badgeAward.NotificationID] = badgeAward +} + +// RemoveBadgeAward remove badge award +func (r *RedDotBadgeAwardCache) RemoveBadgeAward(notificationID string) { + if r.BadgeAwardList == nil { + return + } + delete(r.BadgeAwardList, notificationID) } type NotificationSearch struct { @@ -112,8 +178,8 @@ type NotificationSearch struct { } type NotificationClearRequest struct { + NotificationType string `validate:"required,oneof=inbox achievement" json:"type"` UserID string `json:"-"` - TypeStr string `json:"type" form:"type"` // inbox achievement CanReviewQuestion bool `json:"-"` CanReviewAnswer bool `json:"-"` CanReviewTag bool `json:"-"` diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index 3883de61..dd78fd02 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -21,11 +21,13 @@ package badge import ( "context" + "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/base/translator" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/notice_queue" "github.com/apache/incubator-answer/internal/service/object_info" usercommon "github.com/apache/incubator-answer/internal/service/user_common" "github.com/apache/incubator-answer/pkg/uid" @@ -65,10 +67,11 @@ type BadgeAwardRepo interface { } type BadgeAwardService struct { - badgeAwardRepo BadgeAwardRepo - badgeRepo BadgeRepo - userCommon *usercommon.UserCommon - objectInfoService *object_info.ObjService + badgeAwardRepo BadgeAwardRepo + badgeRepo BadgeRepo + userCommon *usercommon.UserCommon + objectInfoService *object_info.ObjService + notificationQueueService notice_queue.NotificationQueueService } func NewBadgeAwardService( @@ -76,17 +79,19 @@ func NewBadgeAwardService( badgeRepo BadgeRepo, userCommon *usercommon.UserCommon, objectInfoService *object_info.ObjService, + notificationQueueService notice_queue.NotificationQueueService, ) *BadgeAwardService { return &BadgeAwardService{ - badgeAwardRepo: badgeAwardRepo, - badgeRepo: badgeRepo, - userCommon: userCommon, - objectInfoService: objectInfoService, + badgeAwardRepo: badgeAwardRepo, + badgeRepo: badgeRepo, + userCommon: userCommon, + objectInfoService: objectInfoService, + notificationQueueService: notificationQueueService, } } // GetBadgeAwardList get badge award list -func (b *BadgeAwardService) GetBadgeAwardList( +func (bs *BadgeAwardService) GetBadgeAwardList( ctx context.Context, req *schema.GetBadgeAwardWithPageReq, ) (resp []*schema.GetBadgeAwardWithPageResp, total int64, err error) { @@ -94,11 +99,11 @@ func (b *BadgeAwardService) GetBadgeAwardList( badgeAwardList []*entity.BadgeAward ) - req.UserID, err = b.validateUserByUsername(ctx, req.Username) + req.UserID, err = bs.validateUserByUsername(ctx, req.Username) if err != nil { - badgeAwardList, total, err = b.badgeAwardRepo.ListPagedByBadgeId(ctx, req.BadgeID, req.Page, req.PageSize) + badgeAwardList, total, err = bs.badgeAwardRepo.ListPagedByBadgeId(ctx, req.BadgeID, req.Page, req.PageSize) } else { - badgeAwardList, total, err = b.badgeAwardRepo.ListPagedByBadgeIdAndUserId(ctx, req.BadgeID, req.UserID, req.Page, req.PageSize) + badgeAwardList, total, err = bs.badgeAwardRepo.ListPagedByBadgeIdAndUserId(ctx, req.BadgeID, req.UserID, req.Page, req.PageSize) } if err != nil { @@ -113,7 +118,7 @@ func (b *BadgeAwardService) GetBadgeAwardList( ) // if exist object info - objInfo, e := b.objectInfoService.GetInfo(ctx, badgeAward.AwardKey) + objInfo, e := bs.objectInfoService.GetInfo(ctx, badgeAward.AwardKey) if e == nil && !objInfo.IsDeleted() { objectID = objInfo.ObjectID questionID = objInfo.QuestionID @@ -135,7 +140,7 @@ func (b *BadgeAwardService) GetBadgeAwardList( } // get user info - userInfo, exists, e := b.userCommon.GetUserBasicInfoByID(ctx, badgeAward.UserID) + userInfo, exists, e := bs.userCommon.GetUserBasicInfoByID(ctx, badgeAward.UserID) if e != nil { log.Errorf("user not found by id: %s, err: %v", badgeAward.UserID, e) } @@ -150,8 +155,8 @@ func (b *BadgeAwardService) GetBadgeAwardList( } // Award award badge -func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID string, awardKey string) (err error) { - badgeData, exists, err := b.badgeRepo.GetByID(ctx, badgeID) +func (bs *BadgeAwardService) Award(ctx context.Context, badgeID string, userID string, awardKey string) (err error) { + badgeData, exists, err := bs.badgeRepo.GetByID(ctx, badgeID) if err != nil { return err } @@ -160,7 +165,7 @@ func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID st return errors.BadRequest(reason.BadgeObjectNotFound) } - alreadyAwarded, err := b.badgeAwardRepo.CheckIsAward(ctx, badgeID, userID, awardKey, badgeData.Single) + alreadyAwarded, err := bs.badgeAwardRepo.CheckIsAward(ctx, badgeID, userID, awardKey, badgeData.Single) if err != nil { return err } @@ -175,11 +180,27 @@ func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID st BadgeGroupID: badgeData.BadgeGroupID, IsBadgeDeleted: entity.IsBadgeNotDeleted, } - return b.badgeAwardRepo.AwardBadgeForUser(ctx, badgeAward) + err = bs.badgeAwardRepo.AwardBadgeForUser(ctx, badgeAward) + if err != nil { + return err + } + + msg := &schema.NotificationMsg{ + TriggerUserID: badgeAward.UserID, + ReceiverUserID: badgeAward.UserID, + Type: schema.NotificationTypeAchievement, + ObjectID: badgeAward.ID, + ObjectType: constant.BadgeAwardObjectType, + Title: badgeData.Name, + ExtraInfo: map[string]string{"badge_id": badgeData.ID}, + NotificationAction: constant.NotificationEarnedBadge, + } + bs.notificationQueueService.Send(ctx, msg) + return nil } // GetUserBadgeAwardList get user badge award list -func (b *BadgeAwardService) GetUserBadgeAwardList( +func (bs *BadgeAwardService) GetUserBadgeAwardList( ctx *gin.Context, req *schema.GetUserBadgeAwardListReq, ) ( @@ -191,12 +212,12 @@ func (b *BadgeAwardService) GetUserBadgeAwardList( earnedCounts []*entity.BadgeEarnedCount ) - req.UserID, err = b.validateUserByUsername(ctx, req.Username) + req.UserID, err = bs.validateUserByUsername(ctx, req.Username) if err != nil { return } - earnedCounts, err = b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, req.UserID) + earnedCounts, err = bs.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, req.UserID) if err != nil { return } @@ -204,7 +225,7 @@ func (b *BadgeAwardService) GetUserBadgeAwardList( resp = make([]*schema.GetUserBadgeAwardListResp, total) for i, earnedCount := range earnedCounts { - badge, exists, e := b.badgeRepo.GetByID(ctx, earnedCount.BadgeID) + badge, exists, e := bs.badgeRepo.GetByID(ctx, earnedCount.BadgeID) if e != nil { err = e return @@ -225,24 +246,18 @@ func (b *BadgeAwardService) GetUserBadgeAwardList( } // GetUserRecentBadgeAwardList get user badge award list -func (b *BadgeAwardService) GetUserRecentBadgeAwardList( - ctx *gin.Context, - req *schema.GetUserBadgeAwardListReq, -) ( - resp []*schema.GetUserBadgeAwardListResp, - total int64, - err error, -) { +func (bs *BadgeAwardService) GetUserRecentBadgeAwardList(ctx *gin.Context, req *schema.GetUserBadgeAwardListReq) ( + resp []*schema.GetUserBadgeAwardListResp, total int64, err error) { var ( earnedCounts []*entity.BadgeAwardRecent ) - req.UserID, err = b.validateUserByUsername(ctx, req.Username) + req.UserID, err = bs.validateUserByUsername(ctx, req.Username) if err != nil { return } - earnedCounts, err = b.badgeAwardRepo.ListNewestEarned(ctx, req.UserID, req.Limit) + earnedCounts, err = bs.badgeAwardRepo.ListNewestEarned(ctx, req.UserID, req.Limit) if err != nil { return } @@ -251,7 +266,7 @@ func (b *BadgeAwardService) GetUserRecentBadgeAwardList( resp = make([]*schema.GetUserBadgeAwardListResp, total) for i, earnedCount := range earnedCounts { - badge, exists, e := b.badgeRepo.GetByID(ctx, earnedCount.BadgeID) + badge, exists, e := bs.badgeRepo.GetByID(ctx, earnedCount.BadgeID) if e != nil { err = e return @@ -278,14 +293,14 @@ type userReq struct { Username string } -func (b *BadgeAwardService) validateUserByUsername(ctx context.Context, userName string) (userID string, err error) { +func (bs *BadgeAwardService) validateUserByUsername(ctx context.Context, userName string) (userID string, err error) { var ( userInfo *schema.UserBasicInfo exist bool ) // validate user exists or not if len(userName) > 0 { - userInfo, exist, err = b.userCommon.GetUserBasicInfoByUserName(ctx, userName) + userInfo, exist, err = bs.userCommon.GetUserBasicInfoByUserName(ctx, userName) if err != nil { return } diff --git a/internal/service/notification/notification_service.go b/internal/service/notification/notification_service.go index 71febb67..b73d4fda 100644 --- a/internal/service/notification/notification_service.go +++ b/internal/service/notification/notification_service.go @@ -23,7 +23,7 @@ import ( "context" "encoding/json" "fmt" - + "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/report_common" "github.com/apache/incubator-answer/internal/service/review" usercommon "github.com/apache/incubator-answer/internal/service/user_common" @@ -52,6 +52,7 @@ type NotificationService struct { reportRepo report_common.ReportRepo reviewService *review.ReviewService userRepo usercommon.UserRepo + badgeRepo badge.BadgeRepo } func NewNotificationService( @@ -62,6 +63,7 @@ func NewNotificationService( userRepo usercommon.UserRepo, reportRepo report_common.ReportRepo, reviewService *review.ReviewService, + badgeRepo badge.BadgeRepo, ) *NotificationService { return &NotificationService{ data: data, @@ -71,35 +73,60 @@ func NewNotificationService( userRepo: userRepo, reportRepo: reportRepo, reviewService: reviewService, + badgeRepo: badgeRepo, } } func (ns *NotificationService) GetRedDot(ctx context.Context, req *schema.GetRedDot) (resp *schema.RedDot, err error) { + inboxKey := fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeInbox, req.UserID) + achievementKey := fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeAchievement, req.UserID) + redBot := &schema.RedDot{} - inboxKey := fmt.Sprintf("answer_RedDot_%d_%s", schema.NotificationTypeInbox, req.UserID) - achievementKey := fmt.Sprintf("answer_RedDot_%d_%s", schema.NotificationTypeAchievement, req.UserID) - inboxValue, _, err := ns.data.Cache.GetInt64(ctx, inboxKey) - if err != nil { - redBot.Inbox = 0 - } else { - redBot.Inbox = inboxValue - } - achievementValue, _, err := ns.data.Cache.GetInt64(ctx, achievementKey) - if err != nil { - redBot.Achievement = 0 - } else { - redBot.Achievement = achievementValue - } - revisionCount := &schema.RevisionSearch{} - _ = copier.Copy(revisionCount, req) + redBot.Inbox, _, err = ns.data.Cache.GetInt64(ctx, inboxKey) + redBot.Achievement, _, err = ns.data.Cache.GetInt64(ctx, achievementKey) + + // get review amount if req.CanReviewAnswer || req.CanReviewQuestion || req.CanReviewTag { redBot.CanRevision = true redBot.Revision = ns.countAllReviewAmount(ctx, req) } + // get badge award + redBot.BadgeAward = ns.getBadgeAward(ctx, req.UserID) return redBot, nil } +func (ns *NotificationService) getBadgeAward(ctx context.Context, userID string) (badgeAward *schema.RedDotBadgeAward) { + key := fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeBadgeAchievement, userID) + cacheData, exist, err := ns.data.Cache.GetString(ctx, key) + if err != nil { + log.Errorf("get badge award failed: %v", err) + return nil + } + if !exist { + return nil + } + + c := schema.NewRedDotBadgeAwardCache() + c.FromJSON(cacheData) + award := c.GetBadgeAward() + if award == nil { + return nil + } + badgeInfo, exists, err := ns.badgeRepo.GetByID(ctx, award.BadgeID) + if err != nil { + log.Errorf("get badge info failed: %v", err) + return nil + } + if !exists { + return nil + } + award.Name = translator.Tr(handler.GetLangByCtx(ctx), badgeInfo.Name) + award.Icon = badgeInfo.Icon + award.Level = badgeInfo.Level + return award +} + func (ns *NotificationService) countAllReviewAmount(ctx context.Context, req *schema.GetRedDot) (amount int64) { // get queue amount if req.IsAdmin { @@ -137,21 +164,16 @@ func (ns *NotificationService) countAllReviewAmount(ctx context.Context, req *sc } func (ns *NotificationService) ClearRedDot(ctx context.Context, req *schema.NotificationClearRequest) (*schema.RedDot, error) { - botType, ok := schema.NotificationType[req.TypeStr] - if ok { - key := fmt.Sprintf("answer_RedDot_%d_%s", botType, req.UserID) - err := ns.data.Cache.Del(ctx, key) - if err != nil { - log.Error("ClearRedDot del cache error", err.Error()) - } - } - getRedDotreq := &schema.GetRedDot{} - _ = copier.Copy(getRedDotreq, req) - return ns.GetRedDot(ctx, getRedDotreq) + key := fmt.Sprintf(constant.RedDotCacheKey, req.NotificationType, req.UserID) + _ = ns.data.Cache.Del(ctx, key) + + resp := &schema.GetRedDot{} + _ = copier.Copy(resp, req) + return ns.GetRedDot(ctx, resp) } -func (ns *NotificationService) ClearUnRead(ctx context.Context, userID string, botTypeStr string) error { - botType, ok := schema.NotificationType[botTypeStr] +func (ns *NotificationService) ClearUnRead(ctx context.Context, userID string, notificationType string) error { + botType, ok := schema.NotificationType[notificationType] if ok { err := ns.notificationRepo.ClearUnRead(ctx, userID, botType) if err != nil { @@ -164,19 +186,23 @@ func (ns *NotificationService) ClearUnRead(ctx context.Context, userID string, b func (ns *NotificationService) ClearIDUnRead(ctx context.Context, userID string, id string) error { notificationInfo, exist, err := ns.notificationRepo.GetById(ctx, id) if err != nil { - log.Error("notificationRepo.GetById error", err.Error()) + log.Errorf("get notification failed: %v", err) return nil } - if !exist { + if !exist || notificationInfo.UserID != userID { return nil } - if notificationInfo.UserID == userID && notificationInfo.IsRead == schema.NotificationNotRead { + if notificationInfo.IsRead == schema.NotificationNotRead { err := ns.notificationRepo.ClearIDUnRead(ctx, userID, id) if err != nil { return err } } + err = ns.notificationCommon.RemoveBadgeAwardAlertCache(ctx, userID, id) + if err != nil { + log.Errorf("remove badge award alert cache failed: %v", err) + } return nil } @@ -224,6 +250,14 @@ func (ns *NotificationService) formatNotificationPage(ctx context.Context, notif item.NotificationAction == constant.NotificationDownVotedTheAnswer { item.UserInfo = nil } + // If notification is badge, the user info is not needed and the title need to be translated. + if item.ObjectInfo.ObjectType == constant.BadgeAwardObjectType { + badgeName := translator.Tr(lang, item.ObjectInfo.Title) + item.ObjectInfo.Title = translator.TrWithData(lang, constant.NotificationEarnedBadge, struct { + BadgeName string + }{BadgeName: badgeName}) + item.UserInfo = nil + } item.ID = notificationInfo.ID item.NotificationAction = translator.Tr(lang, item.NotificationAction) diff --git a/internal/service/notification_common/notification.go b/internal/service/notification_common/notification.go index 319403b2..a3129b3a 100644 --- a/internal/service/notification_common/notification.go +++ b/internal/service/notification_common/notification.go @@ -103,7 +103,7 @@ func NewNotificationCommon( // ObjectInfo.Title // ObjectInfo.ObjectID // ObjectInfo.ObjectType -func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.NotificationMsg) error { +func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.NotificationMsg) (err error) { if msg.Type == schema.NotificationTypeAchievement && plugin.RankAgentEnabled() { return nil } @@ -119,17 +119,25 @@ func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.N Type: msg.Type, } var questionID string // just for notify all followers - objInfo, err := ns.objectInfoService.GetInfo(ctx, req.ObjectInfo.ObjectID) - if err != nil { - log.Error(err) - } else { - req.ObjectInfo.Title = objInfo.Title - questionID = objInfo.QuestionID + var objInfo *schema.SimpleObjectInfo + if msg.ObjectType == constant.BadgeAwardObjectType { + req.ObjectInfo.Title = msg.Title objectMap := make(map[string]string) - objectMap["question"] = uid.DeShortID(objInfo.QuestionID) - objectMap["answer"] = uid.DeShortID(objInfo.AnswerID) - objectMap["comment"] = objInfo.CommentID + objectMap["badge_id"] = msg.ExtraInfo["badge_id"] req.ObjectInfo.ObjectMap = objectMap + } else { + objInfo, err = ns.objectInfoService.GetInfo(ctx, req.ObjectInfo.ObjectID) + if err != nil { + log.Error(err) + } else { + req.ObjectInfo.Title = objInfo.Title + questionID = objInfo.QuestionID + objectMap := make(map[string]string) + objectMap["question"] = uid.DeShortID(objInfo.QuestionID) + objectMap["answer"] = uid.DeShortID(objInfo.AnswerID) + objectMap["comment"] = objInfo.CommentID + req.ObjectInfo.ObjectMap = objectMap + } } if msg.Type == schema.NotificationTypeAchievement { @@ -188,10 +196,13 @@ func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.N if err != nil { return fmt.Errorf("add notification error: %w", err) } - err = ns.addRedDot(ctx, info.UserID, info.Type) + err = ns.addRedDot(ctx, info.UserID, msg.Type) if err != nil { log.Error("addRedDot Error", err.Error()) } + if req.ObjectInfo.ObjectType == constant.BadgeAwardObjectType { + err = ns.AddBadgeAwardAlertCache(ctx, info.UserID, info.ID, req.ObjectInfo.ObjectMap["badge_id"]) + } go ns.SendNotificationToAllFollower(ctx, msg, questionID) @@ -201,19 +212,67 @@ func (ns *NotificationCommon) AddNotification(ctx context.Context, msg *schema.N return nil } -func (ns *NotificationCommon) addRedDot(ctx context.Context, userID string, botType int) error { - key := fmt.Sprintf("answer_RedDot_%d_%s", botType, userID) - err := ns.data.Cache.SetInt64(ctx, key, 1, 30*24*time.Hour) //Expiration time is one month. +func (ns *NotificationCommon) addRedDot(ctx context.Context, userID string, noticeType int) error { + var key string + if noticeType == schema.NotificationTypeInbox { + key = fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeInbox, userID) + } else { + key = fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeAchievement, userID) + } + err := ns.data.Cache.SetInt64(ctx, key, 1, constant.RedDotCacheTime) if err != nil { return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() } return nil } +// AddBadgeAwardAlertCache add badge award alert cache +func (ns *NotificationCommon) AddBadgeAwardAlertCache(ctx context.Context, userID, notificationID, badgeID string) (err error) { + key := fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeBadgeAchievement, userID) + cacheData, exist, err := ns.data.Cache.GetString(ctx, key) + if err != nil { + return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + if !exist { + c := schema.NewRedDotBadgeAwardCache() + c.AddBadgeAward(&schema.RedDotBadgeAward{ + NotificationID: notificationID, + BadgeID: badgeID, + }) + return ns.data.Cache.SetString(ctx, key, c.ToJSON(), constant.RedDotCacheTime) + } + c := schema.NewRedDotBadgeAwardCache() + c.FromJSON(cacheData) + c.AddBadgeAward(&schema.RedDotBadgeAward{ + NotificationID: notificationID, + BadgeID: badgeID, + }) + return ns.data.Cache.SetString(ctx, key, c.ToJSON(), constant.RedDotCacheTime) +} + +// RemoveBadgeAwardAlertCache remove badge award alert cache +func (ns *NotificationCommon) RemoveBadgeAwardAlertCache(ctx context.Context, userID, notificationID string) (err error) { + key := fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeBadgeAchievement, userID) + cacheData, exist, err := ns.data.Cache.GetString(ctx, key) + if err != nil { + return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + if !exist { + return nil + } + c := schema.NewRedDotBadgeAwardCache() + c.FromJSON(cacheData) + c.RemoveBadgeAward(notificationID) + if len(c.BadgeAwardList) == 0 { + return ns.data.Cache.Del(ctx, key) + } + return ns.data.Cache.SetString(ctx, key, c.ToJSON(), constant.RedDotCacheTime) +} + // SendNotificationToAllFollower send notification to all followers func (ns *NotificationCommon) SendNotificationToAllFollower(ctx context.Context, msg *schema.NotificationMsg, questionID string) { - if msg.NoNeedPushAllFollow { + if msg.NoNeedPushAllFollow || len(questionID) == 0 { return } if msg.NotificationAction != constant.NotificationUpdateQuestion && diff --git a/internal/service/object_info/object_info.go b/internal/service/object_info/object_info.go index 6c2e89a9..9a85f07e 100644 --- a/internal/service/object_info/object_info.go +++ b/internal/service/object_info/object_info.go @@ -21,7 +21,6 @@ package object_info import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/schema" From 5e5551a16fb67e92ba8fed3c32432123bc81319f Mon Sep 17 00:00:00 2001 From: Sonui Date: Wed, 7 Aug 2024 22:51:23 +0800 Subject: [PATCH 047/336] perf: remove invalid nil pointer check in Translate function --- plugin/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/plugin.go b/plugin/plugin.go index 61ed0d8f..85286855 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -219,7 +219,7 @@ func MakeTranslator(key string) Translator { // Translate translates the key to the current language of the context func (t Translator) Translate(ctx *GinContext) string { - if &t == nil || t.Fn == nil { + if t.Fn == nil { return "" } return t.Fn(ctx) From 7d5bfaa3fbbfc65efee99515c32902190c058917 Mon Sep 17 00:00:00 2001 From: Sonui Date: Wed, 14 Aug 2024 00:21:55 +0800 Subject: [PATCH 048/336] perf: update check-asf-header.sh script to support Podman --- script/check-asf-header.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/script/check-asf-header.sh b/script/check-asf-header.sh index ff765eab..808efa10 100755 --- a/script/check-asf-header.sh +++ b/script/check-asf-header.sh @@ -16,5 +16,16 @@ # specific language governing permissions and limitations # under the License. -docker run -it --rm -v $(pwd):/github/workspace ghcr.io/korandoru/hawkeye-native format +# check if docker or podman is installed +if command -v docker >/dev/null 2>&1; then + CONTAINER_RUNTIME="docker" +elif command -v podman >/dev/null 2>&1; then + CONTAINER_RUNTIME="podman" +else + echo "Neither Docker nor Podman is installed. Please install either Docker or Podman." + exit 1 +fi + +$CONTAINER_RUNTIME run -it --rm -v "$(pwd)":/github/workspace ghcr.io/korandoru/hawkeye-native format + gofmt -w -l . From d63ce3673b98a52ef5ece8e297a74b52134ab21f Mon Sep 17 00:00:00 2001 From: Sonui Date: Thu, 15 Aug 2024 21:15:02 +0800 Subject: [PATCH 049/336] perf: remove extra characters in header.html --- ui/template/header.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/template/header.html b/ui/template/header.html index 653f9a28..0243a43d 100644 --- a/ui/template/header.html +++ b/ui/template/header.html @@ -68,14 +68,14 @@ From ebc858579b65c8b4a4496530477adf4e12d39f6d Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 19 Aug 2024 14:10:13 +0800 Subject: [PATCH 050/336] chore(badge): delete not used func --- internal/repo/badge/badge_repo.go | 36 ---------------- internal/repo/badge_award/badge_award_repo.go | 41 +------------------ internal/service/badge/badge_award_service.go | 13 ------ internal/service/badge/badge_service.go | 4 -- 4 files changed, 1 insertion(+), 93 deletions(-) diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index 8537e389..80689541 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -62,36 +62,6 @@ func (r *badgeRepo) GetByIDs(ctx context.Context, ids []string) (badges []*entit return } -// ListByLevel returns a list of badges by level -func (r *badgeRepo) ListByLevel(ctx context.Context, level entity.BadgeLevel) (badges []*entity.Badge, err error) { - badges = make([]*entity.Badge, 0) - err = r.data.DB.Context(ctx).Where("level = ?", level).Find(&badges) - if err != nil { - err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - } - return -} - -// ListByGroup returns a list of badges by group -func (r *badgeRepo) ListByGroup(ctx context.Context, groupID int64) (badges []*entity.Badge, err error) { - badges = make([]*entity.Badge, 0) - err = r.data.DB.Context(ctx).Where("group_id = ?", groupID).Find(&badges) - if err != nil { - err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - } - return -} - -// ListByLevelAndGroup returns a list of badges by level and group -func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) (badges []*entity.Badge, err error) { - badges = make([]*entity.Badge, 0) - err = r.data.DB.Context(ctx).Where("level = ? AND group_id = ?", level, groupID).Find(&badges) - if err != nil { - err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() - } - return -} - // ListPaged returns a list of activated badges func (r *badgeRepo) ListPaged(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { badges = make([]*entity.Badge, 0) @@ -146,12 +116,6 @@ func (r *badgeRepo) ListInactivated(ctx context.Context, page int, pageSize int) return } -// UpdateAwardCount updates the award count of a badge -func (r *badgeRepo) UpdateAwardCount(ctx context.Context, id string, count int64) (err error) { - _, err = r.data.DB.Context(ctx).Where("id = ?", id).Incr("award_count", count).Update(&entity.Badge{}) - return -} - // UpdateStatus updates the award count of a badge func (r *badgeRepo) UpdateStatus(ctx context.Context, id string, status int8) (err error) { _, err = r.data.DB.Transaction(func(session *xorm.Session) (result any, err error) { diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 058fa864..377677d1 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -100,12 +100,6 @@ func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID, userID, awar return isAward, err } -func (r *badgeAwardRepo) CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) { - return -} -func (r *badgeAwardRepo) CountByUserId(ctx context.Context, userID string) (awardCount int64) { - return -} func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) { awardCount, err := r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ?", userID, badgeID).Count(&entity.BadgeAward{}) if err != nil { @@ -113,22 +107,11 @@ func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID str } return } -func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, awardKey string) (awardCount int64) { - return -} -func (r *badgeAwardRepo) CountByObjectIdAndBadgeId(ctx context.Context, awardKey string, badgeID string) (awardCount int64) { - return -} -func (r *badgeAwardRepo) CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, awardKey string, badgeID string) (awardCount int64) { - return -} + func (r *badgeAwardRepo) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) { err = r.data.DB.Context(ctx).Select("badge_id, count(`id`) AS earned_count").Where("user_id = ?", userID).GroupBy("badge_id").Find(&earnedCounts) return } -func (r *badgeAwardRepo) ListAllByUserId(ctx context.Context, userID string) (badgeAwards []*entity.BadgeAward) { - return -} // ListPagedByBadgeId list badge awards by badge id func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error) { @@ -151,21 +134,6 @@ func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeI } return } -func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, awardKey string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { - return -} -func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, awardKey string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { - return -} -func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) { - return -} -func (r *badgeAwardRepo) ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { - return -} -func (r *badgeAwardRepo) ListPagedLatest(ctx context.Context, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { - return -} // ListNewestEarned list newest earned badge awards func (r *badgeAwardRepo) ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) { @@ -179,13 +147,6 @@ func (r *badgeAwardRepo) ListNewestEarned(ctx context.Context, userID string, li return } -func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err error) { - return -} -func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { - return -} - // GetByUserIdAndBadgeId get badge award by user id and badge id func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) ( badgeAward *entity.BadgeAward, exists bool, err error) { diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index dd78fd02..02cdcf1c 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -41,26 +41,13 @@ type BadgeAwardRepo interface { CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) (isAward bool, err error) AwardBadgeForUser(ctx context.Context, badgeAward *entity.BadgeAward) (err error) - CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) - CountByUserId(ctx context.Context, userID string) (awardCount int64) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) - CountByObjectId(ctx context.Context, awardKey string) (awardCount int64) - CountByObjectIdAndBadgeId(ctx context.Context, awardKey string, badgeID string) (awardCount int64) - CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, awardKey string, badgeID string) (awardCount int64) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) - ListAllByUserId(ctx context.Context, userID string) (badgeAwards []*entity.BadgeAward) ListPagedByBadgeId(ctx context.Context, badgeID string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListPagedByObjectId(ctx context.Context, badgeID string, awardKey string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, awardKey string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListPagedLatest(ctx context.Context, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) - ListNewestEarnedByLevel(ctx context.Context, userID string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err error) - ListNewestByUserIdAndLevel(ctx context.Context, userID string, level int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) GetByUserIdAndBadgeIdAndAwardKey(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index acb68cff..031f0f15 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -37,14 +37,10 @@ type BadgeRepo interface { GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) GetByIDs(ctx context.Context, ids []string) (badges []*entity.Badge, err error) - ListByLevel(ctx context.Context, level entity.BadgeLevel) ([]*entity.Badge, error) - ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error) - ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) ([]*entity.Badge, error) ListPaged(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) ListActivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) ListInactivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) - UpdateAwardCount(ctx context.Context, id string, count int64) (err error) UpdateStatus(ctx context.Context, id string, status int8) (err error) } From c50e63dd34ce9ddb7babd769146278ef41e5bfcb Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 19 Aug 2024 15:15:07 +0800 Subject: [PATCH 051/336] fix(dev): delete test file --- dev/i18n/zh_CN.yaml | 2035 ------------------------------------------- 1 file changed, 2035 deletions(-) delete mode 100644 dev/i18n/zh_CN.yaml diff --git a/dev/i18n/zh_CN.yaml b/dev/i18n/zh_CN.yaml deleted file mode 100644 index 6613bfc2..00000000 --- a/dev/i18n/zh_CN.yaml +++ /dev/null @@ -1,2035 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# The following fields are used for back-end -backend: - base: - success: - other: 成功。 - unknown: - other: 未知错误。 - request_format_error: - other: 请求格式错误。 - unauthorized_error: - other: 未授权。 - database_error: - other: 数据服务器错误。 - forbidden_error: - other: 禁止访问。 - duplicate_request_error: - other: 重复提交。 - action: - report: - other: 举报 - edit: - other: 编辑 - delete: - other: 删除 - close: - other: 关闭 - reopen: - other: 重新打开 - forbidden_error: - other: 禁止访问。 - pin: - other: 置顶 - hide: - other: 列表隐藏 - unpin: - other: 取消置顶 - show: - other: 列表显示 - invite_someone_to_answer: - other: 编辑 - undelete: - other: 撤消删除 - role: - name: - user: - other: 用户 - admin: - other: 管理员 - moderator: - other: 版主 - description: - user: - other: 默认没有特殊权限。 - admin: - other: 拥有管理网站的全部权限。 - moderator: - other: 拥有除访问后台管理以外的所有权限。 - privilege: - level_1: - description: - other: 级别 1(少量声望要求,适合私有团队、群组) - level_2: - description: - other: 级别 2(低声望要求,适合初启动的社区) - level_3: - description: - other: 级别 3(高声望要求,适合成熟的社区) - level_custom: - description: - other: 自定义等级 - rank_question_add_label: - other: 提问 - rank_answer_add_label: - other: 写答案 - rank_comment_add_label: - other: 写评论 - rank_report_add_label: - other: 举报 - rank_comment_vote_up_label: - other: 点赞评论 - rank_link_url_limit_label: - other: 每次发布超过 2 个链接 - rank_question_vote_up_label: - other: 点赞问题 - rank_answer_vote_up_label: - other: 点赞答案 - rank_question_vote_down_label: - other: 点踩问题 - rank_answer_vote_down_label: - other: 点踩答案 - rank_invite_someone_to_answer_label: - other: 邀请回答 - rank_tag_add_label: - other: 创建新标签 - rank_tag_edit_label: - other: 编辑标签描述(需要审核) - rank_question_edit_label: - other: 编辑别人的问题(需要审核) - rank_answer_edit_label: - other: 编辑别人的答案(需要审核) - rank_question_edit_without_review_label: - other: 编辑别人的问题无需审核 - rank_answer_edit_without_review_label: - other: 编辑别人的答案无需审核 - rank_question_audit_label: - other: 审核问题编辑 - rank_answer_audit_label: - other: 审核回答编辑 - rank_tag_audit_label: - other: 审核标签编辑 - rank_tag_edit_without_review_label: - other: 编辑标签描述无需审核 - rank_tag_synonym_label: - other: 管理标签同义词 - email: - other: 邮箱 - e_mail: - other: 邮箱 - password: - other: 密码 - pass: - other: 密码 - original_text: - other: 本帖 - email_or_password_wrong_error: - other: 邮箱和密码不匹配。 - error: - common: - invalid_url: - other: 无效的 URL。 - password: - space_invalid: - other: 密码不得含有空格。 - admin: - cannot_update_their_password: - other: 你无法修改自己的密码。 - cannot_edit_their_profile: - other: 您不能修改您的个人资料。 - cannot_modify_self_status: - other: 你无法修改自己的状态。 - email_or_password_wrong: - other: 邮箱和密码不匹配。 - answer: - not_found: - other: 没有找到答案。 - cannot_deleted: - other: 没有删除权限。 - cannot_update: - other: 没有更新权限。 - question_closed_cannot_add: - other: 问题已关闭,无法添加。 - comment: - edit_without_permission: - other: 不允许编辑评论。 - not_found: - other: 评论未找到。 - cannot_edit_after_deadline: - other: 评论时间太久,无法修改。 - email: - duplicate: - other: 邮箱已存在。 - need_to_be_verified: - other: 邮箱需要验证。 - verify_url_expired: - other: 邮箱验证的网址已过期,请重新发送邮件。 - illegal_email_domain_error: - other: 此邮箱不在允许注册的邮箱域中。请使用其他邮箱尝试。 - lang: - not_found: - other: 语言文件未找到。 - object: - captcha_verification_failed: - other: 验证码错误。 - disallow_follow: - other: 你不能关注。 - disallow_vote: - other: 你不能投票。 - disallow_vote_your_self: - other: 你不能为自己的帖子投票。 - not_found: - other: 对象未找到。 - verification_failed: - other: 验证失败。 - email_or_password_incorrect: - other: 邮箱和密码不匹配。 - old_password_verification_failed: - other: 旧密码验证失败。 - new_password_same_as_previous_setting: - other: 新密码和旧密码相同。 - already_deleted: - other: 该帖子已被删除。 - meta: - object_not_found: - other: Meta 对象未找到 - question: - already_deleted: - other: 该帖子已被删除。 - under_review: - other: 您的帖子正在等待审核。它将在它获得批准后可见。 - not_found: - other: 问题未找到。 - cannot_deleted: - other: 没有删除权限。 - cannot_close: - other: 没有关闭权限。 - cannot_update: - other: 没有更新权限。 - rank: - fail_to_meet_the_condition: - other: 声望值未达到要求。 - vote_fail_to_meet_the_condition: - other: 感谢投票。你至少需要 {{.Rank}} 声望才能投票。 - no_enough_rank_to_operate: - other: 你至少需要 {{.Rank}} 声望才能执行此操作。 - report: - handle_failed: - other: 报告处理失败。 - not_found: - other: 报告未找到。 - tag: - already_exist: - other: 标签已存在。 - not_found: - other: 标签未找到。 - recommend_tag_not_found: - other: 推荐标签不存在。 - recommend_tag_enter: - other: 请选择至少一个必选标签。 - not_contain_synonym_tags: - other: 不应包含同义词标签。 - cannot_update: - other: 没有更新权限。 - is_used_cannot_delete: - other: 你不能删除这个正在使用的标签。 - cannot_set_synonym_as_itself: - other: 你不能将当前标签设为自己的同义词。 - smtp: - config_from_name_cannot_be_email: - other: 发件人名称不能是邮箱地址。 - theme: - not_found: - other: 主题未找到。 - revision: - review_underway: - other: 目前无法编辑,有一个版本在审阅队列中。 - no_permission: - other: 无权限修改。 - user: - external_login_missing_user_id: - other: 第三方平台没有提供唯一的 UserID,所以你不能登录,请联系网站管理员。 - external_login_unbinding_forbidden: - other: 请在移除此登录之前为你的账户设置登录密码。 - email_or_password_wrong: - other: - other: 邮箱和密码不匹配。 - not_found: - other: 用户未找到。 - suspended: - other: 用户已被封禁。 - username_invalid: - other: 用户名无效。 - username_duplicate: - other: 用户名已被使用。 - set_avatar: - other: 头像设置错误。 - cannot_update_your_role: - other: 你不能修改自己的角色。 - not_allowed_registration: - other: 该网站暂未开放注册。 - not_allowed_login_via_password: - other: 该网站暂不支持密码登录。 - access_denied: - other: 拒绝访问 - page_access_denied: - other: 您没有权限访问此页面。 - add_bulk_users_format_error: - other: "发生错误,{{.Field}} 格式错误,在 '{{.Content}}' 行数 {{.Line}}. {{.ExtraMessage}}" - add_bulk_users_amount_error: - other: "一次性添加的用户数量应在 1-{{.MaxAmount}} 之间。" - config: - read_config_failed: - other: 读取配置失败 - database: - connection_failed: - other: 数据库连接失败 - create_table_failed: - other: 创建表失败 - install: - create_config_failed: - other: 无法创建 config.yaml 文件。 - upload: - unsupported_file_format: - other: 不支持的文件格式。 - site_info: - config_not_found: - other: 未找到网站的该配置信息。 - reason: - spam: - name: - other: 垃圾信息 - desc: - other: 这个帖子是一个广告,或是破坏性行为。它对当前的主题无帮助或无关。 - rude_or_abusive: - name: - other: 粗鲁或辱骂的 - desc: - other: - - 一个有理智的人都会认为这种内容不适合进行尊重性的讨论。 - - 论坛 - a_duplicate: - name: - other: 重复内容 - desc: - other: 该问题有人问过,而且已经有了答案。 - placeholder: - other: 输入已有的问题链接 - not_a_answer: - name: - other: 不是答案 - desc: - other: - - 这张贴作为答案,但它不会试图回答 - - 这可能是一个编辑、一个评论、另一个问题。 - - 或全部删除。 - no_longer_needed: - name: - other: 不再需要 - desc: - other: 该评论已过时,对话性质或与此帖子无关。 - something: - name: - other: 其他原因 - desc: - other: 此帖子需要工作人员注意,因为是上述所列以外的其他理由。 - placeholder: - other: 让我们具体知道你关心的什么 - community_specific: - name: - other: 社区特定原因 - desc: - other: 该问题不符合社区准则。 - not_clarity: - name: - other: 需要细节或澄清 - desc: - other: 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - looks_ok: - name: - other: 看起来没问题 - desc: - other: 这个帖子是好的,不是低质量。 - needs_edit: - name: - other: 需要编辑,我已做了修改。 - desc: - other: 改进和纠正你自己帖子中的问题。 - needs_close: - name: - other: 需要关闭 - desc: - other: 关闭的问题不能回答,但仍然可以编辑、投票和评论。 - needs_delete: - name: - other: 需要删除 - desc: - other: 该帖子将被删除。 - question: - close: - duplicate: - name: - other: 垃圾信息 - desc: - other: 此问题以前就有人问过,而且已经有了答案。 - guideline: - name: - other: 社区特定原因 - desc: - other: 该问题不符合社区准则。 - multiple: - name: - other: 需要细节或澄清 - desc: - other: - - 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - - 只关注一个问题。 - other: - name: - other: 其他原因 - desc: - other: 该帖子存在上面没有列出的另一个原因。 - operation_type: - asked: - other: 提问于 - answered: - other: 回答于 - modified: - other: 修改于 - deleted_title: - other: 删除的问题 - notification: - action: - update_question: - other: 更新了问题 - answer_the_question: - other: 回答了问题 - update_answer: - other: 更新了答案 - accept_answer: - other: 采纳了答案 - comment_question: - other: 评论了问题 - comment_answer: - other: 评论了答案 - reply_to_you: - other: 回复了你 - mention_you: - other: 提到了你 - your_question_is_closed: - other: 你的问题已被关闭 - your_question_was_deleted: - other: 你的问题已被删除 - your_answer_was_deleted: - other: 你的答案已被删除 - your_comment_was_deleted: - other: 你的评论已被删除 - up_voted_question: - other: 点赞问题 - down_voted_question: - other: 点踩问题 - up_voted_answer: - other: 点赞答案 - down_voted_answer: - other: 点踩回答 - up_voted_comment: - other: 点赞评论 - invited_you_to_answer: - other: 邀请你回答 - email_tpl: - change_email: - title: - other: "[{{.SiteName}}] 确认你的新邮箱地址" - body: - other: "请点击以下链接确认你在 {{.SiteName}} 上的新邮箱地址:
\n{{.ChangeEmailUrl}}

\n\n如果你没有请求此更改,请忽略此邮件。\n" - new_answer: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 回答了你的问题" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - invited_you_to_answer: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 邀请您回答问题" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
我想你可能知道答案。

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - new_comment: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 评论了你的帖子" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - new_question: - title: - other: "[{{.SiteName}}] 新问题: {{.QuestionTitle}}" - body: - other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\n取消订阅" - pass_reset: - title: - other: "[{{.SiteName }}] 重置密码" - body: - other: "有人要求在 [{{.SiteName}}] 上重置你的密码。

\n\n如果这不是你的操作,请安心忽略此电子邮件。

\n\n请点击以下链接设置一个新密码:
\n{{.PassResetUrl}}\n" - register: - title: - other: "[{{.SiteName}}] 确认你的新账户" - body: - other: "欢迎加入 {{.SiteName}}!

\n\n请点击以下链接确认并激活你的新账户:
\n{{.RegisterUrl}}

\n\n如果上面的链接不能点击,请将其复制并粘贴到你的浏览器地址栏中。\n" - test: - title: - other: "[{{.SiteName}}] 测试邮件" - body: - other: "这是一封测试邮件。" - action_activity_type: - upvote: - other: 点赞 - upvoted: - other: 点赞 - downvote: - other: 点踩 - downvoted: - other: 点踩 - accept: - other: 采纳 - accepted: - other: 已采纳 - edit: - other: 编辑 - review: - queued_post: - other: 排队的帖子 - flagged_post: - other: 举报的帖子 - suggested_post_edit: - other: 建议的编辑 - reaction: - tooltip: - other: "{{ .Names }} 以及另外 {{ .Count }} 个..." -plugin: - s3_cdn: - backend: - info: - name: - other: S3 存储 CDN - description: - other: 上传文件到S3存储 - config: - endpoint: - title: - other: Endpoint - description: - other: S3存储的Endpoint - bucket_name: - title: - other: Bucket名称 - description: - other: S3存储的Bucket名称 - object_key_prefix: - title: - other: 对象Key前缀 - description: - other: 对象键的前缀,如'answer/data/',以'/'结尾 - access_key_id: - title: - other: AccessKeyID - description: - other: S3存储的AccessKeyID - access_key_secret: - title: - other: AccessKeySecret - description: - other: S3存储的AccessKeySecret - access_token: - title: - other: AccessToken - description: - other: 访问 S3 所需的 AccessToken - visit_url_prefix: - title: - other: 访问URL前缀 - description: - other: 上传静态文件CDN最终访问地址的前缀,以 '/' 结尾 https://static.example.com/xxx/ - max_file_size: - title: - other: 文件最大大小(MB) - description: - other: 限制上传文件的最大大小,单位MB,默认为10MB - region: - title: - other: 区域(Region) - description: - other: S3存储区域 - disable_ssl: - title: - other: 禁用SSL - description: - other: 我们建议您使用SSL访问S3存储。如果您想禁用SSL,请选中此选项。 - err: - mis_storage_config: - other: 错误的存储配置导致上传失败 - file_not_found: - other: 文件未找到 - unsupported_file_type: - other: 不支持的文件类型 - over_file_size_limit: - other: 超过文件大小限制 - upload_file_failed: - other: 上传文件失败 - aliyunoss_cdn: - backend: - info: - name: - other: 阿里云CDN OSS存储 - description: - other: 上传文件到阿里云CDN OSS存储 - config: - endpoint: - title: - other: Endpoint - description: - other: 阿里云OSS存储的Endpoint - bucket_name: - title: - other: Bucket名称 - description: - other: 阿里云OSS存储的Bucket名称 - object_key_prefix: - title: - other: 对象Key前缀 - description: - other: 对象键的前缀,如'answer/data/',以'/'结尾 - access_key_id: - title: - other: AccessKeyID - description: - other: 阿里云OSS存储的AccessKeyID - access_key_secret: - title: - other: AccessKeySecret - description: - other: 阿里云OSS存储的AccessKeySecret - visit_url_prefix: - title: - other: 访问URL前缀 - description: - other: CDN最终访问地址的前缀,以 '/' 结尾 https://example.com/xxx/ - max_file_size: - title: - other: 最大文件大小(MB) - description: - other: 限制上传文件的最大大小,单位为MB,默认为 10MB - err: - mis_storage_config: - other: 错误的存储配置导致上传失败 - file_not_found: - other: 文件未找到 - unsupported_file_type: - other: 不支持的文件类型 - over_file_size_limit: - other: 超过文件大小限制 - upload_file_failed: - other: 上传文件失败 -# The following fields are used for interface presentation(Front-end) -ui: - how_to_format: - title: 如何排版 - desc: >- -
  • 添加链接

    <https://url.com>

    [标题](https://url.com)
  • 段落之间使用空行分隔

  • _斜体_ 或者 **粗体**

  • 使用 4 个空格缩进代码

  • 在行首添加 > 表示引用

  • 反引号进行转义 `像 _这样_`

  • 使用 ``` 创建代码块

    ```
    这是代码块
    ```
- pagination: - prev: 上一页 - next: 下一页 - page_title: - question: 问题 - questions: 问题 - tag: 标签 - tags: 标签 - tag_wiki: 标签维基 - create_tag: 创建标签 - edit_tag: 编辑标签 - ask_a_question: 提问题 - edit_question: 编辑问题 - edit_answer: 编辑回答 - search: 搜索 - posts_containing: 帖子包含 - settings: 设置 - notifications: 通知 - login: 登录 - sign_up: 注册 - account_recovery: 账号恢复 - account_activation: 账号激活 - confirm_email: 确认电子邮件 - account_suspended: 账号已被封禁 - admin: 后台管理 - change_email: 修改邮箱 - install: Answer 安装 - upgrade: Answer 升级 - maintenance: 网站维护 - users: 用户 - oauth_callback: 处理中 - http_404: HTTP 错误 404 - http_50X: HTTP 错误 500 - http_403: HTTP 错误 403 - logout: 退出 - notifications: - title: 通知 - inbox: 收件箱 - achievement: 成就 - new_alerts: 新通知 - all_read: 全部标记为已读 - show_more: 显示更多 - someone: 有人 - inbox_type: - all: 全部 - posts: 帖子 - invites: 邀请 - votes: 投票 - suspended: - title: 你的账号账号已被封禁 - until_time: "你的账号被封禁直到 {{ time }}。" - forever: 你的账号已被永久封禁。 - end: 你违反了我们的社区准则。 - contact_us: 联系我们 - editor: - blockquote: - text: 引用 - bold: - text: 粗体 - chart: - text: 图表 - flow_chart: 流程图 - sequence_diagram: 时序图 - class_diagram: 类图 - state_diagram: 状态图 - entity_relationship_diagram: 实体关系图 - user_defined_diagram: 用户自定义图表 - gantt_chart: 甘特图 - pie_chart: 饼图 - code: - text: 代码块 - add_code: 添加代码块 - form: - fields: - code: - label: 代码块 - msg: - empty: 代码块不能为空 - language: - label: 语言 - placeholder: 自动识别 - btn_cancel: 取消 - btn_confirm: 添加 - formula: - text: 公式 - options: - inline: 行内公式 - block: 块级公式 - heading: - text: 标题 - options: - h1: 标题 1 - h2: 标题 2 - h3: 标题 3 - h4: 标题 4 - h5: 标题 5 - h6: 标题 6 - help: - text: 帮助 - hr: - text: 水平线 - image: - text: 图片 - add_image: 添加图片 - tab_image: 上传图片 - form_image: - fields: - file: - label: 图像文件 - btn: 选择图片 - msg: - empty: 请选择图片文件。 - only_image: 只能上传图片文件。 - max_size: 文件大小不能超过 4 MB。 - desc: - label: 描述 - tab_url: 图片地址 - form_url: - fields: - url: - label: 图片地址 - msg: - empty: 图片地址不能为空 - name: - label: 描述 - btn_cancel: 取消 - btn_confirm: 添加 - uploading: 上传中 - indent: - text: 缩进 - outdent: - text: 减少缩进 - italic: - text: 斜体 - link: - text: 超链接 - add_link: 添加超链接 - form: - fields: - url: - label: 链接 - msg: - empty: 链接不能为空。 - name: - label: 描述 - btn_cancel: 取消 - btn_confirm: 添加 - ordered_list: - text: 有序列表 - unordered_list: - text: 无序列表 - table: - text: 表格 - heading: 表头 - cell: 单元格 - close_modal: - title: 关闭原因是... - btn_cancel: 取消 - btn_submit: 提交 - remark: - empty: 不能为空。 - msg: - empty: 请选择一个原因。 - report_modal: - flag_title: 我举报这篇帖子的原因是... - close_title: 我关闭这篇帖子的原因是... - review_question_title: 审查问题 - review_answer_title: 审查回答 - review_comment_title: 审查评论 - btn_cancel: 取消 - btn_submit: 提交 - remark: - empty: 不能为空 - msg: - empty: 请选择一个原因。 - not_a_url: URL 格式不正确。 - url_not_match: URL 来源与当前网站不匹配。 - tag_modal: - title: 创建新标签 - form: - fields: - display_name: - label: 显示名称 - msg: - empty: 显示名称不能为空。 - range: 显示名称不能超过 35 个字符。 - slug_name: - label: URL 固定链接 - desc: URL 固定链接不能超过 35 个字符。 - msg: - empty: URL 固定链接不能为空。 - range: URL 固定链接不能超过 35 个字符。 - character: URL 固定链接包含非法字符。 - desc: - label: 描述 - revision: - label: 编辑历史 - edit_summary: - label: 编辑备注 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_cancel: 取消 - btn_submit: 提交 - btn_post: 发布新标签 - tag_info: - created_at: 创建于 - edited_at: 编辑于 - history: 历史 - synonyms: - title: 同义词 - text: 以下标签将被重置到 - empty: 此标签目前没有同义词。 - btn_add: 添加同义词 - btn_edit: 编辑 - btn_save: 保存 - synonyms_text: 以下标签将被重置到 - delete: - title: 删除标签 - tip_with_posts: >- -

我们不允许 删除带有帖子的标签

请先从帖子中移除此标签。

- tip_with_synonyms: >- -

我们不允许 删除带有同义词的标签

请先从此标签中删除同义词。

- tip: 确定要删除吗? - close: 关闭 - edit_tag: - title: 编辑标签 - default_reason: 编辑标签 - default_first_reason: 添加标签 - btn_save_edits: 保存更改 - btn_cancel: 取消 - dates: - long_date: MM 月 DD 日 - long_date_with_year: "YYYY 年 MM 月 DD 日" - long_date_with_time: "YYYY 年 MM 月 DD 日 HH:mm" - now: 刚刚 - x_seconds_ago: "{{count}} 秒前" - x_minutes_ago: "{{count}} 分钟前" - x_hours_ago: "{{count}} 小时前" - hour: 小时 - day: 天 - hours: 小时 - days: 日 - reaction: - heart: 爱心 - smile: 微笑 - frown: 愁 - btn_label: 添加或删除回应。 - undo_emoji: 撤销 {{ emoji }} 回应 - react_emoji: 用 {{ emoji }} 回应 - unreact_emoji: 撤销 {{ emoji }} - comment: - btn_add_comment: 添加评论 - reply_to: 回复 - btn_reply: 回复 - btn_edit: 编辑 - btn_delete: 删除 - btn_flag: 举报 - btn_save_edits: 保存更改 - btn_cancel: 取消 - show_more: "{{count}} 条剩余评论" - tip_question: >- - 使用评论提问更多信息或者提出改进意见。避免在评论里回答问题。 - tip_answer: >- - 使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。 - tip_vote: 它给帖子添加了一些有用的内容 - edit_answer: - title: 编辑回答 - default_reason: 编辑回答 - default_first_reason: 添加答案 - form: - fields: - revision: - label: 编辑历史 - answer: - label: 回答内容 - feedback: - characters: 内容长度至少 6 个字符 - edit_summary: - label: 编辑摘要 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_save_edits: 保存更改 - btn_cancel: 取消 - tags: - title: 标签 - sort_buttons: - popular: 热门 - name: 名称 - newest: 最新 - button_follow: 关注 - button_following: 已关注 - tag_label: 个问题 - search_placeholder: 通过标签名称过滤 - no_desc: 此标签无描述。 - more: 更多 - ask: - title: 新增问题 - edit_title: 编辑问题 - default_reason: 编辑问题 - default_first_reason: 新增问题 - similar_questions: 相似问题 - form: - fields: - revision: - label: 修订版本 - title: - label: 标题 - placeholder: 请详细描述你的问题,想象你在问一个人 - msg: - empty: 标题不能为空。 - range: 标题最多 150 个字符 - body: - label: 内容 - msg: - empty: 内容不能为空。 - tags: - label: 标签 - msg: - empty: 必须选择一个标签 - answer: - label: 回答内容 - msg: - empty: 回答内容不能为空 - edit_summary: - label: 编辑备注 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_post_question: 提交问题 - btn_save_edits: 保存更改 - answer_question: 回答自己的问题 - post_question&answer: 提交问题和回答 - tag_selector: - add_btn: 添加标签 - create_btn: 创建新标签 - search_tag: 搜索标签 - hint: "描述您的问题是关于什么,至少需要一个标签。" - no_result: 没有匹配的标签 - tag_required_text: 必选标签(至少一个) - header: - nav: - question: 问题 - tag: 标签 - user: 用户 - profile: 用户主页 - setting: 账号设置 - logout: 退出 - admin: 后台管理 - review: 审查 - bookmark: 收藏夹 - moderation: 管理 - search: - placeholder: 搜索 - footer: - build_on: >- - 由 <1>Apache Answer 提供动力 - 驱动问答社区的开源软件。
用爱制造 © {{cc}}. - upload_img: - name: 更改 - loading: 加载中... - pic_auth_code: - title: 验证码 - placeholder: 输入图片中的文字 - msg: - empty: 验证码不能为空。 - inactive: - first: >- - 就差一步!我们发送了一封激活邮件到 {{mail}}。请按照邮件中的说明激活你的账户。 - info: "如果没有收到,请检查你的垃圾邮件文件夹。" - another: >- - 我们向你的邮箱 {{mail}} 发送了另一封激活电子邮件。可能需要几分钟才能到达;请务必检查您的垃圾邮件箱。 - btn_name: 重新发送激活邮件 - change_btn_name: 更改邮箱 - msg: - empty: 不能为空。 - resend_email: - url_label: 确定要重新发送激活邮件吗? - url_text: 你也可以将上面的激活链接给该用户。 - login: - login_to_continue: 登录以继续 - info_sign: 没有账户?<1>注册 - info_login: 已经有账户?<1>登录 - agreements: 登录即表示您同意<1>隐私政策和<3>服务条款。 - forgot_pass: 忘记密码? - name: - label: 名字 - msg: - empty: 名字不能为空 - range: 名字应该在 4 到 30 个字符之间 - character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' - email: - label: 邮箱 - msg: - empty: 邮箱不能为空 - password: - label: 密码 - msg: - empty: 密码不能为空 - different: 两次输入密码不一致 - account_forgot: - page_title: 忘记密码 - btn_name: 发送恢复邮件 - send_success: >- - 如果存在邮箱为 {{mail}} 账户,你将很快收到一封重置密码的说明邮件。 - email: - label: 邮箱 - msg: - empty: 邮箱不能为空 - change_email: - btn_cancel: 取消 - btn_update: 更新电子邮件地址 - send_success: >- - 如果存在邮箱为 {{mail}} 的账户,你将很快收到一封重置密码的说明邮件。 - email: - label: 新的电子邮件地址 - msg: - empty: 邮箱不能为空。 - oauth: - connect: 连接到 {{ auth_name }} - remove: 移除 {{ auth_name }} - oauth_bind_email: - subtitle: 向你的账户添加恢复邮件地址。 - btn_update: 更新电子邮件地址 - email: - label: 邮箱 - msg: - empty: 邮箱不能为空。 - modal_title: 邮箱已经存在。 - modal_content: 该电子邮件地址已经注册。你确定要连接到已有账户吗? - modal_cancel: 更改邮箱 - modal_confirm: 连接到已有账户 - password_reset: - page_title: 密码重置 - btn_name: 重置我的密码 - reset_success: >- - 你已经成功更改密码;你将被重定向到登录页面。 - link_invalid: >- - 抱歉,此密码重置链接已失效。也许是你已经重置过密码了? - to_login: 前往登录页面 - password: - label: 密码 - msg: - empty: 密码不能为空。 - length: 密码长度在8-32个字符之间 - different: 两次输入密码不一致 - password_confirm: - label: 确认新密码 - settings: - page_title: 设置 - goto_modify: 前往修改 - nav: - profile: 我的资料 - notification: 通知 - account: 账号 - interface: 界面 - profile: - heading: 个人资料 - btn_name: 保存 - display_name: - label: 显示名称 - msg: 昵称不能为空。 - msg_range: 显示名称不能超过 30 个字符。 - username: - label: 用户名 - caption: 用户可以通过 "@用户名" 来提及你。 - msg: 用户名不能为空 - msg_range: 用户名不能超过 30 个字符。 - character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' - avatar: - label: 头像 - gravatar: Gravatar - gravatar_text: 你可以更改图像在 - custom: 自定义 - custom_text: 你可以上传你的图片。 - default: 系统 - msg: 请上传头像 - bio: - label: 关于我 - website: - label: 网站 - placeholder: "https://example.com" - msg: 网址格式不正确 - location: - label: 位置 - placeholder: "城市,国家" - notification: - heading: 邮件通知 - turn_on: 开启 - inbox: - label: 收件箱通知 - description: 你的提问有新的回答,评论,邀请回答和其他。 - all_new_question: - label: 所有新问题 - description: 获取所有新问题的通知。每周最多有50个问题。 - all_new_question_for_following_tags: - label: 所有关注标签的新问题 - description: 获取关注的标签下新问题通知。 - account: - heading: 账号 - change_email_btn: 更改邮箱 - change_pass_btn: 更改密码 - change_email_info: >- - 邮件已发送。请根据指引完成验证。 - email: - label: 电子邮件地址 - new_email: - label: 新的电子邮件地址 - msg: 新邮箱不能为空。 - pass: - label: 当前密码 - msg: 密码不能为空。 - password_title: 密码 - current_pass: - label: 当前密码 - msg: - empty: 当前密码不能为空 - length: 密码长度必须在 8 至 32 之间 - different: 两次输入的密码不匹配 - new_pass: - label: 新密码 - pass_confirm: - label: 确认新密码 - interface: - heading: 界面 - lang: - label: 界面语言 - text: 设置用户界面语言,在刷新页面后生效。 - my_logins: - title: 我的登录 - label: 使用这些账户登录或注册本网站。 - modal_title: 移除登录 - modal_content: 你确定要从账户里移除该登录? - modal_confirm_btn: 移除 - remove_success: 移除成功 - toast: - update: 更新成功 - update_password: 密码更新成功。 - flag_success: 感谢标记。 - forbidden_operate_self: 禁止对自己执行操作 - review: 您的修订将在审阅通过后显示。 - sent_success: 发送成功 - related_question: - title: 相关问题 - answers: 个回答 - invite_to_answer: - title: 受邀人 - desc: 邀请你认为可能知道答案的人。 - invite: 邀请回答 - add: 添加人员 - search: 搜索人员 - question_detail: - action: 操作 - Asked: 提问于 - asked: 提问于 - update: 修改于 - edit: 编辑于 - commented: 评论 - Views: 阅读次数 - Follow: 关注此问题 - Following: 已关注 - follow_tip: 关注此问题以接收通知 - answered: 回答于 - closed_in: 关闭于 - show_exist: 查看类似问题。 - useful: 有用的 - question_useful: 它是有用和明确的 - question_un_useful: 它不明确或没用的 - question_bookmark: 收藏该问题 - answer_useful: 这是有用的 - answer_un_useful: 它是没有用的 - answers: - title: 个回答 - score: 评分 - newest: 最新 - oldest: 最旧 - btn_accept: 采纳 - btn_accepted: 已被采纳 - write_answer: - title: 你的回答 - edit_answer: 编辑我的回答 - btn_name: 提交你的回答 - add_another_answer: 添加另一个回答 - confirm_title: 继续回答 - continue: 继续 - confirm_info: >- -

你确定要提交一个新的回答吗?

作为替代,你可以通过编辑来完善和改进之前的回答。

- empty: 回答内容不能为空。 - characters: 内容长度至少 6 个字符。 - tips: - header_1: 感谢你的回答 - li1_1: 请务必确定在 回答问题。提供详细信息并分享你的研究。 - li1_2: 用参考资料或个人经历来支持你所做的任何陈述。 - header_2: 但是 请避免... - li2_1: 请求帮助,寻求澄清,或答复其他答案。 - reopen: - confirm_btn: 重新打开 - title: 重新打开这个帖子 - content: 确定要重新打开吗? - list: - confirm_btn: 列表显示 - title: 列表中显示这个帖子 - content: 确定要列表中显示这个帖子吗? - unlist: - confirm_btn: 列表隐藏 - title: 从列表中隐藏这个帖子 - content: 确定要从列表中隐藏这个帖子吗? - pin: - title: 置顶该帖子 - content: 你确定要全局置顶吗?这个帖子将出现在所有帖子列表的顶部。 - confirm_btn: 置顶 - delete: - title: 删除 - question: >- - 我们不建议 删除有回答的帖子。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗? - answer_accepted: >- -

我们不建议删除被采纳的回答。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗? - other: 你确定要删除? - tip_answer_deleted: 该回答已被删除 - undelete_title: 撤销删除本帖 - undelete_desc: 你确定你要撤销删除吗? - btns: - confirm: 确认 - cancel: 取消 - edit: 编辑 - save: 保存 - delete: 删除 - undelete: 撤消删除 - list: 列表显示 - unlist: 列表隐藏 - unlisted: 已隐藏 - login: 登录 - signup: 注册 - logout: 退出 - verify: 验证 - add_question: 我要提问 - approve: 批准 - reject: 拒绝 - skip: 跳过 - discard_draft: 丢弃草稿 - pinned: 已置顶 - all: 全部 - question: 问题 - answer: 回答 - comment: 评论 - refresh: 刷新 - resend: 重新发送 - deactivate: 取消激活 - active: 激活 - suspend: 封禁 - unsuspend: 解禁 - close: 关闭 - reopen: 重新打开 - ok: 确定 - light: 浅色 - dark: 深色 - system_setting: 跟随系统 - default: 默认 - reset: 重置 - tag: 标签 - post_lowercase: 帖子 - filter: 筛选 - ignore: 忽略 - submit: 提交 - normal: 正常 - closed: 已关闭 - deleted: 已删除 - pending: 等待处理 - more: 更多 - search: - title: 搜索结果 - keywords: 关键词 - options: 选项 - follow: 关注 - following: 已关注 - counts: "{{count}} 个结果" - more: 更多 - sort_btns: - relevance: 相关性 - newest: 最新的 - active: 活跃的 - score: 评分 - more: 更多 - tips: - title: 高级搜索提示 - tag: "<1>[tag] 在指定标签中搜索" - user: "<1>user:username 根据作者搜索" - answer: "<1>answers:0 搜索未回答的问题" - score: "<1>score:3 评分 3+ 的帖子" - question: "<1>is:question 搜索问题" - is_answer: "<1>is:answer 搜索回答" - empty: 找不到任何相关的内容。
请尝试其他关键字,或者减少查找内容的长度。 - share: - name: 分享 - copy: 复制链接 - via: 分享到... - copied: 已复制 - facebook: 分享到 Facebook - twitter: 分享到 Twitter - cannot_vote_for_self: 你不能给自己的帖子投票。 - modal_confirm: - title: 发生错误... - account_result: - success: 你的账号已通过验证,即将返回首页。 - link: 返回首页 - invalid: >- - 抱歉,此验证链接已失效。也许你的账号已经激活了? - confirm_new_email: 你的电子邮箱已更新 - confirm_new_email_invalid: >- - 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了? - unsubscribe: - page_title: 退订 - success_title: 退订成功 - success_desc: 您已成功退订,并且将不会再收到我们的邮件。 - link: 更改设置 - question: - following_tags: 已关注的标签 - edit: 编辑 - save: 保存 - follow_tag_tip: 关注标签来筛选你的问题列表。 - hot_questions: 热门问题 - all_questions: 全部问题 - x_questions: "{{ count }} 个问题" - x_answers: "{{ count }} 个回答" - questions: 问题 - answers: 回答 - newest: 最新 - active: 活跃 - hot: 热门 - score: 评分 - unanswered: 未回答 - modified: 更新于 - answered: 回答于 - asked: 提问于 - closed: 已关闭 - follow_a_tag: 关注一个标签 - more: 更多 - personal: - overview: 概览 - answers: 回答 - answer: 回答 - questions: 问题 - question: 问题 - bookmarks: 收藏 - reputation: 声望 - comments: 评论 - votes: 得票 - newest: 最新 - score: 评分 - edit_profile: 编辑资料 - visited_x_days: "已访问 {{ count }} 天" - viewed: 浏览次数 - joined: 加入于 - last_login: 上次登录 - about_me: 关于我 - about_me_empty: "// Hello, World!" - top_answers: 高分回答 - top_questions: 高分问题 - stats: 状态 - list_empty: 没有找到相关的内容。
试试看其他选项卡? - accepted: 已采纳 - answered: 回答于 - asked: 提问于 - downvoted: 点踩 - mod_short: 版主 - mod_long: 版主 - x_reputation: 声望 - x_votes: 得票 - x_answers: 个回答 - x_questions: 个问题 - install: - title: 安装 - next: 下一步 - done: 完成 - config_yaml_error: 无法创建 config.yaml 文件。 - lang: - label: 请选择一种语言 - db_type: - label: 数据库引擎 - db_username: - label: 用户名 - placeholder: root - msg: 用户名不能为空 - db_password: - label: 密码 - placeholder: root - msg: 密码不能为空 - db_host: - label: 数据库主机 - placeholder: "db:3306" - msg: 数据库地址不能为空 - db_name: - label: 数据库名 - placeholder: 回答 - msg: 数据库名称不能为空。 - db_file: - label: 数据库文件 - placeholder: /data/answer.db - msg: 数据库文件不能为空。 - config_yaml: - title: 创建 config.yaml - label: 已创建 config.yaml 文件。 - desc: >- - 你可以手动在 <1>/var/wwww/xxx/ 目录中创建 <1>config.yaml 文件并粘贴以下文本。 - info: 完成后,点击“下一步”按钮。 - site_information: 站点信息 - admin_account: 管理员账号 - site_name: - label: 站点名称 - msg: 站点名称不能为空。 - msg_max_length: 站点名称长度不得超过 30 个字符。 - site_url: - label: 网站网址 - text: 此网站的网址。 - msg: - empty: 网址不能为空。 - incorrect: 网址格式不正确。 - max_length: 网址长度不得超过 512 个字符。 - contact_email: - label: 联系邮箱 - text: 负责本网站的主要联系人的电子邮件地址。 - msg: - empty: 联系人邮箱不能为空。 - incorrect: 联系人邮箱地址不正确。 - login_required: - label: 私有的 - switch: 需要登录 - text: 只有登录用户才能访问这个社区。 - admin_name: - label: 名字 - msg: 名字不能为空。 - character: '只能由 "a-z", "0-9", " - . _" 组成' - msg_max_length: 名字长度不能超过 30 个字符。 - admin_password: - label: 密码 - text: >- - 您需要此密码才能登录。请将其存储在一个安全的位置。 - msg: 密码不能为空。 - msg_min_length: 密码必须至少 8 个字符长。 - msg_max_length: 密码长度不能超过 32 个字符。 - admin_email: - label: 邮箱 - text: 您需要此电子邮件才能登录。 - msg: - empty: 邮箱不能为空。 - incorrect: 邮箱格式不正确。 - ready_title: 您的网站已准备好 - ready_desc: >- - 如果你想改变更多的设置,请访问 <1>管理区域;在网站菜单中找到它。 - good_luck: "玩得愉快,祝你好运!" - warn_title: 警告 - warn_desc: >- - 文件 <1>config.yaml 已存在。如果你要重置该文件中的任何配置项,请先删除它。 - install_now: 您可以尝试 <1>现在安装。 - installed: 已安裝 - installed_desc: >- - 你似乎已经安装过了。如果要重新安装,请先清除旧的数据库表。 - db_failed: 数据连接异常! - db_failed_desc: >- - 这或者意味着数据库信息在 <1>config.yaml 文件不正确,或者无法与数据库服务器建立联系。这可能意味着你的主机数据库服务器故障。 - counts: - views: 次浏览 - votes: 个点赞 - answers: 个回答 - accepted: 已被采纳 - page_error: - http_error: HTTP 错误 {{ code }} - desc_403: 您无权访问此页面。 - desc_404: 很抱歉,此页面不存在。 - desc_50X: 服务器遇到了一个错误,无法完成你的请求。 - back_home: 返回首页 - page_maintenance: - desc: "我们正在进行维护,我们将很快回来。" - nav_menus: - dashboard: 后台管理 - contents: 内容管理 - questions: 问题 - answers: 回答 - users: 用户管理 - flags: 举报管理 - settings: 站点设置 - general: 一般 - interface: 界面 - smtp: SMTP - branding: 品牌 - legal: 法律条款 - write: 撰写 - tos: 服务条款 - privacy: 隐私政策 - seo: SEO - customize: 自定义 - themes: 主题 - css_html: CSS/HTML - login: 登录 - privileges: 特权 - plugins: 插件 - installed_plugins: 已安装插件 - website_welcome: 欢迎来到 {{site_name}} - user_center: - login: 登录 - qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码并登录。 - login_failed_email_tip: 登录失败,请允许此应用访问您的邮箱信息,然后重试。 - admin: - admin_header: - title: 后台管理 - dashboard: - title: 后台管理 - welcome: 欢迎来到管理后台! - site_statistics: 站点统计 - questions: "问题:" - answers: "回答:" - comments: "评论:" - votes: "投票:" - users: "用户:" - flags: "举报:" - reviews: "审查:" - site_health: 网站健康 - version: "版本" - https: "HTTPS:" - upload_folder: "上传文件夹:" - run_mode: "运行模式:" - private: 私有 - public: 公开 - smtp: "SMTP:" - timezone: "时区:" - system_info: 系统信息 - go_version: "Go版本:" - database: "数据库:" - database_size: "数据库大小:" - storage_used: "已用存储空间:" - uptime: "运行时间:" - links: 链接 - plugins: 插件 - github: GitHub - blog: 博客 - contact: 联系 - forum: 论坛 - documents: 文档 - feedback: 用户反馈 - support: 帮助 - review: 审查 - config: 配置 - update_to: 更新到 - latest: 最新版本 - check_failed: 校验失败 - "yes": "是" - "no": "否" - not_allowed: 拒绝 - allowed: 允许 - enabled: 已启用 - disabled: 停用 - writable: 可写 - not_writable: 不可写 - flags: - title: 举报 - pending: 等待处理 - completed: 已完成 - flagged: 被举报内容 - flagged_type: 标记了 {{ type }} - created: 创建于 - action: 操作 - review: 审查 - user_role_modal: - title: 更改用户状态为... - btn_cancel: 取消 - btn_submit: 提交 - new_password_modal: - title: 设置新密码 - form: - fields: - password: - label: 密码 - text: 用户将被退出,需要再次登录。 - msg: 密码的长度必须是8-32个字符。 - btn_cancel: 取消 - btn_submit: 提交 - edit_profile_modal: - title: 编辑资料 - form: - fields: - username: - label: 用户名 - msg_range: 用户名不能超过 30 个字符。 - email: - label: 电子邮件地址 - msg_invalid: 无效的邮箱地址 - edit_success: 修改成功 - btn_cancel: 取消 - btn_submit: 提交 - user_modal: - title: 添加新用户 - form: - fields: - users: - label: 批量添加用户 - placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" - text: 用逗号分隔“name, email, password”,每行一个用户。 - msg: "请输入用户的邮箱,每行一个。" - display_name: - label: 显示名称 - msg: 显示名称长度必须为 4-30 个字符 - email: - label: 邮箱 - msg: 邮箱无效。 - password: - label: 密码 - msg: 密码的长度必须是8-32个字符。 - btn_cancel: 取消 - btn_submit: 提交 - users: - title: 用户 - name: 名称 - email: 邮箱 - reputation: 声望 - created_at: 创建时间 - delete_at: 删除时间 - suspend_at: 封禁时间 - status: 状态 - role: 角色 - action: 操作 - change: 更改 - all: 全部 - staff: 工作人员 - more: 更多 - inactive: 不活跃 - suspended: 已封禁 - deleted: 已删除 - normal: 正常 - Moderator: 版主 - Admin: 管理员 - User: 用户 - filter: - placeholder: "按名称筛选,用户:id" - set_new_password: 设置新密码 - edit_profile: 编辑资料 - change_status: 更改状态 - change_role: 更改角色 - show_logs: 显示日志 - add_user: 添加用户 - deactivate_user: - title: 停用用户 - content: 未激活的用户必须重新验证他们的邮箱。 - delete_user: - title: 删除此用户 - content: 确定要删除此用户?此操作无法撤销! - remove: 移除内容 - label: 删除所有问题、 答案、 评论等 - text: 如果你只想删除用户账户,请不要选中此项。 - suspend_user: - title: 挂起此用户 - content: 被封禁的用户将无法登录。 - questions: - page_title: 问题 - unlisted: 已隐藏 - post: 标题 - votes: 得票数 - answers: 回答数 - created: 创建于 - status: 状态 - action: 操作 - change: 更改 - pending: 等待处理 - filter: - placeholder: "按标题过滤,问题:id" - answers: - page_title: 回答 - post: 标题 - votes: 得票数 - created: 创建于 - status: 状态 - action: 操作 - change: 更改 - filter: - placeholder: "按标题筛选,答案:id" - general: - page_title: 一般 - name: - label: 站点名称 - msg: 不能为空 - text: "站点的名称,作为站点的标题。" - site_url: - label: 网站网址 - msg: 网站网址不能为空。 - validate: 请输入一个有效的 URL。 - text: 此网站的地址。 - short_desc: - label: 简短站点描述 - msg: 简短网站描述不能为空。 - text: "简短的标语,作为网站主页的标题(Html 的 title 标签)。" - desc: - label: 站点描述 - msg: 网站描述不能为空。 - text: "使用一句话描述本站,作为网站的描述(Html 的 meta 标签)。" - contact_email: - label: 联系邮箱 - msg: 联系人邮箱不能为空。 - validate: 联系人邮箱无效。 - text: 本网站的主要联系邮箱地址。 - check_update: - label: 软件更新 - text: 自动检查软件更新 - interface: - page_title: 界面 - language: - label: 界面语言 - msg: 不能为空 - text: 设置用户界面语言,在刷新页面后生效。 - time_zone: - label: 时区 - msg: 时区不能为空。 - text: 选择一个与您相同时区的城市。 - smtp: - page_title: SMTP - from_email: - label: 发件人邮箱 - msg: 发件人邮箱不能为空。 - text: 用于发送邮件的地址。 - from_name: - label: 发件人 - msg: 不能为空 - text: 发件人的名字。 - smtp_host: - label: SMTP 主机 - msg: 不能为空 - text: 邮件服务器 - encryption: - label: 加密 - msg: 不能为空 - text: 对于大多数服务器而言,SSL 是推荐开启的。 - ssl: SSL - tls: TLS - none: 无加密 - smtp_port: - label: SMTP 端口 - msg: SMTP 端口必须在 1 ~ 65535 之间。 - text: 邮件服务器的端口号。 - smtp_username: - label: SMTP 用户名 - msg: 不能为空 - smtp_password: - label: SMTP 密码 - msg: 不能为空 - test_email_recipient: - label: 测试收件邮箱 - text: 提供用于接收测试邮件的邮箱地址。 - msg: 测试收件邮箱无效 - smtp_authentication: - label: 启用身份验证 - title: SMTP 身份验证 - msg: 不能为空 - "yes": "是" - "no": "否" - branding: - page_title: 品牌 - logo: - label: 网站标志(Logo) - msg: 图标不能为空。 - text: 在你的网站左上方的Logo图标。使用一个高度为56,长宽比大于3:1的宽长方形图像。如果留空,将显示网站标题文本。 - mobile_logo: - label: 移动端 Logo - text: 在你的网站的移动版上使用的标志。使用一个高度为56的宽矩形图像。如果留空,将使用 "Logo"设置中的图像。 - square_icon: - label: 方形图标 - msg: 方形图标不能为空。 - text: 用作元数据图标的基础的图像。最好是大于512x512。 - favicon: - label: 收藏夹图标 - text: 网站的图标。要在 CDN 正常工作,它必须是 png。 将调整大小到32x32。如果留空,将使用“方形图标”。 - legal: - page_title: 法律条款 - terms_of_service: - label: 服务条款 - text: "您可以在此添加服务内容的条款。如果您已经在别处托管了文档,请在这里提供完整的URL。" - privacy_policy: - label: 隐私政策 - text: "您可以在此添加隐私政策内容。如果您已经在别处托管了文档,请在这里提供完整的URL。" - write: - page_title: 编辑 - restrict_answer: - title: 限制一个回答 - label: 每个用户对于每个问题只能有一个回答 - text: "用户可以使用编辑按钮优化已有的回答" - recommend_tags: - label: 推荐标签 - text: "请在上方输入标签固定链接,每行一个标签。" - required_tag: - title: 必需的标签 - label: 根据需要设置推荐标签 - text: "每个新问题必须至少有一个推荐标签。" - reserved_tags: - label: 保留标签 - text: "保留的标签只能由版主添加到一个帖子中。" - seo: - page_title: 搜索引擎优化 - permalink: - label: 固定链接 - text: 自定义URL结构可以提高可用性,以及你的链接的向前兼容性。 - robots: - label: robots.txt - text: 这将永久覆盖任何相关的网站设置。 - themes: - page_title: 主题 - themes: - label: 主题 - text: 选择一个现有主题。 - color_scheme: - label: 配色方案 - navbar_style: - label: 导航栏样式 - primary_color: - label: 主色调 - text: 修改您主题使用的颜色 - css_and_html: - page_title: CSS 与 HTML - custom_css: - label: 自定义 CSS - text: > - - head: - label: 头部 - text: > - - header: - label: 页眉 - text: > - - footer: - label: 页脚 - text: 这将在 之前插入. - sidebar: - label: 侧边栏 - text: 这将插入侧边栏中。 - login: - page_title: 登录 - membership: - title: 会员 - label: 允许新注册 - text: 关闭以防止任何人创建新账户。 - email_registration: - title: 邮箱注册 - label: 允许邮箱注册 - text: 关闭以阻止任何人通过邮箱创建新账户。 - allowed_email_domains: - title: 允许的邮箱域 - text: 允许注册账户的邮箱域。每行一个域名。留空时忽略。 - private: - title: 非公开的 - label: 需要登录 - text: 只有登录用户才能访问这个社区。 - password_login: - title: 密码登录 - label: 允许使用邮箱和密码登录 - text: "警告:如果您未配置过其他登录方式,关闭密码登录后您则可能无法登录。" - installed_plugins: - title: 已安装插件 - plugin_link: 插件扩展功能。您可以在<1>插件仓库中找到插件。 - filter: - all: 全部 - active: 已启用 - inactive: 未启用 - outdated: 已过期 - plugins: - label: 插件 - text: 选择一个现有的插件。 - name: 名称 - version: 版本 - status: 状态 - action: 操作 - deactivate: 停用 - activate: 启用 - settings: 设置 - settings_users: - title: 用户 - avatar: - label: 默认头像 - text: 没有自定义头像的用户。 - gravatar_base_url: - label: Gravatar 根路径 URL - text: Gravatar 提供商的 API 基础的 URL。当为空时忽略。 - profile_editable: - title: 个人资料可编辑 - allow_update_display_name: - label: 允许用户修改显示名称 - allow_update_username: - label: 允许用户修改用户名 - allow_update_avatar: - label: 允许用户修改个人头像 - allow_update_bio: - label: 允许用户修改个人介绍 - allow_update_website: - label: 允许用户修改个人主页网址 - allow_update_location: - label: 允许用户更改位置 - privilege: - title: 特权 - level: - label: 级别所需声望 - text: 选择特权所需的声望值 - msg: - should_be_number: 输入必须是数字 - number_larger_1: 数字应该大于等于 1 - form: - optional: (选填) - empty: 不能为空 - invalid: 是无效的 - btn_submit: 保存 - not_found_props: "所需属性 {{ key }} 未找到。" - select: 选择 - page_review: - review: 评论 - proposed: 提案 - question_edit: 问题编辑 - answer_edit: 回答编辑 - tag_edit: '标签管理: 编辑标签' - edit_summary: 编辑备注 - edit_question: 编辑问题 - edit_answer: 编辑回答 - edit_tag: 编辑标签 - empty: 没有剩余的审核任务。 - approve_revision_tip: 您是否批准此修订? - approve_flag_tip: 您是否批准此举报? - approve_post_tip: 您是否批准此帖子? - approve_user_tip: 您是否批准此修订? - suggest_edits: 建议的编辑 - flag_post: 举报帖子 - flag_user: 举报用户 - queued_post: 排队的帖子 - queued_user: 排队用户 - filter_label: 类型 - reputation: 声望值 - flag_post_type: 举报这个帖子的类型是 {{ type }} - flag_user_type: 举报这个用户的类型是 {{ type }} - edit_post: 编辑帖子 - list_post: 文章列表 - unlist_post: 隐藏的帖子 - timeline: - undeleted: 取消删除 - deleted: 删除 - downvote: 反对 - upvote: 点赞 - accept: 采纳 - cancelled: 已取消 - commented: '评论:' - rollback: 回滚 - edited: 最后编辑于 - answered: 回答于 - asked: 提问于 - closed: 关闭 - reopened: 重新开启 - created: 创建于 - pin: 已置顶 - unpin: 取消置頂 - show: 已显示 - hide: 已隐藏 - title: "历史记录" - tag_title: "时间线" - show_votes: "显示投票" - n_or_a: N/A - title_for_question: "时间线" - title_for_answer: "{{ title }} 的 {{ author }} 回答时间线" - title_for_tag: "时间线" - datetime: 日期时间 - type: 类型 - by: 由 - comment: 评论 - no_data: "空空如也" - users: - title: 用户 - users_with_the_most_reputation: 本周声望最高的用户 - users_with_the_most_vote: 本周投票最多的用户 - staffs: 我们的社区工作人员 - reputation: 声望值 - votes: 投票 - prompt: - leave_page: 确定要离开此页面? - changes_not_save: 您的更改尚未保存 - draft: - discard_confirm: 您确定要丢弃您的草稿吗? - messages: - post_deleted: 该帖子已被删除。 - post_pin: 该帖子已被置顶。 - post_unpin: 该帖子已被取消置顶。 - post_hide_list: 此帖子已经从列表中隐藏。 - post_show_list: 该帖子已显示到列表中。 - post_reopen: 这个帖子已被重新打开. - post_list: 这个帖子已经被显示 - post_unlist: 这个帖子已经被隐藏 - post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 From 83155783e74b04f8c199d6f5680c4a9c8b4ab25a Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 19 Aug 2024 15:20:38 +0800 Subject: [PATCH 052/336] Revert "fix(dev): delete test file" This reverts commit c50e63dd34ce9ddb7babd769146278ef41e5bfcb. --- dev/i18n/zh_CN.yaml | 2035 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2035 insertions(+) create mode 100644 dev/i18n/zh_CN.yaml diff --git a/dev/i18n/zh_CN.yaml b/dev/i18n/zh_CN.yaml new file mode 100644 index 00000000..6613bfc2 --- /dev/null +++ b/dev/i18n/zh_CN.yaml @@ -0,0 +1,2035 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# The following fields are used for back-end +backend: + base: + success: + other: 成功。 + unknown: + other: 未知错误。 + request_format_error: + other: 请求格式错误。 + unauthorized_error: + other: 未授权。 + database_error: + other: 数据服务器错误。 + forbidden_error: + other: 禁止访问。 + duplicate_request_error: + other: 重复提交。 + action: + report: + other: 举报 + edit: + other: 编辑 + delete: + other: 删除 + close: + other: 关闭 + reopen: + other: 重新打开 + forbidden_error: + other: 禁止访问。 + pin: + other: 置顶 + hide: + other: 列表隐藏 + unpin: + other: 取消置顶 + show: + other: 列表显示 + invite_someone_to_answer: + other: 编辑 + undelete: + other: 撤消删除 + role: + name: + user: + other: 用户 + admin: + other: 管理员 + moderator: + other: 版主 + description: + user: + other: 默认没有特殊权限。 + admin: + other: 拥有管理网站的全部权限。 + moderator: + other: 拥有除访问后台管理以外的所有权限。 + privilege: + level_1: + description: + other: 级别 1(少量声望要求,适合私有团队、群组) + level_2: + description: + other: 级别 2(低声望要求,适合初启动的社区) + level_3: + description: + other: 级别 3(高声望要求,适合成熟的社区) + level_custom: + description: + other: 自定义等级 + rank_question_add_label: + other: 提问 + rank_answer_add_label: + other: 写答案 + rank_comment_add_label: + other: 写评论 + rank_report_add_label: + other: 举报 + rank_comment_vote_up_label: + other: 点赞评论 + rank_link_url_limit_label: + other: 每次发布超过 2 个链接 + rank_question_vote_up_label: + other: 点赞问题 + rank_answer_vote_up_label: + other: 点赞答案 + rank_question_vote_down_label: + other: 点踩问题 + rank_answer_vote_down_label: + other: 点踩答案 + rank_invite_someone_to_answer_label: + other: 邀请回答 + rank_tag_add_label: + other: 创建新标签 + rank_tag_edit_label: + other: 编辑标签描述(需要审核) + rank_question_edit_label: + other: 编辑别人的问题(需要审核) + rank_answer_edit_label: + other: 编辑别人的答案(需要审核) + rank_question_edit_without_review_label: + other: 编辑别人的问题无需审核 + rank_answer_edit_without_review_label: + other: 编辑别人的答案无需审核 + rank_question_audit_label: + other: 审核问题编辑 + rank_answer_audit_label: + other: 审核回答编辑 + rank_tag_audit_label: + other: 审核标签编辑 + rank_tag_edit_without_review_label: + other: 编辑标签描述无需审核 + rank_tag_synonym_label: + other: 管理标签同义词 + email: + other: 邮箱 + e_mail: + other: 邮箱 + password: + other: 密码 + pass: + other: 密码 + original_text: + other: 本帖 + email_or_password_wrong_error: + other: 邮箱和密码不匹配。 + error: + common: + invalid_url: + other: 无效的 URL。 + password: + space_invalid: + other: 密码不得含有空格。 + admin: + cannot_update_their_password: + other: 你无法修改自己的密码。 + cannot_edit_their_profile: + other: 您不能修改您的个人资料。 + cannot_modify_self_status: + other: 你无法修改自己的状态。 + email_or_password_wrong: + other: 邮箱和密码不匹配。 + answer: + not_found: + other: 没有找到答案。 + cannot_deleted: + other: 没有删除权限。 + cannot_update: + other: 没有更新权限。 + question_closed_cannot_add: + other: 问题已关闭,无法添加。 + comment: + edit_without_permission: + other: 不允许编辑评论。 + not_found: + other: 评论未找到。 + cannot_edit_after_deadline: + other: 评论时间太久,无法修改。 + email: + duplicate: + other: 邮箱已存在。 + need_to_be_verified: + other: 邮箱需要验证。 + verify_url_expired: + other: 邮箱验证的网址已过期,请重新发送邮件。 + illegal_email_domain_error: + other: 此邮箱不在允许注册的邮箱域中。请使用其他邮箱尝试。 + lang: + not_found: + other: 语言文件未找到。 + object: + captcha_verification_failed: + other: 验证码错误。 + disallow_follow: + other: 你不能关注。 + disallow_vote: + other: 你不能投票。 + disallow_vote_your_self: + other: 你不能为自己的帖子投票。 + not_found: + other: 对象未找到。 + verification_failed: + other: 验证失败。 + email_or_password_incorrect: + other: 邮箱和密码不匹配。 + old_password_verification_failed: + other: 旧密码验证失败。 + new_password_same_as_previous_setting: + other: 新密码和旧密码相同。 + already_deleted: + other: 该帖子已被删除。 + meta: + object_not_found: + other: Meta 对象未找到 + question: + already_deleted: + other: 该帖子已被删除。 + under_review: + other: 您的帖子正在等待审核。它将在它获得批准后可见。 + not_found: + other: 问题未找到。 + cannot_deleted: + other: 没有删除权限。 + cannot_close: + other: 没有关闭权限。 + cannot_update: + other: 没有更新权限。 + rank: + fail_to_meet_the_condition: + other: 声望值未达到要求。 + vote_fail_to_meet_the_condition: + other: 感谢投票。你至少需要 {{.Rank}} 声望才能投票。 + no_enough_rank_to_operate: + other: 你至少需要 {{.Rank}} 声望才能执行此操作。 + report: + handle_failed: + other: 报告处理失败。 + not_found: + other: 报告未找到。 + tag: + already_exist: + other: 标签已存在。 + not_found: + other: 标签未找到。 + recommend_tag_not_found: + other: 推荐标签不存在。 + recommend_tag_enter: + other: 请选择至少一个必选标签。 + not_contain_synonym_tags: + other: 不应包含同义词标签。 + cannot_update: + other: 没有更新权限。 + is_used_cannot_delete: + other: 你不能删除这个正在使用的标签。 + cannot_set_synonym_as_itself: + other: 你不能将当前标签设为自己的同义词。 + smtp: + config_from_name_cannot_be_email: + other: 发件人名称不能是邮箱地址。 + theme: + not_found: + other: 主题未找到。 + revision: + review_underway: + other: 目前无法编辑,有一个版本在审阅队列中。 + no_permission: + other: 无权限修改。 + user: + external_login_missing_user_id: + other: 第三方平台没有提供唯一的 UserID,所以你不能登录,请联系网站管理员。 + external_login_unbinding_forbidden: + other: 请在移除此登录之前为你的账户设置登录密码。 + email_or_password_wrong: + other: + other: 邮箱和密码不匹配。 + not_found: + other: 用户未找到。 + suspended: + other: 用户已被封禁。 + username_invalid: + other: 用户名无效。 + username_duplicate: + other: 用户名已被使用。 + set_avatar: + other: 头像设置错误。 + cannot_update_your_role: + other: 你不能修改自己的角色。 + not_allowed_registration: + other: 该网站暂未开放注册。 + not_allowed_login_via_password: + other: 该网站暂不支持密码登录。 + access_denied: + other: 拒绝访问 + page_access_denied: + other: 您没有权限访问此页面。 + add_bulk_users_format_error: + other: "发生错误,{{.Field}} 格式错误,在 '{{.Content}}' 行数 {{.Line}}. {{.ExtraMessage}}" + add_bulk_users_amount_error: + other: "一次性添加的用户数量应在 1-{{.MaxAmount}} 之间。" + config: + read_config_failed: + other: 读取配置失败 + database: + connection_failed: + other: 数据库连接失败 + create_table_failed: + other: 创建表失败 + install: + create_config_failed: + other: 无法创建 config.yaml 文件。 + upload: + unsupported_file_format: + other: 不支持的文件格式。 + site_info: + config_not_found: + other: 未找到网站的该配置信息。 + reason: + spam: + name: + other: 垃圾信息 + desc: + other: 这个帖子是一个广告,或是破坏性行为。它对当前的主题无帮助或无关。 + rude_or_abusive: + name: + other: 粗鲁或辱骂的 + desc: + other: + - 一个有理智的人都会认为这种内容不适合进行尊重性的讨论。 + - 论坛 + a_duplicate: + name: + other: 重复内容 + desc: + other: 该问题有人问过,而且已经有了答案。 + placeholder: + other: 输入已有的问题链接 + not_a_answer: + name: + other: 不是答案 + desc: + other: + - 这张贴作为答案,但它不会试图回答 + - 这可能是一个编辑、一个评论、另一个问题。 + - 或全部删除。 + no_longer_needed: + name: + other: 不再需要 + desc: + other: 该评论已过时,对话性质或与此帖子无关。 + something: + name: + other: 其他原因 + desc: + other: 此帖子需要工作人员注意,因为是上述所列以外的其他理由。 + placeholder: + other: 让我们具体知道你关心的什么 + community_specific: + name: + other: 社区特定原因 + desc: + other: 该问题不符合社区准则。 + not_clarity: + name: + other: 需要细节或澄清 + desc: + other: 该问题目前涵盖多个问题。它应该侧重在一个问题上。 + looks_ok: + name: + other: 看起来没问题 + desc: + other: 这个帖子是好的,不是低质量。 + needs_edit: + name: + other: 需要编辑,我已做了修改。 + desc: + other: 改进和纠正你自己帖子中的问题。 + needs_close: + name: + other: 需要关闭 + desc: + other: 关闭的问题不能回答,但仍然可以编辑、投票和评论。 + needs_delete: + name: + other: 需要删除 + desc: + other: 该帖子将被删除。 + question: + close: + duplicate: + name: + other: 垃圾信息 + desc: + other: 此问题以前就有人问过,而且已经有了答案。 + guideline: + name: + other: 社区特定原因 + desc: + other: 该问题不符合社区准则。 + multiple: + name: + other: 需要细节或澄清 + desc: + other: + - 该问题目前涵盖多个问题。它应该侧重在一个问题上。 + - 只关注一个问题。 + other: + name: + other: 其他原因 + desc: + other: 该帖子存在上面没有列出的另一个原因。 + operation_type: + asked: + other: 提问于 + answered: + other: 回答于 + modified: + other: 修改于 + deleted_title: + other: 删除的问题 + notification: + action: + update_question: + other: 更新了问题 + answer_the_question: + other: 回答了问题 + update_answer: + other: 更新了答案 + accept_answer: + other: 采纳了答案 + comment_question: + other: 评论了问题 + comment_answer: + other: 评论了答案 + reply_to_you: + other: 回复了你 + mention_you: + other: 提到了你 + your_question_is_closed: + other: 你的问题已被关闭 + your_question_was_deleted: + other: 你的问题已被删除 + your_answer_was_deleted: + other: 你的答案已被删除 + your_comment_was_deleted: + other: 你的评论已被删除 + up_voted_question: + other: 点赞问题 + down_voted_question: + other: 点踩问题 + up_voted_answer: + other: 点赞答案 + down_voted_answer: + other: 点踩回答 + up_voted_comment: + other: 点赞评论 + invited_you_to_answer: + other: 邀请你回答 + email_tpl: + change_email: + title: + other: "[{{.SiteName}}] 确认你的新邮箱地址" + body: + other: "请点击以下链接确认你在 {{.SiteName}} 上的新邮箱地址:
\n{{.ChangeEmailUrl}}

\n\n如果你没有请求此更改,请忽略此邮件。\n" + new_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} 回答了你的问题" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" + invited_you_to_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} 邀请您回答问题" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
我想你可能知道答案。

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" + new_comment: + title: + other: "[{{.SiteName}}] {{.DisplayName}} 评论了你的帖子" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" + new_question: + title: + other: "[{{.SiteName}}] 新问题: {{.QuestionTitle}}" + body: + other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\n取消订阅" + pass_reset: + title: + other: "[{{.SiteName }}] 重置密码" + body: + other: "有人要求在 [{{.SiteName}}] 上重置你的密码。

\n\n如果这不是你的操作,请安心忽略此电子邮件。

\n\n请点击以下链接设置一个新密码:
\n{{.PassResetUrl}}\n" + register: + title: + other: "[{{.SiteName}}] 确认你的新账户" + body: + other: "欢迎加入 {{.SiteName}}!

\n\n请点击以下链接确认并激活你的新账户:
\n{{.RegisterUrl}}

\n\n如果上面的链接不能点击,请将其复制并粘贴到你的浏览器地址栏中。\n" + test: + title: + other: "[{{.SiteName}}] 测试邮件" + body: + other: "这是一封测试邮件。" + action_activity_type: + upvote: + other: 点赞 + upvoted: + other: 点赞 + downvote: + other: 点踩 + downvoted: + other: 点踩 + accept: + other: 采纳 + accepted: + other: 已采纳 + edit: + other: 编辑 + review: + queued_post: + other: 排队的帖子 + flagged_post: + other: 举报的帖子 + suggested_post_edit: + other: 建议的编辑 + reaction: + tooltip: + other: "{{ .Names }} 以及另外 {{ .Count }} 个..." +plugin: + s3_cdn: + backend: + info: + name: + other: S3 存储 CDN + description: + other: 上传文件到S3存储 + config: + endpoint: + title: + other: Endpoint + description: + other: S3存储的Endpoint + bucket_name: + title: + other: Bucket名称 + description: + other: S3存储的Bucket名称 + object_key_prefix: + title: + other: 对象Key前缀 + description: + other: 对象键的前缀,如'answer/data/',以'/'结尾 + access_key_id: + title: + other: AccessKeyID + description: + other: S3存储的AccessKeyID + access_key_secret: + title: + other: AccessKeySecret + description: + other: S3存储的AccessKeySecret + access_token: + title: + other: AccessToken + description: + other: 访问 S3 所需的 AccessToken + visit_url_prefix: + title: + other: 访问URL前缀 + description: + other: 上传静态文件CDN最终访问地址的前缀,以 '/' 结尾 https://static.example.com/xxx/ + max_file_size: + title: + other: 文件最大大小(MB) + description: + other: 限制上传文件的最大大小,单位MB,默认为10MB + region: + title: + other: 区域(Region) + description: + other: S3存储区域 + disable_ssl: + title: + other: 禁用SSL + description: + other: 我们建议您使用SSL访问S3存储。如果您想禁用SSL,请选中此选项。 + err: + mis_storage_config: + other: 错误的存储配置导致上传失败 + file_not_found: + other: 文件未找到 + unsupported_file_type: + other: 不支持的文件类型 + over_file_size_limit: + other: 超过文件大小限制 + upload_file_failed: + other: 上传文件失败 + aliyunoss_cdn: + backend: + info: + name: + other: 阿里云CDN OSS存储 + description: + other: 上传文件到阿里云CDN OSS存储 + config: + endpoint: + title: + other: Endpoint + description: + other: 阿里云OSS存储的Endpoint + bucket_name: + title: + other: Bucket名称 + description: + other: 阿里云OSS存储的Bucket名称 + object_key_prefix: + title: + other: 对象Key前缀 + description: + other: 对象键的前缀,如'answer/data/',以'/'结尾 + access_key_id: + title: + other: AccessKeyID + description: + other: 阿里云OSS存储的AccessKeyID + access_key_secret: + title: + other: AccessKeySecret + description: + other: 阿里云OSS存储的AccessKeySecret + visit_url_prefix: + title: + other: 访问URL前缀 + description: + other: CDN最终访问地址的前缀,以 '/' 结尾 https://example.com/xxx/ + max_file_size: + title: + other: 最大文件大小(MB) + description: + other: 限制上传文件的最大大小,单位为MB,默认为 10MB + err: + mis_storage_config: + other: 错误的存储配置导致上传失败 + file_not_found: + other: 文件未找到 + unsupported_file_type: + other: 不支持的文件类型 + over_file_size_limit: + other: 超过文件大小限制 + upload_file_failed: + other: 上传文件失败 +# The following fields are used for interface presentation(Front-end) +ui: + how_to_format: + title: 如何排版 + desc: >- +
  • 添加链接

    <https://url.com>

    [标题](https://url.com)
  • 段落之间使用空行分隔

  • _斜体_ 或者 **粗体**

  • 使用 4 个空格缩进代码

  • 在行首添加 > 表示引用

  • 反引号进行转义 `像 _这样_`

  • 使用 ``` 创建代码块

    ```
    这是代码块
    ```
+ pagination: + prev: 上一页 + next: 下一页 + page_title: + question: 问题 + questions: 问题 + tag: 标签 + tags: 标签 + tag_wiki: 标签维基 + create_tag: 创建标签 + edit_tag: 编辑标签 + ask_a_question: 提问题 + edit_question: 编辑问题 + edit_answer: 编辑回答 + search: 搜索 + posts_containing: 帖子包含 + settings: 设置 + notifications: 通知 + login: 登录 + sign_up: 注册 + account_recovery: 账号恢复 + account_activation: 账号激活 + confirm_email: 确认电子邮件 + account_suspended: 账号已被封禁 + admin: 后台管理 + change_email: 修改邮箱 + install: Answer 安装 + upgrade: Answer 升级 + maintenance: 网站维护 + users: 用户 + oauth_callback: 处理中 + http_404: HTTP 错误 404 + http_50X: HTTP 错误 500 + http_403: HTTP 错误 403 + logout: 退出 + notifications: + title: 通知 + inbox: 收件箱 + achievement: 成就 + new_alerts: 新通知 + all_read: 全部标记为已读 + show_more: 显示更多 + someone: 有人 + inbox_type: + all: 全部 + posts: 帖子 + invites: 邀请 + votes: 投票 + suspended: + title: 你的账号账号已被封禁 + until_time: "你的账号被封禁直到 {{ time }}。" + forever: 你的账号已被永久封禁。 + end: 你违反了我们的社区准则。 + contact_us: 联系我们 + editor: + blockquote: + text: 引用 + bold: + text: 粗体 + chart: + text: 图表 + flow_chart: 流程图 + sequence_diagram: 时序图 + class_diagram: 类图 + state_diagram: 状态图 + entity_relationship_diagram: 实体关系图 + user_defined_diagram: 用户自定义图表 + gantt_chart: 甘特图 + pie_chart: 饼图 + code: + text: 代码块 + add_code: 添加代码块 + form: + fields: + code: + label: 代码块 + msg: + empty: 代码块不能为空 + language: + label: 语言 + placeholder: 自动识别 + btn_cancel: 取消 + btn_confirm: 添加 + formula: + text: 公式 + options: + inline: 行内公式 + block: 块级公式 + heading: + text: 标题 + options: + h1: 标题 1 + h2: 标题 2 + h3: 标题 3 + h4: 标题 4 + h5: 标题 5 + h6: 标题 6 + help: + text: 帮助 + hr: + text: 水平线 + image: + text: 图片 + add_image: 添加图片 + tab_image: 上传图片 + form_image: + fields: + file: + label: 图像文件 + btn: 选择图片 + msg: + empty: 请选择图片文件。 + only_image: 只能上传图片文件。 + max_size: 文件大小不能超过 4 MB。 + desc: + label: 描述 + tab_url: 图片地址 + form_url: + fields: + url: + label: 图片地址 + msg: + empty: 图片地址不能为空 + name: + label: 描述 + btn_cancel: 取消 + btn_confirm: 添加 + uploading: 上传中 + indent: + text: 缩进 + outdent: + text: 减少缩进 + italic: + text: 斜体 + link: + text: 超链接 + add_link: 添加超链接 + form: + fields: + url: + label: 链接 + msg: + empty: 链接不能为空。 + name: + label: 描述 + btn_cancel: 取消 + btn_confirm: 添加 + ordered_list: + text: 有序列表 + unordered_list: + text: 无序列表 + table: + text: 表格 + heading: 表头 + cell: 单元格 + close_modal: + title: 关闭原因是... + btn_cancel: 取消 + btn_submit: 提交 + remark: + empty: 不能为空。 + msg: + empty: 请选择一个原因。 + report_modal: + flag_title: 我举报这篇帖子的原因是... + close_title: 我关闭这篇帖子的原因是... + review_question_title: 审查问题 + review_answer_title: 审查回答 + review_comment_title: 审查评论 + btn_cancel: 取消 + btn_submit: 提交 + remark: + empty: 不能为空 + msg: + empty: 请选择一个原因。 + not_a_url: URL 格式不正确。 + url_not_match: URL 来源与当前网站不匹配。 + tag_modal: + title: 创建新标签 + form: + fields: + display_name: + label: 显示名称 + msg: + empty: 显示名称不能为空。 + range: 显示名称不能超过 35 个字符。 + slug_name: + label: URL 固定链接 + desc: URL 固定链接不能超过 35 个字符。 + msg: + empty: URL 固定链接不能为空。 + range: URL 固定链接不能超过 35 个字符。 + character: URL 固定链接包含非法字符。 + desc: + label: 描述 + revision: + label: 编辑历史 + edit_summary: + label: 编辑备注 + placeholder: >- + 简单描述更改原因(更正拼写、修复语法、改进格式) + btn_cancel: 取消 + btn_submit: 提交 + btn_post: 发布新标签 + tag_info: + created_at: 创建于 + edited_at: 编辑于 + history: 历史 + synonyms: + title: 同义词 + text: 以下标签将被重置到 + empty: 此标签目前没有同义词。 + btn_add: 添加同义词 + btn_edit: 编辑 + btn_save: 保存 + synonyms_text: 以下标签将被重置到 + delete: + title: 删除标签 + tip_with_posts: >- +

我们不允许 删除带有帖子的标签

请先从帖子中移除此标签。

+ tip_with_synonyms: >- +

我们不允许 删除带有同义词的标签

请先从此标签中删除同义词。

+ tip: 确定要删除吗? + close: 关闭 + edit_tag: + title: 编辑标签 + default_reason: 编辑标签 + default_first_reason: 添加标签 + btn_save_edits: 保存更改 + btn_cancel: 取消 + dates: + long_date: MM 月 DD 日 + long_date_with_year: "YYYY 年 MM 月 DD 日" + long_date_with_time: "YYYY 年 MM 月 DD 日 HH:mm" + now: 刚刚 + x_seconds_ago: "{{count}} 秒前" + x_minutes_ago: "{{count}} 分钟前" + x_hours_ago: "{{count}} 小时前" + hour: 小时 + day: 天 + hours: 小时 + days: 日 + reaction: + heart: 爱心 + smile: 微笑 + frown: 愁 + btn_label: 添加或删除回应。 + undo_emoji: 撤销 {{ emoji }} 回应 + react_emoji: 用 {{ emoji }} 回应 + unreact_emoji: 撤销 {{ emoji }} + comment: + btn_add_comment: 添加评论 + reply_to: 回复 + btn_reply: 回复 + btn_edit: 编辑 + btn_delete: 删除 + btn_flag: 举报 + btn_save_edits: 保存更改 + btn_cancel: 取消 + show_more: "{{count}} 条剩余评论" + tip_question: >- + 使用评论提问更多信息或者提出改进意见。避免在评论里回答问题。 + tip_answer: >- + 使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。 + tip_vote: 它给帖子添加了一些有用的内容 + edit_answer: + title: 编辑回答 + default_reason: 编辑回答 + default_first_reason: 添加答案 + form: + fields: + revision: + label: 编辑历史 + answer: + label: 回答内容 + feedback: + characters: 内容长度至少 6 个字符 + edit_summary: + label: 编辑摘要 + placeholder: >- + 简单描述更改原因(更正拼写、修复语法、改进格式) + btn_save_edits: 保存更改 + btn_cancel: 取消 + tags: + title: 标签 + sort_buttons: + popular: 热门 + name: 名称 + newest: 最新 + button_follow: 关注 + button_following: 已关注 + tag_label: 个问题 + search_placeholder: 通过标签名称过滤 + no_desc: 此标签无描述。 + more: 更多 + ask: + title: 新增问题 + edit_title: 编辑问题 + default_reason: 编辑问题 + default_first_reason: 新增问题 + similar_questions: 相似问题 + form: + fields: + revision: + label: 修订版本 + title: + label: 标题 + placeholder: 请详细描述你的问题,想象你在问一个人 + msg: + empty: 标题不能为空。 + range: 标题最多 150 个字符 + body: + label: 内容 + msg: + empty: 内容不能为空。 + tags: + label: 标签 + msg: + empty: 必须选择一个标签 + answer: + label: 回答内容 + msg: + empty: 回答内容不能为空 + edit_summary: + label: 编辑备注 + placeholder: >- + 简单描述更改原因(更正拼写、修复语法、改进格式) + btn_post_question: 提交问题 + btn_save_edits: 保存更改 + answer_question: 回答自己的问题 + post_question&answer: 提交问题和回答 + tag_selector: + add_btn: 添加标签 + create_btn: 创建新标签 + search_tag: 搜索标签 + hint: "描述您的问题是关于什么,至少需要一个标签。" + no_result: 没有匹配的标签 + tag_required_text: 必选标签(至少一个) + header: + nav: + question: 问题 + tag: 标签 + user: 用户 + profile: 用户主页 + setting: 账号设置 + logout: 退出 + admin: 后台管理 + review: 审查 + bookmark: 收藏夹 + moderation: 管理 + search: + placeholder: 搜索 + footer: + build_on: >- + 由 <1>Apache Answer 提供动力 - 驱动问答社区的开源软件。
用爱制造 © {{cc}}. + upload_img: + name: 更改 + loading: 加载中... + pic_auth_code: + title: 验证码 + placeholder: 输入图片中的文字 + msg: + empty: 验证码不能为空。 + inactive: + first: >- + 就差一步!我们发送了一封激活邮件到 {{mail}}。请按照邮件中的说明激活你的账户。 + info: "如果没有收到,请检查你的垃圾邮件文件夹。" + another: >- + 我们向你的邮箱 {{mail}} 发送了另一封激活电子邮件。可能需要几分钟才能到达;请务必检查您的垃圾邮件箱。 + btn_name: 重新发送激活邮件 + change_btn_name: 更改邮箱 + msg: + empty: 不能为空。 + resend_email: + url_label: 确定要重新发送激活邮件吗? + url_text: 你也可以将上面的激活链接给该用户。 + login: + login_to_continue: 登录以继续 + info_sign: 没有账户?<1>注册 + info_login: 已经有账户?<1>登录 + agreements: 登录即表示您同意<1>隐私政策和<3>服务条款。 + forgot_pass: 忘记密码? + name: + label: 名字 + msg: + empty: 名字不能为空 + range: 名字应该在 4 到 30 个字符之间 + character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' + email: + label: 邮箱 + msg: + empty: 邮箱不能为空 + password: + label: 密码 + msg: + empty: 密码不能为空 + different: 两次输入密码不一致 + account_forgot: + page_title: 忘记密码 + btn_name: 发送恢复邮件 + send_success: >- + 如果存在邮箱为 {{mail}} 账户,你将很快收到一封重置密码的说明邮件。 + email: + label: 邮箱 + msg: + empty: 邮箱不能为空 + change_email: + btn_cancel: 取消 + btn_update: 更新电子邮件地址 + send_success: >- + 如果存在邮箱为 {{mail}} 的账户,你将很快收到一封重置密码的说明邮件。 + email: + label: 新的电子邮件地址 + msg: + empty: 邮箱不能为空。 + oauth: + connect: 连接到 {{ auth_name }} + remove: 移除 {{ auth_name }} + oauth_bind_email: + subtitle: 向你的账户添加恢复邮件地址。 + btn_update: 更新电子邮件地址 + email: + label: 邮箱 + msg: + empty: 邮箱不能为空。 + modal_title: 邮箱已经存在。 + modal_content: 该电子邮件地址已经注册。你确定要连接到已有账户吗? + modal_cancel: 更改邮箱 + modal_confirm: 连接到已有账户 + password_reset: + page_title: 密码重置 + btn_name: 重置我的密码 + reset_success: >- + 你已经成功更改密码;你将被重定向到登录页面。 + link_invalid: >- + 抱歉,此密码重置链接已失效。也许是你已经重置过密码了? + to_login: 前往登录页面 + password: + label: 密码 + msg: + empty: 密码不能为空。 + length: 密码长度在8-32个字符之间 + different: 两次输入密码不一致 + password_confirm: + label: 确认新密码 + settings: + page_title: 设置 + goto_modify: 前往修改 + nav: + profile: 我的资料 + notification: 通知 + account: 账号 + interface: 界面 + profile: + heading: 个人资料 + btn_name: 保存 + display_name: + label: 显示名称 + msg: 昵称不能为空。 + msg_range: 显示名称不能超过 30 个字符。 + username: + label: 用户名 + caption: 用户可以通过 "@用户名" 来提及你。 + msg: 用户名不能为空 + msg_range: 用户名不能超过 30 个字符。 + character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' + avatar: + label: 头像 + gravatar: Gravatar + gravatar_text: 你可以更改图像在 + custom: 自定义 + custom_text: 你可以上传你的图片。 + default: 系统 + msg: 请上传头像 + bio: + label: 关于我 + website: + label: 网站 + placeholder: "https://example.com" + msg: 网址格式不正确 + location: + label: 位置 + placeholder: "城市,国家" + notification: + heading: 邮件通知 + turn_on: 开启 + inbox: + label: 收件箱通知 + description: 你的提问有新的回答,评论,邀请回答和其他。 + all_new_question: + label: 所有新问题 + description: 获取所有新问题的通知。每周最多有50个问题。 + all_new_question_for_following_tags: + label: 所有关注标签的新问题 + description: 获取关注的标签下新问题通知。 + account: + heading: 账号 + change_email_btn: 更改邮箱 + change_pass_btn: 更改密码 + change_email_info: >- + 邮件已发送。请根据指引完成验证。 + email: + label: 电子邮件地址 + new_email: + label: 新的电子邮件地址 + msg: 新邮箱不能为空。 + pass: + label: 当前密码 + msg: 密码不能为空。 + password_title: 密码 + current_pass: + label: 当前密码 + msg: + empty: 当前密码不能为空 + length: 密码长度必须在 8 至 32 之间 + different: 两次输入的密码不匹配 + new_pass: + label: 新密码 + pass_confirm: + label: 确认新密码 + interface: + heading: 界面 + lang: + label: 界面语言 + text: 设置用户界面语言,在刷新页面后生效。 + my_logins: + title: 我的登录 + label: 使用这些账户登录或注册本网站。 + modal_title: 移除登录 + modal_content: 你确定要从账户里移除该登录? + modal_confirm_btn: 移除 + remove_success: 移除成功 + toast: + update: 更新成功 + update_password: 密码更新成功。 + flag_success: 感谢标记。 + forbidden_operate_self: 禁止对自己执行操作 + review: 您的修订将在审阅通过后显示。 + sent_success: 发送成功 + related_question: + title: 相关问题 + answers: 个回答 + invite_to_answer: + title: 受邀人 + desc: 邀请你认为可能知道答案的人。 + invite: 邀请回答 + add: 添加人员 + search: 搜索人员 + question_detail: + action: 操作 + Asked: 提问于 + asked: 提问于 + update: 修改于 + edit: 编辑于 + commented: 评论 + Views: 阅读次数 + Follow: 关注此问题 + Following: 已关注 + follow_tip: 关注此问题以接收通知 + answered: 回答于 + closed_in: 关闭于 + show_exist: 查看类似问题。 + useful: 有用的 + question_useful: 它是有用和明确的 + question_un_useful: 它不明确或没用的 + question_bookmark: 收藏该问题 + answer_useful: 这是有用的 + answer_un_useful: 它是没有用的 + answers: + title: 个回答 + score: 评分 + newest: 最新 + oldest: 最旧 + btn_accept: 采纳 + btn_accepted: 已被采纳 + write_answer: + title: 你的回答 + edit_answer: 编辑我的回答 + btn_name: 提交你的回答 + add_another_answer: 添加另一个回答 + confirm_title: 继续回答 + continue: 继续 + confirm_info: >- +

你确定要提交一个新的回答吗?

作为替代,你可以通过编辑来完善和改进之前的回答。

+ empty: 回答内容不能为空。 + characters: 内容长度至少 6 个字符。 + tips: + header_1: 感谢你的回答 + li1_1: 请务必确定在 回答问题。提供详细信息并分享你的研究。 + li1_2: 用参考资料或个人经历来支持你所做的任何陈述。 + header_2: 但是 请避免... + li2_1: 请求帮助,寻求澄清,或答复其他答案。 + reopen: + confirm_btn: 重新打开 + title: 重新打开这个帖子 + content: 确定要重新打开吗? + list: + confirm_btn: 列表显示 + title: 列表中显示这个帖子 + content: 确定要列表中显示这个帖子吗? + unlist: + confirm_btn: 列表隐藏 + title: 从列表中隐藏这个帖子 + content: 确定要从列表中隐藏这个帖子吗? + pin: + title: 置顶该帖子 + content: 你确定要全局置顶吗?这个帖子将出现在所有帖子列表的顶部。 + confirm_btn: 置顶 + delete: + title: 删除 + question: >- + 我们不建议 删除有回答的帖子。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗? + answer_accepted: >- +

我们不建议删除被采纳的回答。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗? + other: 你确定要删除? + tip_answer_deleted: 该回答已被删除 + undelete_title: 撤销删除本帖 + undelete_desc: 你确定你要撤销删除吗? + btns: + confirm: 确认 + cancel: 取消 + edit: 编辑 + save: 保存 + delete: 删除 + undelete: 撤消删除 + list: 列表显示 + unlist: 列表隐藏 + unlisted: 已隐藏 + login: 登录 + signup: 注册 + logout: 退出 + verify: 验证 + add_question: 我要提问 + approve: 批准 + reject: 拒绝 + skip: 跳过 + discard_draft: 丢弃草稿 + pinned: 已置顶 + all: 全部 + question: 问题 + answer: 回答 + comment: 评论 + refresh: 刷新 + resend: 重新发送 + deactivate: 取消激活 + active: 激活 + suspend: 封禁 + unsuspend: 解禁 + close: 关闭 + reopen: 重新打开 + ok: 确定 + light: 浅色 + dark: 深色 + system_setting: 跟随系统 + default: 默认 + reset: 重置 + tag: 标签 + post_lowercase: 帖子 + filter: 筛选 + ignore: 忽略 + submit: 提交 + normal: 正常 + closed: 已关闭 + deleted: 已删除 + pending: 等待处理 + more: 更多 + search: + title: 搜索结果 + keywords: 关键词 + options: 选项 + follow: 关注 + following: 已关注 + counts: "{{count}} 个结果" + more: 更多 + sort_btns: + relevance: 相关性 + newest: 最新的 + active: 活跃的 + score: 评分 + more: 更多 + tips: + title: 高级搜索提示 + tag: "<1>[tag] 在指定标签中搜索" + user: "<1>user:username 根据作者搜索" + answer: "<1>answers:0 搜索未回答的问题" + score: "<1>score:3 评分 3+ 的帖子" + question: "<1>is:question 搜索问题" + is_answer: "<1>is:answer 搜索回答" + empty: 找不到任何相关的内容。
请尝试其他关键字,或者减少查找内容的长度。 + share: + name: 分享 + copy: 复制链接 + via: 分享到... + copied: 已复制 + facebook: 分享到 Facebook + twitter: 分享到 Twitter + cannot_vote_for_self: 你不能给自己的帖子投票。 + modal_confirm: + title: 发生错误... + account_result: + success: 你的账号已通过验证,即将返回首页。 + link: 返回首页 + invalid: >- + 抱歉,此验证链接已失效。也许你的账号已经激活了? + confirm_new_email: 你的电子邮箱已更新 + confirm_new_email_invalid: >- + 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了? + unsubscribe: + page_title: 退订 + success_title: 退订成功 + success_desc: 您已成功退订,并且将不会再收到我们的邮件。 + link: 更改设置 + question: + following_tags: 已关注的标签 + edit: 编辑 + save: 保存 + follow_tag_tip: 关注标签来筛选你的问题列表。 + hot_questions: 热门问题 + all_questions: 全部问题 + x_questions: "{{ count }} 个问题" + x_answers: "{{ count }} 个回答" + questions: 问题 + answers: 回答 + newest: 最新 + active: 活跃 + hot: 热门 + score: 评分 + unanswered: 未回答 + modified: 更新于 + answered: 回答于 + asked: 提问于 + closed: 已关闭 + follow_a_tag: 关注一个标签 + more: 更多 + personal: + overview: 概览 + answers: 回答 + answer: 回答 + questions: 问题 + question: 问题 + bookmarks: 收藏 + reputation: 声望 + comments: 评论 + votes: 得票 + newest: 最新 + score: 评分 + edit_profile: 编辑资料 + visited_x_days: "已访问 {{ count }} 天" + viewed: 浏览次数 + joined: 加入于 + last_login: 上次登录 + about_me: 关于我 + about_me_empty: "// Hello, World!" + top_answers: 高分回答 + top_questions: 高分问题 + stats: 状态 + list_empty: 没有找到相关的内容。
试试看其他选项卡? + accepted: 已采纳 + answered: 回答于 + asked: 提问于 + downvoted: 点踩 + mod_short: 版主 + mod_long: 版主 + x_reputation: 声望 + x_votes: 得票 + x_answers: 个回答 + x_questions: 个问题 + install: + title: 安装 + next: 下一步 + done: 完成 + config_yaml_error: 无法创建 config.yaml 文件。 + lang: + label: 请选择一种语言 + db_type: + label: 数据库引擎 + db_username: + label: 用户名 + placeholder: root + msg: 用户名不能为空 + db_password: + label: 密码 + placeholder: root + msg: 密码不能为空 + db_host: + label: 数据库主机 + placeholder: "db:3306" + msg: 数据库地址不能为空 + db_name: + label: 数据库名 + placeholder: 回答 + msg: 数据库名称不能为空。 + db_file: + label: 数据库文件 + placeholder: /data/answer.db + msg: 数据库文件不能为空。 + config_yaml: + title: 创建 config.yaml + label: 已创建 config.yaml 文件。 + desc: >- + 你可以手动在 <1>/var/wwww/xxx/ 目录中创建 <1>config.yaml 文件并粘贴以下文本。 + info: 完成后,点击“下一步”按钮。 + site_information: 站点信息 + admin_account: 管理员账号 + site_name: + label: 站点名称 + msg: 站点名称不能为空。 + msg_max_length: 站点名称长度不得超过 30 个字符。 + site_url: + label: 网站网址 + text: 此网站的网址。 + msg: + empty: 网址不能为空。 + incorrect: 网址格式不正确。 + max_length: 网址长度不得超过 512 个字符。 + contact_email: + label: 联系邮箱 + text: 负责本网站的主要联系人的电子邮件地址。 + msg: + empty: 联系人邮箱不能为空。 + incorrect: 联系人邮箱地址不正确。 + login_required: + label: 私有的 + switch: 需要登录 + text: 只有登录用户才能访问这个社区。 + admin_name: + label: 名字 + msg: 名字不能为空。 + character: '只能由 "a-z", "0-9", " - . _" 组成' + msg_max_length: 名字长度不能超过 30 个字符。 + admin_password: + label: 密码 + text: >- + 您需要此密码才能登录。请将其存储在一个安全的位置。 + msg: 密码不能为空。 + msg_min_length: 密码必须至少 8 个字符长。 + msg_max_length: 密码长度不能超过 32 个字符。 + admin_email: + label: 邮箱 + text: 您需要此电子邮件才能登录。 + msg: + empty: 邮箱不能为空。 + incorrect: 邮箱格式不正确。 + ready_title: 您的网站已准备好 + ready_desc: >- + 如果你想改变更多的设置,请访问 <1>管理区域;在网站菜单中找到它。 + good_luck: "玩得愉快,祝你好运!" + warn_title: 警告 + warn_desc: >- + 文件 <1>config.yaml 已存在。如果你要重置该文件中的任何配置项,请先删除它。 + install_now: 您可以尝试 <1>现在安装。 + installed: 已安裝 + installed_desc: >- + 你似乎已经安装过了。如果要重新安装,请先清除旧的数据库表。 + db_failed: 数据连接异常! + db_failed_desc: >- + 这或者意味着数据库信息在 <1>config.yaml 文件不正确,或者无法与数据库服务器建立联系。这可能意味着你的主机数据库服务器故障。 + counts: + views: 次浏览 + votes: 个点赞 + answers: 个回答 + accepted: 已被采纳 + page_error: + http_error: HTTP 错误 {{ code }} + desc_403: 您无权访问此页面。 + desc_404: 很抱歉,此页面不存在。 + desc_50X: 服务器遇到了一个错误,无法完成你的请求。 + back_home: 返回首页 + page_maintenance: + desc: "我们正在进行维护,我们将很快回来。" + nav_menus: + dashboard: 后台管理 + contents: 内容管理 + questions: 问题 + answers: 回答 + users: 用户管理 + flags: 举报管理 + settings: 站点设置 + general: 一般 + interface: 界面 + smtp: SMTP + branding: 品牌 + legal: 法律条款 + write: 撰写 + tos: 服务条款 + privacy: 隐私政策 + seo: SEO + customize: 自定义 + themes: 主题 + css_html: CSS/HTML + login: 登录 + privileges: 特权 + plugins: 插件 + installed_plugins: 已安装插件 + website_welcome: 欢迎来到 {{site_name}} + user_center: + login: 登录 + qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码并登录。 + login_failed_email_tip: 登录失败,请允许此应用访问您的邮箱信息,然后重试。 + admin: + admin_header: + title: 后台管理 + dashboard: + title: 后台管理 + welcome: 欢迎来到管理后台! + site_statistics: 站点统计 + questions: "问题:" + answers: "回答:" + comments: "评论:" + votes: "投票:" + users: "用户:" + flags: "举报:" + reviews: "审查:" + site_health: 网站健康 + version: "版本" + https: "HTTPS:" + upload_folder: "上传文件夹:" + run_mode: "运行模式:" + private: 私有 + public: 公开 + smtp: "SMTP:" + timezone: "时区:" + system_info: 系统信息 + go_version: "Go版本:" + database: "数据库:" + database_size: "数据库大小:" + storage_used: "已用存储空间:" + uptime: "运行时间:" + links: 链接 + plugins: 插件 + github: GitHub + blog: 博客 + contact: 联系 + forum: 论坛 + documents: 文档 + feedback: 用户反馈 + support: 帮助 + review: 审查 + config: 配置 + update_to: 更新到 + latest: 最新版本 + check_failed: 校验失败 + "yes": "是" + "no": "否" + not_allowed: 拒绝 + allowed: 允许 + enabled: 已启用 + disabled: 停用 + writable: 可写 + not_writable: 不可写 + flags: + title: 举报 + pending: 等待处理 + completed: 已完成 + flagged: 被举报内容 + flagged_type: 标记了 {{ type }} + created: 创建于 + action: 操作 + review: 审查 + user_role_modal: + title: 更改用户状态为... + btn_cancel: 取消 + btn_submit: 提交 + new_password_modal: + title: 设置新密码 + form: + fields: + password: + label: 密码 + text: 用户将被退出,需要再次登录。 + msg: 密码的长度必须是8-32个字符。 + btn_cancel: 取消 + btn_submit: 提交 + edit_profile_modal: + title: 编辑资料 + form: + fields: + username: + label: 用户名 + msg_range: 用户名不能超过 30 个字符。 + email: + label: 电子邮件地址 + msg_invalid: 无效的邮箱地址 + edit_success: 修改成功 + btn_cancel: 取消 + btn_submit: 提交 + user_modal: + title: 添加新用户 + form: + fields: + users: + label: 批量添加用户 + placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" + text: 用逗号分隔“name, email, password”,每行一个用户。 + msg: "请输入用户的邮箱,每行一个。" + display_name: + label: 显示名称 + msg: 显示名称长度必须为 4-30 个字符 + email: + label: 邮箱 + msg: 邮箱无效。 + password: + label: 密码 + msg: 密码的长度必须是8-32个字符。 + btn_cancel: 取消 + btn_submit: 提交 + users: + title: 用户 + name: 名称 + email: 邮箱 + reputation: 声望 + created_at: 创建时间 + delete_at: 删除时间 + suspend_at: 封禁时间 + status: 状态 + role: 角色 + action: 操作 + change: 更改 + all: 全部 + staff: 工作人员 + more: 更多 + inactive: 不活跃 + suspended: 已封禁 + deleted: 已删除 + normal: 正常 + Moderator: 版主 + Admin: 管理员 + User: 用户 + filter: + placeholder: "按名称筛选,用户:id" + set_new_password: 设置新密码 + edit_profile: 编辑资料 + change_status: 更改状态 + change_role: 更改角色 + show_logs: 显示日志 + add_user: 添加用户 + deactivate_user: + title: 停用用户 + content: 未激活的用户必须重新验证他们的邮箱。 + delete_user: + title: 删除此用户 + content: 确定要删除此用户?此操作无法撤销! + remove: 移除内容 + label: 删除所有问题、 答案、 评论等 + text: 如果你只想删除用户账户,请不要选中此项。 + suspend_user: + title: 挂起此用户 + content: 被封禁的用户将无法登录。 + questions: + page_title: 问题 + unlisted: 已隐藏 + post: 标题 + votes: 得票数 + answers: 回答数 + created: 创建于 + status: 状态 + action: 操作 + change: 更改 + pending: 等待处理 + filter: + placeholder: "按标题过滤,问题:id" + answers: + page_title: 回答 + post: 标题 + votes: 得票数 + created: 创建于 + status: 状态 + action: 操作 + change: 更改 + filter: + placeholder: "按标题筛选,答案:id" + general: + page_title: 一般 + name: + label: 站点名称 + msg: 不能为空 + text: "站点的名称,作为站点的标题。" + site_url: + label: 网站网址 + msg: 网站网址不能为空。 + validate: 请输入一个有效的 URL。 + text: 此网站的地址。 + short_desc: + label: 简短站点描述 + msg: 简短网站描述不能为空。 + text: "简短的标语,作为网站主页的标题(Html 的 title 标签)。" + desc: + label: 站点描述 + msg: 网站描述不能为空。 + text: "使用一句话描述本站,作为网站的描述(Html 的 meta 标签)。" + contact_email: + label: 联系邮箱 + msg: 联系人邮箱不能为空。 + validate: 联系人邮箱无效。 + text: 本网站的主要联系邮箱地址。 + check_update: + label: 软件更新 + text: 自动检查软件更新 + interface: + page_title: 界面 + language: + label: 界面语言 + msg: 不能为空 + text: 设置用户界面语言,在刷新页面后生效。 + time_zone: + label: 时区 + msg: 时区不能为空。 + text: 选择一个与您相同时区的城市。 + smtp: + page_title: SMTP + from_email: + label: 发件人邮箱 + msg: 发件人邮箱不能为空。 + text: 用于发送邮件的地址。 + from_name: + label: 发件人 + msg: 不能为空 + text: 发件人的名字。 + smtp_host: + label: SMTP 主机 + msg: 不能为空 + text: 邮件服务器 + encryption: + label: 加密 + msg: 不能为空 + text: 对于大多数服务器而言,SSL 是推荐开启的。 + ssl: SSL + tls: TLS + none: 无加密 + smtp_port: + label: SMTP 端口 + msg: SMTP 端口必须在 1 ~ 65535 之间。 + text: 邮件服务器的端口号。 + smtp_username: + label: SMTP 用户名 + msg: 不能为空 + smtp_password: + label: SMTP 密码 + msg: 不能为空 + test_email_recipient: + label: 测试收件邮箱 + text: 提供用于接收测试邮件的邮箱地址。 + msg: 测试收件邮箱无效 + smtp_authentication: + label: 启用身份验证 + title: SMTP 身份验证 + msg: 不能为空 + "yes": "是" + "no": "否" + branding: + page_title: 品牌 + logo: + label: 网站标志(Logo) + msg: 图标不能为空。 + text: 在你的网站左上方的Logo图标。使用一个高度为56,长宽比大于3:1的宽长方形图像。如果留空,将显示网站标题文本。 + mobile_logo: + label: 移动端 Logo + text: 在你的网站的移动版上使用的标志。使用一个高度为56的宽矩形图像。如果留空,将使用 "Logo"设置中的图像。 + square_icon: + label: 方形图标 + msg: 方形图标不能为空。 + text: 用作元数据图标的基础的图像。最好是大于512x512。 + favicon: + label: 收藏夹图标 + text: 网站的图标。要在 CDN 正常工作,它必须是 png。 将调整大小到32x32。如果留空,将使用“方形图标”。 + legal: + page_title: 法律条款 + terms_of_service: + label: 服务条款 + text: "您可以在此添加服务内容的条款。如果您已经在别处托管了文档,请在这里提供完整的URL。" + privacy_policy: + label: 隐私政策 + text: "您可以在此添加隐私政策内容。如果您已经在别处托管了文档,请在这里提供完整的URL。" + write: + page_title: 编辑 + restrict_answer: + title: 限制一个回答 + label: 每个用户对于每个问题只能有一个回答 + text: "用户可以使用编辑按钮优化已有的回答" + recommend_tags: + label: 推荐标签 + text: "请在上方输入标签固定链接,每行一个标签。" + required_tag: + title: 必需的标签 + label: 根据需要设置推荐标签 + text: "每个新问题必须至少有一个推荐标签。" + reserved_tags: + label: 保留标签 + text: "保留的标签只能由版主添加到一个帖子中。" + seo: + page_title: 搜索引擎优化 + permalink: + label: 固定链接 + text: 自定义URL结构可以提高可用性,以及你的链接的向前兼容性。 + robots: + label: robots.txt + text: 这将永久覆盖任何相关的网站设置。 + themes: + page_title: 主题 + themes: + label: 主题 + text: 选择一个现有主题。 + color_scheme: + label: 配色方案 + navbar_style: + label: 导航栏样式 + primary_color: + label: 主色调 + text: 修改您主题使用的颜色 + css_and_html: + page_title: CSS 与 HTML + custom_css: + label: 自定义 CSS + text: > + + head: + label: 头部 + text: > + + header: + label: 页眉 + text: > + + footer: + label: 页脚 + text: 这将在 之前插入. + sidebar: + label: 侧边栏 + text: 这将插入侧边栏中。 + login: + page_title: 登录 + membership: + title: 会员 + label: 允许新注册 + text: 关闭以防止任何人创建新账户。 + email_registration: + title: 邮箱注册 + label: 允许邮箱注册 + text: 关闭以阻止任何人通过邮箱创建新账户。 + allowed_email_domains: + title: 允许的邮箱域 + text: 允许注册账户的邮箱域。每行一个域名。留空时忽略。 + private: + title: 非公开的 + label: 需要登录 + text: 只有登录用户才能访问这个社区。 + password_login: + title: 密码登录 + label: 允许使用邮箱和密码登录 + text: "警告:如果您未配置过其他登录方式,关闭密码登录后您则可能无法登录。" + installed_plugins: + title: 已安装插件 + plugin_link: 插件扩展功能。您可以在<1>插件仓库中找到插件。 + filter: + all: 全部 + active: 已启用 + inactive: 未启用 + outdated: 已过期 + plugins: + label: 插件 + text: 选择一个现有的插件。 + name: 名称 + version: 版本 + status: 状态 + action: 操作 + deactivate: 停用 + activate: 启用 + settings: 设置 + settings_users: + title: 用户 + avatar: + label: 默认头像 + text: 没有自定义头像的用户。 + gravatar_base_url: + label: Gravatar 根路径 URL + text: Gravatar 提供商的 API 基础的 URL。当为空时忽略。 + profile_editable: + title: 个人资料可编辑 + allow_update_display_name: + label: 允许用户修改显示名称 + allow_update_username: + label: 允许用户修改用户名 + allow_update_avatar: + label: 允许用户修改个人头像 + allow_update_bio: + label: 允许用户修改个人介绍 + allow_update_website: + label: 允许用户修改个人主页网址 + allow_update_location: + label: 允许用户更改位置 + privilege: + title: 特权 + level: + label: 级别所需声望 + text: 选择特权所需的声望值 + msg: + should_be_number: 输入必须是数字 + number_larger_1: 数字应该大于等于 1 + form: + optional: (选填) + empty: 不能为空 + invalid: 是无效的 + btn_submit: 保存 + not_found_props: "所需属性 {{ key }} 未找到。" + select: 选择 + page_review: + review: 评论 + proposed: 提案 + question_edit: 问题编辑 + answer_edit: 回答编辑 + tag_edit: '标签管理: 编辑标签' + edit_summary: 编辑备注 + edit_question: 编辑问题 + edit_answer: 编辑回答 + edit_tag: 编辑标签 + empty: 没有剩余的审核任务。 + approve_revision_tip: 您是否批准此修订? + approve_flag_tip: 您是否批准此举报? + approve_post_tip: 您是否批准此帖子? + approve_user_tip: 您是否批准此修订? + suggest_edits: 建议的编辑 + flag_post: 举报帖子 + flag_user: 举报用户 + queued_post: 排队的帖子 + queued_user: 排队用户 + filter_label: 类型 + reputation: 声望值 + flag_post_type: 举报这个帖子的类型是 {{ type }} + flag_user_type: 举报这个用户的类型是 {{ type }} + edit_post: 编辑帖子 + list_post: 文章列表 + unlist_post: 隐藏的帖子 + timeline: + undeleted: 取消删除 + deleted: 删除 + downvote: 反对 + upvote: 点赞 + accept: 采纳 + cancelled: 已取消 + commented: '评论:' + rollback: 回滚 + edited: 最后编辑于 + answered: 回答于 + asked: 提问于 + closed: 关闭 + reopened: 重新开启 + created: 创建于 + pin: 已置顶 + unpin: 取消置頂 + show: 已显示 + hide: 已隐藏 + title: "历史记录" + tag_title: "时间线" + show_votes: "显示投票" + n_or_a: N/A + title_for_question: "时间线" + title_for_answer: "{{ title }} 的 {{ author }} 回答时间线" + title_for_tag: "时间线" + datetime: 日期时间 + type: 类型 + by: 由 + comment: 评论 + no_data: "空空如也" + users: + title: 用户 + users_with_the_most_reputation: 本周声望最高的用户 + users_with_the_most_vote: 本周投票最多的用户 + staffs: 我们的社区工作人员 + reputation: 声望值 + votes: 投票 + prompt: + leave_page: 确定要离开此页面? + changes_not_save: 您的更改尚未保存 + draft: + discard_confirm: 您确定要丢弃您的草稿吗? + messages: + post_deleted: 该帖子已被删除。 + post_pin: 该帖子已被置顶。 + post_unpin: 该帖子已被取消置顶。 + post_hide_list: 此帖子已经从列表中隐藏。 + post_show_list: 该帖子已显示到列表中。 + post_reopen: 这个帖子已被重新打开. + post_list: 这个帖子已经被显示 + post_unlist: 这个帖子已经被隐藏 + post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 From 38834e6294b566e29fdeca2ed318cdce6bf3dc26 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Mon, 5 Aug 2024 17:03:23 +0800 Subject: [PATCH 053/336] feat: Add Open Search support --- internal/controller/template_controller.go | 8 +++++ .../controller/template_render/question.go | 22 ++++++++++++++ internal/router/template_router.go | 2 ++ ui/template/header.html | 1 + ui/template/opensearch.xml | 29 +++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 ui/template/opensearch.xml diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index a7d69ebc..09f5bffc 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -562,6 +562,14 @@ func (tc *TemplateController) html(ctx *gin.Context, code int, tpl string, siteI ctx.HTML(code, tpl, data) } +func (tc *TemplateController) OpenSearch(ctx *gin.Context) { + if tc.checkPrivateMode(ctx) { + tc.Page404(ctx) + return + } + tc.templateRenderController.OpenSearch(ctx) +} + func (tc *TemplateController) Sitemap(ctx *gin.Context) { if tc.checkPrivateMode(ctx) { tc.Page404(ctx) diff --git a/internal/controller/template_render/question.go b/internal/controller/template_render/question.go index a65c3083..83d08dc7 100644 --- a/internal/controller/template_render/question.go +++ b/internal/controller/template_render/question.go @@ -89,6 +89,28 @@ func (t *TemplateRenderController) Sitemap(ctx *gin.Context) { ) } +func (t *TemplateRenderController) OpenSearch(ctx *gin.Context) { + general, err := t.siteInfoService.GetSiteGeneral(ctx) + if err != nil { + log.Error("get site general failed:", err) + return + } + + favicon := "favicon.ico" + branding, err := t.siteInfoService.GetSiteBranding(ctx) + if err == nil { + favicon = branding.Favicon + } + + ctx.Header("Content-Type", "application/xml") + ctx.HTML( + http.StatusOK, "opensearch.xml", gin.H{ + "general": general, + "favicon": favicon, + }, + ) +} + func (t *TemplateRenderController) SitemapPage(ctx *gin.Context, page int) error { general, err := t.siteInfoService.GetSiteGeneral(ctx) if err != nil { diff --git a/internal/router/template_router.go b/internal/router/template_router.go index 01e8b307..195030f9 100644 --- a/internal/router/template_router.go +++ b/internal/router/template_router.go @@ -60,6 +60,8 @@ func (a *TemplateRouter) RegisterTemplateRouter(r *gin.RouterGroup, baseURLPath seoNoAuth.GET("/404", a.templateController.Page404) + seoNoAuth.GET("/opensearch.xml", a.templateController.OpenSearch) + seo := r.Group(baseURLPath) seo.Use(a.authUserMiddleware.CheckPrivateMode()) seo.GET("/", a.templateController.Index) diff --git a/ui/template/header.html b/ui/template/header.html index 6eff7340..653f9a28 100644 --- a/ui/template/header.html +++ b/ui/template/header.html @@ -33,6 +33,7 @@ + + + {{$.general.Name}} + {{if $.general.Description}} + {{$.general.Description}} + {{end}} + UTF-8 + {{$.favicon}} + + From 1b043d3a64fc6f7f9b30ee1e735bd7d37a4492ff Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Tue, 6 Aug 2024 15:39:55 +0800 Subject: [PATCH 054/336] fix: branding favicon might be empty --- internal/controller/template_render/question.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/controller/template_render/question.go b/internal/controller/template_render/question.go index 83d08dc7..b9753618 100644 --- a/internal/controller/template_render/question.go +++ b/internal/controller/template_render/question.go @@ -96,9 +96,9 @@ func (t *TemplateRenderController) OpenSearch(ctx *gin.Context) { return } - favicon := "favicon.ico" + favicon := general.SiteUrl + "/favicon.ico" branding, err := t.siteInfoService.GetSiteBranding(ctx) - if err == nil { + if err == nil && len(branding.Favicon) > 0 { favicon = branding.Favicon } From 016abd1a9825ca710cee5b6df03ee5e27008e00e Mon Sep 17 00:00:00 2001 From: "James Roller, Jr." Date: Mon, 5 Aug 2024 20:10:12 -0700 Subject: [PATCH 055/336] add pvc dataSource - allow for restoring a volumeSnapshot --- charts/templates/pvc.yaml | 8 +++++++- charts/values.yaml | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/charts/templates/pvc.yaml b/charts/templates/pvc.yaml index 5dfab8fc..640fb9fe 100644 --- a/charts/templates/pvc.yaml +++ b/charts/templates/pvc.yaml @@ -20,7 +20,7 @@ kind: PersistentVolumeClaim apiVersion: v1 metadata: name: {{ include "answer.fullname" . }}-claim - {{- with .Values.persistence.annotations }} + {{- with .Values.persistence.annotations }} annotations: {{ toYaml . | indent 4 }} {{- end }} @@ -39,4 +39,10 @@ spec: resources: requests: storage: {{ .Values.persistence.size | quote }} + {{- with .Values.persistence.dataSource }} + dataSource: + name: {{ .name }} + kind: {{ .kind | default "VolumeSnapshot" }} + apiGroup: {{ .apiGroup | default "snapshot.storage.k8s.io" }} + {{- end }} {{- end }} \ No newline at end of file diff --git a/charts/values.yaml b/charts/values.yaml index 8bb36c46..d932db84 100644 --- a/charts/values.yaml +++ b/charts/values.yaml @@ -68,7 +68,7 @@ env: # Configure extra containers extraContainers: [] - # - name: cloudsql-proxy + # - name: cloudsql-proxy # image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.1.2 # command: # - /cloud-sql-proxy @@ -91,6 +91,12 @@ persistence: accessMode: ReadWriteOnce size: 5Gi annotations: {} + # To restore a PVC from a VolumeSnapshot, set the dataSource; + # the kind and apiGroup are optional and default to the shown values + dataSource: {} + # name: my-volume-snapshot + # kind: VolumeSnapshot + # apiGroup: snapshot.storage.k8s.io imagePullSecrets: [] nameOverride: "" From eda39380758e838a6c294d2a52ce1c325ebb2cd3 Mon Sep 17 00:00:00 2001 From: Sonui Date: Wed, 7 Aug 2024 22:51:23 +0800 Subject: [PATCH 056/336] perf: remove invalid nil pointer check in Translate function --- plugin/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/plugin.go b/plugin/plugin.go index 61ed0d8f..85286855 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -219,7 +219,7 @@ func MakeTranslator(key string) Translator { // Translate translates the key to the current language of the context func (t Translator) Translate(ctx *GinContext) string { - if &t == nil || t.Fn == nil { + if t.Fn == nil { return "" } return t.Fn(ctx) From 4b3e0eaa4e407842d62ec19b4313942b53d3809e Mon Sep 17 00:00:00 2001 From: Sonui Date: Wed, 14 Aug 2024 00:21:55 +0800 Subject: [PATCH 057/336] perf: update check-asf-header.sh script to support Podman --- script/check-asf-header.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/script/check-asf-header.sh b/script/check-asf-header.sh index ff765eab..808efa10 100755 --- a/script/check-asf-header.sh +++ b/script/check-asf-header.sh @@ -16,5 +16,16 @@ # specific language governing permissions and limitations # under the License. -docker run -it --rm -v $(pwd):/github/workspace ghcr.io/korandoru/hawkeye-native format +# check if docker or podman is installed +if command -v docker >/dev/null 2>&1; then + CONTAINER_RUNTIME="docker" +elif command -v podman >/dev/null 2>&1; then + CONTAINER_RUNTIME="podman" +else + echo "Neither Docker nor Podman is installed. Please install either Docker or Podman." + exit 1 +fi + +$CONTAINER_RUNTIME run -it --rm -v "$(pwd)":/github/workspace ghcr.io/korandoru/hawkeye-native format + gofmt -w -l . From 969169243bac95cc15eeee53e5dd4ebb307c37b1 Mon Sep 17 00:00:00 2001 From: Sonui Date: Thu, 15 Aug 2024 21:15:02 +0800 Subject: [PATCH 058/336] perf: remove extra characters in header.html --- ui/template/header.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/template/header.html b/ui/template/header.html index 653f9a28..0243a43d 100644 --- a/ui/template/header.html +++ b/ui/template/header.html @@ -68,14 +68,14 @@ From b41bafad30587ccada6818b58dd3328f22876aa4 Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 19 Aug 2024 15:15:07 +0800 Subject: [PATCH 059/336] fix(dev): delete test file --- dev/i18n/zh_CN.yaml | 2035 ------------------------------------------- 1 file changed, 2035 deletions(-) delete mode 100644 dev/i18n/zh_CN.yaml diff --git a/dev/i18n/zh_CN.yaml b/dev/i18n/zh_CN.yaml deleted file mode 100644 index 6613bfc2..00000000 --- a/dev/i18n/zh_CN.yaml +++ /dev/null @@ -1,2035 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# The following fields are used for back-end -backend: - base: - success: - other: 成功。 - unknown: - other: 未知错误。 - request_format_error: - other: 请求格式错误。 - unauthorized_error: - other: 未授权。 - database_error: - other: 数据服务器错误。 - forbidden_error: - other: 禁止访问。 - duplicate_request_error: - other: 重复提交。 - action: - report: - other: 举报 - edit: - other: 编辑 - delete: - other: 删除 - close: - other: 关闭 - reopen: - other: 重新打开 - forbidden_error: - other: 禁止访问。 - pin: - other: 置顶 - hide: - other: 列表隐藏 - unpin: - other: 取消置顶 - show: - other: 列表显示 - invite_someone_to_answer: - other: 编辑 - undelete: - other: 撤消删除 - role: - name: - user: - other: 用户 - admin: - other: 管理员 - moderator: - other: 版主 - description: - user: - other: 默认没有特殊权限。 - admin: - other: 拥有管理网站的全部权限。 - moderator: - other: 拥有除访问后台管理以外的所有权限。 - privilege: - level_1: - description: - other: 级别 1(少量声望要求,适合私有团队、群组) - level_2: - description: - other: 级别 2(低声望要求,适合初启动的社区) - level_3: - description: - other: 级别 3(高声望要求,适合成熟的社区) - level_custom: - description: - other: 自定义等级 - rank_question_add_label: - other: 提问 - rank_answer_add_label: - other: 写答案 - rank_comment_add_label: - other: 写评论 - rank_report_add_label: - other: 举报 - rank_comment_vote_up_label: - other: 点赞评论 - rank_link_url_limit_label: - other: 每次发布超过 2 个链接 - rank_question_vote_up_label: - other: 点赞问题 - rank_answer_vote_up_label: - other: 点赞答案 - rank_question_vote_down_label: - other: 点踩问题 - rank_answer_vote_down_label: - other: 点踩答案 - rank_invite_someone_to_answer_label: - other: 邀请回答 - rank_tag_add_label: - other: 创建新标签 - rank_tag_edit_label: - other: 编辑标签描述(需要审核) - rank_question_edit_label: - other: 编辑别人的问题(需要审核) - rank_answer_edit_label: - other: 编辑别人的答案(需要审核) - rank_question_edit_without_review_label: - other: 编辑别人的问题无需审核 - rank_answer_edit_without_review_label: - other: 编辑别人的答案无需审核 - rank_question_audit_label: - other: 审核问题编辑 - rank_answer_audit_label: - other: 审核回答编辑 - rank_tag_audit_label: - other: 审核标签编辑 - rank_tag_edit_without_review_label: - other: 编辑标签描述无需审核 - rank_tag_synonym_label: - other: 管理标签同义词 - email: - other: 邮箱 - e_mail: - other: 邮箱 - password: - other: 密码 - pass: - other: 密码 - original_text: - other: 本帖 - email_or_password_wrong_error: - other: 邮箱和密码不匹配。 - error: - common: - invalid_url: - other: 无效的 URL。 - password: - space_invalid: - other: 密码不得含有空格。 - admin: - cannot_update_their_password: - other: 你无法修改自己的密码。 - cannot_edit_their_profile: - other: 您不能修改您的个人资料。 - cannot_modify_self_status: - other: 你无法修改自己的状态。 - email_or_password_wrong: - other: 邮箱和密码不匹配。 - answer: - not_found: - other: 没有找到答案。 - cannot_deleted: - other: 没有删除权限。 - cannot_update: - other: 没有更新权限。 - question_closed_cannot_add: - other: 问题已关闭,无法添加。 - comment: - edit_without_permission: - other: 不允许编辑评论。 - not_found: - other: 评论未找到。 - cannot_edit_after_deadline: - other: 评论时间太久,无法修改。 - email: - duplicate: - other: 邮箱已存在。 - need_to_be_verified: - other: 邮箱需要验证。 - verify_url_expired: - other: 邮箱验证的网址已过期,请重新发送邮件。 - illegal_email_domain_error: - other: 此邮箱不在允许注册的邮箱域中。请使用其他邮箱尝试。 - lang: - not_found: - other: 语言文件未找到。 - object: - captcha_verification_failed: - other: 验证码错误。 - disallow_follow: - other: 你不能关注。 - disallow_vote: - other: 你不能投票。 - disallow_vote_your_self: - other: 你不能为自己的帖子投票。 - not_found: - other: 对象未找到。 - verification_failed: - other: 验证失败。 - email_or_password_incorrect: - other: 邮箱和密码不匹配。 - old_password_verification_failed: - other: 旧密码验证失败。 - new_password_same_as_previous_setting: - other: 新密码和旧密码相同。 - already_deleted: - other: 该帖子已被删除。 - meta: - object_not_found: - other: Meta 对象未找到 - question: - already_deleted: - other: 该帖子已被删除。 - under_review: - other: 您的帖子正在等待审核。它将在它获得批准后可见。 - not_found: - other: 问题未找到。 - cannot_deleted: - other: 没有删除权限。 - cannot_close: - other: 没有关闭权限。 - cannot_update: - other: 没有更新权限。 - rank: - fail_to_meet_the_condition: - other: 声望值未达到要求。 - vote_fail_to_meet_the_condition: - other: 感谢投票。你至少需要 {{.Rank}} 声望才能投票。 - no_enough_rank_to_operate: - other: 你至少需要 {{.Rank}} 声望才能执行此操作。 - report: - handle_failed: - other: 报告处理失败。 - not_found: - other: 报告未找到。 - tag: - already_exist: - other: 标签已存在。 - not_found: - other: 标签未找到。 - recommend_tag_not_found: - other: 推荐标签不存在。 - recommend_tag_enter: - other: 请选择至少一个必选标签。 - not_contain_synonym_tags: - other: 不应包含同义词标签。 - cannot_update: - other: 没有更新权限。 - is_used_cannot_delete: - other: 你不能删除这个正在使用的标签。 - cannot_set_synonym_as_itself: - other: 你不能将当前标签设为自己的同义词。 - smtp: - config_from_name_cannot_be_email: - other: 发件人名称不能是邮箱地址。 - theme: - not_found: - other: 主题未找到。 - revision: - review_underway: - other: 目前无法编辑,有一个版本在审阅队列中。 - no_permission: - other: 无权限修改。 - user: - external_login_missing_user_id: - other: 第三方平台没有提供唯一的 UserID,所以你不能登录,请联系网站管理员。 - external_login_unbinding_forbidden: - other: 请在移除此登录之前为你的账户设置登录密码。 - email_or_password_wrong: - other: - other: 邮箱和密码不匹配。 - not_found: - other: 用户未找到。 - suspended: - other: 用户已被封禁。 - username_invalid: - other: 用户名无效。 - username_duplicate: - other: 用户名已被使用。 - set_avatar: - other: 头像设置错误。 - cannot_update_your_role: - other: 你不能修改自己的角色。 - not_allowed_registration: - other: 该网站暂未开放注册。 - not_allowed_login_via_password: - other: 该网站暂不支持密码登录。 - access_denied: - other: 拒绝访问 - page_access_denied: - other: 您没有权限访问此页面。 - add_bulk_users_format_error: - other: "发生错误,{{.Field}} 格式错误,在 '{{.Content}}' 行数 {{.Line}}. {{.ExtraMessage}}" - add_bulk_users_amount_error: - other: "一次性添加的用户数量应在 1-{{.MaxAmount}} 之间。" - config: - read_config_failed: - other: 读取配置失败 - database: - connection_failed: - other: 数据库连接失败 - create_table_failed: - other: 创建表失败 - install: - create_config_failed: - other: 无法创建 config.yaml 文件。 - upload: - unsupported_file_format: - other: 不支持的文件格式。 - site_info: - config_not_found: - other: 未找到网站的该配置信息。 - reason: - spam: - name: - other: 垃圾信息 - desc: - other: 这个帖子是一个广告,或是破坏性行为。它对当前的主题无帮助或无关。 - rude_or_abusive: - name: - other: 粗鲁或辱骂的 - desc: - other: - - 一个有理智的人都会认为这种内容不适合进行尊重性的讨论。 - - 论坛 - a_duplicate: - name: - other: 重复内容 - desc: - other: 该问题有人问过,而且已经有了答案。 - placeholder: - other: 输入已有的问题链接 - not_a_answer: - name: - other: 不是答案 - desc: - other: - - 这张贴作为答案,但它不会试图回答 - - 这可能是一个编辑、一个评论、另一个问题。 - - 或全部删除。 - no_longer_needed: - name: - other: 不再需要 - desc: - other: 该评论已过时,对话性质或与此帖子无关。 - something: - name: - other: 其他原因 - desc: - other: 此帖子需要工作人员注意,因为是上述所列以外的其他理由。 - placeholder: - other: 让我们具体知道你关心的什么 - community_specific: - name: - other: 社区特定原因 - desc: - other: 该问题不符合社区准则。 - not_clarity: - name: - other: 需要细节或澄清 - desc: - other: 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - looks_ok: - name: - other: 看起来没问题 - desc: - other: 这个帖子是好的,不是低质量。 - needs_edit: - name: - other: 需要编辑,我已做了修改。 - desc: - other: 改进和纠正你自己帖子中的问题。 - needs_close: - name: - other: 需要关闭 - desc: - other: 关闭的问题不能回答,但仍然可以编辑、投票和评论。 - needs_delete: - name: - other: 需要删除 - desc: - other: 该帖子将被删除。 - question: - close: - duplicate: - name: - other: 垃圾信息 - desc: - other: 此问题以前就有人问过,而且已经有了答案。 - guideline: - name: - other: 社区特定原因 - desc: - other: 该问题不符合社区准则。 - multiple: - name: - other: 需要细节或澄清 - desc: - other: - - 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - - 只关注一个问题。 - other: - name: - other: 其他原因 - desc: - other: 该帖子存在上面没有列出的另一个原因。 - operation_type: - asked: - other: 提问于 - answered: - other: 回答于 - modified: - other: 修改于 - deleted_title: - other: 删除的问题 - notification: - action: - update_question: - other: 更新了问题 - answer_the_question: - other: 回答了问题 - update_answer: - other: 更新了答案 - accept_answer: - other: 采纳了答案 - comment_question: - other: 评论了问题 - comment_answer: - other: 评论了答案 - reply_to_you: - other: 回复了你 - mention_you: - other: 提到了你 - your_question_is_closed: - other: 你的问题已被关闭 - your_question_was_deleted: - other: 你的问题已被删除 - your_answer_was_deleted: - other: 你的答案已被删除 - your_comment_was_deleted: - other: 你的评论已被删除 - up_voted_question: - other: 点赞问题 - down_voted_question: - other: 点踩问题 - up_voted_answer: - other: 点赞答案 - down_voted_answer: - other: 点踩回答 - up_voted_comment: - other: 点赞评论 - invited_you_to_answer: - other: 邀请你回答 - email_tpl: - change_email: - title: - other: "[{{.SiteName}}] 确认你的新邮箱地址" - body: - other: "请点击以下链接确认你在 {{.SiteName}} 上的新邮箱地址:
\n{{.ChangeEmailUrl}}

\n\n如果你没有请求此更改,请忽略此邮件。\n" - new_answer: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 回答了你的问题" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - invited_you_to_answer: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 邀请您回答问题" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
我想你可能知道答案。

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - new_comment: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 评论了你的帖子" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - new_question: - title: - other: "[{{.SiteName}}] 新问题: {{.QuestionTitle}}" - body: - other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\n取消订阅" - pass_reset: - title: - other: "[{{.SiteName }}] 重置密码" - body: - other: "有人要求在 [{{.SiteName}}] 上重置你的密码。

\n\n如果这不是你的操作,请安心忽略此电子邮件。

\n\n请点击以下链接设置一个新密码:
\n{{.PassResetUrl}}\n" - register: - title: - other: "[{{.SiteName}}] 确认你的新账户" - body: - other: "欢迎加入 {{.SiteName}}!

\n\n请点击以下链接确认并激活你的新账户:
\n{{.RegisterUrl}}

\n\n如果上面的链接不能点击,请将其复制并粘贴到你的浏览器地址栏中。\n" - test: - title: - other: "[{{.SiteName}}] 测试邮件" - body: - other: "这是一封测试邮件。" - action_activity_type: - upvote: - other: 点赞 - upvoted: - other: 点赞 - downvote: - other: 点踩 - downvoted: - other: 点踩 - accept: - other: 采纳 - accepted: - other: 已采纳 - edit: - other: 编辑 - review: - queued_post: - other: 排队的帖子 - flagged_post: - other: 举报的帖子 - suggested_post_edit: - other: 建议的编辑 - reaction: - tooltip: - other: "{{ .Names }} 以及另外 {{ .Count }} 个..." -plugin: - s3_cdn: - backend: - info: - name: - other: S3 存储 CDN - description: - other: 上传文件到S3存储 - config: - endpoint: - title: - other: Endpoint - description: - other: S3存储的Endpoint - bucket_name: - title: - other: Bucket名称 - description: - other: S3存储的Bucket名称 - object_key_prefix: - title: - other: 对象Key前缀 - description: - other: 对象键的前缀,如'answer/data/',以'/'结尾 - access_key_id: - title: - other: AccessKeyID - description: - other: S3存储的AccessKeyID - access_key_secret: - title: - other: AccessKeySecret - description: - other: S3存储的AccessKeySecret - access_token: - title: - other: AccessToken - description: - other: 访问 S3 所需的 AccessToken - visit_url_prefix: - title: - other: 访问URL前缀 - description: - other: 上传静态文件CDN最终访问地址的前缀,以 '/' 结尾 https://static.example.com/xxx/ - max_file_size: - title: - other: 文件最大大小(MB) - description: - other: 限制上传文件的最大大小,单位MB,默认为10MB - region: - title: - other: 区域(Region) - description: - other: S3存储区域 - disable_ssl: - title: - other: 禁用SSL - description: - other: 我们建议您使用SSL访问S3存储。如果您想禁用SSL,请选中此选项。 - err: - mis_storage_config: - other: 错误的存储配置导致上传失败 - file_not_found: - other: 文件未找到 - unsupported_file_type: - other: 不支持的文件类型 - over_file_size_limit: - other: 超过文件大小限制 - upload_file_failed: - other: 上传文件失败 - aliyunoss_cdn: - backend: - info: - name: - other: 阿里云CDN OSS存储 - description: - other: 上传文件到阿里云CDN OSS存储 - config: - endpoint: - title: - other: Endpoint - description: - other: 阿里云OSS存储的Endpoint - bucket_name: - title: - other: Bucket名称 - description: - other: 阿里云OSS存储的Bucket名称 - object_key_prefix: - title: - other: 对象Key前缀 - description: - other: 对象键的前缀,如'answer/data/',以'/'结尾 - access_key_id: - title: - other: AccessKeyID - description: - other: 阿里云OSS存储的AccessKeyID - access_key_secret: - title: - other: AccessKeySecret - description: - other: 阿里云OSS存储的AccessKeySecret - visit_url_prefix: - title: - other: 访问URL前缀 - description: - other: CDN最终访问地址的前缀,以 '/' 结尾 https://example.com/xxx/ - max_file_size: - title: - other: 最大文件大小(MB) - description: - other: 限制上传文件的最大大小,单位为MB,默认为 10MB - err: - mis_storage_config: - other: 错误的存储配置导致上传失败 - file_not_found: - other: 文件未找到 - unsupported_file_type: - other: 不支持的文件类型 - over_file_size_limit: - other: 超过文件大小限制 - upload_file_failed: - other: 上传文件失败 -# The following fields are used for interface presentation(Front-end) -ui: - how_to_format: - title: 如何排版 - desc: >- -
  • 添加链接

    <https://url.com>

    [标题](https://url.com)
  • 段落之间使用空行分隔

  • _斜体_ 或者 **粗体**

  • 使用 4 个空格缩进代码

  • 在行首添加 > 表示引用

  • 反引号进行转义 `像 _这样_`

  • 使用 ``` 创建代码块

    ```
    这是代码块
    ```
- pagination: - prev: 上一页 - next: 下一页 - page_title: - question: 问题 - questions: 问题 - tag: 标签 - tags: 标签 - tag_wiki: 标签维基 - create_tag: 创建标签 - edit_tag: 编辑标签 - ask_a_question: 提问题 - edit_question: 编辑问题 - edit_answer: 编辑回答 - search: 搜索 - posts_containing: 帖子包含 - settings: 设置 - notifications: 通知 - login: 登录 - sign_up: 注册 - account_recovery: 账号恢复 - account_activation: 账号激活 - confirm_email: 确认电子邮件 - account_suspended: 账号已被封禁 - admin: 后台管理 - change_email: 修改邮箱 - install: Answer 安装 - upgrade: Answer 升级 - maintenance: 网站维护 - users: 用户 - oauth_callback: 处理中 - http_404: HTTP 错误 404 - http_50X: HTTP 错误 500 - http_403: HTTP 错误 403 - logout: 退出 - notifications: - title: 通知 - inbox: 收件箱 - achievement: 成就 - new_alerts: 新通知 - all_read: 全部标记为已读 - show_more: 显示更多 - someone: 有人 - inbox_type: - all: 全部 - posts: 帖子 - invites: 邀请 - votes: 投票 - suspended: - title: 你的账号账号已被封禁 - until_time: "你的账号被封禁直到 {{ time }}。" - forever: 你的账号已被永久封禁。 - end: 你违反了我们的社区准则。 - contact_us: 联系我们 - editor: - blockquote: - text: 引用 - bold: - text: 粗体 - chart: - text: 图表 - flow_chart: 流程图 - sequence_diagram: 时序图 - class_diagram: 类图 - state_diagram: 状态图 - entity_relationship_diagram: 实体关系图 - user_defined_diagram: 用户自定义图表 - gantt_chart: 甘特图 - pie_chart: 饼图 - code: - text: 代码块 - add_code: 添加代码块 - form: - fields: - code: - label: 代码块 - msg: - empty: 代码块不能为空 - language: - label: 语言 - placeholder: 自动识别 - btn_cancel: 取消 - btn_confirm: 添加 - formula: - text: 公式 - options: - inline: 行内公式 - block: 块级公式 - heading: - text: 标题 - options: - h1: 标题 1 - h2: 标题 2 - h3: 标题 3 - h4: 标题 4 - h5: 标题 5 - h6: 标题 6 - help: - text: 帮助 - hr: - text: 水平线 - image: - text: 图片 - add_image: 添加图片 - tab_image: 上传图片 - form_image: - fields: - file: - label: 图像文件 - btn: 选择图片 - msg: - empty: 请选择图片文件。 - only_image: 只能上传图片文件。 - max_size: 文件大小不能超过 4 MB。 - desc: - label: 描述 - tab_url: 图片地址 - form_url: - fields: - url: - label: 图片地址 - msg: - empty: 图片地址不能为空 - name: - label: 描述 - btn_cancel: 取消 - btn_confirm: 添加 - uploading: 上传中 - indent: - text: 缩进 - outdent: - text: 减少缩进 - italic: - text: 斜体 - link: - text: 超链接 - add_link: 添加超链接 - form: - fields: - url: - label: 链接 - msg: - empty: 链接不能为空。 - name: - label: 描述 - btn_cancel: 取消 - btn_confirm: 添加 - ordered_list: - text: 有序列表 - unordered_list: - text: 无序列表 - table: - text: 表格 - heading: 表头 - cell: 单元格 - close_modal: - title: 关闭原因是... - btn_cancel: 取消 - btn_submit: 提交 - remark: - empty: 不能为空。 - msg: - empty: 请选择一个原因。 - report_modal: - flag_title: 我举报这篇帖子的原因是... - close_title: 我关闭这篇帖子的原因是... - review_question_title: 审查问题 - review_answer_title: 审查回答 - review_comment_title: 审查评论 - btn_cancel: 取消 - btn_submit: 提交 - remark: - empty: 不能为空 - msg: - empty: 请选择一个原因。 - not_a_url: URL 格式不正确。 - url_not_match: URL 来源与当前网站不匹配。 - tag_modal: - title: 创建新标签 - form: - fields: - display_name: - label: 显示名称 - msg: - empty: 显示名称不能为空。 - range: 显示名称不能超过 35 个字符。 - slug_name: - label: URL 固定链接 - desc: URL 固定链接不能超过 35 个字符。 - msg: - empty: URL 固定链接不能为空。 - range: URL 固定链接不能超过 35 个字符。 - character: URL 固定链接包含非法字符。 - desc: - label: 描述 - revision: - label: 编辑历史 - edit_summary: - label: 编辑备注 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_cancel: 取消 - btn_submit: 提交 - btn_post: 发布新标签 - tag_info: - created_at: 创建于 - edited_at: 编辑于 - history: 历史 - synonyms: - title: 同义词 - text: 以下标签将被重置到 - empty: 此标签目前没有同义词。 - btn_add: 添加同义词 - btn_edit: 编辑 - btn_save: 保存 - synonyms_text: 以下标签将被重置到 - delete: - title: 删除标签 - tip_with_posts: >- -

我们不允许 删除带有帖子的标签

请先从帖子中移除此标签。

- tip_with_synonyms: >- -

我们不允许 删除带有同义词的标签

请先从此标签中删除同义词。

- tip: 确定要删除吗? - close: 关闭 - edit_tag: - title: 编辑标签 - default_reason: 编辑标签 - default_first_reason: 添加标签 - btn_save_edits: 保存更改 - btn_cancel: 取消 - dates: - long_date: MM 月 DD 日 - long_date_with_year: "YYYY 年 MM 月 DD 日" - long_date_with_time: "YYYY 年 MM 月 DD 日 HH:mm" - now: 刚刚 - x_seconds_ago: "{{count}} 秒前" - x_minutes_ago: "{{count}} 分钟前" - x_hours_ago: "{{count}} 小时前" - hour: 小时 - day: 天 - hours: 小时 - days: 日 - reaction: - heart: 爱心 - smile: 微笑 - frown: 愁 - btn_label: 添加或删除回应。 - undo_emoji: 撤销 {{ emoji }} 回应 - react_emoji: 用 {{ emoji }} 回应 - unreact_emoji: 撤销 {{ emoji }} - comment: - btn_add_comment: 添加评论 - reply_to: 回复 - btn_reply: 回复 - btn_edit: 编辑 - btn_delete: 删除 - btn_flag: 举报 - btn_save_edits: 保存更改 - btn_cancel: 取消 - show_more: "{{count}} 条剩余评论" - tip_question: >- - 使用评论提问更多信息或者提出改进意见。避免在评论里回答问题。 - tip_answer: >- - 使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。 - tip_vote: 它给帖子添加了一些有用的内容 - edit_answer: - title: 编辑回答 - default_reason: 编辑回答 - default_first_reason: 添加答案 - form: - fields: - revision: - label: 编辑历史 - answer: - label: 回答内容 - feedback: - characters: 内容长度至少 6 个字符 - edit_summary: - label: 编辑摘要 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_save_edits: 保存更改 - btn_cancel: 取消 - tags: - title: 标签 - sort_buttons: - popular: 热门 - name: 名称 - newest: 最新 - button_follow: 关注 - button_following: 已关注 - tag_label: 个问题 - search_placeholder: 通过标签名称过滤 - no_desc: 此标签无描述。 - more: 更多 - ask: - title: 新增问题 - edit_title: 编辑问题 - default_reason: 编辑问题 - default_first_reason: 新增问题 - similar_questions: 相似问题 - form: - fields: - revision: - label: 修订版本 - title: - label: 标题 - placeholder: 请详细描述你的问题,想象你在问一个人 - msg: - empty: 标题不能为空。 - range: 标题最多 150 个字符 - body: - label: 内容 - msg: - empty: 内容不能为空。 - tags: - label: 标签 - msg: - empty: 必须选择一个标签 - answer: - label: 回答内容 - msg: - empty: 回答内容不能为空 - edit_summary: - label: 编辑备注 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_post_question: 提交问题 - btn_save_edits: 保存更改 - answer_question: 回答自己的问题 - post_question&answer: 提交问题和回答 - tag_selector: - add_btn: 添加标签 - create_btn: 创建新标签 - search_tag: 搜索标签 - hint: "描述您的问题是关于什么,至少需要一个标签。" - no_result: 没有匹配的标签 - tag_required_text: 必选标签(至少一个) - header: - nav: - question: 问题 - tag: 标签 - user: 用户 - profile: 用户主页 - setting: 账号设置 - logout: 退出 - admin: 后台管理 - review: 审查 - bookmark: 收藏夹 - moderation: 管理 - search: - placeholder: 搜索 - footer: - build_on: >- - 由 <1>Apache Answer 提供动力 - 驱动问答社区的开源软件。
用爱制造 © {{cc}}. - upload_img: - name: 更改 - loading: 加载中... - pic_auth_code: - title: 验证码 - placeholder: 输入图片中的文字 - msg: - empty: 验证码不能为空。 - inactive: - first: >- - 就差一步!我们发送了一封激活邮件到 {{mail}}。请按照邮件中的说明激活你的账户。 - info: "如果没有收到,请检查你的垃圾邮件文件夹。" - another: >- - 我们向你的邮箱 {{mail}} 发送了另一封激活电子邮件。可能需要几分钟才能到达;请务必检查您的垃圾邮件箱。 - btn_name: 重新发送激活邮件 - change_btn_name: 更改邮箱 - msg: - empty: 不能为空。 - resend_email: - url_label: 确定要重新发送激活邮件吗? - url_text: 你也可以将上面的激活链接给该用户。 - login: - login_to_continue: 登录以继续 - info_sign: 没有账户?<1>注册 - info_login: 已经有账户?<1>登录 - agreements: 登录即表示您同意<1>隐私政策和<3>服务条款。 - forgot_pass: 忘记密码? - name: - label: 名字 - msg: - empty: 名字不能为空 - range: 名字应该在 4 到 30 个字符之间 - character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' - email: - label: 邮箱 - msg: - empty: 邮箱不能为空 - password: - label: 密码 - msg: - empty: 密码不能为空 - different: 两次输入密码不一致 - account_forgot: - page_title: 忘记密码 - btn_name: 发送恢复邮件 - send_success: >- - 如果存在邮箱为 {{mail}} 账户,你将很快收到一封重置密码的说明邮件。 - email: - label: 邮箱 - msg: - empty: 邮箱不能为空 - change_email: - btn_cancel: 取消 - btn_update: 更新电子邮件地址 - send_success: >- - 如果存在邮箱为 {{mail}} 的账户,你将很快收到一封重置密码的说明邮件。 - email: - label: 新的电子邮件地址 - msg: - empty: 邮箱不能为空。 - oauth: - connect: 连接到 {{ auth_name }} - remove: 移除 {{ auth_name }} - oauth_bind_email: - subtitle: 向你的账户添加恢复邮件地址。 - btn_update: 更新电子邮件地址 - email: - label: 邮箱 - msg: - empty: 邮箱不能为空。 - modal_title: 邮箱已经存在。 - modal_content: 该电子邮件地址已经注册。你确定要连接到已有账户吗? - modal_cancel: 更改邮箱 - modal_confirm: 连接到已有账户 - password_reset: - page_title: 密码重置 - btn_name: 重置我的密码 - reset_success: >- - 你已经成功更改密码;你将被重定向到登录页面。 - link_invalid: >- - 抱歉,此密码重置链接已失效。也许是你已经重置过密码了? - to_login: 前往登录页面 - password: - label: 密码 - msg: - empty: 密码不能为空。 - length: 密码长度在8-32个字符之间 - different: 两次输入密码不一致 - password_confirm: - label: 确认新密码 - settings: - page_title: 设置 - goto_modify: 前往修改 - nav: - profile: 我的资料 - notification: 通知 - account: 账号 - interface: 界面 - profile: - heading: 个人资料 - btn_name: 保存 - display_name: - label: 显示名称 - msg: 昵称不能为空。 - msg_range: 显示名称不能超过 30 个字符。 - username: - label: 用户名 - caption: 用户可以通过 "@用户名" 来提及你。 - msg: 用户名不能为空 - msg_range: 用户名不能超过 30 个字符。 - character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' - avatar: - label: 头像 - gravatar: Gravatar - gravatar_text: 你可以更改图像在 - custom: 自定义 - custom_text: 你可以上传你的图片。 - default: 系统 - msg: 请上传头像 - bio: - label: 关于我 - website: - label: 网站 - placeholder: "https://example.com" - msg: 网址格式不正确 - location: - label: 位置 - placeholder: "城市,国家" - notification: - heading: 邮件通知 - turn_on: 开启 - inbox: - label: 收件箱通知 - description: 你的提问有新的回答,评论,邀请回答和其他。 - all_new_question: - label: 所有新问题 - description: 获取所有新问题的通知。每周最多有50个问题。 - all_new_question_for_following_tags: - label: 所有关注标签的新问题 - description: 获取关注的标签下新问题通知。 - account: - heading: 账号 - change_email_btn: 更改邮箱 - change_pass_btn: 更改密码 - change_email_info: >- - 邮件已发送。请根据指引完成验证。 - email: - label: 电子邮件地址 - new_email: - label: 新的电子邮件地址 - msg: 新邮箱不能为空。 - pass: - label: 当前密码 - msg: 密码不能为空。 - password_title: 密码 - current_pass: - label: 当前密码 - msg: - empty: 当前密码不能为空 - length: 密码长度必须在 8 至 32 之间 - different: 两次输入的密码不匹配 - new_pass: - label: 新密码 - pass_confirm: - label: 确认新密码 - interface: - heading: 界面 - lang: - label: 界面语言 - text: 设置用户界面语言,在刷新页面后生效。 - my_logins: - title: 我的登录 - label: 使用这些账户登录或注册本网站。 - modal_title: 移除登录 - modal_content: 你确定要从账户里移除该登录? - modal_confirm_btn: 移除 - remove_success: 移除成功 - toast: - update: 更新成功 - update_password: 密码更新成功。 - flag_success: 感谢标记。 - forbidden_operate_self: 禁止对自己执行操作 - review: 您的修订将在审阅通过后显示。 - sent_success: 发送成功 - related_question: - title: 相关问题 - answers: 个回答 - invite_to_answer: - title: 受邀人 - desc: 邀请你认为可能知道答案的人。 - invite: 邀请回答 - add: 添加人员 - search: 搜索人员 - question_detail: - action: 操作 - Asked: 提问于 - asked: 提问于 - update: 修改于 - edit: 编辑于 - commented: 评论 - Views: 阅读次数 - Follow: 关注此问题 - Following: 已关注 - follow_tip: 关注此问题以接收通知 - answered: 回答于 - closed_in: 关闭于 - show_exist: 查看类似问题。 - useful: 有用的 - question_useful: 它是有用和明确的 - question_un_useful: 它不明确或没用的 - question_bookmark: 收藏该问题 - answer_useful: 这是有用的 - answer_un_useful: 它是没有用的 - answers: - title: 个回答 - score: 评分 - newest: 最新 - oldest: 最旧 - btn_accept: 采纳 - btn_accepted: 已被采纳 - write_answer: - title: 你的回答 - edit_answer: 编辑我的回答 - btn_name: 提交你的回答 - add_another_answer: 添加另一个回答 - confirm_title: 继续回答 - continue: 继续 - confirm_info: >- -

你确定要提交一个新的回答吗?

作为替代,你可以通过编辑来完善和改进之前的回答。

- empty: 回答内容不能为空。 - characters: 内容长度至少 6 个字符。 - tips: - header_1: 感谢你的回答 - li1_1: 请务必确定在 回答问题。提供详细信息并分享你的研究。 - li1_2: 用参考资料或个人经历来支持你所做的任何陈述。 - header_2: 但是 请避免... - li2_1: 请求帮助,寻求澄清,或答复其他答案。 - reopen: - confirm_btn: 重新打开 - title: 重新打开这个帖子 - content: 确定要重新打开吗? - list: - confirm_btn: 列表显示 - title: 列表中显示这个帖子 - content: 确定要列表中显示这个帖子吗? - unlist: - confirm_btn: 列表隐藏 - title: 从列表中隐藏这个帖子 - content: 确定要从列表中隐藏这个帖子吗? - pin: - title: 置顶该帖子 - content: 你确定要全局置顶吗?这个帖子将出现在所有帖子列表的顶部。 - confirm_btn: 置顶 - delete: - title: 删除 - question: >- - 我们不建议 删除有回答的帖子。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗? - answer_accepted: >- -

我们不建议删除被采纳的回答。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗? - other: 你确定要删除? - tip_answer_deleted: 该回答已被删除 - undelete_title: 撤销删除本帖 - undelete_desc: 你确定你要撤销删除吗? - btns: - confirm: 确认 - cancel: 取消 - edit: 编辑 - save: 保存 - delete: 删除 - undelete: 撤消删除 - list: 列表显示 - unlist: 列表隐藏 - unlisted: 已隐藏 - login: 登录 - signup: 注册 - logout: 退出 - verify: 验证 - add_question: 我要提问 - approve: 批准 - reject: 拒绝 - skip: 跳过 - discard_draft: 丢弃草稿 - pinned: 已置顶 - all: 全部 - question: 问题 - answer: 回答 - comment: 评论 - refresh: 刷新 - resend: 重新发送 - deactivate: 取消激活 - active: 激活 - suspend: 封禁 - unsuspend: 解禁 - close: 关闭 - reopen: 重新打开 - ok: 确定 - light: 浅色 - dark: 深色 - system_setting: 跟随系统 - default: 默认 - reset: 重置 - tag: 标签 - post_lowercase: 帖子 - filter: 筛选 - ignore: 忽略 - submit: 提交 - normal: 正常 - closed: 已关闭 - deleted: 已删除 - pending: 等待处理 - more: 更多 - search: - title: 搜索结果 - keywords: 关键词 - options: 选项 - follow: 关注 - following: 已关注 - counts: "{{count}} 个结果" - more: 更多 - sort_btns: - relevance: 相关性 - newest: 最新的 - active: 活跃的 - score: 评分 - more: 更多 - tips: - title: 高级搜索提示 - tag: "<1>[tag] 在指定标签中搜索" - user: "<1>user:username 根据作者搜索" - answer: "<1>answers:0 搜索未回答的问题" - score: "<1>score:3 评分 3+ 的帖子" - question: "<1>is:question 搜索问题" - is_answer: "<1>is:answer 搜索回答" - empty: 找不到任何相关的内容。
请尝试其他关键字,或者减少查找内容的长度。 - share: - name: 分享 - copy: 复制链接 - via: 分享到... - copied: 已复制 - facebook: 分享到 Facebook - twitter: 分享到 Twitter - cannot_vote_for_self: 你不能给自己的帖子投票。 - modal_confirm: - title: 发生错误... - account_result: - success: 你的账号已通过验证,即将返回首页。 - link: 返回首页 - invalid: >- - 抱歉,此验证链接已失效。也许你的账号已经激活了? - confirm_new_email: 你的电子邮箱已更新 - confirm_new_email_invalid: >- - 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了? - unsubscribe: - page_title: 退订 - success_title: 退订成功 - success_desc: 您已成功退订,并且将不会再收到我们的邮件。 - link: 更改设置 - question: - following_tags: 已关注的标签 - edit: 编辑 - save: 保存 - follow_tag_tip: 关注标签来筛选你的问题列表。 - hot_questions: 热门问题 - all_questions: 全部问题 - x_questions: "{{ count }} 个问题" - x_answers: "{{ count }} 个回答" - questions: 问题 - answers: 回答 - newest: 最新 - active: 活跃 - hot: 热门 - score: 评分 - unanswered: 未回答 - modified: 更新于 - answered: 回答于 - asked: 提问于 - closed: 已关闭 - follow_a_tag: 关注一个标签 - more: 更多 - personal: - overview: 概览 - answers: 回答 - answer: 回答 - questions: 问题 - question: 问题 - bookmarks: 收藏 - reputation: 声望 - comments: 评论 - votes: 得票 - newest: 最新 - score: 评分 - edit_profile: 编辑资料 - visited_x_days: "已访问 {{ count }} 天" - viewed: 浏览次数 - joined: 加入于 - last_login: 上次登录 - about_me: 关于我 - about_me_empty: "// Hello, World!" - top_answers: 高分回答 - top_questions: 高分问题 - stats: 状态 - list_empty: 没有找到相关的内容。
试试看其他选项卡? - accepted: 已采纳 - answered: 回答于 - asked: 提问于 - downvoted: 点踩 - mod_short: 版主 - mod_long: 版主 - x_reputation: 声望 - x_votes: 得票 - x_answers: 个回答 - x_questions: 个问题 - install: - title: 安装 - next: 下一步 - done: 完成 - config_yaml_error: 无法创建 config.yaml 文件。 - lang: - label: 请选择一种语言 - db_type: - label: 数据库引擎 - db_username: - label: 用户名 - placeholder: root - msg: 用户名不能为空 - db_password: - label: 密码 - placeholder: root - msg: 密码不能为空 - db_host: - label: 数据库主机 - placeholder: "db:3306" - msg: 数据库地址不能为空 - db_name: - label: 数据库名 - placeholder: 回答 - msg: 数据库名称不能为空。 - db_file: - label: 数据库文件 - placeholder: /data/answer.db - msg: 数据库文件不能为空。 - config_yaml: - title: 创建 config.yaml - label: 已创建 config.yaml 文件。 - desc: >- - 你可以手动在 <1>/var/wwww/xxx/ 目录中创建 <1>config.yaml 文件并粘贴以下文本。 - info: 完成后,点击“下一步”按钮。 - site_information: 站点信息 - admin_account: 管理员账号 - site_name: - label: 站点名称 - msg: 站点名称不能为空。 - msg_max_length: 站点名称长度不得超过 30 个字符。 - site_url: - label: 网站网址 - text: 此网站的网址。 - msg: - empty: 网址不能为空。 - incorrect: 网址格式不正确。 - max_length: 网址长度不得超过 512 个字符。 - contact_email: - label: 联系邮箱 - text: 负责本网站的主要联系人的电子邮件地址。 - msg: - empty: 联系人邮箱不能为空。 - incorrect: 联系人邮箱地址不正确。 - login_required: - label: 私有的 - switch: 需要登录 - text: 只有登录用户才能访问这个社区。 - admin_name: - label: 名字 - msg: 名字不能为空。 - character: '只能由 "a-z", "0-9", " - . _" 组成' - msg_max_length: 名字长度不能超过 30 个字符。 - admin_password: - label: 密码 - text: >- - 您需要此密码才能登录。请将其存储在一个安全的位置。 - msg: 密码不能为空。 - msg_min_length: 密码必须至少 8 个字符长。 - msg_max_length: 密码长度不能超过 32 个字符。 - admin_email: - label: 邮箱 - text: 您需要此电子邮件才能登录。 - msg: - empty: 邮箱不能为空。 - incorrect: 邮箱格式不正确。 - ready_title: 您的网站已准备好 - ready_desc: >- - 如果你想改变更多的设置,请访问 <1>管理区域;在网站菜单中找到它。 - good_luck: "玩得愉快,祝你好运!" - warn_title: 警告 - warn_desc: >- - 文件 <1>config.yaml 已存在。如果你要重置该文件中的任何配置项,请先删除它。 - install_now: 您可以尝试 <1>现在安装。 - installed: 已安裝 - installed_desc: >- - 你似乎已经安装过了。如果要重新安装,请先清除旧的数据库表。 - db_failed: 数据连接异常! - db_failed_desc: >- - 这或者意味着数据库信息在 <1>config.yaml 文件不正确,或者无法与数据库服务器建立联系。这可能意味着你的主机数据库服务器故障。 - counts: - views: 次浏览 - votes: 个点赞 - answers: 个回答 - accepted: 已被采纳 - page_error: - http_error: HTTP 错误 {{ code }} - desc_403: 您无权访问此页面。 - desc_404: 很抱歉,此页面不存在。 - desc_50X: 服务器遇到了一个错误,无法完成你的请求。 - back_home: 返回首页 - page_maintenance: - desc: "我们正在进行维护,我们将很快回来。" - nav_menus: - dashboard: 后台管理 - contents: 内容管理 - questions: 问题 - answers: 回答 - users: 用户管理 - flags: 举报管理 - settings: 站点设置 - general: 一般 - interface: 界面 - smtp: SMTP - branding: 品牌 - legal: 法律条款 - write: 撰写 - tos: 服务条款 - privacy: 隐私政策 - seo: SEO - customize: 自定义 - themes: 主题 - css_html: CSS/HTML - login: 登录 - privileges: 特权 - plugins: 插件 - installed_plugins: 已安装插件 - website_welcome: 欢迎来到 {{site_name}} - user_center: - login: 登录 - qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码并登录。 - login_failed_email_tip: 登录失败,请允许此应用访问您的邮箱信息,然后重试。 - admin: - admin_header: - title: 后台管理 - dashboard: - title: 后台管理 - welcome: 欢迎来到管理后台! - site_statistics: 站点统计 - questions: "问题:" - answers: "回答:" - comments: "评论:" - votes: "投票:" - users: "用户:" - flags: "举报:" - reviews: "审查:" - site_health: 网站健康 - version: "版本" - https: "HTTPS:" - upload_folder: "上传文件夹:" - run_mode: "运行模式:" - private: 私有 - public: 公开 - smtp: "SMTP:" - timezone: "时区:" - system_info: 系统信息 - go_version: "Go版本:" - database: "数据库:" - database_size: "数据库大小:" - storage_used: "已用存储空间:" - uptime: "运行时间:" - links: 链接 - plugins: 插件 - github: GitHub - blog: 博客 - contact: 联系 - forum: 论坛 - documents: 文档 - feedback: 用户反馈 - support: 帮助 - review: 审查 - config: 配置 - update_to: 更新到 - latest: 最新版本 - check_failed: 校验失败 - "yes": "是" - "no": "否" - not_allowed: 拒绝 - allowed: 允许 - enabled: 已启用 - disabled: 停用 - writable: 可写 - not_writable: 不可写 - flags: - title: 举报 - pending: 等待处理 - completed: 已完成 - flagged: 被举报内容 - flagged_type: 标记了 {{ type }} - created: 创建于 - action: 操作 - review: 审查 - user_role_modal: - title: 更改用户状态为... - btn_cancel: 取消 - btn_submit: 提交 - new_password_modal: - title: 设置新密码 - form: - fields: - password: - label: 密码 - text: 用户将被退出,需要再次登录。 - msg: 密码的长度必须是8-32个字符。 - btn_cancel: 取消 - btn_submit: 提交 - edit_profile_modal: - title: 编辑资料 - form: - fields: - username: - label: 用户名 - msg_range: 用户名不能超过 30 个字符。 - email: - label: 电子邮件地址 - msg_invalid: 无效的邮箱地址 - edit_success: 修改成功 - btn_cancel: 取消 - btn_submit: 提交 - user_modal: - title: 添加新用户 - form: - fields: - users: - label: 批量添加用户 - placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" - text: 用逗号分隔“name, email, password”,每行一个用户。 - msg: "请输入用户的邮箱,每行一个。" - display_name: - label: 显示名称 - msg: 显示名称长度必须为 4-30 个字符 - email: - label: 邮箱 - msg: 邮箱无效。 - password: - label: 密码 - msg: 密码的长度必须是8-32个字符。 - btn_cancel: 取消 - btn_submit: 提交 - users: - title: 用户 - name: 名称 - email: 邮箱 - reputation: 声望 - created_at: 创建时间 - delete_at: 删除时间 - suspend_at: 封禁时间 - status: 状态 - role: 角色 - action: 操作 - change: 更改 - all: 全部 - staff: 工作人员 - more: 更多 - inactive: 不活跃 - suspended: 已封禁 - deleted: 已删除 - normal: 正常 - Moderator: 版主 - Admin: 管理员 - User: 用户 - filter: - placeholder: "按名称筛选,用户:id" - set_new_password: 设置新密码 - edit_profile: 编辑资料 - change_status: 更改状态 - change_role: 更改角色 - show_logs: 显示日志 - add_user: 添加用户 - deactivate_user: - title: 停用用户 - content: 未激活的用户必须重新验证他们的邮箱。 - delete_user: - title: 删除此用户 - content: 确定要删除此用户?此操作无法撤销! - remove: 移除内容 - label: 删除所有问题、 答案、 评论等 - text: 如果你只想删除用户账户,请不要选中此项。 - suspend_user: - title: 挂起此用户 - content: 被封禁的用户将无法登录。 - questions: - page_title: 问题 - unlisted: 已隐藏 - post: 标题 - votes: 得票数 - answers: 回答数 - created: 创建于 - status: 状态 - action: 操作 - change: 更改 - pending: 等待处理 - filter: - placeholder: "按标题过滤,问题:id" - answers: - page_title: 回答 - post: 标题 - votes: 得票数 - created: 创建于 - status: 状态 - action: 操作 - change: 更改 - filter: - placeholder: "按标题筛选,答案:id" - general: - page_title: 一般 - name: - label: 站点名称 - msg: 不能为空 - text: "站点的名称,作为站点的标题。" - site_url: - label: 网站网址 - msg: 网站网址不能为空。 - validate: 请输入一个有效的 URL。 - text: 此网站的地址。 - short_desc: - label: 简短站点描述 - msg: 简短网站描述不能为空。 - text: "简短的标语,作为网站主页的标题(Html 的 title 标签)。" - desc: - label: 站点描述 - msg: 网站描述不能为空。 - text: "使用一句话描述本站,作为网站的描述(Html 的 meta 标签)。" - contact_email: - label: 联系邮箱 - msg: 联系人邮箱不能为空。 - validate: 联系人邮箱无效。 - text: 本网站的主要联系邮箱地址。 - check_update: - label: 软件更新 - text: 自动检查软件更新 - interface: - page_title: 界面 - language: - label: 界面语言 - msg: 不能为空 - text: 设置用户界面语言,在刷新页面后生效。 - time_zone: - label: 时区 - msg: 时区不能为空。 - text: 选择一个与您相同时区的城市。 - smtp: - page_title: SMTP - from_email: - label: 发件人邮箱 - msg: 发件人邮箱不能为空。 - text: 用于发送邮件的地址。 - from_name: - label: 发件人 - msg: 不能为空 - text: 发件人的名字。 - smtp_host: - label: SMTP 主机 - msg: 不能为空 - text: 邮件服务器 - encryption: - label: 加密 - msg: 不能为空 - text: 对于大多数服务器而言,SSL 是推荐开启的。 - ssl: SSL - tls: TLS - none: 无加密 - smtp_port: - label: SMTP 端口 - msg: SMTP 端口必须在 1 ~ 65535 之间。 - text: 邮件服务器的端口号。 - smtp_username: - label: SMTP 用户名 - msg: 不能为空 - smtp_password: - label: SMTP 密码 - msg: 不能为空 - test_email_recipient: - label: 测试收件邮箱 - text: 提供用于接收测试邮件的邮箱地址。 - msg: 测试收件邮箱无效 - smtp_authentication: - label: 启用身份验证 - title: SMTP 身份验证 - msg: 不能为空 - "yes": "是" - "no": "否" - branding: - page_title: 品牌 - logo: - label: 网站标志(Logo) - msg: 图标不能为空。 - text: 在你的网站左上方的Logo图标。使用一个高度为56,长宽比大于3:1的宽长方形图像。如果留空,将显示网站标题文本。 - mobile_logo: - label: 移动端 Logo - text: 在你的网站的移动版上使用的标志。使用一个高度为56的宽矩形图像。如果留空,将使用 "Logo"设置中的图像。 - square_icon: - label: 方形图标 - msg: 方形图标不能为空。 - text: 用作元数据图标的基础的图像。最好是大于512x512。 - favicon: - label: 收藏夹图标 - text: 网站的图标。要在 CDN 正常工作,它必须是 png。 将调整大小到32x32。如果留空,将使用“方形图标”。 - legal: - page_title: 法律条款 - terms_of_service: - label: 服务条款 - text: "您可以在此添加服务内容的条款。如果您已经在别处托管了文档,请在这里提供完整的URL。" - privacy_policy: - label: 隐私政策 - text: "您可以在此添加隐私政策内容。如果您已经在别处托管了文档,请在这里提供完整的URL。" - write: - page_title: 编辑 - restrict_answer: - title: 限制一个回答 - label: 每个用户对于每个问题只能有一个回答 - text: "用户可以使用编辑按钮优化已有的回答" - recommend_tags: - label: 推荐标签 - text: "请在上方输入标签固定链接,每行一个标签。" - required_tag: - title: 必需的标签 - label: 根据需要设置推荐标签 - text: "每个新问题必须至少有一个推荐标签。" - reserved_tags: - label: 保留标签 - text: "保留的标签只能由版主添加到一个帖子中。" - seo: - page_title: 搜索引擎优化 - permalink: - label: 固定链接 - text: 自定义URL结构可以提高可用性,以及你的链接的向前兼容性。 - robots: - label: robots.txt - text: 这将永久覆盖任何相关的网站设置。 - themes: - page_title: 主题 - themes: - label: 主题 - text: 选择一个现有主题。 - color_scheme: - label: 配色方案 - navbar_style: - label: 导航栏样式 - primary_color: - label: 主色调 - text: 修改您主题使用的颜色 - css_and_html: - page_title: CSS 与 HTML - custom_css: - label: 自定义 CSS - text: > - - head: - label: 头部 - text: > - - header: - label: 页眉 - text: > - - footer: - label: 页脚 - text: 这将在 之前插入. - sidebar: - label: 侧边栏 - text: 这将插入侧边栏中。 - login: - page_title: 登录 - membership: - title: 会员 - label: 允许新注册 - text: 关闭以防止任何人创建新账户。 - email_registration: - title: 邮箱注册 - label: 允许邮箱注册 - text: 关闭以阻止任何人通过邮箱创建新账户。 - allowed_email_domains: - title: 允许的邮箱域 - text: 允许注册账户的邮箱域。每行一个域名。留空时忽略。 - private: - title: 非公开的 - label: 需要登录 - text: 只有登录用户才能访问这个社区。 - password_login: - title: 密码登录 - label: 允许使用邮箱和密码登录 - text: "警告:如果您未配置过其他登录方式,关闭密码登录后您则可能无法登录。" - installed_plugins: - title: 已安装插件 - plugin_link: 插件扩展功能。您可以在<1>插件仓库中找到插件。 - filter: - all: 全部 - active: 已启用 - inactive: 未启用 - outdated: 已过期 - plugins: - label: 插件 - text: 选择一个现有的插件。 - name: 名称 - version: 版本 - status: 状态 - action: 操作 - deactivate: 停用 - activate: 启用 - settings: 设置 - settings_users: - title: 用户 - avatar: - label: 默认头像 - text: 没有自定义头像的用户。 - gravatar_base_url: - label: Gravatar 根路径 URL - text: Gravatar 提供商的 API 基础的 URL。当为空时忽略。 - profile_editable: - title: 个人资料可编辑 - allow_update_display_name: - label: 允许用户修改显示名称 - allow_update_username: - label: 允许用户修改用户名 - allow_update_avatar: - label: 允许用户修改个人头像 - allow_update_bio: - label: 允许用户修改个人介绍 - allow_update_website: - label: 允许用户修改个人主页网址 - allow_update_location: - label: 允许用户更改位置 - privilege: - title: 特权 - level: - label: 级别所需声望 - text: 选择特权所需的声望值 - msg: - should_be_number: 输入必须是数字 - number_larger_1: 数字应该大于等于 1 - form: - optional: (选填) - empty: 不能为空 - invalid: 是无效的 - btn_submit: 保存 - not_found_props: "所需属性 {{ key }} 未找到。" - select: 选择 - page_review: - review: 评论 - proposed: 提案 - question_edit: 问题编辑 - answer_edit: 回答编辑 - tag_edit: '标签管理: 编辑标签' - edit_summary: 编辑备注 - edit_question: 编辑问题 - edit_answer: 编辑回答 - edit_tag: 编辑标签 - empty: 没有剩余的审核任务。 - approve_revision_tip: 您是否批准此修订? - approve_flag_tip: 您是否批准此举报? - approve_post_tip: 您是否批准此帖子? - approve_user_tip: 您是否批准此修订? - suggest_edits: 建议的编辑 - flag_post: 举报帖子 - flag_user: 举报用户 - queued_post: 排队的帖子 - queued_user: 排队用户 - filter_label: 类型 - reputation: 声望值 - flag_post_type: 举报这个帖子的类型是 {{ type }} - flag_user_type: 举报这个用户的类型是 {{ type }} - edit_post: 编辑帖子 - list_post: 文章列表 - unlist_post: 隐藏的帖子 - timeline: - undeleted: 取消删除 - deleted: 删除 - downvote: 反对 - upvote: 点赞 - accept: 采纳 - cancelled: 已取消 - commented: '评论:' - rollback: 回滚 - edited: 最后编辑于 - answered: 回答于 - asked: 提问于 - closed: 关闭 - reopened: 重新开启 - created: 创建于 - pin: 已置顶 - unpin: 取消置頂 - show: 已显示 - hide: 已隐藏 - title: "历史记录" - tag_title: "时间线" - show_votes: "显示投票" - n_or_a: N/A - title_for_question: "时间线" - title_for_answer: "{{ title }} 的 {{ author }} 回答时间线" - title_for_tag: "时间线" - datetime: 日期时间 - type: 类型 - by: 由 - comment: 评论 - no_data: "空空如也" - users: - title: 用户 - users_with_the_most_reputation: 本周声望最高的用户 - users_with_the_most_vote: 本周投票最多的用户 - staffs: 我们的社区工作人员 - reputation: 声望值 - votes: 投票 - prompt: - leave_page: 确定要离开此页面? - changes_not_save: 您的更改尚未保存 - draft: - discard_confirm: 您确定要丢弃您的草稿吗? - messages: - post_deleted: 该帖子已被删除。 - post_pin: 该帖子已被置顶。 - post_unpin: 该帖子已被取消置顶。 - post_hide_list: 此帖子已经从列表中隐藏。 - post_show_list: 该帖子已显示到列表中。 - post_reopen: 这个帖子已被重新打开. - post_list: 这个帖子已经被显示 - post_unlist: 这个帖子已经被隐藏 - post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 From e9c925082b7a11391e59082f308989c37c2fe0d6 Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 19 Aug 2024 15:20:38 +0800 Subject: [PATCH 060/336] Revert "fix(dev): delete test file" This reverts commit c50e63dd34ce9ddb7babd769146278ef41e5bfcb. --- dev/i18n/zh_CN.yaml | 2035 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2035 insertions(+) create mode 100644 dev/i18n/zh_CN.yaml diff --git a/dev/i18n/zh_CN.yaml b/dev/i18n/zh_CN.yaml new file mode 100644 index 00000000..6613bfc2 --- /dev/null +++ b/dev/i18n/zh_CN.yaml @@ -0,0 +1,2035 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# The following fields are used for back-end +backend: + base: + success: + other: 成功。 + unknown: + other: 未知错误。 + request_format_error: + other: 请求格式错误。 + unauthorized_error: + other: 未授权。 + database_error: + other: 数据服务器错误。 + forbidden_error: + other: 禁止访问。 + duplicate_request_error: + other: 重复提交。 + action: + report: + other: 举报 + edit: + other: 编辑 + delete: + other: 删除 + close: + other: 关闭 + reopen: + other: 重新打开 + forbidden_error: + other: 禁止访问。 + pin: + other: 置顶 + hide: + other: 列表隐藏 + unpin: + other: 取消置顶 + show: + other: 列表显示 + invite_someone_to_answer: + other: 编辑 + undelete: + other: 撤消删除 + role: + name: + user: + other: 用户 + admin: + other: 管理员 + moderator: + other: 版主 + description: + user: + other: 默认没有特殊权限。 + admin: + other: 拥有管理网站的全部权限。 + moderator: + other: 拥有除访问后台管理以外的所有权限。 + privilege: + level_1: + description: + other: 级别 1(少量声望要求,适合私有团队、群组) + level_2: + description: + other: 级别 2(低声望要求,适合初启动的社区) + level_3: + description: + other: 级别 3(高声望要求,适合成熟的社区) + level_custom: + description: + other: 自定义等级 + rank_question_add_label: + other: 提问 + rank_answer_add_label: + other: 写答案 + rank_comment_add_label: + other: 写评论 + rank_report_add_label: + other: 举报 + rank_comment_vote_up_label: + other: 点赞评论 + rank_link_url_limit_label: + other: 每次发布超过 2 个链接 + rank_question_vote_up_label: + other: 点赞问题 + rank_answer_vote_up_label: + other: 点赞答案 + rank_question_vote_down_label: + other: 点踩问题 + rank_answer_vote_down_label: + other: 点踩答案 + rank_invite_someone_to_answer_label: + other: 邀请回答 + rank_tag_add_label: + other: 创建新标签 + rank_tag_edit_label: + other: 编辑标签描述(需要审核) + rank_question_edit_label: + other: 编辑别人的问题(需要审核) + rank_answer_edit_label: + other: 编辑别人的答案(需要审核) + rank_question_edit_without_review_label: + other: 编辑别人的问题无需审核 + rank_answer_edit_without_review_label: + other: 编辑别人的答案无需审核 + rank_question_audit_label: + other: 审核问题编辑 + rank_answer_audit_label: + other: 审核回答编辑 + rank_tag_audit_label: + other: 审核标签编辑 + rank_tag_edit_without_review_label: + other: 编辑标签描述无需审核 + rank_tag_synonym_label: + other: 管理标签同义词 + email: + other: 邮箱 + e_mail: + other: 邮箱 + password: + other: 密码 + pass: + other: 密码 + original_text: + other: 本帖 + email_or_password_wrong_error: + other: 邮箱和密码不匹配。 + error: + common: + invalid_url: + other: 无效的 URL。 + password: + space_invalid: + other: 密码不得含有空格。 + admin: + cannot_update_their_password: + other: 你无法修改自己的密码。 + cannot_edit_their_profile: + other: 您不能修改您的个人资料。 + cannot_modify_self_status: + other: 你无法修改自己的状态。 + email_or_password_wrong: + other: 邮箱和密码不匹配。 + answer: + not_found: + other: 没有找到答案。 + cannot_deleted: + other: 没有删除权限。 + cannot_update: + other: 没有更新权限。 + question_closed_cannot_add: + other: 问题已关闭,无法添加。 + comment: + edit_without_permission: + other: 不允许编辑评论。 + not_found: + other: 评论未找到。 + cannot_edit_after_deadline: + other: 评论时间太久,无法修改。 + email: + duplicate: + other: 邮箱已存在。 + need_to_be_verified: + other: 邮箱需要验证。 + verify_url_expired: + other: 邮箱验证的网址已过期,请重新发送邮件。 + illegal_email_domain_error: + other: 此邮箱不在允许注册的邮箱域中。请使用其他邮箱尝试。 + lang: + not_found: + other: 语言文件未找到。 + object: + captcha_verification_failed: + other: 验证码错误。 + disallow_follow: + other: 你不能关注。 + disallow_vote: + other: 你不能投票。 + disallow_vote_your_self: + other: 你不能为自己的帖子投票。 + not_found: + other: 对象未找到。 + verification_failed: + other: 验证失败。 + email_or_password_incorrect: + other: 邮箱和密码不匹配。 + old_password_verification_failed: + other: 旧密码验证失败。 + new_password_same_as_previous_setting: + other: 新密码和旧密码相同。 + already_deleted: + other: 该帖子已被删除。 + meta: + object_not_found: + other: Meta 对象未找到 + question: + already_deleted: + other: 该帖子已被删除。 + under_review: + other: 您的帖子正在等待审核。它将在它获得批准后可见。 + not_found: + other: 问题未找到。 + cannot_deleted: + other: 没有删除权限。 + cannot_close: + other: 没有关闭权限。 + cannot_update: + other: 没有更新权限。 + rank: + fail_to_meet_the_condition: + other: 声望值未达到要求。 + vote_fail_to_meet_the_condition: + other: 感谢投票。你至少需要 {{.Rank}} 声望才能投票。 + no_enough_rank_to_operate: + other: 你至少需要 {{.Rank}} 声望才能执行此操作。 + report: + handle_failed: + other: 报告处理失败。 + not_found: + other: 报告未找到。 + tag: + already_exist: + other: 标签已存在。 + not_found: + other: 标签未找到。 + recommend_tag_not_found: + other: 推荐标签不存在。 + recommend_tag_enter: + other: 请选择至少一个必选标签。 + not_contain_synonym_tags: + other: 不应包含同义词标签。 + cannot_update: + other: 没有更新权限。 + is_used_cannot_delete: + other: 你不能删除这个正在使用的标签。 + cannot_set_synonym_as_itself: + other: 你不能将当前标签设为自己的同义词。 + smtp: + config_from_name_cannot_be_email: + other: 发件人名称不能是邮箱地址。 + theme: + not_found: + other: 主题未找到。 + revision: + review_underway: + other: 目前无法编辑,有一个版本在审阅队列中。 + no_permission: + other: 无权限修改。 + user: + external_login_missing_user_id: + other: 第三方平台没有提供唯一的 UserID,所以你不能登录,请联系网站管理员。 + external_login_unbinding_forbidden: + other: 请在移除此登录之前为你的账户设置登录密码。 + email_or_password_wrong: + other: + other: 邮箱和密码不匹配。 + not_found: + other: 用户未找到。 + suspended: + other: 用户已被封禁。 + username_invalid: + other: 用户名无效。 + username_duplicate: + other: 用户名已被使用。 + set_avatar: + other: 头像设置错误。 + cannot_update_your_role: + other: 你不能修改自己的角色。 + not_allowed_registration: + other: 该网站暂未开放注册。 + not_allowed_login_via_password: + other: 该网站暂不支持密码登录。 + access_denied: + other: 拒绝访问 + page_access_denied: + other: 您没有权限访问此页面。 + add_bulk_users_format_error: + other: "发生错误,{{.Field}} 格式错误,在 '{{.Content}}' 行数 {{.Line}}. {{.ExtraMessage}}" + add_bulk_users_amount_error: + other: "一次性添加的用户数量应在 1-{{.MaxAmount}} 之间。" + config: + read_config_failed: + other: 读取配置失败 + database: + connection_failed: + other: 数据库连接失败 + create_table_failed: + other: 创建表失败 + install: + create_config_failed: + other: 无法创建 config.yaml 文件。 + upload: + unsupported_file_format: + other: 不支持的文件格式。 + site_info: + config_not_found: + other: 未找到网站的该配置信息。 + reason: + spam: + name: + other: 垃圾信息 + desc: + other: 这个帖子是一个广告,或是破坏性行为。它对当前的主题无帮助或无关。 + rude_or_abusive: + name: + other: 粗鲁或辱骂的 + desc: + other: + - 一个有理智的人都会认为这种内容不适合进行尊重性的讨论。 + - 论坛 + a_duplicate: + name: + other: 重复内容 + desc: + other: 该问题有人问过,而且已经有了答案。 + placeholder: + other: 输入已有的问题链接 + not_a_answer: + name: + other: 不是答案 + desc: + other: + - 这张贴作为答案,但它不会试图回答 + - 这可能是一个编辑、一个评论、另一个问题。 + - 或全部删除。 + no_longer_needed: + name: + other: 不再需要 + desc: + other: 该评论已过时,对话性质或与此帖子无关。 + something: + name: + other: 其他原因 + desc: + other: 此帖子需要工作人员注意,因为是上述所列以外的其他理由。 + placeholder: + other: 让我们具体知道你关心的什么 + community_specific: + name: + other: 社区特定原因 + desc: + other: 该问题不符合社区准则。 + not_clarity: + name: + other: 需要细节或澄清 + desc: + other: 该问题目前涵盖多个问题。它应该侧重在一个问题上。 + looks_ok: + name: + other: 看起来没问题 + desc: + other: 这个帖子是好的,不是低质量。 + needs_edit: + name: + other: 需要编辑,我已做了修改。 + desc: + other: 改进和纠正你自己帖子中的问题。 + needs_close: + name: + other: 需要关闭 + desc: + other: 关闭的问题不能回答,但仍然可以编辑、投票和评论。 + needs_delete: + name: + other: 需要删除 + desc: + other: 该帖子将被删除。 + question: + close: + duplicate: + name: + other: 垃圾信息 + desc: + other: 此问题以前就有人问过,而且已经有了答案。 + guideline: + name: + other: 社区特定原因 + desc: + other: 该问题不符合社区准则。 + multiple: + name: + other: 需要细节或澄清 + desc: + other: + - 该问题目前涵盖多个问题。它应该侧重在一个问题上。 + - 只关注一个问题。 + other: + name: + other: 其他原因 + desc: + other: 该帖子存在上面没有列出的另一个原因。 + operation_type: + asked: + other: 提问于 + answered: + other: 回答于 + modified: + other: 修改于 + deleted_title: + other: 删除的问题 + notification: + action: + update_question: + other: 更新了问题 + answer_the_question: + other: 回答了问题 + update_answer: + other: 更新了答案 + accept_answer: + other: 采纳了答案 + comment_question: + other: 评论了问题 + comment_answer: + other: 评论了答案 + reply_to_you: + other: 回复了你 + mention_you: + other: 提到了你 + your_question_is_closed: + other: 你的问题已被关闭 + your_question_was_deleted: + other: 你的问题已被删除 + your_answer_was_deleted: + other: 你的答案已被删除 + your_comment_was_deleted: + other: 你的评论已被删除 + up_voted_question: + other: 点赞问题 + down_voted_question: + other: 点踩问题 + up_voted_answer: + other: 点赞答案 + down_voted_answer: + other: 点踩回答 + up_voted_comment: + other: 点赞评论 + invited_you_to_answer: + other: 邀请你回答 + email_tpl: + change_email: + title: + other: "[{{.SiteName}}] 确认你的新邮箱地址" + body: + other: "请点击以下链接确认你在 {{.SiteName}} 上的新邮箱地址:
\n{{.ChangeEmailUrl}}

\n\n如果你没有请求此更改,请忽略此邮件。\n" + new_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} 回答了你的问题" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" + invited_you_to_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} 邀请您回答问题" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
我想你可能知道答案。

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" + new_comment: + title: + other: "[{{.SiteName}}] {{.DisplayName}} 评论了你的帖子" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" + new_question: + title: + other: "[{{.SiteName}}] 新问题: {{.QuestionTitle}}" + body: + other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\n取消订阅" + pass_reset: + title: + other: "[{{.SiteName }}] 重置密码" + body: + other: "有人要求在 [{{.SiteName}}] 上重置你的密码。

\n\n如果这不是你的操作,请安心忽略此电子邮件。

\n\n请点击以下链接设置一个新密码:
\n{{.PassResetUrl}}\n" + register: + title: + other: "[{{.SiteName}}] 确认你的新账户" + body: + other: "欢迎加入 {{.SiteName}}!

\n\n请点击以下链接确认并激活你的新账户:
\n{{.RegisterUrl}}

\n\n如果上面的链接不能点击,请将其复制并粘贴到你的浏览器地址栏中。\n" + test: + title: + other: "[{{.SiteName}}] 测试邮件" + body: + other: "这是一封测试邮件。" + action_activity_type: + upvote: + other: 点赞 + upvoted: + other: 点赞 + downvote: + other: 点踩 + downvoted: + other: 点踩 + accept: + other: 采纳 + accepted: + other: 已采纳 + edit: + other: 编辑 + review: + queued_post: + other: 排队的帖子 + flagged_post: + other: 举报的帖子 + suggested_post_edit: + other: 建议的编辑 + reaction: + tooltip: + other: "{{ .Names }} 以及另外 {{ .Count }} 个..." +plugin: + s3_cdn: + backend: + info: + name: + other: S3 存储 CDN + description: + other: 上传文件到S3存储 + config: + endpoint: + title: + other: Endpoint + description: + other: S3存储的Endpoint + bucket_name: + title: + other: Bucket名称 + description: + other: S3存储的Bucket名称 + object_key_prefix: + title: + other: 对象Key前缀 + description: + other: 对象键的前缀,如'answer/data/',以'/'结尾 + access_key_id: + title: + other: AccessKeyID + description: + other: S3存储的AccessKeyID + access_key_secret: + title: + other: AccessKeySecret + description: + other: S3存储的AccessKeySecret + access_token: + title: + other: AccessToken + description: + other: 访问 S3 所需的 AccessToken + visit_url_prefix: + title: + other: 访问URL前缀 + description: + other: 上传静态文件CDN最终访问地址的前缀,以 '/' 结尾 https://static.example.com/xxx/ + max_file_size: + title: + other: 文件最大大小(MB) + description: + other: 限制上传文件的最大大小,单位MB,默认为10MB + region: + title: + other: 区域(Region) + description: + other: S3存储区域 + disable_ssl: + title: + other: 禁用SSL + description: + other: 我们建议您使用SSL访问S3存储。如果您想禁用SSL,请选中此选项。 + err: + mis_storage_config: + other: 错误的存储配置导致上传失败 + file_not_found: + other: 文件未找到 + unsupported_file_type: + other: 不支持的文件类型 + over_file_size_limit: + other: 超过文件大小限制 + upload_file_failed: + other: 上传文件失败 + aliyunoss_cdn: + backend: + info: + name: + other: 阿里云CDN OSS存储 + description: + other: 上传文件到阿里云CDN OSS存储 + config: + endpoint: + title: + other: Endpoint + description: + other: 阿里云OSS存储的Endpoint + bucket_name: + title: + other: Bucket名称 + description: + other: 阿里云OSS存储的Bucket名称 + object_key_prefix: + title: + other: 对象Key前缀 + description: + other: 对象键的前缀,如'answer/data/',以'/'结尾 + access_key_id: + title: + other: AccessKeyID + description: + other: 阿里云OSS存储的AccessKeyID + access_key_secret: + title: + other: AccessKeySecret + description: + other: 阿里云OSS存储的AccessKeySecret + visit_url_prefix: + title: + other: 访问URL前缀 + description: + other: CDN最终访问地址的前缀,以 '/' 结尾 https://example.com/xxx/ + max_file_size: + title: + other: 最大文件大小(MB) + description: + other: 限制上传文件的最大大小,单位为MB,默认为 10MB + err: + mis_storage_config: + other: 错误的存储配置导致上传失败 + file_not_found: + other: 文件未找到 + unsupported_file_type: + other: 不支持的文件类型 + over_file_size_limit: + other: 超过文件大小限制 + upload_file_failed: + other: 上传文件失败 +# The following fields are used for interface presentation(Front-end) +ui: + how_to_format: + title: 如何排版 + desc: >- +
  • 添加链接

    <https://url.com>

    [标题](https://url.com)
  • 段落之间使用空行分隔

  • _斜体_ 或者 **粗体**

  • 使用 4 个空格缩进代码

  • 在行首添加 > 表示引用

  • 反引号进行转义 `像 _这样_`

  • 使用 ``` 创建代码块

    ```
    这是代码块
    ```
+ pagination: + prev: 上一页 + next: 下一页 + page_title: + question: 问题 + questions: 问题 + tag: 标签 + tags: 标签 + tag_wiki: 标签维基 + create_tag: 创建标签 + edit_tag: 编辑标签 + ask_a_question: 提问题 + edit_question: 编辑问题 + edit_answer: 编辑回答 + search: 搜索 + posts_containing: 帖子包含 + settings: 设置 + notifications: 通知 + login: 登录 + sign_up: 注册 + account_recovery: 账号恢复 + account_activation: 账号激活 + confirm_email: 确认电子邮件 + account_suspended: 账号已被封禁 + admin: 后台管理 + change_email: 修改邮箱 + install: Answer 安装 + upgrade: Answer 升级 + maintenance: 网站维护 + users: 用户 + oauth_callback: 处理中 + http_404: HTTP 错误 404 + http_50X: HTTP 错误 500 + http_403: HTTP 错误 403 + logout: 退出 + notifications: + title: 通知 + inbox: 收件箱 + achievement: 成就 + new_alerts: 新通知 + all_read: 全部标记为已读 + show_more: 显示更多 + someone: 有人 + inbox_type: + all: 全部 + posts: 帖子 + invites: 邀请 + votes: 投票 + suspended: + title: 你的账号账号已被封禁 + until_time: "你的账号被封禁直到 {{ time }}。" + forever: 你的账号已被永久封禁。 + end: 你违反了我们的社区准则。 + contact_us: 联系我们 + editor: + blockquote: + text: 引用 + bold: + text: 粗体 + chart: + text: 图表 + flow_chart: 流程图 + sequence_diagram: 时序图 + class_diagram: 类图 + state_diagram: 状态图 + entity_relationship_diagram: 实体关系图 + user_defined_diagram: 用户自定义图表 + gantt_chart: 甘特图 + pie_chart: 饼图 + code: + text: 代码块 + add_code: 添加代码块 + form: + fields: + code: + label: 代码块 + msg: + empty: 代码块不能为空 + language: + label: 语言 + placeholder: 自动识别 + btn_cancel: 取消 + btn_confirm: 添加 + formula: + text: 公式 + options: + inline: 行内公式 + block: 块级公式 + heading: + text: 标题 + options: + h1: 标题 1 + h2: 标题 2 + h3: 标题 3 + h4: 标题 4 + h5: 标题 5 + h6: 标题 6 + help: + text: 帮助 + hr: + text: 水平线 + image: + text: 图片 + add_image: 添加图片 + tab_image: 上传图片 + form_image: + fields: + file: + label: 图像文件 + btn: 选择图片 + msg: + empty: 请选择图片文件。 + only_image: 只能上传图片文件。 + max_size: 文件大小不能超过 4 MB。 + desc: + label: 描述 + tab_url: 图片地址 + form_url: + fields: + url: + label: 图片地址 + msg: + empty: 图片地址不能为空 + name: + label: 描述 + btn_cancel: 取消 + btn_confirm: 添加 + uploading: 上传中 + indent: + text: 缩进 + outdent: + text: 减少缩进 + italic: + text: 斜体 + link: + text: 超链接 + add_link: 添加超链接 + form: + fields: + url: + label: 链接 + msg: + empty: 链接不能为空。 + name: + label: 描述 + btn_cancel: 取消 + btn_confirm: 添加 + ordered_list: + text: 有序列表 + unordered_list: + text: 无序列表 + table: + text: 表格 + heading: 表头 + cell: 单元格 + close_modal: + title: 关闭原因是... + btn_cancel: 取消 + btn_submit: 提交 + remark: + empty: 不能为空。 + msg: + empty: 请选择一个原因。 + report_modal: + flag_title: 我举报这篇帖子的原因是... + close_title: 我关闭这篇帖子的原因是... + review_question_title: 审查问题 + review_answer_title: 审查回答 + review_comment_title: 审查评论 + btn_cancel: 取消 + btn_submit: 提交 + remark: + empty: 不能为空 + msg: + empty: 请选择一个原因。 + not_a_url: URL 格式不正确。 + url_not_match: URL 来源与当前网站不匹配。 + tag_modal: + title: 创建新标签 + form: + fields: + display_name: + label: 显示名称 + msg: + empty: 显示名称不能为空。 + range: 显示名称不能超过 35 个字符。 + slug_name: + label: URL 固定链接 + desc: URL 固定链接不能超过 35 个字符。 + msg: + empty: URL 固定链接不能为空。 + range: URL 固定链接不能超过 35 个字符。 + character: URL 固定链接包含非法字符。 + desc: + label: 描述 + revision: + label: 编辑历史 + edit_summary: + label: 编辑备注 + placeholder: >- + 简单描述更改原因(更正拼写、修复语法、改进格式) + btn_cancel: 取消 + btn_submit: 提交 + btn_post: 发布新标签 + tag_info: + created_at: 创建于 + edited_at: 编辑于 + history: 历史 + synonyms: + title: 同义词 + text: 以下标签将被重置到 + empty: 此标签目前没有同义词。 + btn_add: 添加同义词 + btn_edit: 编辑 + btn_save: 保存 + synonyms_text: 以下标签将被重置到 + delete: + title: 删除标签 + tip_with_posts: >- +

我们不允许 删除带有帖子的标签

请先从帖子中移除此标签。

+ tip_with_synonyms: >- +

我们不允许 删除带有同义词的标签

请先从此标签中删除同义词。

+ tip: 确定要删除吗? + close: 关闭 + edit_tag: + title: 编辑标签 + default_reason: 编辑标签 + default_first_reason: 添加标签 + btn_save_edits: 保存更改 + btn_cancel: 取消 + dates: + long_date: MM 月 DD 日 + long_date_with_year: "YYYY 年 MM 月 DD 日" + long_date_with_time: "YYYY 年 MM 月 DD 日 HH:mm" + now: 刚刚 + x_seconds_ago: "{{count}} 秒前" + x_minutes_ago: "{{count}} 分钟前" + x_hours_ago: "{{count}} 小时前" + hour: 小时 + day: 天 + hours: 小时 + days: 日 + reaction: + heart: 爱心 + smile: 微笑 + frown: 愁 + btn_label: 添加或删除回应。 + undo_emoji: 撤销 {{ emoji }} 回应 + react_emoji: 用 {{ emoji }} 回应 + unreact_emoji: 撤销 {{ emoji }} + comment: + btn_add_comment: 添加评论 + reply_to: 回复 + btn_reply: 回复 + btn_edit: 编辑 + btn_delete: 删除 + btn_flag: 举报 + btn_save_edits: 保存更改 + btn_cancel: 取消 + show_more: "{{count}} 条剩余评论" + tip_question: >- + 使用评论提问更多信息或者提出改进意见。避免在评论里回答问题。 + tip_answer: >- + 使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。 + tip_vote: 它给帖子添加了一些有用的内容 + edit_answer: + title: 编辑回答 + default_reason: 编辑回答 + default_first_reason: 添加答案 + form: + fields: + revision: + label: 编辑历史 + answer: + label: 回答内容 + feedback: + characters: 内容长度至少 6 个字符 + edit_summary: + label: 编辑摘要 + placeholder: >- + 简单描述更改原因(更正拼写、修复语法、改进格式) + btn_save_edits: 保存更改 + btn_cancel: 取消 + tags: + title: 标签 + sort_buttons: + popular: 热门 + name: 名称 + newest: 最新 + button_follow: 关注 + button_following: 已关注 + tag_label: 个问题 + search_placeholder: 通过标签名称过滤 + no_desc: 此标签无描述。 + more: 更多 + ask: + title: 新增问题 + edit_title: 编辑问题 + default_reason: 编辑问题 + default_first_reason: 新增问题 + similar_questions: 相似问题 + form: + fields: + revision: + label: 修订版本 + title: + label: 标题 + placeholder: 请详细描述你的问题,想象你在问一个人 + msg: + empty: 标题不能为空。 + range: 标题最多 150 个字符 + body: + label: 内容 + msg: + empty: 内容不能为空。 + tags: + label: 标签 + msg: + empty: 必须选择一个标签 + answer: + label: 回答内容 + msg: + empty: 回答内容不能为空 + edit_summary: + label: 编辑备注 + placeholder: >- + 简单描述更改原因(更正拼写、修复语法、改进格式) + btn_post_question: 提交问题 + btn_save_edits: 保存更改 + answer_question: 回答自己的问题 + post_question&answer: 提交问题和回答 + tag_selector: + add_btn: 添加标签 + create_btn: 创建新标签 + search_tag: 搜索标签 + hint: "描述您的问题是关于什么,至少需要一个标签。" + no_result: 没有匹配的标签 + tag_required_text: 必选标签(至少一个) + header: + nav: + question: 问题 + tag: 标签 + user: 用户 + profile: 用户主页 + setting: 账号设置 + logout: 退出 + admin: 后台管理 + review: 审查 + bookmark: 收藏夹 + moderation: 管理 + search: + placeholder: 搜索 + footer: + build_on: >- + 由 <1>Apache Answer 提供动力 - 驱动问答社区的开源软件。
用爱制造 © {{cc}}. + upload_img: + name: 更改 + loading: 加载中... + pic_auth_code: + title: 验证码 + placeholder: 输入图片中的文字 + msg: + empty: 验证码不能为空。 + inactive: + first: >- + 就差一步!我们发送了一封激活邮件到 {{mail}}。请按照邮件中的说明激活你的账户。 + info: "如果没有收到,请检查你的垃圾邮件文件夹。" + another: >- + 我们向你的邮箱 {{mail}} 发送了另一封激活电子邮件。可能需要几分钟才能到达;请务必检查您的垃圾邮件箱。 + btn_name: 重新发送激活邮件 + change_btn_name: 更改邮箱 + msg: + empty: 不能为空。 + resend_email: + url_label: 确定要重新发送激活邮件吗? + url_text: 你也可以将上面的激活链接给该用户。 + login: + login_to_continue: 登录以继续 + info_sign: 没有账户?<1>注册 + info_login: 已经有账户?<1>登录 + agreements: 登录即表示您同意<1>隐私政策和<3>服务条款。 + forgot_pass: 忘记密码? + name: + label: 名字 + msg: + empty: 名字不能为空 + range: 名字应该在 4 到 30 个字符之间 + character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' + email: + label: 邮箱 + msg: + empty: 邮箱不能为空 + password: + label: 密码 + msg: + empty: 密码不能为空 + different: 两次输入密码不一致 + account_forgot: + page_title: 忘记密码 + btn_name: 发送恢复邮件 + send_success: >- + 如果存在邮箱为 {{mail}} 账户,你将很快收到一封重置密码的说明邮件。 + email: + label: 邮箱 + msg: + empty: 邮箱不能为空 + change_email: + btn_cancel: 取消 + btn_update: 更新电子邮件地址 + send_success: >- + 如果存在邮箱为 {{mail}} 的账户,你将很快收到一封重置密码的说明邮件。 + email: + label: 新的电子邮件地址 + msg: + empty: 邮箱不能为空。 + oauth: + connect: 连接到 {{ auth_name }} + remove: 移除 {{ auth_name }} + oauth_bind_email: + subtitle: 向你的账户添加恢复邮件地址。 + btn_update: 更新电子邮件地址 + email: + label: 邮箱 + msg: + empty: 邮箱不能为空。 + modal_title: 邮箱已经存在。 + modal_content: 该电子邮件地址已经注册。你确定要连接到已有账户吗? + modal_cancel: 更改邮箱 + modal_confirm: 连接到已有账户 + password_reset: + page_title: 密码重置 + btn_name: 重置我的密码 + reset_success: >- + 你已经成功更改密码;你将被重定向到登录页面。 + link_invalid: >- + 抱歉,此密码重置链接已失效。也许是你已经重置过密码了? + to_login: 前往登录页面 + password: + label: 密码 + msg: + empty: 密码不能为空。 + length: 密码长度在8-32个字符之间 + different: 两次输入密码不一致 + password_confirm: + label: 确认新密码 + settings: + page_title: 设置 + goto_modify: 前往修改 + nav: + profile: 我的资料 + notification: 通知 + account: 账号 + interface: 界面 + profile: + heading: 个人资料 + btn_name: 保存 + display_name: + label: 显示名称 + msg: 昵称不能为空。 + msg_range: 显示名称不能超过 30 个字符。 + username: + label: 用户名 + caption: 用户可以通过 "@用户名" 来提及你。 + msg: 用户名不能为空 + msg_range: 用户名不能超过 30 个字符。 + character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' + avatar: + label: 头像 + gravatar: Gravatar + gravatar_text: 你可以更改图像在 + custom: 自定义 + custom_text: 你可以上传你的图片。 + default: 系统 + msg: 请上传头像 + bio: + label: 关于我 + website: + label: 网站 + placeholder: "https://example.com" + msg: 网址格式不正确 + location: + label: 位置 + placeholder: "城市,国家" + notification: + heading: 邮件通知 + turn_on: 开启 + inbox: + label: 收件箱通知 + description: 你的提问有新的回答,评论,邀请回答和其他。 + all_new_question: + label: 所有新问题 + description: 获取所有新问题的通知。每周最多有50个问题。 + all_new_question_for_following_tags: + label: 所有关注标签的新问题 + description: 获取关注的标签下新问题通知。 + account: + heading: 账号 + change_email_btn: 更改邮箱 + change_pass_btn: 更改密码 + change_email_info: >- + 邮件已发送。请根据指引完成验证。 + email: + label: 电子邮件地址 + new_email: + label: 新的电子邮件地址 + msg: 新邮箱不能为空。 + pass: + label: 当前密码 + msg: 密码不能为空。 + password_title: 密码 + current_pass: + label: 当前密码 + msg: + empty: 当前密码不能为空 + length: 密码长度必须在 8 至 32 之间 + different: 两次输入的密码不匹配 + new_pass: + label: 新密码 + pass_confirm: + label: 确认新密码 + interface: + heading: 界面 + lang: + label: 界面语言 + text: 设置用户界面语言,在刷新页面后生效。 + my_logins: + title: 我的登录 + label: 使用这些账户登录或注册本网站。 + modal_title: 移除登录 + modal_content: 你确定要从账户里移除该登录? + modal_confirm_btn: 移除 + remove_success: 移除成功 + toast: + update: 更新成功 + update_password: 密码更新成功。 + flag_success: 感谢标记。 + forbidden_operate_self: 禁止对自己执行操作 + review: 您的修订将在审阅通过后显示。 + sent_success: 发送成功 + related_question: + title: 相关问题 + answers: 个回答 + invite_to_answer: + title: 受邀人 + desc: 邀请你认为可能知道答案的人。 + invite: 邀请回答 + add: 添加人员 + search: 搜索人员 + question_detail: + action: 操作 + Asked: 提问于 + asked: 提问于 + update: 修改于 + edit: 编辑于 + commented: 评论 + Views: 阅读次数 + Follow: 关注此问题 + Following: 已关注 + follow_tip: 关注此问题以接收通知 + answered: 回答于 + closed_in: 关闭于 + show_exist: 查看类似问题。 + useful: 有用的 + question_useful: 它是有用和明确的 + question_un_useful: 它不明确或没用的 + question_bookmark: 收藏该问题 + answer_useful: 这是有用的 + answer_un_useful: 它是没有用的 + answers: + title: 个回答 + score: 评分 + newest: 最新 + oldest: 最旧 + btn_accept: 采纳 + btn_accepted: 已被采纳 + write_answer: + title: 你的回答 + edit_answer: 编辑我的回答 + btn_name: 提交你的回答 + add_another_answer: 添加另一个回答 + confirm_title: 继续回答 + continue: 继续 + confirm_info: >- +

你确定要提交一个新的回答吗?

作为替代,你可以通过编辑来完善和改进之前的回答。

+ empty: 回答内容不能为空。 + characters: 内容长度至少 6 个字符。 + tips: + header_1: 感谢你的回答 + li1_1: 请务必确定在 回答问题。提供详细信息并分享你的研究。 + li1_2: 用参考资料或个人经历来支持你所做的任何陈述。 + header_2: 但是 请避免... + li2_1: 请求帮助,寻求澄清,或答复其他答案。 + reopen: + confirm_btn: 重新打开 + title: 重新打开这个帖子 + content: 确定要重新打开吗? + list: + confirm_btn: 列表显示 + title: 列表中显示这个帖子 + content: 确定要列表中显示这个帖子吗? + unlist: + confirm_btn: 列表隐藏 + title: 从列表中隐藏这个帖子 + content: 确定要从列表中隐藏这个帖子吗? + pin: + title: 置顶该帖子 + content: 你确定要全局置顶吗?这个帖子将出现在所有帖子列表的顶部。 + confirm_btn: 置顶 + delete: + title: 删除 + question: >- + 我们不建议 删除有回答的帖子。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗? + answer_accepted: >- +

我们不建议删除被采纳的回答。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗? + other: 你确定要删除? + tip_answer_deleted: 该回答已被删除 + undelete_title: 撤销删除本帖 + undelete_desc: 你确定你要撤销删除吗? + btns: + confirm: 确认 + cancel: 取消 + edit: 编辑 + save: 保存 + delete: 删除 + undelete: 撤消删除 + list: 列表显示 + unlist: 列表隐藏 + unlisted: 已隐藏 + login: 登录 + signup: 注册 + logout: 退出 + verify: 验证 + add_question: 我要提问 + approve: 批准 + reject: 拒绝 + skip: 跳过 + discard_draft: 丢弃草稿 + pinned: 已置顶 + all: 全部 + question: 问题 + answer: 回答 + comment: 评论 + refresh: 刷新 + resend: 重新发送 + deactivate: 取消激活 + active: 激活 + suspend: 封禁 + unsuspend: 解禁 + close: 关闭 + reopen: 重新打开 + ok: 确定 + light: 浅色 + dark: 深色 + system_setting: 跟随系统 + default: 默认 + reset: 重置 + tag: 标签 + post_lowercase: 帖子 + filter: 筛选 + ignore: 忽略 + submit: 提交 + normal: 正常 + closed: 已关闭 + deleted: 已删除 + pending: 等待处理 + more: 更多 + search: + title: 搜索结果 + keywords: 关键词 + options: 选项 + follow: 关注 + following: 已关注 + counts: "{{count}} 个结果" + more: 更多 + sort_btns: + relevance: 相关性 + newest: 最新的 + active: 活跃的 + score: 评分 + more: 更多 + tips: + title: 高级搜索提示 + tag: "<1>[tag] 在指定标签中搜索" + user: "<1>user:username 根据作者搜索" + answer: "<1>answers:0 搜索未回答的问题" + score: "<1>score:3 评分 3+ 的帖子" + question: "<1>is:question 搜索问题" + is_answer: "<1>is:answer 搜索回答" + empty: 找不到任何相关的内容。
请尝试其他关键字,或者减少查找内容的长度。 + share: + name: 分享 + copy: 复制链接 + via: 分享到... + copied: 已复制 + facebook: 分享到 Facebook + twitter: 分享到 Twitter + cannot_vote_for_self: 你不能给自己的帖子投票。 + modal_confirm: + title: 发生错误... + account_result: + success: 你的账号已通过验证,即将返回首页。 + link: 返回首页 + invalid: >- + 抱歉,此验证链接已失效。也许你的账号已经激活了? + confirm_new_email: 你的电子邮箱已更新 + confirm_new_email_invalid: >- + 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了? + unsubscribe: + page_title: 退订 + success_title: 退订成功 + success_desc: 您已成功退订,并且将不会再收到我们的邮件。 + link: 更改设置 + question: + following_tags: 已关注的标签 + edit: 编辑 + save: 保存 + follow_tag_tip: 关注标签来筛选你的问题列表。 + hot_questions: 热门问题 + all_questions: 全部问题 + x_questions: "{{ count }} 个问题" + x_answers: "{{ count }} 个回答" + questions: 问题 + answers: 回答 + newest: 最新 + active: 活跃 + hot: 热门 + score: 评分 + unanswered: 未回答 + modified: 更新于 + answered: 回答于 + asked: 提问于 + closed: 已关闭 + follow_a_tag: 关注一个标签 + more: 更多 + personal: + overview: 概览 + answers: 回答 + answer: 回答 + questions: 问题 + question: 问题 + bookmarks: 收藏 + reputation: 声望 + comments: 评论 + votes: 得票 + newest: 最新 + score: 评分 + edit_profile: 编辑资料 + visited_x_days: "已访问 {{ count }} 天" + viewed: 浏览次数 + joined: 加入于 + last_login: 上次登录 + about_me: 关于我 + about_me_empty: "// Hello, World!" + top_answers: 高分回答 + top_questions: 高分问题 + stats: 状态 + list_empty: 没有找到相关的内容。
试试看其他选项卡? + accepted: 已采纳 + answered: 回答于 + asked: 提问于 + downvoted: 点踩 + mod_short: 版主 + mod_long: 版主 + x_reputation: 声望 + x_votes: 得票 + x_answers: 个回答 + x_questions: 个问题 + install: + title: 安装 + next: 下一步 + done: 完成 + config_yaml_error: 无法创建 config.yaml 文件。 + lang: + label: 请选择一种语言 + db_type: + label: 数据库引擎 + db_username: + label: 用户名 + placeholder: root + msg: 用户名不能为空 + db_password: + label: 密码 + placeholder: root + msg: 密码不能为空 + db_host: + label: 数据库主机 + placeholder: "db:3306" + msg: 数据库地址不能为空 + db_name: + label: 数据库名 + placeholder: 回答 + msg: 数据库名称不能为空。 + db_file: + label: 数据库文件 + placeholder: /data/answer.db + msg: 数据库文件不能为空。 + config_yaml: + title: 创建 config.yaml + label: 已创建 config.yaml 文件。 + desc: >- + 你可以手动在 <1>/var/wwww/xxx/ 目录中创建 <1>config.yaml 文件并粘贴以下文本。 + info: 完成后,点击“下一步”按钮。 + site_information: 站点信息 + admin_account: 管理员账号 + site_name: + label: 站点名称 + msg: 站点名称不能为空。 + msg_max_length: 站点名称长度不得超过 30 个字符。 + site_url: + label: 网站网址 + text: 此网站的网址。 + msg: + empty: 网址不能为空。 + incorrect: 网址格式不正确。 + max_length: 网址长度不得超过 512 个字符。 + contact_email: + label: 联系邮箱 + text: 负责本网站的主要联系人的电子邮件地址。 + msg: + empty: 联系人邮箱不能为空。 + incorrect: 联系人邮箱地址不正确。 + login_required: + label: 私有的 + switch: 需要登录 + text: 只有登录用户才能访问这个社区。 + admin_name: + label: 名字 + msg: 名字不能为空。 + character: '只能由 "a-z", "0-9", " - . _" 组成' + msg_max_length: 名字长度不能超过 30 个字符。 + admin_password: + label: 密码 + text: >- + 您需要此密码才能登录。请将其存储在一个安全的位置。 + msg: 密码不能为空。 + msg_min_length: 密码必须至少 8 个字符长。 + msg_max_length: 密码长度不能超过 32 个字符。 + admin_email: + label: 邮箱 + text: 您需要此电子邮件才能登录。 + msg: + empty: 邮箱不能为空。 + incorrect: 邮箱格式不正确。 + ready_title: 您的网站已准备好 + ready_desc: >- + 如果你想改变更多的设置,请访问 <1>管理区域;在网站菜单中找到它。 + good_luck: "玩得愉快,祝你好运!" + warn_title: 警告 + warn_desc: >- + 文件 <1>config.yaml 已存在。如果你要重置该文件中的任何配置项,请先删除它。 + install_now: 您可以尝试 <1>现在安装。 + installed: 已安裝 + installed_desc: >- + 你似乎已经安装过了。如果要重新安装,请先清除旧的数据库表。 + db_failed: 数据连接异常! + db_failed_desc: >- + 这或者意味着数据库信息在 <1>config.yaml 文件不正确,或者无法与数据库服务器建立联系。这可能意味着你的主机数据库服务器故障。 + counts: + views: 次浏览 + votes: 个点赞 + answers: 个回答 + accepted: 已被采纳 + page_error: + http_error: HTTP 错误 {{ code }} + desc_403: 您无权访问此页面。 + desc_404: 很抱歉,此页面不存在。 + desc_50X: 服务器遇到了一个错误,无法完成你的请求。 + back_home: 返回首页 + page_maintenance: + desc: "我们正在进行维护,我们将很快回来。" + nav_menus: + dashboard: 后台管理 + contents: 内容管理 + questions: 问题 + answers: 回答 + users: 用户管理 + flags: 举报管理 + settings: 站点设置 + general: 一般 + interface: 界面 + smtp: SMTP + branding: 品牌 + legal: 法律条款 + write: 撰写 + tos: 服务条款 + privacy: 隐私政策 + seo: SEO + customize: 自定义 + themes: 主题 + css_html: CSS/HTML + login: 登录 + privileges: 特权 + plugins: 插件 + installed_plugins: 已安装插件 + website_welcome: 欢迎来到 {{site_name}} + user_center: + login: 登录 + qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码并登录。 + login_failed_email_tip: 登录失败,请允许此应用访问您的邮箱信息,然后重试。 + admin: + admin_header: + title: 后台管理 + dashboard: + title: 后台管理 + welcome: 欢迎来到管理后台! + site_statistics: 站点统计 + questions: "问题:" + answers: "回答:" + comments: "评论:" + votes: "投票:" + users: "用户:" + flags: "举报:" + reviews: "审查:" + site_health: 网站健康 + version: "版本" + https: "HTTPS:" + upload_folder: "上传文件夹:" + run_mode: "运行模式:" + private: 私有 + public: 公开 + smtp: "SMTP:" + timezone: "时区:" + system_info: 系统信息 + go_version: "Go版本:" + database: "数据库:" + database_size: "数据库大小:" + storage_used: "已用存储空间:" + uptime: "运行时间:" + links: 链接 + plugins: 插件 + github: GitHub + blog: 博客 + contact: 联系 + forum: 论坛 + documents: 文档 + feedback: 用户反馈 + support: 帮助 + review: 审查 + config: 配置 + update_to: 更新到 + latest: 最新版本 + check_failed: 校验失败 + "yes": "是" + "no": "否" + not_allowed: 拒绝 + allowed: 允许 + enabled: 已启用 + disabled: 停用 + writable: 可写 + not_writable: 不可写 + flags: + title: 举报 + pending: 等待处理 + completed: 已完成 + flagged: 被举报内容 + flagged_type: 标记了 {{ type }} + created: 创建于 + action: 操作 + review: 审查 + user_role_modal: + title: 更改用户状态为... + btn_cancel: 取消 + btn_submit: 提交 + new_password_modal: + title: 设置新密码 + form: + fields: + password: + label: 密码 + text: 用户将被退出,需要再次登录。 + msg: 密码的长度必须是8-32个字符。 + btn_cancel: 取消 + btn_submit: 提交 + edit_profile_modal: + title: 编辑资料 + form: + fields: + username: + label: 用户名 + msg_range: 用户名不能超过 30 个字符。 + email: + label: 电子邮件地址 + msg_invalid: 无效的邮箱地址 + edit_success: 修改成功 + btn_cancel: 取消 + btn_submit: 提交 + user_modal: + title: 添加新用户 + form: + fields: + users: + label: 批量添加用户 + placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" + text: 用逗号分隔“name, email, password”,每行一个用户。 + msg: "请输入用户的邮箱,每行一个。" + display_name: + label: 显示名称 + msg: 显示名称长度必须为 4-30 个字符 + email: + label: 邮箱 + msg: 邮箱无效。 + password: + label: 密码 + msg: 密码的长度必须是8-32个字符。 + btn_cancel: 取消 + btn_submit: 提交 + users: + title: 用户 + name: 名称 + email: 邮箱 + reputation: 声望 + created_at: 创建时间 + delete_at: 删除时间 + suspend_at: 封禁时间 + status: 状态 + role: 角色 + action: 操作 + change: 更改 + all: 全部 + staff: 工作人员 + more: 更多 + inactive: 不活跃 + suspended: 已封禁 + deleted: 已删除 + normal: 正常 + Moderator: 版主 + Admin: 管理员 + User: 用户 + filter: + placeholder: "按名称筛选,用户:id" + set_new_password: 设置新密码 + edit_profile: 编辑资料 + change_status: 更改状态 + change_role: 更改角色 + show_logs: 显示日志 + add_user: 添加用户 + deactivate_user: + title: 停用用户 + content: 未激活的用户必须重新验证他们的邮箱。 + delete_user: + title: 删除此用户 + content: 确定要删除此用户?此操作无法撤销! + remove: 移除内容 + label: 删除所有问题、 答案、 评论等 + text: 如果你只想删除用户账户,请不要选中此项。 + suspend_user: + title: 挂起此用户 + content: 被封禁的用户将无法登录。 + questions: + page_title: 问题 + unlisted: 已隐藏 + post: 标题 + votes: 得票数 + answers: 回答数 + created: 创建于 + status: 状态 + action: 操作 + change: 更改 + pending: 等待处理 + filter: + placeholder: "按标题过滤,问题:id" + answers: + page_title: 回答 + post: 标题 + votes: 得票数 + created: 创建于 + status: 状态 + action: 操作 + change: 更改 + filter: + placeholder: "按标题筛选,答案:id" + general: + page_title: 一般 + name: + label: 站点名称 + msg: 不能为空 + text: "站点的名称,作为站点的标题。" + site_url: + label: 网站网址 + msg: 网站网址不能为空。 + validate: 请输入一个有效的 URL。 + text: 此网站的地址。 + short_desc: + label: 简短站点描述 + msg: 简短网站描述不能为空。 + text: "简短的标语,作为网站主页的标题(Html 的 title 标签)。" + desc: + label: 站点描述 + msg: 网站描述不能为空。 + text: "使用一句话描述本站,作为网站的描述(Html 的 meta 标签)。" + contact_email: + label: 联系邮箱 + msg: 联系人邮箱不能为空。 + validate: 联系人邮箱无效。 + text: 本网站的主要联系邮箱地址。 + check_update: + label: 软件更新 + text: 自动检查软件更新 + interface: + page_title: 界面 + language: + label: 界面语言 + msg: 不能为空 + text: 设置用户界面语言,在刷新页面后生效。 + time_zone: + label: 时区 + msg: 时区不能为空。 + text: 选择一个与您相同时区的城市。 + smtp: + page_title: SMTP + from_email: + label: 发件人邮箱 + msg: 发件人邮箱不能为空。 + text: 用于发送邮件的地址。 + from_name: + label: 发件人 + msg: 不能为空 + text: 发件人的名字。 + smtp_host: + label: SMTP 主机 + msg: 不能为空 + text: 邮件服务器 + encryption: + label: 加密 + msg: 不能为空 + text: 对于大多数服务器而言,SSL 是推荐开启的。 + ssl: SSL + tls: TLS + none: 无加密 + smtp_port: + label: SMTP 端口 + msg: SMTP 端口必须在 1 ~ 65535 之间。 + text: 邮件服务器的端口号。 + smtp_username: + label: SMTP 用户名 + msg: 不能为空 + smtp_password: + label: SMTP 密码 + msg: 不能为空 + test_email_recipient: + label: 测试收件邮箱 + text: 提供用于接收测试邮件的邮箱地址。 + msg: 测试收件邮箱无效 + smtp_authentication: + label: 启用身份验证 + title: SMTP 身份验证 + msg: 不能为空 + "yes": "是" + "no": "否" + branding: + page_title: 品牌 + logo: + label: 网站标志(Logo) + msg: 图标不能为空。 + text: 在你的网站左上方的Logo图标。使用一个高度为56,长宽比大于3:1的宽长方形图像。如果留空,将显示网站标题文本。 + mobile_logo: + label: 移动端 Logo + text: 在你的网站的移动版上使用的标志。使用一个高度为56的宽矩形图像。如果留空,将使用 "Logo"设置中的图像。 + square_icon: + label: 方形图标 + msg: 方形图标不能为空。 + text: 用作元数据图标的基础的图像。最好是大于512x512。 + favicon: + label: 收藏夹图标 + text: 网站的图标。要在 CDN 正常工作,它必须是 png。 将调整大小到32x32。如果留空,将使用“方形图标”。 + legal: + page_title: 法律条款 + terms_of_service: + label: 服务条款 + text: "您可以在此添加服务内容的条款。如果您已经在别处托管了文档,请在这里提供完整的URL。" + privacy_policy: + label: 隐私政策 + text: "您可以在此添加隐私政策内容。如果您已经在别处托管了文档,请在这里提供完整的URL。" + write: + page_title: 编辑 + restrict_answer: + title: 限制一个回答 + label: 每个用户对于每个问题只能有一个回答 + text: "用户可以使用编辑按钮优化已有的回答" + recommend_tags: + label: 推荐标签 + text: "请在上方输入标签固定链接,每行一个标签。" + required_tag: + title: 必需的标签 + label: 根据需要设置推荐标签 + text: "每个新问题必须至少有一个推荐标签。" + reserved_tags: + label: 保留标签 + text: "保留的标签只能由版主添加到一个帖子中。" + seo: + page_title: 搜索引擎优化 + permalink: + label: 固定链接 + text: 自定义URL结构可以提高可用性,以及你的链接的向前兼容性。 + robots: + label: robots.txt + text: 这将永久覆盖任何相关的网站设置。 + themes: + page_title: 主题 + themes: + label: 主题 + text: 选择一个现有主题。 + color_scheme: + label: 配色方案 + navbar_style: + label: 导航栏样式 + primary_color: + label: 主色调 + text: 修改您主题使用的颜色 + css_and_html: + page_title: CSS 与 HTML + custom_css: + label: 自定义 CSS + text: > + + head: + label: 头部 + text: > + + header: + label: 页眉 + text: > + + footer: + label: 页脚 + text: 这将在 之前插入. + sidebar: + label: 侧边栏 + text: 这将插入侧边栏中。 + login: + page_title: 登录 + membership: + title: 会员 + label: 允许新注册 + text: 关闭以防止任何人创建新账户。 + email_registration: + title: 邮箱注册 + label: 允许邮箱注册 + text: 关闭以阻止任何人通过邮箱创建新账户。 + allowed_email_domains: + title: 允许的邮箱域 + text: 允许注册账户的邮箱域。每行一个域名。留空时忽略。 + private: + title: 非公开的 + label: 需要登录 + text: 只有登录用户才能访问这个社区。 + password_login: + title: 密码登录 + label: 允许使用邮箱和密码登录 + text: "警告:如果您未配置过其他登录方式,关闭密码登录后您则可能无法登录。" + installed_plugins: + title: 已安装插件 + plugin_link: 插件扩展功能。您可以在<1>插件仓库中找到插件。 + filter: + all: 全部 + active: 已启用 + inactive: 未启用 + outdated: 已过期 + plugins: + label: 插件 + text: 选择一个现有的插件。 + name: 名称 + version: 版本 + status: 状态 + action: 操作 + deactivate: 停用 + activate: 启用 + settings: 设置 + settings_users: + title: 用户 + avatar: + label: 默认头像 + text: 没有自定义头像的用户。 + gravatar_base_url: + label: Gravatar 根路径 URL + text: Gravatar 提供商的 API 基础的 URL。当为空时忽略。 + profile_editable: + title: 个人资料可编辑 + allow_update_display_name: + label: 允许用户修改显示名称 + allow_update_username: + label: 允许用户修改用户名 + allow_update_avatar: + label: 允许用户修改个人头像 + allow_update_bio: + label: 允许用户修改个人介绍 + allow_update_website: + label: 允许用户修改个人主页网址 + allow_update_location: + label: 允许用户更改位置 + privilege: + title: 特权 + level: + label: 级别所需声望 + text: 选择特权所需的声望值 + msg: + should_be_number: 输入必须是数字 + number_larger_1: 数字应该大于等于 1 + form: + optional: (选填) + empty: 不能为空 + invalid: 是无效的 + btn_submit: 保存 + not_found_props: "所需属性 {{ key }} 未找到。" + select: 选择 + page_review: + review: 评论 + proposed: 提案 + question_edit: 问题编辑 + answer_edit: 回答编辑 + tag_edit: '标签管理: 编辑标签' + edit_summary: 编辑备注 + edit_question: 编辑问题 + edit_answer: 编辑回答 + edit_tag: 编辑标签 + empty: 没有剩余的审核任务。 + approve_revision_tip: 您是否批准此修订? + approve_flag_tip: 您是否批准此举报? + approve_post_tip: 您是否批准此帖子? + approve_user_tip: 您是否批准此修订? + suggest_edits: 建议的编辑 + flag_post: 举报帖子 + flag_user: 举报用户 + queued_post: 排队的帖子 + queued_user: 排队用户 + filter_label: 类型 + reputation: 声望值 + flag_post_type: 举报这个帖子的类型是 {{ type }} + flag_user_type: 举报这个用户的类型是 {{ type }} + edit_post: 编辑帖子 + list_post: 文章列表 + unlist_post: 隐藏的帖子 + timeline: + undeleted: 取消删除 + deleted: 删除 + downvote: 反对 + upvote: 点赞 + accept: 采纳 + cancelled: 已取消 + commented: '评论:' + rollback: 回滚 + edited: 最后编辑于 + answered: 回答于 + asked: 提问于 + closed: 关闭 + reopened: 重新开启 + created: 创建于 + pin: 已置顶 + unpin: 取消置頂 + show: 已显示 + hide: 已隐藏 + title: "历史记录" + tag_title: "时间线" + show_votes: "显示投票" + n_or_a: N/A + title_for_question: "时间线" + title_for_answer: "{{ title }} 的 {{ author }} 回答时间线" + title_for_tag: "时间线" + datetime: 日期时间 + type: 类型 + by: 由 + comment: 评论 + no_data: "空空如也" + users: + title: 用户 + users_with_the_most_reputation: 本周声望最高的用户 + users_with_the_most_vote: 本周投票最多的用户 + staffs: 我们的社区工作人员 + reputation: 声望值 + votes: 投票 + prompt: + leave_page: 确定要离开此页面? + changes_not_save: 您的更改尚未保存 + draft: + discard_confirm: 您确定要丢弃您的草稿吗? + messages: + post_deleted: 该帖子已被删除。 + post_pin: 该帖子已被置顶。 + post_unpin: 该帖子已被取消置顶。 + post_hide_list: 此帖子已经从列表中隐藏。 + post_show_list: 该帖子已显示到列表中。 + post_reopen: 这个帖子已被重新打开. + post_list: 这个帖子已经被显示 + post_unlist: 这个帖子已经被隐藏 + post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 From f660b6368ddc8c909c0d08d5a54334d7d30e734b Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 19 Aug 2024 15:22:06 +0800 Subject: [PATCH 061/336] fix(dev): delete test file --- dev/i18n/zh_CN.yaml | 2035 ------------------------------------------- 1 file changed, 2035 deletions(-) delete mode 100644 dev/i18n/zh_CN.yaml diff --git a/dev/i18n/zh_CN.yaml b/dev/i18n/zh_CN.yaml deleted file mode 100644 index 6613bfc2..00000000 --- a/dev/i18n/zh_CN.yaml +++ /dev/null @@ -1,2035 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# The following fields are used for back-end -backend: - base: - success: - other: 成功。 - unknown: - other: 未知错误。 - request_format_error: - other: 请求格式错误。 - unauthorized_error: - other: 未授权。 - database_error: - other: 数据服务器错误。 - forbidden_error: - other: 禁止访问。 - duplicate_request_error: - other: 重复提交。 - action: - report: - other: 举报 - edit: - other: 编辑 - delete: - other: 删除 - close: - other: 关闭 - reopen: - other: 重新打开 - forbidden_error: - other: 禁止访问。 - pin: - other: 置顶 - hide: - other: 列表隐藏 - unpin: - other: 取消置顶 - show: - other: 列表显示 - invite_someone_to_answer: - other: 编辑 - undelete: - other: 撤消删除 - role: - name: - user: - other: 用户 - admin: - other: 管理员 - moderator: - other: 版主 - description: - user: - other: 默认没有特殊权限。 - admin: - other: 拥有管理网站的全部权限。 - moderator: - other: 拥有除访问后台管理以外的所有权限。 - privilege: - level_1: - description: - other: 级别 1(少量声望要求,适合私有团队、群组) - level_2: - description: - other: 级别 2(低声望要求,适合初启动的社区) - level_3: - description: - other: 级别 3(高声望要求,适合成熟的社区) - level_custom: - description: - other: 自定义等级 - rank_question_add_label: - other: 提问 - rank_answer_add_label: - other: 写答案 - rank_comment_add_label: - other: 写评论 - rank_report_add_label: - other: 举报 - rank_comment_vote_up_label: - other: 点赞评论 - rank_link_url_limit_label: - other: 每次发布超过 2 个链接 - rank_question_vote_up_label: - other: 点赞问题 - rank_answer_vote_up_label: - other: 点赞答案 - rank_question_vote_down_label: - other: 点踩问题 - rank_answer_vote_down_label: - other: 点踩答案 - rank_invite_someone_to_answer_label: - other: 邀请回答 - rank_tag_add_label: - other: 创建新标签 - rank_tag_edit_label: - other: 编辑标签描述(需要审核) - rank_question_edit_label: - other: 编辑别人的问题(需要审核) - rank_answer_edit_label: - other: 编辑别人的答案(需要审核) - rank_question_edit_without_review_label: - other: 编辑别人的问题无需审核 - rank_answer_edit_without_review_label: - other: 编辑别人的答案无需审核 - rank_question_audit_label: - other: 审核问题编辑 - rank_answer_audit_label: - other: 审核回答编辑 - rank_tag_audit_label: - other: 审核标签编辑 - rank_tag_edit_without_review_label: - other: 编辑标签描述无需审核 - rank_tag_synonym_label: - other: 管理标签同义词 - email: - other: 邮箱 - e_mail: - other: 邮箱 - password: - other: 密码 - pass: - other: 密码 - original_text: - other: 本帖 - email_or_password_wrong_error: - other: 邮箱和密码不匹配。 - error: - common: - invalid_url: - other: 无效的 URL。 - password: - space_invalid: - other: 密码不得含有空格。 - admin: - cannot_update_their_password: - other: 你无法修改自己的密码。 - cannot_edit_their_profile: - other: 您不能修改您的个人资料。 - cannot_modify_self_status: - other: 你无法修改自己的状态。 - email_or_password_wrong: - other: 邮箱和密码不匹配。 - answer: - not_found: - other: 没有找到答案。 - cannot_deleted: - other: 没有删除权限。 - cannot_update: - other: 没有更新权限。 - question_closed_cannot_add: - other: 问题已关闭,无法添加。 - comment: - edit_without_permission: - other: 不允许编辑评论。 - not_found: - other: 评论未找到。 - cannot_edit_after_deadline: - other: 评论时间太久,无法修改。 - email: - duplicate: - other: 邮箱已存在。 - need_to_be_verified: - other: 邮箱需要验证。 - verify_url_expired: - other: 邮箱验证的网址已过期,请重新发送邮件。 - illegal_email_domain_error: - other: 此邮箱不在允许注册的邮箱域中。请使用其他邮箱尝试。 - lang: - not_found: - other: 语言文件未找到。 - object: - captcha_verification_failed: - other: 验证码错误。 - disallow_follow: - other: 你不能关注。 - disallow_vote: - other: 你不能投票。 - disallow_vote_your_self: - other: 你不能为自己的帖子投票。 - not_found: - other: 对象未找到。 - verification_failed: - other: 验证失败。 - email_or_password_incorrect: - other: 邮箱和密码不匹配。 - old_password_verification_failed: - other: 旧密码验证失败。 - new_password_same_as_previous_setting: - other: 新密码和旧密码相同。 - already_deleted: - other: 该帖子已被删除。 - meta: - object_not_found: - other: Meta 对象未找到 - question: - already_deleted: - other: 该帖子已被删除。 - under_review: - other: 您的帖子正在等待审核。它将在它获得批准后可见。 - not_found: - other: 问题未找到。 - cannot_deleted: - other: 没有删除权限。 - cannot_close: - other: 没有关闭权限。 - cannot_update: - other: 没有更新权限。 - rank: - fail_to_meet_the_condition: - other: 声望值未达到要求。 - vote_fail_to_meet_the_condition: - other: 感谢投票。你至少需要 {{.Rank}} 声望才能投票。 - no_enough_rank_to_operate: - other: 你至少需要 {{.Rank}} 声望才能执行此操作。 - report: - handle_failed: - other: 报告处理失败。 - not_found: - other: 报告未找到。 - tag: - already_exist: - other: 标签已存在。 - not_found: - other: 标签未找到。 - recommend_tag_not_found: - other: 推荐标签不存在。 - recommend_tag_enter: - other: 请选择至少一个必选标签。 - not_contain_synonym_tags: - other: 不应包含同义词标签。 - cannot_update: - other: 没有更新权限。 - is_used_cannot_delete: - other: 你不能删除这个正在使用的标签。 - cannot_set_synonym_as_itself: - other: 你不能将当前标签设为自己的同义词。 - smtp: - config_from_name_cannot_be_email: - other: 发件人名称不能是邮箱地址。 - theme: - not_found: - other: 主题未找到。 - revision: - review_underway: - other: 目前无法编辑,有一个版本在审阅队列中。 - no_permission: - other: 无权限修改。 - user: - external_login_missing_user_id: - other: 第三方平台没有提供唯一的 UserID,所以你不能登录,请联系网站管理员。 - external_login_unbinding_forbidden: - other: 请在移除此登录之前为你的账户设置登录密码。 - email_or_password_wrong: - other: - other: 邮箱和密码不匹配。 - not_found: - other: 用户未找到。 - suspended: - other: 用户已被封禁。 - username_invalid: - other: 用户名无效。 - username_duplicate: - other: 用户名已被使用。 - set_avatar: - other: 头像设置错误。 - cannot_update_your_role: - other: 你不能修改自己的角色。 - not_allowed_registration: - other: 该网站暂未开放注册。 - not_allowed_login_via_password: - other: 该网站暂不支持密码登录。 - access_denied: - other: 拒绝访问 - page_access_denied: - other: 您没有权限访问此页面。 - add_bulk_users_format_error: - other: "发生错误,{{.Field}} 格式错误,在 '{{.Content}}' 行数 {{.Line}}. {{.ExtraMessage}}" - add_bulk_users_amount_error: - other: "一次性添加的用户数量应在 1-{{.MaxAmount}} 之间。" - config: - read_config_failed: - other: 读取配置失败 - database: - connection_failed: - other: 数据库连接失败 - create_table_failed: - other: 创建表失败 - install: - create_config_failed: - other: 无法创建 config.yaml 文件。 - upload: - unsupported_file_format: - other: 不支持的文件格式。 - site_info: - config_not_found: - other: 未找到网站的该配置信息。 - reason: - spam: - name: - other: 垃圾信息 - desc: - other: 这个帖子是一个广告,或是破坏性行为。它对当前的主题无帮助或无关。 - rude_or_abusive: - name: - other: 粗鲁或辱骂的 - desc: - other: - - 一个有理智的人都会认为这种内容不适合进行尊重性的讨论。 - - 论坛 - a_duplicate: - name: - other: 重复内容 - desc: - other: 该问题有人问过,而且已经有了答案。 - placeholder: - other: 输入已有的问题链接 - not_a_answer: - name: - other: 不是答案 - desc: - other: - - 这张贴作为答案,但它不会试图回答 - - 这可能是一个编辑、一个评论、另一个问题。 - - 或全部删除。 - no_longer_needed: - name: - other: 不再需要 - desc: - other: 该评论已过时,对话性质或与此帖子无关。 - something: - name: - other: 其他原因 - desc: - other: 此帖子需要工作人员注意,因为是上述所列以外的其他理由。 - placeholder: - other: 让我们具体知道你关心的什么 - community_specific: - name: - other: 社区特定原因 - desc: - other: 该问题不符合社区准则。 - not_clarity: - name: - other: 需要细节或澄清 - desc: - other: 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - looks_ok: - name: - other: 看起来没问题 - desc: - other: 这个帖子是好的,不是低质量。 - needs_edit: - name: - other: 需要编辑,我已做了修改。 - desc: - other: 改进和纠正你自己帖子中的问题。 - needs_close: - name: - other: 需要关闭 - desc: - other: 关闭的问题不能回答,但仍然可以编辑、投票和评论。 - needs_delete: - name: - other: 需要删除 - desc: - other: 该帖子将被删除。 - question: - close: - duplicate: - name: - other: 垃圾信息 - desc: - other: 此问题以前就有人问过,而且已经有了答案。 - guideline: - name: - other: 社区特定原因 - desc: - other: 该问题不符合社区准则。 - multiple: - name: - other: 需要细节或澄清 - desc: - other: - - 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - - 只关注一个问题。 - other: - name: - other: 其他原因 - desc: - other: 该帖子存在上面没有列出的另一个原因。 - operation_type: - asked: - other: 提问于 - answered: - other: 回答于 - modified: - other: 修改于 - deleted_title: - other: 删除的问题 - notification: - action: - update_question: - other: 更新了问题 - answer_the_question: - other: 回答了问题 - update_answer: - other: 更新了答案 - accept_answer: - other: 采纳了答案 - comment_question: - other: 评论了问题 - comment_answer: - other: 评论了答案 - reply_to_you: - other: 回复了你 - mention_you: - other: 提到了你 - your_question_is_closed: - other: 你的问题已被关闭 - your_question_was_deleted: - other: 你的问题已被删除 - your_answer_was_deleted: - other: 你的答案已被删除 - your_comment_was_deleted: - other: 你的评论已被删除 - up_voted_question: - other: 点赞问题 - down_voted_question: - other: 点踩问题 - up_voted_answer: - other: 点赞答案 - down_voted_answer: - other: 点踩回答 - up_voted_comment: - other: 点赞评论 - invited_you_to_answer: - other: 邀请你回答 - email_tpl: - change_email: - title: - other: "[{{.SiteName}}] 确认你的新邮箱地址" - body: - other: "请点击以下链接确认你在 {{.SiteName}} 上的新邮箱地址:
\n{{.ChangeEmailUrl}}

\n\n如果你没有请求此更改,请忽略此邮件。\n" - new_answer: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 回答了你的问题" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - invited_you_to_answer: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 邀请您回答问题" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
我想你可能知道答案。

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - new_comment: - title: - other: "[{{.SiteName}}] {{.DisplayName}} 评论了你的帖子" - body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\n在 {{.SiteName}} 上查看

\n\n--
\n取消订阅" - new_question: - title: - other: "[{{.SiteName}}] 新问题: {{.QuestionTitle}}" - body: - other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\n取消订阅" - pass_reset: - title: - other: "[{{.SiteName }}] 重置密码" - body: - other: "有人要求在 [{{.SiteName}}] 上重置你的密码。

\n\n如果这不是你的操作,请安心忽略此电子邮件。

\n\n请点击以下链接设置一个新密码:
\n{{.PassResetUrl}}\n" - register: - title: - other: "[{{.SiteName}}] 确认你的新账户" - body: - other: "欢迎加入 {{.SiteName}}!

\n\n请点击以下链接确认并激活你的新账户:
\n{{.RegisterUrl}}

\n\n如果上面的链接不能点击,请将其复制并粘贴到你的浏览器地址栏中。\n" - test: - title: - other: "[{{.SiteName}}] 测试邮件" - body: - other: "这是一封测试邮件。" - action_activity_type: - upvote: - other: 点赞 - upvoted: - other: 点赞 - downvote: - other: 点踩 - downvoted: - other: 点踩 - accept: - other: 采纳 - accepted: - other: 已采纳 - edit: - other: 编辑 - review: - queued_post: - other: 排队的帖子 - flagged_post: - other: 举报的帖子 - suggested_post_edit: - other: 建议的编辑 - reaction: - tooltip: - other: "{{ .Names }} 以及另外 {{ .Count }} 个..." -plugin: - s3_cdn: - backend: - info: - name: - other: S3 存储 CDN - description: - other: 上传文件到S3存储 - config: - endpoint: - title: - other: Endpoint - description: - other: S3存储的Endpoint - bucket_name: - title: - other: Bucket名称 - description: - other: S3存储的Bucket名称 - object_key_prefix: - title: - other: 对象Key前缀 - description: - other: 对象键的前缀,如'answer/data/',以'/'结尾 - access_key_id: - title: - other: AccessKeyID - description: - other: S3存储的AccessKeyID - access_key_secret: - title: - other: AccessKeySecret - description: - other: S3存储的AccessKeySecret - access_token: - title: - other: AccessToken - description: - other: 访问 S3 所需的 AccessToken - visit_url_prefix: - title: - other: 访问URL前缀 - description: - other: 上传静态文件CDN最终访问地址的前缀,以 '/' 结尾 https://static.example.com/xxx/ - max_file_size: - title: - other: 文件最大大小(MB) - description: - other: 限制上传文件的最大大小,单位MB,默认为10MB - region: - title: - other: 区域(Region) - description: - other: S3存储区域 - disable_ssl: - title: - other: 禁用SSL - description: - other: 我们建议您使用SSL访问S3存储。如果您想禁用SSL,请选中此选项。 - err: - mis_storage_config: - other: 错误的存储配置导致上传失败 - file_not_found: - other: 文件未找到 - unsupported_file_type: - other: 不支持的文件类型 - over_file_size_limit: - other: 超过文件大小限制 - upload_file_failed: - other: 上传文件失败 - aliyunoss_cdn: - backend: - info: - name: - other: 阿里云CDN OSS存储 - description: - other: 上传文件到阿里云CDN OSS存储 - config: - endpoint: - title: - other: Endpoint - description: - other: 阿里云OSS存储的Endpoint - bucket_name: - title: - other: Bucket名称 - description: - other: 阿里云OSS存储的Bucket名称 - object_key_prefix: - title: - other: 对象Key前缀 - description: - other: 对象键的前缀,如'answer/data/',以'/'结尾 - access_key_id: - title: - other: AccessKeyID - description: - other: 阿里云OSS存储的AccessKeyID - access_key_secret: - title: - other: AccessKeySecret - description: - other: 阿里云OSS存储的AccessKeySecret - visit_url_prefix: - title: - other: 访问URL前缀 - description: - other: CDN最终访问地址的前缀,以 '/' 结尾 https://example.com/xxx/ - max_file_size: - title: - other: 最大文件大小(MB) - description: - other: 限制上传文件的最大大小,单位为MB,默认为 10MB - err: - mis_storage_config: - other: 错误的存储配置导致上传失败 - file_not_found: - other: 文件未找到 - unsupported_file_type: - other: 不支持的文件类型 - over_file_size_limit: - other: 超过文件大小限制 - upload_file_failed: - other: 上传文件失败 -# The following fields are used for interface presentation(Front-end) -ui: - how_to_format: - title: 如何排版 - desc: >- -
  • 添加链接

    <https://url.com>

    [标题](https://url.com)
  • 段落之间使用空行分隔

  • _斜体_ 或者 **粗体**

  • 使用 4 个空格缩进代码

  • 在行首添加 > 表示引用

  • 反引号进行转义 `像 _这样_`

  • 使用 ``` 创建代码块

    ```
    这是代码块
    ```
- pagination: - prev: 上一页 - next: 下一页 - page_title: - question: 问题 - questions: 问题 - tag: 标签 - tags: 标签 - tag_wiki: 标签维基 - create_tag: 创建标签 - edit_tag: 编辑标签 - ask_a_question: 提问题 - edit_question: 编辑问题 - edit_answer: 编辑回答 - search: 搜索 - posts_containing: 帖子包含 - settings: 设置 - notifications: 通知 - login: 登录 - sign_up: 注册 - account_recovery: 账号恢复 - account_activation: 账号激活 - confirm_email: 确认电子邮件 - account_suspended: 账号已被封禁 - admin: 后台管理 - change_email: 修改邮箱 - install: Answer 安装 - upgrade: Answer 升级 - maintenance: 网站维护 - users: 用户 - oauth_callback: 处理中 - http_404: HTTP 错误 404 - http_50X: HTTP 错误 500 - http_403: HTTP 错误 403 - logout: 退出 - notifications: - title: 通知 - inbox: 收件箱 - achievement: 成就 - new_alerts: 新通知 - all_read: 全部标记为已读 - show_more: 显示更多 - someone: 有人 - inbox_type: - all: 全部 - posts: 帖子 - invites: 邀请 - votes: 投票 - suspended: - title: 你的账号账号已被封禁 - until_time: "你的账号被封禁直到 {{ time }}。" - forever: 你的账号已被永久封禁。 - end: 你违反了我们的社区准则。 - contact_us: 联系我们 - editor: - blockquote: - text: 引用 - bold: - text: 粗体 - chart: - text: 图表 - flow_chart: 流程图 - sequence_diagram: 时序图 - class_diagram: 类图 - state_diagram: 状态图 - entity_relationship_diagram: 实体关系图 - user_defined_diagram: 用户自定义图表 - gantt_chart: 甘特图 - pie_chart: 饼图 - code: - text: 代码块 - add_code: 添加代码块 - form: - fields: - code: - label: 代码块 - msg: - empty: 代码块不能为空 - language: - label: 语言 - placeholder: 自动识别 - btn_cancel: 取消 - btn_confirm: 添加 - formula: - text: 公式 - options: - inline: 行内公式 - block: 块级公式 - heading: - text: 标题 - options: - h1: 标题 1 - h2: 标题 2 - h3: 标题 3 - h4: 标题 4 - h5: 标题 5 - h6: 标题 6 - help: - text: 帮助 - hr: - text: 水平线 - image: - text: 图片 - add_image: 添加图片 - tab_image: 上传图片 - form_image: - fields: - file: - label: 图像文件 - btn: 选择图片 - msg: - empty: 请选择图片文件。 - only_image: 只能上传图片文件。 - max_size: 文件大小不能超过 4 MB。 - desc: - label: 描述 - tab_url: 图片地址 - form_url: - fields: - url: - label: 图片地址 - msg: - empty: 图片地址不能为空 - name: - label: 描述 - btn_cancel: 取消 - btn_confirm: 添加 - uploading: 上传中 - indent: - text: 缩进 - outdent: - text: 减少缩进 - italic: - text: 斜体 - link: - text: 超链接 - add_link: 添加超链接 - form: - fields: - url: - label: 链接 - msg: - empty: 链接不能为空。 - name: - label: 描述 - btn_cancel: 取消 - btn_confirm: 添加 - ordered_list: - text: 有序列表 - unordered_list: - text: 无序列表 - table: - text: 表格 - heading: 表头 - cell: 单元格 - close_modal: - title: 关闭原因是... - btn_cancel: 取消 - btn_submit: 提交 - remark: - empty: 不能为空。 - msg: - empty: 请选择一个原因。 - report_modal: - flag_title: 我举报这篇帖子的原因是... - close_title: 我关闭这篇帖子的原因是... - review_question_title: 审查问题 - review_answer_title: 审查回答 - review_comment_title: 审查评论 - btn_cancel: 取消 - btn_submit: 提交 - remark: - empty: 不能为空 - msg: - empty: 请选择一个原因。 - not_a_url: URL 格式不正确。 - url_not_match: URL 来源与当前网站不匹配。 - tag_modal: - title: 创建新标签 - form: - fields: - display_name: - label: 显示名称 - msg: - empty: 显示名称不能为空。 - range: 显示名称不能超过 35 个字符。 - slug_name: - label: URL 固定链接 - desc: URL 固定链接不能超过 35 个字符。 - msg: - empty: URL 固定链接不能为空。 - range: URL 固定链接不能超过 35 个字符。 - character: URL 固定链接包含非法字符。 - desc: - label: 描述 - revision: - label: 编辑历史 - edit_summary: - label: 编辑备注 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_cancel: 取消 - btn_submit: 提交 - btn_post: 发布新标签 - tag_info: - created_at: 创建于 - edited_at: 编辑于 - history: 历史 - synonyms: - title: 同义词 - text: 以下标签将被重置到 - empty: 此标签目前没有同义词。 - btn_add: 添加同义词 - btn_edit: 编辑 - btn_save: 保存 - synonyms_text: 以下标签将被重置到 - delete: - title: 删除标签 - tip_with_posts: >- -

我们不允许 删除带有帖子的标签

请先从帖子中移除此标签。

- tip_with_synonyms: >- -

我们不允许 删除带有同义词的标签

请先从此标签中删除同义词。

- tip: 确定要删除吗? - close: 关闭 - edit_tag: - title: 编辑标签 - default_reason: 编辑标签 - default_first_reason: 添加标签 - btn_save_edits: 保存更改 - btn_cancel: 取消 - dates: - long_date: MM 月 DD 日 - long_date_with_year: "YYYY 年 MM 月 DD 日" - long_date_with_time: "YYYY 年 MM 月 DD 日 HH:mm" - now: 刚刚 - x_seconds_ago: "{{count}} 秒前" - x_minutes_ago: "{{count}} 分钟前" - x_hours_ago: "{{count}} 小时前" - hour: 小时 - day: 天 - hours: 小时 - days: 日 - reaction: - heart: 爱心 - smile: 微笑 - frown: 愁 - btn_label: 添加或删除回应。 - undo_emoji: 撤销 {{ emoji }} 回应 - react_emoji: 用 {{ emoji }} 回应 - unreact_emoji: 撤销 {{ emoji }} - comment: - btn_add_comment: 添加评论 - reply_to: 回复 - btn_reply: 回复 - btn_edit: 编辑 - btn_delete: 删除 - btn_flag: 举报 - btn_save_edits: 保存更改 - btn_cancel: 取消 - show_more: "{{count}} 条剩余评论" - tip_question: >- - 使用评论提问更多信息或者提出改进意见。避免在评论里回答问题。 - tip_answer: >- - 使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。 - tip_vote: 它给帖子添加了一些有用的内容 - edit_answer: - title: 编辑回答 - default_reason: 编辑回答 - default_first_reason: 添加答案 - form: - fields: - revision: - label: 编辑历史 - answer: - label: 回答内容 - feedback: - characters: 内容长度至少 6 个字符 - edit_summary: - label: 编辑摘要 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_save_edits: 保存更改 - btn_cancel: 取消 - tags: - title: 标签 - sort_buttons: - popular: 热门 - name: 名称 - newest: 最新 - button_follow: 关注 - button_following: 已关注 - tag_label: 个问题 - search_placeholder: 通过标签名称过滤 - no_desc: 此标签无描述。 - more: 更多 - ask: - title: 新增问题 - edit_title: 编辑问题 - default_reason: 编辑问题 - default_first_reason: 新增问题 - similar_questions: 相似问题 - form: - fields: - revision: - label: 修订版本 - title: - label: 标题 - placeholder: 请详细描述你的问题,想象你在问一个人 - msg: - empty: 标题不能为空。 - range: 标题最多 150 个字符 - body: - label: 内容 - msg: - empty: 内容不能为空。 - tags: - label: 标签 - msg: - empty: 必须选择一个标签 - answer: - label: 回答内容 - msg: - empty: 回答内容不能为空 - edit_summary: - label: 编辑备注 - placeholder: >- - 简单描述更改原因(更正拼写、修复语法、改进格式) - btn_post_question: 提交问题 - btn_save_edits: 保存更改 - answer_question: 回答自己的问题 - post_question&answer: 提交问题和回答 - tag_selector: - add_btn: 添加标签 - create_btn: 创建新标签 - search_tag: 搜索标签 - hint: "描述您的问题是关于什么,至少需要一个标签。" - no_result: 没有匹配的标签 - tag_required_text: 必选标签(至少一个) - header: - nav: - question: 问题 - tag: 标签 - user: 用户 - profile: 用户主页 - setting: 账号设置 - logout: 退出 - admin: 后台管理 - review: 审查 - bookmark: 收藏夹 - moderation: 管理 - search: - placeholder: 搜索 - footer: - build_on: >- - 由 <1>Apache Answer 提供动力 - 驱动问答社区的开源软件。
用爱制造 © {{cc}}. - upload_img: - name: 更改 - loading: 加载中... - pic_auth_code: - title: 验证码 - placeholder: 输入图片中的文字 - msg: - empty: 验证码不能为空。 - inactive: - first: >- - 就差一步!我们发送了一封激活邮件到 {{mail}}。请按照邮件中的说明激活你的账户。 - info: "如果没有收到,请检查你的垃圾邮件文件夹。" - another: >- - 我们向你的邮箱 {{mail}} 发送了另一封激活电子邮件。可能需要几分钟才能到达;请务必检查您的垃圾邮件箱。 - btn_name: 重新发送激活邮件 - change_btn_name: 更改邮箱 - msg: - empty: 不能为空。 - resend_email: - url_label: 确定要重新发送激活邮件吗? - url_text: 你也可以将上面的激活链接给该用户。 - login: - login_to_continue: 登录以继续 - info_sign: 没有账户?<1>注册 - info_login: 已经有账户?<1>登录 - agreements: 登录即表示您同意<1>隐私政策和<3>服务条款。 - forgot_pass: 忘记密码? - name: - label: 名字 - msg: - empty: 名字不能为空 - range: 名字应该在 4 到 30 个字符之间 - character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' - email: - label: 邮箱 - msg: - empty: 邮箱不能为空 - password: - label: 密码 - msg: - empty: 密码不能为空 - different: 两次输入密码不一致 - account_forgot: - page_title: 忘记密码 - btn_name: 发送恢复邮件 - send_success: >- - 如果存在邮箱为 {{mail}} 账户,你将很快收到一封重置密码的说明邮件。 - email: - label: 邮箱 - msg: - empty: 邮箱不能为空 - change_email: - btn_cancel: 取消 - btn_update: 更新电子邮件地址 - send_success: >- - 如果存在邮箱为 {{mail}} 的账户,你将很快收到一封重置密码的说明邮件。 - email: - label: 新的电子邮件地址 - msg: - empty: 邮箱不能为空。 - oauth: - connect: 连接到 {{ auth_name }} - remove: 移除 {{ auth_name }} - oauth_bind_email: - subtitle: 向你的账户添加恢复邮件地址。 - btn_update: 更新电子邮件地址 - email: - label: 邮箱 - msg: - empty: 邮箱不能为空。 - modal_title: 邮箱已经存在。 - modal_content: 该电子邮件地址已经注册。你确定要连接到已有账户吗? - modal_cancel: 更改邮箱 - modal_confirm: 连接到已有账户 - password_reset: - page_title: 密码重置 - btn_name: 重置我的密码 - reset_success: >- - 你已经成功更改密码;你将被重定向到登录页面。 - link_invalid: >- - 抱歉,此密码重置链接已失效。也许是你已经重置过密码了? - to_login: 前往登录页面 - password: - label: 密码 - msg: - empty: 密码不能为空。 - length: 密码长度在8-32个字符之间 - different: 两次输入密码不一致 - password_confirm: - label: 确认新密码 - settings: - page_title: 设置 - goto_modify: 前往修改 - nav: - profile: 我的资料 - notification: 通知 - account: 账号 - interface: 界面 - profile: - heading: 个人资料 - btn_name: 保存 - display_name: - label: 显示名称 - msg: 昵称不能为空。 - msg_range: 显示名称不能超过 30 个字符。 - username: - label: 用户名 - caption: 用户可以通过 "@用户名" 来提及你。 - msg: 用户名不能为空 - msg_range: 用户名不能超过 30 个字符。 - character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' - avatar: - label: 头像 - gravatar: Gravatar - gravatar_text: 你可以更改图像在 - custom: 自定义 - custom_text: 你可以上传你的图片。 - default: 系统 - msg: 请上传头像 - bio: - label: 关于我 - website: - label: 网站 - placeholder: "https://example.com" - msg: 网址格式不正确 - location: - label: 位置 - placeholder: "城市,国家" - notification: - heading: 邮件通知 - turn_on: 开启 - inbox: - label: 收件箱通知 - description: 你的提问有新的回答,评论,邀请回答和其他。 - all_new_question: - label: 所有新问题 - description: 获取所有新问题的通知。每周最多有50个问题。 - all_new_question_for_following_tags: - label: 所有关注标签的新问题 - description: 获取关注的标签下新问题通知。 - account: - heading: 账号 - change_email_btn: 更改邮箱 - change_pass_btn: 更改密码 - change_email_info: >- - 邮件已发送。请根据指引完成验证。 - email: - label: 电子邮件地址 - new_email: - label: 新的电子邮件地址 - msg: 新邮箱不能为空。 - pass: - label: 当前密码 - msg: 密码不能为空。 - password_title: 密码 - current_pass: - label: 当前密码 - msg: - empty: 当前密码不能为空 - length: 密码长度必须在 8 至 32 之间 - different: 两次输入的密码不匹配 - new_pass: - label: 新密码 - pass_confirm: - label: 确认新密码 - interface: - heading: 界面 - lang: - label: 界面语言 - text: 设置用户界面语言,在刷新页面后生效。 - my_logins: - title: 我的登录 - label: 使用这些账户登录或注册本网站。 - modal_title: 移除登录 - modal_content: 你确定要从账户里移除该登录? - modal_confirm_btn: 移除 - remove_success: 移除成功 - toast: - update: 更新成功 - update_password: 密码更新成功。 - flag_success: 感谢标记。 - forbidden_operate_self: 禁止对自己执行操作 - review: 您的修订将在审阅通过后显示。 - sent_success: 发送成功 - related_question: - title: 相关问题 - answers: 个回答 - invite_to_answer: - title: 受邀人 - desc: 邀请你认为可能知道答案的人。 - invite: 邀请回答 - add: 添加人员 - search: 搜索人员 - question_detail: - action: 操作 - Asked: 提问于 - asked: 提问于 - update: 修改于 - edit: 编辑于 - commented: 评论 - Views: 阅读次数 - Follow: 关注此问题 - Following: 已关注 - follow_tip: 关注此问题以接收通知 - answered: 回答于 - closed_in: 关闭于 - show_exist: 查看类似问题。 - useful: 有用的 - question_useful: 它是有用和明确的 - question_un_useful: 它不明确或没用的 - question_bookmark: 收藏该问题 - answer_useful: 这是有用的 - answer_un_useful: 它是没有用的 - answers: - title: 个回答 - score: 评分 - newest: 最新 - oldest: 最旧 - btn_accept: 采纳 - btn_accepted: 已被采纳 - write_answer: - title: 你的回答 - edit_answer: 编辑我的回答 - btn_name: 提交你的回答 - add_another_answer: 添加另一个回答 - confirm_title: 继续回答 - continue: 继续 - confirm_info: >- -

你确定要提交一个新的回答吗?

作为替代,你可以通过编辑来完善和改进之前的回答。

- empty: 回答内容不能为空。 - characters: 内容长度至少 6 个字符。 - tips: - header_1: 感谢你的回答 - li1_1: 请务必确定在 回答问题。提供详细信息并分享你的研究。 - li1_2: 用参考资料或个人经历来支持你所做的任何陈述。 - header_2: 但是 请避免... - li2_1: 请求帮助,寻求澄清,或答复其他答案。 - reopen: - confirm_btn: 重新打开 - title: 重新打开这个帖子 - content: 确定要重新打开吗? - list: - confirm_btn: 列表显示 - title: 列表中显示这个帖子 - content: 确定要列表中显示这个帖子吗? - unlist: - confirm_btn: 列表隐藏 - title: 从列表中隐藏这个帖子 - content: 确定要从列表中隐藏这个帖子吗? - pin: - title: 置顶该帖子 - content: 你确定要全局置顶吗?这个帖子将出现在所有帖子列表的顶部。 - confirm_btn: 置顶 - delete: - title: 删除 - question: >- - 我们不建议 删除有回答的帖子。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗? - answer_accepted: >- -

我们不建议删除被采纳的回答。因为这样做会使得后来的读者无法从该帖子中获得帮助。

如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗? - other: 你确定要删除? - tip_answer_deleted: 该回答已被删除 - undelete_title: 撤销删除本帖 - undelete_desc: 你确定你要撤销删除吗? - btns: - confirm: 确认 - cancel: 取消 - edit: 编辑 - save: 保存 - delete: 删除 - undelete: 撤消删除 - list: 列表显示 - unlist: 列表隐藏 - unlisted: 已隐藏 - login: 登录 - signup: 注册 - logout: 退出 - verify: 验证 - add_question: 我要提问 - approve: 批准 - reject: 拒绝 - skip: 跳过 - discard_draft: 丢弃草稿 - pinned: 已置顶 - all: 全部 - question: 问题 - answer: 回答 - comment: 评论 - refresh: 刷新 - resend: 重新发送 - deactivate: 取消激活 - active: 激活 - suspend: 封禁 - unsuspend: 解禁 - close: 关闭 - reopen: 重新打开 - ok: 确定 - light: 浅色 - dark: 深色 - system_setting: 跟随系统 - default: 默认 - reset: 重置 - tag: 标签 - post_lowercase: 帖子 - filter: 筛选 - ignore: 忽略 - submit: 提交 - normal: 正常 - closed: 已关闭 - deleted: 已删除 - pending: 等待处理 - more: 更多 - search: - title: 搜索结果 - keywords: 关键词 - options: 选项 - follow: 关注 - following: 已关注 - counts: "{{count}} 个结果" - more: 更多 - sort_btns: - relevance: 相关性 - newest: 最新的 - active: 活跃的 - score: 评分 - more: 更多 - tips: - title: 高级搜索提示 - tag: "<1>[tag] 在指定标签中搜索" - user: "<1>user:username 根据作者搜索" - answer: "<1>answers:0 搜索未回答的问题" - score: "<1>score:3 评分 3+ 的帖子" - question: "<1>is:question 搜索问题" - is_answer: "<1>is:answer 搜索回答" - empty: 找不到任何相关的内容。
请尝试其他关键字,或者减少查找内容的长度。 - share: - name: 分享 - copy: 复制链接 - via: 分享到... - copied: 已复制 - facebook: 分享到 Facebook - twitter: 分享到 Twitter - cannot_vote_for_self: 你不能给自己的帖子投票。 - modal_confirm: - title: 发生错误... - account_result: - success: 你的账号已通过验证,即将返回首页。 - link: 返回首页 - invalid: >- - 抱歉,此验证链接已失效。也许你的账号已经激活了? - confirm_new_email: 你的电子邮箱已更新 - confirm_new_email_invalid: >- - 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了? - unsubscribe: - page_title: 退订 - success_title: 退订成功 - success_desc: 您已成功退订,并且将不会再收到我们的邮件。 - link: 更改设置 - question: - following_tags: 已关注的标签 - edit: 编辑 - save: 保存 - follow_tag_tip: 关注标签来筛选你的问题列表。 - hot_questions: 热门问题 - all_questions: 全部问题 - x_questions: "{{ count }} 个问题" - x_answers: "{{ count }} 个回答" - questions: 问题 - answers: 回答 - newest: 最新 - active: 活跃 - hot: 热门 - score: 评分 - unanswered: 未回答 - modified: 更新于 - answered: 回答于 - asked: 提问于 - closed: 已关闭 - follow_a_tag: 关注一个标签 - more: 更多 - personal: - overview: 概览 - answers: 回答 - answer: 回答 - questions: 问题 - question: 问题 - bookmarks: 收藏 - reputation: 声望 - comments: 评论 - votes: 得票 - newest: 最新 - score: 评分 - edit_profile: 编辑资料 - visited_x_days: "已访问 {{ count }} 天" - viewed: 浏览次数 - joined: 加入于 - last_login: 上次登录 - about_me: 关于我 - about_me_empty: "// Hello, World!" - top_answers: 高分回答 - top_questions: 高分问题 - stats: 状态 - list_empty: 没有找到相关的内容。
试试看其他选项卡? - accepted: 已采纳 - answered: 回答于 - asked: 提问于 - downvoted: 点踩 - mod_short: 版主 - mod_long: 版主 - x_reputation: 声望 - x_votes: 得票 - x_answers: 个回答 - x_questions: 个问题 - install: - title: 安装 - next: 下一步 - done: 完成 - config_yaml_error: 无法创建 config.yaml 文件。 - lang: - label: 请选择一种语言 - db_type: - label: 数据库引擎 - db_username: - label: 用户名 - placeholder: root - msg: 用户名不能为空 - db_password: - label: 密码 - placeholder: root - msg: 密码不能为空 - db_host: - label: 数据库主机 - placeholder: "db:3306" - msg: 数据库地址不能为空 - db_name: - label: 数据库名 - placeholder: 回答 - msg: 数据库名称不能为空。 - db_file: - label: 数据库文件 - placeholder: /data/answer.db - msg: 数据库文件不能为空。 - config_yaml: - title: 创建 config.yaml - label: 已创建 config.yaml 文件。 - desc: >- - 你可以手动在 <1>/var/wwww/xxx/ 目录中创建 <1>config.yaml 文件并粘贴以下文本。 - info: 完成后,点击“下一步”按钮。 - site_information: 站点信息 - admin_account: 管理员账号 - site_name: - label: 站点名称 - msg: 站点名称不能为空。 - msg_max_length: 站点名称长度不得超过 30 个字符。 - site_url: - label: 网站网址 - text: 此网站的网址。 - msg: - empty: 网址不能为空。 - incorrect: 网址格式不正确。 - max_length: 网址长度不得超过 512 个字符。 - contact_email: - label: 联系邮箱 - text: 负责本网站的主要联系人的电子邮件地址。 - msg: - empty: 联系人邮箱不能为空。 - incorrect: 联系人邮箱地址不正确。 - login_required: - label: 私有的 - switch: 需要登录 - text: 只有登录用户才能访问这个社区。 - admin_name: - label: 名字 - msg: 名字不能为空。 - character: '只能由 "a-z", "0-9", " - . _" 组成' - msg_max_length: 名字长度不能超过 30 个字符。 - admin_password: - label: 密码 - text: >- - 您需要此密码才能登录。请将其存储在一个安全的位置。 - msg: 密码不能为空。 - msg_min_length: 密码必须至少 8 个字符长。 - msg_max_length: 密码长度不能超过 32 个字符。 - admin_email: - label: 邮箱 - text: 您需要此电子邮件才能登录。 - msg: - empty: 邮箱不能为空。 - incorrect: 邮箱格式不正确。 - ready_title: 您的网站已准备好 - ready_desc: >- - 如果你想改变更多的设置,请访问 <1>管理区域;在网站菜单中找到它。 - good_luck: "玩得愉快,祝你好运!" - warn_title: 警告 - warn_desc: >- - 文件 <1>config.yaml 已存在。如果你要重置该文件中的任何配置项,请先删除它。 - install_now: 您可以尝试 <1>现在安装。 - installed: 已安裝 - installed_desc: >- - 你似乎已经安装过了。如果要重新安装,请先清除旧的数据库表。 - db_failed: 数据连接异常! - db_failed_desc: >- - 这或者意味着数据库信息在 <1>config.yaml 文件不正确,或者无法与数据库服务器建立联系。这可能意味着你的主机数据库服务器故障。 - counts: - views: 次浏览 - votes: 个点赞 - answers: 个回答 - accepted: 已被采纳 - page_error: - http_error: HTTP 错误 {{ code }} - desc_403: 您无权访问此页面。 - desc_404: 很抱歉,此页面不存在。 - desc_50X: 服务器遇到了一个错误,无法完成你的请求。 - back_home: 返回首页 - page_maintenance: - desc: "我们正在进行维护,我们将很快回来。" - nav_menus: - dashboard: 后台管理 - contents: 内容管理 - questions: 问题 - answers: 回答 - users: 用户管理 - flags: 举报管理 - settings: 站点设置 - general: 一般 - interface: 界面 - smtp: SMTP - branding: 品牌 - legal: 法律条款 - write: 撰写 - tos: 服务条款 - privacy: 隐私政策 - seo: SEO - customize: 自定义 - themes: 主题 - css_html: CSS/HTML - login: 登录 - privileges: 特权 - plugins: 插件 - installed_plugins: 已安装插件 - website_welcome: 欢迎来到 {{site_name}} - user_center: - login: 登录 - qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码并登录。 - login_failed_email_tip: 登录失败,请允许此应用访问您的邮箱信息,然后重试。 - admin: - admin_header: - title: 后台管理 - dashboard: - title: 后台管理 - welcome: 欢迎来到管理后台! - site_statistics: 站点统计 - questions: "问题:" - answers: "回答:" - comments: "评论:" - votes: "投票:" - users: "用户:" - flags: "举报:" - reviews: "审查:" - site_health: 网站健康 - version: "版本" - https: "HTTPS:" - upload_folder: "上传文件夹:" - run_mode: "运行模式:" - private: 私有 - public: 公开 - smtp: "SMTP:" - timezone: "时区:" - system_info: 系统信息 - go_version: "Go版本:" - database: "数据库:" - database_size: "数据库大小:" - storage_used: "已用存储空间:" - uptime: "运行时间:" - links: 链接 - plugins: 插件 - github: GitHub - blog: 博客 - contact: 联系 - forum: 论坛 - documents: 文档 - feedback: 用户反馈 - support: 帮助 - review: 审查 - config: 配置 - update_to: 更新到 - latest: 最新版本 - check_failed: 校验失败 - "yes": "是" - "no": "否" - not_allowed: 拒绝 - allowed: 允许 - enabled: 已启用 - disabled: 停用 - writable: 可写 - not_writable: 不可写 - flags: - title: 举报 - pending: 等待处理 - completed: 已完成 - flagged: 被举报内容 - flagged_type: 标记了 {{ type }} - created: 创建于 - action: 操作 - review: 审查 - user_role_modal: - title: 更改用户状态为... - btn_cancel: 取消 - btn_submit: 提交 - new_password_modal: - title: 设置新密码 - form: - fields: - password: - label: 密码 - text: 用户将被退出,需要再次登录。 - msg: 密码的长度必须是8-32个字符。 - btn_cancel: 取消 - btn_submit: 提交 - edit_profile_modal: - title: 编辑资料 - form: - fields: - username: - label: 用户名 - msg_range: 用户名不能超过 30 个字符。 - email: - label: 电子邮件地址 - msg_invalid: 无效的邮箱地址 - edit_success: 修改成功 - btn_cancel: 取消 - btn_submit: 提交 - user_modal: - title: 添加新用户 - form: - fields: - users: - label: 批量添加用户 - placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" - text: 用逗号分隔“name, email, password”,每行一个用户。 - msg: "请输入用户的邮箱,每行一个。" - display_name: - label: 显示名称 - msg: 显示名称长度必须为 4-30 个字符 - email: - label: 邮箱 - msg: 邮箱无效。 - password: - label: 密码 - msg: 密码的长度必须是8-32个字符。 - btn_cancel: 取消 - btn_submit: 提交 - users: - title: 用户 - name: 名称 - email: 邮箱 - reputation: 声望 - created_at: 创建时间 - delete_at: 删除时间 - suspend_at: 封禁时间 - status: 状态 - role: 角色 - action: 操作 - change: 更改 - all: 全部 - staff: 工作人员 - more: 更多 - inactive: 不活跃 - suspended: 已封禁 - deleted: 已删除 - normal: 正常 - Moderator: 版主 - Admin: 管理员 - User: 用户 - filter: - placeholder: "按名称筛选,用户:id" - set_new_password: 设置新密码 - edit_profile: 编辑资料 - change_status: 更改状态 - change_role: 更改角色 - show_logs: 显示日志 - add_user: 添加用户 - deactivate_user: - title: 停用用户 - content: 未激活的用户必须重新验证他们的邮箱。 - delete_user: - title: 删除此用户 - content: 确定要删除此用户?此操作无法撤销! - remove: 移除内容 - label: 删除所有问题、 答案、 评论等 - text: 如果你只想删除用户账户,请不要选中此项。 - suspend_user: - title: 挂起此用户 - content: 被封禁的用户将无法登录。 - questions: - page_title: 问题 - unlisted: 已隐藏 - post: 标题 - votes: 得票数 - answers: 回答数 - created: 创建于 - status: 状态 - action: 操作 - change: 更改 - pending: 等待处理 - filter: - placeholder: "按标题过滤,问题:id" - answers: - page_title: 回答 - post: 标题 - votes: 得票数 - created: 创建于 - status: 状态 - action: 操作 - change: 更改 - filter: - placeholder: "按标题筛选,答案:id" - general: - page_title: 一般 - name: - label: 站点名称 - msg: 不能为空 - text: "站点的名称,作为站点的标题。" - site_url: - label: 网站网址 - msg: 网站网址不能为空。 - validate: 请输入一个有效的 URL。 - text: 此网站的地址。 - short_desc: - label: 简短站点描述 - msg: 简短网站描述不能为空。 - text: "简短的标语,作为网站主页的标题(Html 的 title 标签)。" - desc: - label: 站点描述 - msg: 网站描述不能为空。 - text: "使用一句话描述本站,作为网站的描述(Html 的 meta 标签)。" - contact_email: - label: 联系邮箱 - msg: 联系人邮箱不能为空。 - validate: 联系人邮箱无效。 - text: 本网站的主要联系邮箱地址。 - check_update: - label: 软件更新 - text: 自动检查软件更新 - interface: - page_title: 界面 - language: - label: 界面语言 - msg: 不能为空 - text: 设置用户界面语言,在刷新页面后生效。 - time_zone: - label: 时区 - msg: 时区不能为空。 - text: 选择一个与您相同时区的城市。 - smtp: - page_title: SMTP - from_email: - label: 发件人邮箱 - msg: 发件人邮箱不能为空。 - text: 用于发送邮件的地址。 - from_name: - label: 发件人 - msg: 不能为空 - text: 发件人的名字。 - smtp_host: - label: SMTP 主机 - msg: 不能为空 - text: 邮件服务器 - encryption: - label: 加密 - msg: 不能为空 - text: 对于大多数服务器而言,SSL 是推荐开启的。 - ssl: SSL - tls: TLS - none: 无加密 - smtp_port: - label: SMTP 端口 - msg: SMTP 端口必须在 1 ~ 65535 之间。 - text: 邮件服务器的端口号。 - smtp_username: - label: SMTP 用户名 - msg: 不能为空 - smtp_password: - label: SMTP 密码 - msg: 不能为空 - test_email_recipient: - label: 测试收件邮箱 - text: 提供用于接收测试邮件的邮箱地址。 - msg: 测试收件邮箱无效 - smtp_authentication: - label: 启用身份验证 - title: SMTP 身份验证 - msg: 不能为空 - "yes": "是" - "no": "否" - branding: - page_title: 品牌 - logo: - label: 网站标志(Logo) - msg: 图标不能为空。 - text: 在你的网站左上方的Logo图标。使用一个高度为56,长宽比大于3:1的宽长方形图像。如果留空,将显示网站标题文本。 - mobile_logo: - label: 移动端 Logo - text: 在你的网站的移动版上使用的标志。使用一个高度为56的宽矩形图像。如果留空,将使用 "Logo"设置中的图像。 - square_icon: - label: 方形图标 - msg: 方形图标不能为空。 - text: 用作元数据图标的基础的图像。最好是大于512x512。 - favicon: - label: 收藏夹图标 - text: 网站的图标。要在 CDN 正常工作,它必须是 png。 将调整大小到32x32。如果留空,将使用“方形图标”。 - legal: - page_title: 法律条款 - terms_of_service: - label: 服务条款 - text: "您可以在此添加服务内容的条款。如果您已经在别处托管了文档,请在这里提供完整的URL。" - privacy_policy: - label: 隐私政策 - text: "您可以在此添加隐私政策内容。如果您已经在别处托管了文档,请在这里提供完整的URL。" - write: - page_title: 编辑 - restrict_answer: - title: 限制一个回答 - label: 每个用户对于每个问题只能有一个回答 - text: "用户可以使用编辑按钮优化已有的回答" - recommend_tags: - label: 推荐标签 - text: "请在上方输入标签固定链接,每行一个标签。" - required_tag: - title: 必需的标签 - label: 根据需要设置推荐标签 - text: "每个新问题必须至少有一个推荐标签。" - reserved_tags: - label: 保留标签 - text: "保留的标签只能由版主添加到一个帖子中。" - seo: - page_title: 搜索引擎优化 - permalink: - label: 固定链接 - text: 自定义URL结构可以提高可用性,以及你的链接的向前兼容性。 - robots: - label: robots.txt - text: 这将永久覆盖任何相关的网站设置。 - themes: - page_title: 主题 - themes: - label: 主题 - text: 选择一个现有主题。 - color_scheme: - label: 配色方案 - navbar_style: - label: 导航栏样式 - primary_color: - label: 主色调 - text: 修改您主题使用的颜色 - css_and_html: - page_title: CSS 与 HTML - custom_css: - label: 自定义 CSS - text: > - - head: - label: 头部 - text: > - - header: - label: 页眉 - text: > - - footer: - label: 页脚 - text: 这将在 之前插入. - sidebar: - label: 侧边栏 - text: 这将插入侧边栏中。 - login: - page_title: 登录 - membership: - title: 会员 - label: 允许新注册 - text: 关闭以防止任何人创建新账户。 - email_registration: - title: 邮箱注册 - label: 允许邮箱注册 - text: 关闭以阻止任何人通过邮箱创建新账户。 - allowed_email_domains: - title: 允许的邮箱域 - text: 允许注册账户的邮箱域。每行一个域名。留空时忽略。 - private: - title: 非公开的 - label: 需要登录 - text: 只有登录用户才能访问这个社区。 - password_login: - title: 密码登录 - label: 允许使用邮箱和密码登录 - text: "警告:如果您未配置过其他登录方式,关闭密码登录后您则可能无法登录。" - installed_plugins: - title: 已安装插件 - plugin_link: 插件扩展功能。您可以在<1>插件仓库中找到插件。 - filter: - all: 全部 - active: 已启用 - inactive: 未启用 - outdated: 已过期 - plugins: - label: 插件 - text: 选择一个现有的插件。 - name: 名称 - version: 版本 - status: 状态 - action: 操作 - deactivate: 停用 - activate: 启用 - settings: 设置 - settings_users: - title: 用户 - avatar: - label: 默认头像 - text: 没有自定义头像的用户。 - gravatar_base_url: - label: Gravatar 根路径 URL - text: Gravatar 提供商的 API 基础的 URL。当为空时忽略。 - profile_editable: - title: 个人资料可编辑 - allow_update_display_name: - label: 允许用户修改显示名称 - allow_update_username: - label: 允许用户修改用户名 - allow_update_avatar: - label: 允许用户修改个人头像 - allow_update_bio: - label: 允许用户修改个人介绍 - allow_update_website: - label: 允许用户修改个人主页网址 - allow_update_location: - label: 允许用户更改位置 - privilege: - title: 特权 - level: - label: 级别所需声望 - text: 选择特权所需的声望值 - msg: - should_be_number: 输入必须是数字 - number_larger_1: 数字应该大于等于 1 - form: - optional: (选填) - empty: 不能为空 - invalid: 是无效的 - btn_submit: 保存 - not_found_props: "所需属性 {{ key }} 未找到。" - select: 选择 - page_review: - review: 评论 - proposed: 提案 - question_edit: 问题编辑 - answer_edit: 回答编辑 - tag_edit: '标签管理: 编辑标签' - edit_summary: 编辑备注 - edit_question: 编辑问题 - edit_answer: 编辑回答 - edit_tag: 编辑标签 - empty: 没有剩余的审核任务。 - approve_revision_tip: 您是否批准此修订? - approve_flag_tip: 您是否批准此举报? - approve_post_tip: 您是否批准此帖子? - approve_user_tip: 您是否批准此修订? - suggest_edits: 建议的编辑 - flag_post: 举报帖子 - flag_user: 举报用户 - queued_post: 排队的帖子 - queued_user: 排队用户 - filter_label: 类型 - reputation: 声望值 - flag_post_type: 举报这个帖子的类型是 {{ type }} - flag_user_type: 举报这个用户的类型是 {{ type }} - edit_post: 编辑帖子 - list_post: 文章列表 - unlist_post: 隐藏的帖子 - timeline: - undeleted: 取消删除 - deleted: 删除 - downvote: 反对 - upvote: 点赞 - accept: 采纳 - cancelled: 已取消 - commented: '评论:' - rollback: 回滚 - edited: 最后编辑于 - answered: 回答于 - asked: 提问于 - closed: 关闭 - reopened: 重新开启 - created: 创建于 - pin: 已置顶 - unpin: 取消置頂 - show: 已显示 - hide: 已隐藏 - title: "历史记录" - tag_title: "时间线" - show_votes: "显示投票" - n_or_a: N/A - title_for_question: "时间线" - title_for_answer: "{{ title }} 的 {{ author }} 回答时间线" - title_for_tag: "时间线" - datetime: 日期时间 - type: 类型 - by: 由 - comment: 评论 - no_data: "空空如也" - users: - title: 用户 - users_with_the_most_reputation: 本周声望最高的用户 - users_with_the_most_vote: 本周投票最多的用户 - staffs: 我们的社区工作人员 - reputation: 声望值 - votes: 投票 - prompt: - leave_page: 确定要离开此页面? - changes_not_save: 您的更改尚未保存 - draft: - discard_confirm: 您确定要丢弃您的草稿吗? - messages: - post_deleted: 该帖子已被删除。 - post_pin: 该帖子已被置顶。 - post_unpin: 该帖子已被取消置顶。 - post_hide_list: 此帖子已经从列表中隐藏。 - post_show_list: 该帖子已显示到列表中。 - post_reopen: 这个帖子已被重新打开. - post_list: 这个帖子已经被显示 - post_unlist: 这个帖子已经被隐藏 - post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 From 1d9f88f803cb6427c9eb7d1166436494a2314d83 Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 19 Aug 2024 16:15:21 +0800 Subject: [PATCH 062/336] fix(embed): embed plugin type definition --- docs/docs.go | 90 ++++++++++++++++++------ docs/swagger.json | 92 ++++++++++++++++++------- docs/swagger.yaml | 65 ++++++++++++----- internal/controller/embed_controller.go | 22 ++---- internal/schema/plugin_option_schema.go | 25 ------- plugin/embed.go | 8 +++ 6 files changed, 195 insertions(+), 107 deletions(-) delete mode 100644 internal/schema/plugin_option_schema.go diff --git a/docs/docs.go b/docs/docs.go index cf1264d1..fab0d8e9 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2738,7 +2738,7 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetEmbedOptionResp" + "$ref": "#/definitions/plugin.EmbedConfig" } } } @@ -4410,7 +4410,7 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetTagResp" + "$ref": "#/definitions/schema.GetTagBasicResp" } } } @@ -5380,7 +5380,7 @@ const docTemplate = `{ }, "/answer/api/v1/tags": { "get": { - "description": "get tags list", + "description": "get tags list by slug name", "produces": [ "application/json" ], @@ -5404,7 +5404,22 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handler.RespBody" + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetTagBasicResp" + } + } + } + } + ] } } } @@ -6571,14 +6586,14 @@ const docTemplate = `{ }, "/custom.css": { "get": { - "description": "get site robots information", + "description": "get site custom CSS", "produces": [ - "application/json" + "text/css" ], "tags": [ "site" ], - "summary": "get site robots information", + "summary": "get site custom CSS", "responses": { "200": { "description": "OK", @@ -7004,6 +7019,17 @@ const docTemplate = `{ "list": {} } }, + "plugin.EmbedConfig": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "platform": { + "type": "string" + } + } + }, "schema.AcceptAnswerReq": { "type": "object", "required": [ @@ -7813,17 +7839,6 @@ const docTemplate = `{ } } }, - "schema.GetEmbedOptionResp": { - "type": "object", - "properties": { - "enable": { - "type": "boolean" - }, - "platform": { - "type": "string" - } - } - }, "schema.GetFollowingTagsResp": { "type": "object", "properties": { @@ -8242,6 +8257,23 @@ const docTemplate = `{ } } }, + "schema.GetTagBasicResp": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "recommend": { + "type": "boolean" + }, + "reserved": { + "type": "boolean" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.GetTagPageResp": { "type": "object", "properties": { @@ -9819,7 +9851,7 @@ const docTemplate = `{ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9828,7 +9860,7 @@ const docTemplate = `{ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9842,7 +9874,7 @@ const docTemplate = `{ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9851,7 +9883,7 @@ const docTemplate = `{ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9859,6 +9891,20 @@ const docTemplate = `{ } } }, + "schema.SiteWriteTag": { + "type": "object", + "required": [ + "slug_name" + ], + "properties": { + "display_name": { + "type": "string" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.TagItem": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 1e93d2b0..9ea2d2ee 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2708,7 +2708,7 @@ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetEmbedOptionResp" + "$ref": "#/definitions/plugin.EmbedConfig" } } } @@ -4380,7 +4380,7 @@ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetTagResp" + "$ref": "#/definitions/schema.GetTagBasicResp" } } } @@ -5350,7 +5350,7 @@ }, "/answer/api/v1/tags": { "get": { - "description": "get tags list", + "description": "get tags list by slug name", "produces": [ "application/json" ], @@ -5374,7 +5374,22 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handler.RespBody" + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetTagBasicResp" + } + } + } + } + ] } } } @@ -6541,14 +6556,14 @@ }, "/custom.css": { "get": { - "description": "get site robots information", + "description": "get site custom CSS", "produces": [ - "application/json" + "text/css" ], "tags": [ "site" ], - "summary": "get site robots information", + "summary": "get site custom CSS", "responses": { "200": { "description": "OK", @@ -6974,6 +6989,17 @@ "list": {} } }, + "plugin.EmbedConfig": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + }, + "platform": { + "type": "string" + } + } + }, "schema.AcceptAnswerReq": { "type": "object", "required": [ @@ -7783,17 +7809,6 @@ } } }, - "schema.GetEmbedOptionResp": { - "type": "object", - "properties": { - "enable": { - "type": "boolean" - }, - "platform": { - "type": "string" - } - } - }, "schema.GetFollowingTagsResp": { "type": "object", "properties": { @@ -8212,6 +8227,23 @@ } } }, + "schema.GetTagBasicResp": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "recommend": { + "type": "boolean" + }, + "reserved": { + "type": "boolean" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.GetTagPageResp": { "type": "object", "properties": { @@ -8809,7 +8841,7 @@ "enum": [ "newest", "active", - "frequent", + "hot", "score", "unanswered" ] @@ -9789,7 +9821,7 @@ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9798,7 +9830,7 @@ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9812,7 +9844,7 @@ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9821,7 +9853,7 @@ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9829,6 +9861,20 @@ } } }, + "schema.SiteWriteTag": { + "type": "object", + "required": [ + "slug_name" + ], + "properties": { + "display_name": { + "type": "string" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.TagItem": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 93f8116a..1b176960 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -117,6 +117,13 @@ definitions: type: integer list: {} type: object + plugin.EmbedConfig: + properties: + enable: + type: boolean + platform: + type: string + type: object schema.AcceptAnswerReq: properties: answer_id: @@ -687,13 +694,6 @@ definitions: description: website type: string type: object - schema.GetEmbedOptionResp: - properties: - enable: - type: boolean - platform: - type: string - type: object schema.GetFollowingTagsResp: properties: display_name: @@ -983,6 +983,17 @@ definitions: terms_of_service_parsed_text: type: string type: object + schema.GetTagBasicResp: + properties: + display_name: + type: string + recommend: + type: boolean + reserved: + type: boolean + slug_name: + type: string + type: object schema.GetTagPageResp: properties: created_at: @@ -1401,7 +1412,7 @@ definitions: enum: - newest - active - - frequent + - hot - score - unanswered type: string @@ -2071,13 +2082,13 @@ definitions: properties: recommend_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array required_tag: type: boolean reserved_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array restrict_answer: type: boolean @@ -2086,17 +2097,26 @@ definitions: properties: recommend_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array required_tag: type: boolean reserved_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array restrict_answer: type: boolean type: object + schema.SiteWriteTag: + properties: + display_name: + type: string + slug_name: + type: string + required: + - slug_name + type: object schema.TagItem: properties: display_name: @@ -4353,7 +4373,7 @@ paths: - properties: data: items: - $ref: '#/definitions/schema.GetEmbedOptionResp' + $ref: '#/definitions/plugin.EmbedConfig' type: array type: object summary: GetEmbedConfig @@ -5382,7 +5402,7 @@ paths: - properties: data: items: - $ref: '#/definitions/schema.GetTagResp' + $ref: '#/definitions/schema.GetTagBasicResp' type: array type: object security: @@ -5965,7 +5985,7 @@ paths: - Tag /answer/api/v1/tags: get: - description: get tags list + description: get tags list by slug name parameters: - collectionFormat: csv description: string collection @@ -5980,7 +6000,14 @@ paths: "200": description: OK schema: - $ref: '#/definitions/handler.RespBody' + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetTagBasicResp' + type: array + type: object summary: get tags list tags: - Tag @@ -6677,15 +6704,15 @@ paths: - Activity /custom.css: get: - description: get site robots information + description: get site custom CSS produces: - - application/json + - text/css responses: "200": description: OK schema: type: string - summary: get site robots information + summary: get site custom CSS tags: - site /installation/base-info: diff --git a/internal/controller/embed_controller.go b/internal/controller/embed_controller.go index c9691d29..a61bd68c 100644 --- a/internal/controller/embed_controller.go +++ b/internal/controller/embed_controller.go @@ -21,7 +21,6 @@ package controller import ( "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/plugin" "github.com/gin-gonic/gin" ) @@ -40,27 +39,14 @@ func NewEmbedController() *EmbedController { // @Accept json // @Produce json // @Router /answer/api/v1/embed/config [get] -// @Success 200 {object} handler.RespBody{data=[]schema.GetEmbedOptionResp} +// @Success 200 {object} handler.RespBody{data=[]plugin.EmbedConfig} func (c *EmbedController) GetEmbedConfig(ctx *gin.Context) { - resp := make([]*schema.GetEmbedOptionResp, 0) - var slugName string + resp := make([]*plugin.EmbedConfig, 0) - _ = plugin.CallEmbed(func(base plugin.Embed) error { - slugName = base.Info().SlugName + _ = plugin.CallEmbed(func(embed plugin.Embed) (err error) { + resp, err = embed.GetEmbedConfigs(ctx) return nil }) - _ = plugin.CallConfig(func(fn plugin.Config) error { - if fn.Info().SlugName == slugName { - for _, field := range fn.ConfigFields() { - resp = append(resp, &schema.GetEmbedOptionResp{ - Platform: field.Name, - Enable: field.Value.(bool), - }) - } - return nil - } - return nil - }) handler.HandleResponse(ctx, nil, resp) } diff --git a/internal/schema/plugin_option_schema.go b/internal/schema/plugin_option_schema.go deleted file mode 100644 index 8db22973..00000000 --- a/internal/schema/plugin_option_schema.go +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package schema - -type GetEmbedOptionResp struct { - Platform string `json:"platform"` - Enable bool `json:"enable"` -} diff --git a/plugin/embed.go b/plugin/embed.go index 55149f66..e853c8c2 100644 --- a/plugin/embed.go +++ b/plugin/embed.go @@ -19,8 +19,16 @@ package plugin +import "github.com/gin-gonic/gin" + +type EmbedConfig struct { + Platform string `json:"platform"` + Enable bool `json:"enable"` +} + type Embed interface { Base + GetEmbedConfigs(ctx *gin.Context) (embedConfigs []*EmbedConfig, err error) } var ( From 3d8cf0ef418f57524d4b1403c91453059e307fb7 Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 5 Aug 2024 15:00:54 +0800 Subject: [PATCH 063/336] feat: bages ui --- i18n/en_US.yaml | 10 + ui/package.json | 5 +- ui/pnpm-lock.yaml | 1008 ++++++++++++++++- ui/src/components/CardBadge/index.scss | 36 + ui/src/components/CardBadge/index.tsx | 51 + ui/src/components/SideNav/index.tsx | 5 + ui/src/components/index.ts | 2 + ui/src/pages/Badges/Detail/index.tsx | 97 ++ ui/src/pages/Badges/index.tsx | 45 + .../Users/Personal/components/Alert/index.tsx | 23 +- .../Personal/components/Badges/index.tsx | 43 + .../Personal/components/NavBar/index.tsx | 5 + .../Personal/components/Overview/index.tsx | 36 +- .../Personal/components/TopList/index.tsx | 58 +- .../pages/Users/Personal/components/index.ts | 2 + ui/src/pages/Users/Personal/index.tsx | 70 +- ui/src/router/routes.ts | 8 + 17 files changed, 1388 insertions(+), 116 deletions(-) create mode 100644 ui/src/components/CardBadge/index.scss create mode 100644 ui/src/components/CardBadge/index.tsx create mode 100644 ui/src/pages/Badges/Detail/index.tsx create mode 100644 ui/src/pages/Badges/index.tsx create mode 100644 ui/src/pages/Users/Personal/components/Badges/index.tsx diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 4de69658..f9787eda 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1155,6 +1155,7 @@ ui: question: Questions tag: Tags user: Users + badges: Badges profile: Profile setting: Settings logout: Log out @@ -1572,12 +1573,14 @@ ui: reputation: Reputation comments: Comments votes: Votes + badges: Badges newest: Newest score: Score edit_profile: Edit profile visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: ',' last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1733,6 +1736,13 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + title: Badges + awarded: Awarded + earned_x: Earned x{{ number }} + x_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + admin: admin_header: diff --git a/ui/package.json b/ui/package.json index 8a087428..0ae727e2 100644 --- a/ui/package.json +++ b/ui/package.json @@ -45,7 +45,8 @@ "react-router-dom": "^6.22.3", "semver": "^7.3.8", "swr": "^1.3.0", - "zustand": "^4.1.1" + "zustand": "^4.1.1", + "demo": "workspace:*" }, "devDependencies": { "@commitlint/cli": "^17.0.3", @@ -98,4 +99,4 @@ "pnpm": ">=8" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index 77bbee2d..50fdae8f 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: dayjs: specifier: ^1.11.5 version: 1.11.5 + demo: + specifier: workspace:* + version: link:src/plugins/demo diff: specifier: ^5.1.0 version: 5.1.0 @@ -229,6 +232,52 @@ importers: specifier: ^0.8.0 version: 0.8.0 + src/plugins/demo: + dependencies: + react: + specifier: ^18.2.0 + version: 18.2.0 + react-bootstrap: + specifier: ^2.10.0 + version: 2.10.0(@types/react@18.0.20)(react-dom@18.2.0)(react@18.2.0) + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-i18next: + specifier: ^11.18.3 + version: 11.18.6(i18next@21.9.2)(react-dom@18.2.0)(react@18.2.0) + devDependencies: + '@modyfi/vite-plugin-yaml': + specifier: ^1.1.0 + version: 1.1.0(rollup@2.79.0)(vite@4.5.3) + '@typescript-eslint/eslint-plugin': + specifier: ^6.0.0 + version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.5.4) + '@typescript-eslint/parser': + specifier: ^6.0.0 + version: 6.11.0(eslint@8.53.0)(typescript@5.5.4) + '@vitejs/plugin-react-swc': + specifier: ^3.3.2 + version: 3.7.0(vite@4.5.3) + eslint: + specifier: ^8.45.0 + version: 8.53.0 + eslint-plugin-react-hooks: + specifier: ^4.6.0 + version: 4.6.0(eslint@8.53.0) + eslint-plugin-react-refresh: + specifier: ^0.4.3 + version: 0.4.9(eslint@8.53.0) + typescript: + specifier: ^5.0.2 + version: 5.5.4 + vite: + specifier: ^4.4.5 + version: 4.5.3(@types/node@16.11.59)(sass@1.54.9) + vite-plugin-dts: + specifier: ^3.9.1 + version: 3.9.1(@types/node@16.11.59)(rollup@2.79.0)(typescript@5.5.4)(vite@4.5.3) + packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -549,6 +598,14 @@ packages: dependencies: '@babel/types': 7.19.0 + /@babel/parser@7.25.0: + resolution: {integrity: sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.23.6 + dev: true + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.19.1): resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} engines: {node: '>=6.9.0'} @@ -2191,6 +2248,204 @@ packages: postcss: 8.4.16 postcss-selector-parser: 6.0.10 + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.53.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2495,14 +2750,14 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/sourcemap-codec': 1.4.15 /@jridgewell/gen-mapping@0.3.2: resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.17 /@jridgewell/gen-mapping@0.3.3: @@ -2510,7 +2765,7 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.22 dev: true @@ -2545,6 +2800,9 @@ packages: /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} dev: true /@jridgewell/trace-mapping@0.3.15: @@ -2563,14 +2821,14 @@ packages: resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} dependencies: '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 dev: true /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/sourcemap-codec': 1.4.15 /@leichtgewicht/ip-codec@2.0.4: resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} @@ -2702,6 +2960,63 @@ packages: '@lezer/lr': 1.4.0 dev: false + /@microsoft/api-extractor-model@7.28.13(@types/node@16.11.59): + resolution: {integrity: sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==} + dependencies: + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.0.2(@types/node@16.11.59) + transitivePeerDependencies: + - '@types/node' + dev: true + + /@microsoft/api-extractor@7.43.0(@types/node@16.11.59): + resolution: {integrity: sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==} + hasBin: true + dependencies: + '@microsoft/api-extractor-model': 7.28.13(@types/node@16.11.59) + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.0.2(@types/node@16.11.59) + '@rushstack/rig-package': 0.5.2 + '@rushstack/terminal': 0.10.0(@types/node@16.11.59) + '@rushstack/ts-command-line': 4.19.1(@types/node@16.11.59) + lodash: 4.17.21 + minimatch: 3.0.4 + resolve: 1.22.1 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.4.2 + transitivePeerDependencies: + - '@types/node' + dev: true + + /@microsoft/tsdoc-config@0.16.2: + resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} + dependencies: + '@microsoft/tsdoc': 0.14.2 + ajv: 6.12.6 + jju: 1.4.0 + resolve: 1.19.0 + dev: true + + /@microsoft/tsdoc@0.14.2: + resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + dev: true + + /@modyfi/vite-plugin-yaml@1.1.0(rollup@2.79.0)(vite@4.5.3): + resolution: {integrity: sha512-L26xfzkSo1yamODCAtk/ipVlL6OEw2bcJ92zunyHu8zxi7+meV0zefA9xscRMDCsMY8xL3C3wi3DhMiPxcbxbw==} + peerDependencies: + vite: ^3.2.7 || ^4.0.5 || ^5.0.5 + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@2.79.0) + js-yaml: 4.1.0 + tosource: 2.0.0-alpha.3 + vite: 4.5.3(@types/node@16.11.59)(sass@1.54.9) + transitivePeerDependencies: + - rollup + dev: true + /@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1: resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} dependencies: @@ -2873,9 +3188,72 @@ packages: picomatch: 2.3.1 rollup: 2.79.0 + /@rollup/pluginutils@5.1.0(rollup@2.79.0): + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + rollup: 2.79.0 + dev: true + /@rushstack/eslint-patch@1.2.0: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} + /@rushstack/node-core-library@4.0.2(@types/node@16.11.59): + resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 16.11.59 + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.1 + semver: 7.5.4 + z-schema: 5.0.5 + dev: true + + /@rushstack/rig-package@0.5.2: + resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} + dependencies: + resolve: 1.22.1 + strip-json-comments: 3.1.1 + dev: true + + /@rushstack/terminal@0.10.0(@types/node@16.11.59): + resolution: {integrity: sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@rushstack/node-core-library': 4.0.2(@types/node@16.11.59) + '@types/node': 16.11.59 + supports-color: 8.1.1 + dev: true + + /@rushstack/ts-command-line@4.19.1(@types/node@16.11.59): + resolution: {integrity: sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==} + dependencies: + '@rushstack/terminal': 0.10.0(@types/node@16.11.59) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + dev: true + /@sinclair/typebox@0.24.42: resolution: {integrity: sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==} @@ -2992,12 +3370,141 @@ packages: transitivePeerDependencies: - supports-color + /@swc/core-darwin-arm64@1.7.3: + resolution: {integrity: sha512-CTkHa6MJdov9t41vuV2kmQIMu+Q19LrEHGIR/UiJYH06SC/sOu35ZZH8DyfLp9ZoaCn21gwgWd61ixOGQlwzTw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@swc/core-darwin-x64@1.7.3: + resolution: {integrity: sha512-mun623y6rCoZ2EFIYfIRqXYRFufJOopoYSJcxYhZUrfTpAvQ1zLngjQpWCUU1krggXR2U0PQj+ls0DfXUTraNg==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm-gnueabihf@1.7.3: + resolution: {integrity: sha512-4Jz4UcIcvZNMp9qoHbBx35bo3rjt8hpYLPqnR4FFq6gkAsJIMFC56UhRZwdEQoDuYiOFMBnnrsg31Fyo6YQypA==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm64-gnu@1.7.3: + resolution: {integrity: sha512-p+U/M/oqV7HC4erQ5TVWHhJU1984QD+wQBPxslAYq751bOQGm0R/mXK42GjugqjnR6yYrAiwKKbpq4iWVXNePA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm64-musl@1.7.3: + resolution: {integrity: sha512-s6VzyaJwaRGTi2mz2h6Ywxfmgpkc69IxhuMzl+sl34plH0V0RgnZDm14HoCGIKIzRk4+a2EcBV1ZLAfWmPACQg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-x64-gnu@1.7.3: + resolution: {integrity: sha512-IrFY48C356Z2dU2pjYg080yvMXzmSV3Lmm/Wna4cfcB1nkVLjWsuYwwRAk9CY7E19c+q8N1sMNggubAUDYoX2g==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-x64-musl@1.7.3: + resolution: {integrity: sha512-qoLgxBlBnnyUEDu5vmRQqX90h9jldU1JXI96e6eh2d1gJyKRA0oSK7xXmTzorv1fGHiHulv9qiJOUG+g6uzJWg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-arm64-msvc@1.7.3: + resolution: {integrity: sha512-OAd7jVVJ7nb0Ev80VAa1aeK+FldPeC4eZ35H4Qn6EICzIz0iqJo2T33qLKkSZiZEBKSoF4KcwrqYfkjLOp5qWg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-ia32-msvc@1.7.3: + resolution: {integrity: sha512-31+Le1NyfSnILFV9+AhxfFOG0DK0272MNhbIlbcv4w/iqpjkhaOnNQnLsYJD1Ow7lTX1MtIZzTjOhRlzSviRWg==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-x64-msvc@1.7.3: + resolution: {integrity: sha512-jVQPbYrwcuueI4QB0fHC29SVrkFOBcfIspYDlgSoHnEz6tmLMqUy+txZUypY/ZH/KaK0HEY74JkzgbRC1S6LFQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core@1.7.3: + resolution: {integrity: sha512-HHAlbXjWI6Kl9JmmUW1LSygT1YbblXgj2UvvDzMkTBPRzYMhW6xchxdO8HbtMPtFYRt/EQq9u1z7j4ttRSrFsA==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.12 + optionalDependencies: + '@swc/core-darwin-arm64': 1.7.3 + '@swc/core-darwin-x64': 1.7.3 + '@swc/core-linux-arm-gnueabihf': 1.7.3 + '@swc/core-linux-arm64-gnu': 1.7.3 + '@swc/core-linux-arm64-musl': 1.7.3 + '@swc/core-linux-x64-gnu': 1.7.3 + '@swc/core-linux-x64-musl': 1.7.3 + '@swc/core-win32-arm64-msvc': 1.7.3 + '@swc/core-win32-ia32-msvc': 1.7.3 + '@swc/core-win32-x64-msvc': 1.7.3 + dev: true + + /@swc/counter@0.1.3: + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + dev: true + /@swc/helpers@0.5.3: resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==} dependencies: tslib: 2.6.2 dev: false + /@swc/types@0.1.12: + resolution: {integrity: sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==} + dependencies: + '@swc/counter': 0.1.3 + dev: true + /@testing-library/dom@8.18.1: resolution: {integrity: sha512-oEvsm2B/WtcHKE+IcEeeCqNU/ltFGaVyGbpcm4g/2ytuT49jrlH9x5qRKL/H3A6yfM4YAbSbC0ceT5+9CEXnLg==} engines: {node: '>=12'} @@ -3071,6 +3578,10 @@ packages: /@tsconfig/node16@1.0.3: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} + /@types/argparse@1.0.38: + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + dev: true + /@types/aria-query@4.2.2: resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} dev: true @@ -3148,7 +3659,7 @@ packages: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: '@types/eslint': 8.4.6 - '@types/estree': 0.0.51 + '@types/estree': 1.0.5 /@types/eslint-scope@3.7.7: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -3160,7 +3671,7 @@ packages: /@types/eslint@8.4.6: resolution: {integrity: sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==} dependencies: - '@types/estree': 1.0.0 + '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 /@types/eslint@8.56.2: @@ -3176,12 +3687,8 @@ packages: /@types/estree@0.0.51: resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} - /@types/estree@1.0.0: - resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} - /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - dev: true /@types/express-serve-static-core@4.17.31: resolution: {integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==} @@ -3426,6 +3933,35 @@ packages: - supports-color dev: true + /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.5.4): + resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.5.4) + '@typescript-eslint/scope-manager': 6.11.0 + '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.5.4) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 6.11.0 + debug: 4.3.4 + eslint: 8.53.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/experimental-utils@5.38.0(eslint@8.53.0)(typescript@4.9.5): resolution: {integrity: sha512-kzXBRfvGlicgGk4CYuRUqKvwc2s3wHXNssUWWJU18bhMRxriFm3BZWyQ6vEHBRpEIMKB6b7MIQHO+9lYlts19w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3478,6 +4014,27 @@ packages: - supports-color dev: true + /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.5.4): + resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 6.11.0 + '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 6.11.0 + debug: 4.3.4 + eslint: 8.53.0 + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@5.38.0: resolution: {integrity: sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3532,6 +4089,26 @@ packages: - supports-color dev: true + /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.5.4): + resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.5.4) + '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.5.4) + debug: 4.3.4 + eslint: 8.53.0 + ts-api-utils: 1.0.3(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types@5.38.0: resolution: {integrity: sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3582,6 +4159,27 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@6.11.0(typescript@5.5.4): + resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/visitor-keys': 6.11.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + ts-api-utils: 1.0.3(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils@5.38.0(eslint@8.53.0)(typescript@4.9.5): resolution: {integrity: sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3618,6 +4216,25 @@ packages: - typescript dev: true + /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.5.4): + resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.5 + '@typescript-eslint/scope-manager': 6.11.0 + '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.5.4) + eslint: 8.53.0 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@5.38.0: resolution: {integrity: sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3636,6 +4253,77 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + /@vitejs/plugin-react-swc@3.7.0(vite@4.5.3): + resolution: {integrity: sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==} + peerDependencies: + vite: ^4 || ^5 + dependencies: + '@swc/core': 1.7.3 + vite: 4.5.3(@types/node@16.11.59)(sass@1.54.9) + transitivePeerDependencies: + - '@swc/helpers' + dev: true + + /@volar/language-core@1.11.1: + resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} + dependencies: + '@volar/source-map': 1.11.1 + dev: true + + /@volar/source-map@1.11.1: + resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==} + dependencies: + muggle-string: 0.3.1 + dev: true + + /@volar/typescript@1.11.1: + resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} + dependencies: + '@volar/language-core': 1.11.1 + path-browserify: 1.0.1 + dev: true + + /@vue/compiler-core@3.4.34: + resolution: {integrity: sha512-Z0izUf32+wAnQewjHu+pQf1yw00EGOmevl1kE+ljjjMe7oEfpQ+BI3/JNK7yMB4IrUsqLDmPecUrpj3mCP+yJQ==} + dependencies: + '@babel/parser': 7.25.0 + '@vue/shared': 3.4.34 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + dev: true + + /@vue/compiler-dom@3.4.34: + resolution: {integrity: sha512-3PUOTS1h5cskdOJMExCu2TInXuM0j60DRPpSCJDqOCupCfUZCJoyQmKtRmA8EgDNZ5kcEE7vketamRZfrEuVDw==} + dependencies: + '@vue/compiler-core': 3.4.34 + '@vue/shared': 3.4.34 + dev: true + + /@vue/language-core@1.8.27(typescript@5.5.4): + resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@volar/language-core': 1.11.1 + '@volar/source-map': 1.11.1 + '@vue/compiler-dom': 3.4.34 + '@vue/shared': 3.4.34 + computeds: 0.0.1 + minimatch: 9.0.5 + muggle-string: 0.3.1 + path-browserify: 1.0.1 + typescript: 5.5.4 + vue-template-compiler: 2.7.16 + dev: true + + /@vue/shared@3.4.34: + resolution: {integrity: sha512-x5LmiRLpRsd9KTjAB8MPKf0CDPMcuItjP0gbNqFCIgL1I8iYp4zglhj9w9FPCdIbHG2M91RVeIbArFfFTz9I3A==} + dev: true + /@webassemblyjs/ast@1.11.1: resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} dependencies: @@ -3878,12 +4566,12 @@ packages: acorn: 8.11.3 dev: true - /acorn-jsx@5.3.2(acorn@8.10.0): + /acorn-jsx@5.3.2(acorn@8.11.3): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.10.0 + acorn: 8.11.3 /acorn-node@1.8.2: resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} @@ -3905,11 +4593,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - /acorn@8.10.0: - resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} - engines: {node: '>=0.4.0'} - hasBin: true - /acorn@8.11.3: resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} engines: {node: '>=0.4.0'} @@ -4802,6 +5485,13 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + requiresBuild: true + dev: true + optional: true + /common-path-prefix@3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} @@ -4839,6 +5529,10 @@ packages: transitivePeerDependencies: - supports-color + /computeds@0.0.1: + resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -5227,6 +5921,10 @@ packages: resolution: {integrity: sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==} dev: false + /de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + dev: true + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -5596,6 +6294,11 @@ packages: /entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==, tarball: https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz} + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: true + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -5727,6 +6430,36 @@ packages: is-date-object: 1.0.5 is-symbol: 1.0.4 + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -6139,6 +6872,14 @@ packages: dependencies: eslint: 8.53.0 + /eslint-plugin-react-refresh@0.4.9(eslint@8.53.0): + resolution: {integrity: sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA==} + peerDependencies: + eslint: '>=7' + dependencies: + eslint: 8.53.0 + dev: true + /eslint-plugin-react@7.33.2(eslint@8.53.0): resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} @@ -6283,8 +7024,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) + acorn: 8.11.3 + acorn-jsx: 5.3.2(acorn@8.11.3) eslint-visitor-keys: 3.4.3 /esprima@4.0.1: @@ -6315,6 +7056,10 @@ packages: /estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -6633,6 +7378,15 @@ packages: jsonfile: 6.1.0 universalify: 2.0.0 + /fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: true + /fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -7099,6 +7853,11 @@ packages: parent-module: 1.0.1 resolve-from: 4.0.0 + /import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + dev: true + /import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} @@ -8101,6 +8860,12 @@ packages: engines: {node: '>=6'} hasBin: true + /jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -8153,6 +8918,10 @@ packages: resolution: {integrity: sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==} engines: {node: '>= 8'} + /kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + dev: true + /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -8271,6 +9040,14 @@ packages: resolution: {integrity: sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==} dev: true + /lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + dev: true + + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: true + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -8324,6 +9101,12 @@ packages: dependencies: sourcemap-codec: 1.4.8 + /magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + dev: true + /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -8465,6 +9248,13 @@ packages: dependencies: brace-expansion: 2.0.1 + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} @@ -8492,6 +9282,10 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + /muggle-string@0.3.1: + resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} + dev: true + /multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true @@ -8504,6 +9298,12 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -8844,6 +9644,10 @@ packages: no-case: 3.0.4 tslib: 2.6.2 + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true + /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -8884,6 +9688,10 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + /picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + dev: true + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -9621,6 +10429,15 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postcss@8.4.40: + resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + dev: true + /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -10327,6 +11144,13 @@ packages: resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==} engines: {node: '>=10'} + /resolve@1.19.0: + resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} + dependencies: + is-core-module: 2.10.0 + path-parse: 1.0.7 + dev: true + /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true @@ -10394,6 +11218,14 @@ packages: optionalDependencies: fsevents: 2.3.3 + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + /run-applescript@5.0.0: resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} engines: {node: '>=12'} @@ -10736,6 +11568,11 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + dev: true + /source-map-loader@3.0.1(webpack@5.74.0): resolution: {integrity: sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==} engines: {node: '>= 12.13.0'} @@ -11324,6 +12161,11 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + /tosource@2.0.0-alpha.3: + resolution: {integrity: sha512-KAB2lrSS48y91MzFPFuDg4hLbvDiyTjOVgaK7Erw+5AmZXNq4sFRVn8r6yxSLuNs15PaokrDRpS61ERY9uZOug==} + engines: {node: '>=10'} + dev: true + /tough-cookie@4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} engines: {node: '>=6'} @@ -11361,6 +12203,15 @@ packages: typescript: 4.9.5 dev: true + /ts-api-utils@1.0.3(typescript@5.5.4): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.5.4 + dev: true + /ts-node@10.9.1(@types/node@16.11.59)(typescript@4.9.5): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -11513,6 +12364,18 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + /typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -11566,6 +12429,11 @@ packages: dependencies: crypto-random-string: 2.0.0 + /universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: true + /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -11598,7 +12466,7 @@ packages: dependencies: browserslist: 4.22.2 escalade: 3.1.1 - picocolors: 1.0.0 + picocolors: 1.0.1 dev: true /update-browserslist-db@1.0.9(browserslist@4.21.4): @@ -11675,15 +12543,101 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /validator@13.12.0: + resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} + engines: {node: '>= 0.10'} + dev: true + /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + /vite-plugin-dts@3.9.1(@types/node@16.11.59)(rollup@2.79.0)(typescript@5.5.4)(vite@4.5.3): + resolution: {integrity: sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + dependencies: + '@microsoft/api-extractor': 7.43.0(@types/node@16.11.59) + '@rollup/pluginutils': 5.1.0(rollup@2.79.0) + '@vue/language-core': 1.8.27(typescript@5.5.4) + debug: 4.3.4 + kolorist: 1.8.0 + magic-string: 0.30.11 + typescript: 5.5.4 + vite: 4.5.3(@types/node@16.11.59)(sass@1.54.9) + vue-tsc: 1.8.27(typescript@5.5.4) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + dev: true + + /vite@4.5.3(@types/node@16.11.59)(sass@1.54.9): + resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 16.11.59 + esbuild: 0.18.20 + postcss: 8.4.40 + rollup: 3.29.4 + sass: 1.54.9 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /void-elements@3.1.0: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} dev: false + /vue-template-compiler@2.7.16: + resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true + + /vue-tsc@1.8.27(typescript@5.5.4): + resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==} + hasBin: true + peerDependencies: + typescript: '*' + dependencies: + '@volar/typescript': 1.11.1 + '@vue/language-core': 1.8.27(typescript@5.5.4) + semver: 7.5.4 + typescript: 5.5.4 + dev: true + /w3c-hr-time@1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} dependencies: @@ -12320,6 +13274,18 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + /z-schema@5.0.5: + resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} + engines: {node: '>=8.0.0'} + hasBin: true + dependencies: + lodash.get: 4.4.2 + lodash.isequal: 4.5.0 + validator: 13.12.0 + optionalDependencies: + commander: 9.5.0 + dev: true + /zustand@4.1.1(react@18.2.0): resolution: {integrity: sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==} engines: {node: '>=12.7.0'} diff --git a/ui/src/components/CardBadge/index.scss b/ui/src/components/CardBadge/index.scss new file mode 100644 index 00000000..30c30cb1 --- /dev/null +++ b/ui/src/components/CardBadge/index.scss @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +.badge-card { + width: 194px; + margin: 12px; + + .label { + position: absolute; + top: 1rem; + right: 1rem; + } +} + + +@media screen and (max-width: 768px) { + .badge-card { + width: 163.5px; + } +} diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx new file mode 100644 index 00000000..b8dde502 --- /dev/null +++ b/ui/src/components/CardBadge/index.tsx @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { useTranslation } from 'react-i18next'; +import { FC } from 'react'; +import { Card, Badge } from 'react-bootstrap'; + +import { formatCount } from '@/utils'; + +import './index.scss'; + +interface IProps { + data: any; + badgePill: boolean; +} + +const Index: FC = ({ data, badgePill }) => { + const { t } = useTranslation('translation', { keyPrefix: 'badges' }); + console.log(data); + return ( + + + + 0 + + +
Nice Question
+
+ {t('x_awarded', { number: formatCount(16) })} +
+
+
+ ); +}; + +export default Index; diff --git a/ui/src/components/SideNav/index.tsx b/ui/src/components/SideNav/index.tsx index 6c53fe59..327d7b38 100644 --- a/ui/src/components/SideNav/index.tsx +++ b/ui/src/components/SideNav/index.tsx @@ -73,6 +73,11 @@ const Index: FC = () => { {t('header.nav.user')} + + + {t('header.nav.badges')} + + {can_revision || userInfo?.role_id === 2 ? ( <>
diff --git a/ui/src/components/index.ts b/ui/src/components/index.ts index fdf052d3..44dc1516 100644 --- a/ui/src/components/index.ts +++ b/ui/src/components/index.ts @@ -60,6 +60,7 @@ import ImgViewer from './ImgViewer'; import SideNav from './SideNav'; import PluginRender from './PluginRender'; import HighlightText from './HighlightText'; +import CardBadge from './CardBadge'; export { Avatar, @@ -107,5 +108,6 @@ export { SideNav, PluginRender, HighlightText, + CardBadge, }; export type { EditorRef, JSONSchema, UISchema }; diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx new file mode 100644 index 00000000..7a192a13 --- /dev/null +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Card, Badge, Row, Col } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; + +import { Avatar, FormatTime } from '@/components'; +import { usePageTags } from '@/hooks'; +import { formatCount } from '@/utils'; + +const Index = () => { + const { t } = useTranslation('translation', { keyPrefix: 'badges' }); + + usePageTags({ + title: t('title'), + }); + + return ( +
+

{t('title')}

+ + + +
+
Support Expert
+
+ This badge is granted for achieving the expert level of our + community support programme. This certifies that the recipient has + demonstrated a high level of skills and abilities to manage and + support multiple communities/instances. +
+
{t('can_earn_multiple')}
+
+ + {t('x_awarded', { number: formatCount(16) })} + + + {t('earned_x', { number: 2 })} + +
+
+
+
+ + {[0, 1, 2, 3, 4, 5, 6].map((item) => { + return ( + + +
+ + + +
+ + username + +
+ 980 {t('x_reputation', { keyPrefix: 'personal' })} +
+
+
+ + How to `go test` all tests in my project? + + + ); + })} +
+
+ ); +}; + +export default Index; diff --git a/ui/src/pages/Badges/index.tsx b/ui/src/pages/Badges/index.tsx new file mode 100644 index 00000000..84784c53 --- /dev/null +++ b/ui/src/pages/Badges/index.tsx @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { useTranslation } from 'react-i18next'; + +import { CardBadge } from '@/components'; +import { usePageTags } from '@/hooks'; + +const Index = () => { + const { t } = useTranslation('translation', { keyPrefix: 'badges' }); + + usePageTags({ + title: t('title'), + }); + + return ( +
+

{t('title')}

+
Community Badges
+
+ {[0, 1, 2, 3, 4, 5, 6].map((item) => { + return ; + })} +
+
+ ); +}; + +export default Index; diff --git a/ui/src/pages/Users/Personal/components/Alert/index.tsx b/ui/src/pages/Users/Personal/components/Alert/index.tsx index 65fd157b..8bde01f2 100644 --- a/ui/src/pages/Users/Personal/components/Alert/index.tsx +++ b/ui/src/pages/Users/Personal/components/Alert/index.tsx @@ -18,7 +18,7 @@ */ import { memo, FC, useState } from 'react'; -import { Alert, Col } from 'react-bootstrap'; +import { Alert } from 'react-bootstrap'; interface Props { data; @@ -27,17 +27,16 @@ const Index: FC = ({ data }) => { const [show, setShow] = useState(Boolean(data)); return ( - - { - setShow(false); - }}> -
- - + { + setShow(false); + }}> +
+ ); }; diff --git a/ui/src/pages/Users/Personal/components/Badges/index.tsx b/ui/src/pages/Users/Personal/components/Badges/index.tsx new file mode 100644 index 00000000..a7bd3e58 --- /dev/null +++ b/ui/src/pages/Users/Personal/components/Badges/index.tsx @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FC } from 'react'; + +import { CardBadge } from '@/components'; + +interface IProps { + data: any[]; + visible: boolean; +} + +const Index: FC = ({ data, visible }) => { + console.log(data); + if (!visible) { + return null; + } + return ( +
+ {[0, 1, 2, 3, 4, 5, 6].map((item) => { + return ; + })} +
+ ); +}; + +export default Index; diff --git a/ui/src/pages/Users/Personal/components/NavBar/index.tsx b/ui/src/pages/Users/Personal/components/NavBar/index.tsx index d201a579..5f4360ed 100644 --- a/ui/src/pages/Users/Personal/components/NavBar/index.tsx +++ b/ui/src/pages/Users/Personal/components/NavBar/index.tsx @@ -59,6 +59,11 @@ const list = [ path: '/votes', name: 'votes', }, + { + role: 'self', // Only visible to author + path: '/badges', + name: 'badges', + }, ]; const Index: FC = ({ slug, tabName = 'overview', isSelf }) => { const { t } = useTranslation('translation', { keyPrefix: 'personal' }); diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 3d5c7360..4f228061 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -19,6 +19,7 @@ import { FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; +import { Row, Col } from 'react-bootstrap'; import TopList from '../TopList'; @@ -37,26 +38,31 @@ const Index: FC = ({ visible, introduction, data }) => {
{t('about_me')}
{introduction ? (
) : ( -
{t('about_me_empty')}
+
{t('about_me_empty')}
)} - {data?.answer?.length > 0 && ( - <> -
{t('top_answers')}
- - - )} - - {data?.question?.length > 0 && ( - <> -
{t('top_questions')}
- - - )} + + + {data?.answer?.length > 0 && ( + <> +
{t('top_answers')}
+ + + )} + + + {data?.question?.length > 0 && ( + <> +
{t('top_questions')}
+ + + )} + +
); }; diff --git a/ui/src/pages/Users/Personal/components/TopList/index.tsx b/ui/src/pages/Users/Personal/components/TopList/index.tsx index ad9044fa..04553428 100644 --- a/ui/src/pages/Users/Personal/components/TopList/index.tsx +++ b/ui/src/pages/Users/Personal/components/TopList/index.tsx @@ -31,14 +31,13 @@ interface Props { const Index: FC = ({ data, type }) => { const { t } = useTranslation('translation', { keyPrefix: 'personal' }); return ( -
    - {data?.map((item) => { +
      + {data?.map((item, index) => { return (
    1. = ({ data, type }) => { {type === 'answer' ? item.question_info.title : item.title} -
      +
      {item.vote_count} {t('votes', { keyPrefix: 'counts' })} -
      - {type === 'question' && ( -
      0 ? 'text-success' : '' - }`}> - {Number(item.accepted_answer_id) > 0 ? ( + + {type === 'question' && ( +
      0 ? 'text-success' : '' + }`}> + {Number(item.accepted_answer_id) > 0 ? ( + + ) : ( + + )} + + + {' '} + {item.answer_count} {t('answers', { keyPrefix: 'counts' })} + +
      + )} + + {type === 'answer' && item.accepted === 2 && ( +
      - ) : ( - - )} - - - {' '} - {item.answer_count} {t('answers', { keyPrefix: 'counts' })} - -
      - )} - - {type === 'answer' && item.accepted === 2 && ( -
      - - {t('accepted')} -
      - )} + {t('accepted')} +
      + )} +
    2. ); })} diff --git a/ui/src/pages/Users/Personal/components/index.ts b/ui/src/pages/Users/Personal/components/index.ts index c2c3ec79..0a9baab1 100644 --- a/ui/src/pages/Users/Personal/components/index.ts +++ b/ui/src/pages/Users/Personal/components/index.ts @@ -28,6 +28,7 @@ import Reputation from './Reputation'; import Comments from './Comments'; import Votes from './Votes'; import Answers from './Answers'; +import Badges from './Badges'; export { Alert, @@ -41,4 +42,5 @@ export { Comments, Votes, Answers, + Badges, }; diff --git a/ui/src/pages/Users/Personal/index.tsx b/ui/src/pages/Users/Personal/index.tsx index 2d205a42..96704b85 100644 --- a/ui/src/pages/Users/Personal/index.tsx +++ b/ui/src/pages/Users/Personal/index.tsx @@ -43,6 +43,7 @@ import { Comments, Answers, Votes, + Badges, } from './components'; const Personal: FC = () => { @@ -79,36 +80,30 @@ const Personal: FC = () => { return (
      - {userInfo?.status !== 'normal' && userInfo?.status_msg && ( - - )} - - - - - {isSelf && ( -
      - - {t('edit_profile')} - -
      + + {userInfo?.status !== 'normal' && userInfo?.status_msg && ( + )} - -
      - - - +
      + + {isSelf && ( +
      + + {t('edit_profile')} + +
      + )} +
      + + + { + {!list?.length && !isLoading && } {count > 0 && ( @@ -135,20 +131,20 @@ const Personal: FC = () => { />
      )} - - -
      {t('stats')}
      - {userInfo?.created_at && ( + + {tabName === 'overview' && ( <> -
      - -
      -
      - -
      +
      {t('stats')}
      + {userInfo?.created_at && ( +
      + + {t('comma')}{' '} + +
      + )} )} diff --git a/ui/src/router/routes.ts b/ui/src/router/routes.ts index bd4a0c79..aa31266e 100644 --- a/ui/src/router/routes.ts +++ b/ui/src/router/routes.ts @@ -217,6 +217,14 @@ const routes: RouteNode[] = [ path: 'review', page: 'pages/Review', }, + { + path: '/badges', + page: 'pages/Badges/index', + }, + { + path: '/badges/:badge_id', + page: 'pages/Badges/Detail/index', + }, ], }, { From 6973a0045e8e7c5e66667449f2969e5d5378d256 Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 6 Aug 2024 10:50:58 +0800 Subject: [PATCH 064/336] fix: personal add recent bages ui --- i18n/en_US.yaml | 1 + ui/src/components/CardBadge/index.tsx | 11 +++++++---- .../Users/Personal/components/Overview/index.tsx | 12 +++++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index f9787eda..09596b78 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1598,6 +1598,7 @@ ui: x_votes: votes received x_answers: answers x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Next diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index b8dde502..9251b38c 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -27,9 +27,10 @@ import './index.scss'; interface IProps { data: any; badgePill: boolean; + showAwardedCount?: boolean; } -const Index: FC = ({ data, badgePill }) => { +const Index: FC = ({ data, badgePill, showAwardedCount = false }) => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); console.log(data); return ( @@ -40,9 +41,11 @@ const Index: FC = ({ data, badgePill }) => {
      Nice Question
      -
      - {t('x_awarded', { number: formatCount(16) })} -
      + {showAwardedCount && ( +
      + {t('x_awarded', { number: formatCount(16) })} +
      + )} ); diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 4f228061..384689dc 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -21,6 +21,7 @@ import { FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; import { Row, Col } from 'react-bootstrap'; +import { CardBadge } from '@/components'; import TopList from '../TopList'; interface Props { @@ -54,7 +55,7 @@ const Index: FC = ({ visible, introduction, data }) => { )} - + {data?.question?.length > 0 && ( <>
      {t('top_questions')}
      @@ -63,6 +64,15 @@ const Index: FC = ({ visible, introduction, data }) => { )} + +
      +
      {t('recent_badges')}
      +
      + {[0, 1, 2, 3, 4, 5, 6].map((item) => { + return ; + })} +
      +
); }; From 8534079687e6257fed2eb3dae07fa116b1a8c590 Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 6 Aug 2024 15:56:30 +0800 Subject: [PATCH 065/336] fix: replace share params shareUserId to share --- ui/src/components/Share/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/components/Share/index.tsx b/ui/src/components/Share/index.tsx index 203a72d6..392d1fbd 100644 --- a/ui/src/components/Share/index.tsx +++ b/ui/src/components/Share/index.tsx @@ -46,7 +46,7 @@ const Index: FC = ({ type, qid, aid, title }) => { ? `${BASE_ORIGIN}/questions/${qid}` : `${BASE_ORIGIN}/questions/${qid}/${aid}`; if (user.id) { - baseUrl = `${baseUrl}?shareUserId=${user.username}`; + baseUrl = `${baseUrl}?share=${user.username}`; } const closeShare = () => { From 3f1f31581f6bb0b9165b607a04ab95234dd09bdd Mon Sep 17 00:00:00 2001 From: shuai Date: Thu, 8 Aug 2024 18:28:37 +0800 Subject: [PATCH 066/336] fix: badge list and badge detail docking api --- ui/package.json | 3 +- ui/pnpm-lock.yaml | 968 ------------------ ui/src/common/interface.ts | 32 + ui/src/components/CardBadge/index.tsx | 46 +- ui/src/index.scss | 10 + .../Badges/Detail/components/Badge/index.tsx | 93 ++ .../Detail/components/HeaderLoader/index.tsx | 49 + .../Badges/Detail/components/Loader/index.tsx | 55 + ui/src/pages/Badges/Detail/index.tsx | 133 +-- ui/src/pages/Badges/index.tsx | 21 +- .../Personal/components/Badges/index.tsx | 7 +- .../Personal/components/Overview/index.tsx | 7 +- ui/src/services/client/badges.ts | 64 ++ ui/src/services/client/index.ts | 1 + 14 files changed, 439 insertions(+), 1050 deletions(-) create mode 100644 ui/src/pages/Badges/Detail/components/Badge/index.tsx create mode 100644 ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx create mode 100644 ui/src/pages/Badges/Detail/components/Loader/index.tsx create mode 100644 ui/src/services/client/badges.ts diff --git a/ui/package.json b/ui/package.json index 0ae727e2..2344125d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -45,8 +45,7 @@ "react-router-dom": "^6.22.3", "semver": "^7.3.8", "swr": "^1.3.0", - "zustand": "^4.1.1", - "demo": "workspace:*" + "zustand": "^4.1.1" }, "devDependencies": { "@commitlint/cli": "^17.0.3", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index 50fdae8f..0fd9c0f1 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -44,9 +44,6 @@ importers: dayjs: specifier: ^1.11.5 version: 1.11.5 - demo: - specifier: workspace:* - version: link:src/plugins/demo diff: specifier: ^5.1.0 version: 5.1.0 @@ -232,52 +229,6 @@ importers: specifier: ^0.8.0 version: 0.8.0 - src/plugins/demo: - dependencies: - react: - specifier: ^18.2.0 - version: 18.2.0 - react-bootstrap: - specifier: ^2.10.0 - version: 2.10.0(@types/react@18.0.20)(react-dom@18.2.0)(react@18.2.0) - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - react-i18next: - specifier: ^11.18.3 - version: 11.18.6(i18next@21.9.2)(react-dom@18.2.0)(react@18.2.0) - devDependencies: - '@modyfi/vite-plugin-yaml': - specifier: ^1.1.0 - version: 1.1.0(rollup@2.79.0)(vite@4.5.3) - '@typescript-eslint/eslint-plugin': - specifier: ^6.0.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.5.4) - '@typescript-eslint/parser': - specifier: ^6.0.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.5.4) - '@vitejs/plugin-react-swc': - specifier: ^3.3.2 - version: 3.7.0(vite@4.5.3) - eslint: - specifier: ^8.45.0 - version: 8.53.0 - eslint-plugin-react-hooks: - specifier: ^4.6.0 - version: 4.6.0(eslint@8.53.0) - eslint-plugin-react-refresh: - specifier: ^0.4.3 - version: 0.4.9(eslint@8.53.0) - typescript: - specifier: ^5.0.2 - version: 5.5.4 - vite: - specifier: ^4.4.5 - version: 4.5.3(@types/node@16.11.59)(sass@1.54.9) - vite-plugin-dts: - specifier: ^3.9.1 - version: 3.9.1(@types/node@16.11.59)(rollup@2.79.0)(typescript@5.5.4)(vite@4.5.3) - packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -598,14 +549,6 @@ packages: dependencies: '@babel/types': 7.19.0 - /@babel/parser@7.25.0: - resolution: {integrity: sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.23.6 - dev: true - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.19.1): resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} engines: {node: '>=6.9.0'} @@ -2248,204 +2191,6 @@ packages: postcss: 8.4.16 postcss-selector-parser: 6.0.10 - /@esbuild/android-arm64@0.18.20: - resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-arm@0.18.20: - resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/android-x64@0.18.20: - resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-arm64@0.18.20: - resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/darwin-x64@0.18.20: - resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-arm64@0.18.20: - resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/freebsd-x64@0.18.20: - resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm64@0.18.20: - resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-arm@0.18.20: - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ia32@0.18.20: - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-loong64@0.18.20: - resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-mips64el@0.18.20: - resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-ppc64@0.18.20: - resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-riscv64@0.18.20: - resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-s390x@0.18.20: - resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/linux-x64@0.18.20: - resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@esbuild/netbsd-x64@0.18.20: - resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/openbsd-x64@0.18.20: - resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - - /@esbuild/sunos-x64@0.18.20: - resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-arm64@0.18.20: - resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-ia32@0.18.20: - resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@esbuild/win32-x64@0.18.20: - resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.53.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2960,63 +2705,6 @@ packages: '@lezer/lr': 1.4.0 dev: false - /@microsoft/api-extractor-model@7.28.13(@types/node@16.11.59): - resolution: {integrity: sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==} - dependencies: - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 4.0.2(@types/node@16.11.59) - transitivePeerDependencies: - - '@types/node' - dev: true - - /@microsoft/api-extractor@7.43.0(@types/node@16.11.59): - resolution: {integrity: sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==} - hasBin: true - dependencies: - '@microsoft/api-extractor-model': 7.28.13(@types/node@16.11.59) - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 4.0.2(@types/node@16.11.59) - '@rushstack/rig-package': 0.5.2 - '@rushstack/terminal': 0.10.0(@types/node@16.11.59) - '@rushstack/ts-command-line': 4.19.1(@types/node@16.11.59) - lodash: 4.17.21 - minimatch: 3.0.4 - resolve: 1.22.1 - semver: 7.5.4 - source-map: 0.6.1 - typescript: 5.4.2 - transitivePeerDependencies: - - '@types/node' - dev: true - - /@microsoft/tsdoc-config@0.16.2: - resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} - dependencies: - '@microsoft/tsdoc': 0.14.2 - ajv: 6.12.6 - jju: 1.4.0 - resolve: 1.19.0 - dev: true - - /@microsoft/tsdoc@0.14.2: - resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} - dev: true - - /@modyfi/vite-plugin-yaml@1.1.0(rollup@2.79.0)(vite@4.5.3): - resolution: {integrity: sha512-L26xfzkSo1yamODCAtk/ipVlL6OEw2bcJ92zunyHu8zxi7+meV0zefA9xscRMDCsMY8xL3C3wi3DhMiPxcbxbw==} - peerDependencies: - vite: ^3.2.7 || ^4.0.5 || ^5.0.5 - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@2.79.0) - js-yaml: 4.1.0 - tosource: 2.0.0-alpha.3 - vite: 4.5.3(@types/node@16.11.59)(sass@1.54.9) - transitivePeerDependencies: - - rollup - dev: true - /@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1: resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} dependencies: @@ -3188,72 +2876,9 @@ packages: picomatch: 2.3.1 rollup: 2.79.0 - /@rollup/pluginutils@5.1.0(rollup@2.79.0): - resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - rollup: 2.79.0 - dev: true - /@rushstack/eslint-patch@1.2.0: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} - /@rushstack/node-core-library@4.0.2(@types/node@16.11.59): - resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true - dependencies: - '@types/node': 16.11.59 - fs-extra: 7.0.1 - import-lazy: 4.0.0 - jju: 1.4.0 - resolve: 1.22.1 - semver: 7.5.4 - z-schema: 5.0.5 - dev: true - - /@rushstack/rig-package@0.5.2: - resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} - dependencies: - resolve: 1.22.1 - strip-json-comments: 3.1.1 - dev: true - - /@rushstack/terminal@0.10.0(@types/node@16.11.59): - resolution: {integrity: sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true - dependencies: - '@rushstack/node-core-library': 4.0.2(@types/node@16.11.59) - '@types/node': 16.11.59 - supports-color: 8.1.1 - dev: true - - /@rushstack/ts-command-line@4.19.1(@types/node@16.11.59): - resolution: {integrity: sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==} - dependencies: - '@rushstack/terminal': 0.10.0(@types/node@16.11.59) - '@types/argparse': 1.0.38 - argparse: 1.0.10 - string-argv: 0.3.2 - transitivePeerDependencies: - - '@types/node' - dev: true - /@sinclair/typebox@0.24.42: resolution: {integrity: sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==} @@ -3370,141 +2995,12 @@ packages: transitivePeerDependencies: - supports-color - /@swc/core-darwin-arm64@1.7.3: - resolution: {integrity: sha512-CTkHa6MJdov9t41vuV2kmQIMu+Q19LrEHGIR/UiJYH06SC/sOu35ZZH8DyfLp9ZoaCn21gwgWd61ixOGQlwzTw==} - engines: {node: '>=10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@swc/core-darwin-x64@1.7.3: - resolution: {integrity: sha512-mun623y6rCoZ2EFIYfIRqXYRFufJOopoYSJcxYhZUrfTpAvQ1zLngjQpWCUU1krggXR2U0PQj+ls0DfXUTraNg==} - engines: {node: '>=10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-arm-gnueabihf@1.7.3: - resolution: {integrity: sha512-4Jz4UcIcvZNMp9qoHbBx35bo3rjt8hpYLPqnR4FFq6gkAsJIMFC56UhRZwdEQoDuYiOFMBnnrsg31Fyo6YQypA==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-arm64-gnu@1.7.3: - resolution: {integrity: sha512-p+U/M/oqV7HC4erQ5TVWHhJU1984QD+wQBPxslAYq751bOQGm0R/mXK42GjugqjnR6yYrAiwKKbpq4iWVXNePA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-arm64-musl@1.7.3: - resolution: {integrity: sha512-s6VzyaJwaRGTi2mz2h6Ywxfmgpkc69IxhuMzl+sl34plH0V0RgnZDm14HoCGIKIzRk4+a2EcBV1ZLAfWmPACQg==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-x64-gnu@1.7.3: - resolution: {integrity: sha512-IrFY48C356Z2dU2pjYg080yvMXzmSV3Lmm/Wna4cfcB1nkVLjWsuYwwRAk9CY7E19c+q8N1sMNggubAUDYoX2g==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - libc: [glibc] - requiresBuild: true - dev: true - optional: true - - /@swc/core-linux-x64-musl@1.7.3: - resolution: {integrity: sha512-qoLgxBlBnnyUEDu5vmRQqX90h9jldU1JXI96e6eh2d1gJyKRA0oSK7xXmTzorv1fGHiHulv9qiJOUG+g6uzJWg==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - libc: [musl] - requiresBuild: true - dev: true - optional: true - - /@swc/core-win32-arm64-msvc@1.7.3: - resolution: {integrity: sha512-OAd7jVVJ7nb0Ev80VAa1aeK+FldPeC4eZ35H4Qn6EICzIz0iqJo2T33qLKkSZiZEBKSoF4KcwrqYfkjLOp5qWg==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@swc/core-win32-ia32-msvc@1.7.3: - resolution: {integrity: sha512-31+Le1NyfSnILFV9+AhxfFOG0DK0272MNhbIlbcv4w/iqpjkhaOnNQnLsYJD1Ow7lTX1MtIZzTjOhRlzSviRWg==} - engines: {node: '>=10'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@swc/core-win32-x64-msvc@1.7.3: - resolution: {integrity: sha512-jVQPbYrwcuueI4QB0fHC29SVrkFOBcfIspYDlgSoHnEz6tmLMqUy+txZUypY/ZH/KaK0HEY74JkzgbRC1S6LFQ==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@swc/core@1.7.3: - resolution: {integrity: sha512-HHAlbXjWI6Kl9JmmUW1LSygT1YbblXgj2UvvDzMkTBPRzYMhW6xchxdO8HbtMPtFYRt/EQq9u1z7j4ttRSrFsA==} - engines: {node: '>=10'} - requiresBuild: true - peerDependencies: - '@swc/helpers': '*' - peerDependenciesMeta: - '@swc/helpers': - optional: true - dependencies: - '@swc/counter': 0.1.3 - '@swc/types': 0.1.12 - optionalDependencies: - '@swc/core-darwin-arm64': 1.7.3 - '@swc/core-darwin-x64': 1.7.3 - '@swc/core-linux-arm-gnueabihf': 1.7.3 - '@swc/core-linux-arm64-gnu': 1.7.3 - '@swc/core-linux-arm64-musl': 1.7.3 - '@swc/core-linux-x64-gnu': 1.7.3 - '@swc/core-linux-x64-musl': 1.7.3 - '@swc/core-win32-arm64-msvc': 1.7.3 - '@swc/core-win32-ia32-msvc': 1.7.3 - '@swc/core-win32-x64-msvc': 1.7.3 - dev: true - - /@swc/counter@0.1.3: - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - dev: true - /@swc/helpers@0.5.3: resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==} dependencies: tslib: 2.6.2 dev: false - /@swc/types@0.1.12: - resolution: {integrity: sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==} - dependencies: - '@swc/counter': 0.1.3 - dev: true - /@testing-library/dom@8.18.1: resolution: {integrity: sha512-oEvsm2B/WtcHKE+IcEeeCqNU/ltFGaVyGbpcm4g/2ytuT49jrlH9x5qRKL/H3A6yfM4YAbSbC0ceT5+9CEXnLg==} engines: {node: '>=12'} @@ -3578,10 +3074,6 @@ packages: /@tsconfig/node16@1.0.3: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} - /@types/argparse@1.0.38: - resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} - dev: true - /@types/aria-query@4.2.2: resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} dev: true @@ -3933,35 +3425,6 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.5.4): - resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.5.4) - '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.5.4) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 6.11.0 - debug: 4.3.4 - eslint: 8.53.0 - graphemer: 1.4.0 - ignore: 5.2.4 - natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.5.4) - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/experimental-utils@5.38.0(eslint@8.53.0)(typescript@4.9.5): resolution: {integrity: sha512-kzXBRfvGlicgGk4CYuRUqKvwc2s3wHXNssUWWJU18bhMRxriFm3BZWyQ6vEHBRpEIMKB6b7MIQHO+9lYlts19w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4014,27 +3477,6 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.5.4): - resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.5.4) - '@typescript-eslint/visitor-keys': 6.11.0 - debug: 4.3.4 - eslint: 8.53.0 - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/scope-manager@5.38.0: resolution: {integrity: sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4089,26 +3531,6 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.5.4): - resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.5.4) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.5.4) - debug: 4.3.4 - eslint: 8.53.0 - ts-api-utils: 1.0.3(typescript@5.5.4) - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/types@5.38.0: resolution: {integrity: sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4159,27 +3581,6 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.11.0(typescript@5.5.4): - resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/visitor-keys': 6.11.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.5.4) - typescript: 5.5.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/utils@5.38.0(eslint@8.53.0)(typescript@4.9.5): resolution: {integrity: sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4216,25 +3617,6 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.5.4): - resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.5 - '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.5.4) - eslint: 8.53.0 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/visitor-keys@5.38.0: resolution: {integrity: sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4253,77 +3635,6 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@vitejs/plugin-react-swc@3.7.0(vite@4.5.3): - resolution: {integrity: sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==} - peerDependencies: - vite: ^4 || ^5 - dependencies: - '@swc/core': 1.7.3 - vite: 4.5.3(@types/node@16.11.59)(sass@1.54.9) - transitivePeerDependencies: - - '@swc/helpers' - dev: true - - /@volar/language-core@1.11.1: - resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} - dependencies: - '@volar/source-map': 1.11.1 - dev: true - - /@volar/source-map@1.11.1: - resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==} - dependencies: - muggle-string: 0.3.1 - dev: true - - /@volar/typescript@1.11.1: - resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} - dependencies: - '@volar/language-core': 1.11.1 - path-browserify: 1.0.1 - dev: true - - /@vue/compiler-core@3.4.34: - resolution: {integrity: sha512-Z0izUf32+wAnQewjHu+pQf1yw00EGOmevl1kE+ljjjMe7oEfpQ+BI3/JNK7yMB4IrUsqLDmPecUrpj3mCP+yJQ==} - dependencies: - '@babel/parser': 7.25.0 - '@vue/shared': 3.4.34 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.0 - dev: true - - /@vue/compiler-dom@3.4.34: - resolution: {integrity: sha512-3PUOTS1h5cskdOJMExCu2TInXuM0j60DRPpSCJDqOCupCfUZCJoyQmKtRmA8EgDNZ5kcEE7vketamRZfrEuVDw==} - dependencies: - '@vue/compiler-core': 3.4.34 - '@vue/shared': 3.4.34 - dev: true - - /@vue/language-core@1.8.27(typescript@5.5.4): - resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@volar/language-core': 1.11.1 - '@volar/source-map': 1.11.1 - '@vue/compiler-dom': 3.4.34 - '@vue/shared': 3.4.34 - computeds: 0.0.1 - minimatch: 9.0.5 - muggle-string: 0.3.1 - path-browserify: 1.0.1 - typescript: 5.5.4 - vue-template-compiler: 2.7.16 - dev: true - - /@vue/shared@3.4.34: - resolution: {integrity: sha512-x5LmiRLpRsd9KTjAB8MPKf0CDPMcuItjP0gbNqFCIgL1I8iYp4zglhj9w9FPCdIbHG2M91RVeIbArFfFTz9I3A==} - dev: true - /@webassemblyjs/ast@1.11.1: resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} dependencies: @@ -5485,13 +4796,6 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - requiresBuild: true - dev: true - optional: true - /common-path-prefix@3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} @@ -5529,10 +4833,6 @@ packages: transitivePeerDependencies: - supports-color - /computeds@0.0.1: - resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} - dev: true - /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -5921,10 +5221,6 @@ packages: resolution: {integrity: sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==} dev: false - /de-indent@1.0.2: - resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - dev: true - /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -6294,11 +5590,6 @@ packages: /entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==, tarball: https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz} - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - dev: true - /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -6430,36 +5721,6 @@ packages: is-date-object: 1.0.5 is-symbol: 1.0.4 - /esbuild@0.18.20: - resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - dev: true - /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -6872,14 +6133,6 @@ packages: dependencies: eslint: 8.53.0 - /eslint-plugin-react-refresh@0.4.9(eslint@8.53.0): - resolution: {integrity: sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA==} - peerDependencies: - eslint: '>=7' - dependencies: - eslint: 8.53.0 - dev: true - /eslint-plugin-react@7.33.2(eslint@8.53.0): resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} @@ -7056,10 +6309,6 @@ packages: /estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true - /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -7378,15 +6627,6 @@ packages: jsonfile: 6.1.0 universalify: 2.0.0 - /fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - /fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -7853,11 +7093,6 @@ packages: parent-module: 1.0.1 resolve-from: 4.0.0 - /import-lazy@4.0.0: - resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} - engines: {node: '>=8'} - dev: true - /import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} @@ -8860,12 +8095,6 @@ packages: engines: {node: '>=6'} hasBin: true - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -8918,10 +8147,6 @@ packages: resolution: {integrity: sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==} engines: {node: '>= 8'} - /kolorist@1.8.0: - resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - dev: true - /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -9040,14 +8265,6 @@ packages: resolution: {integrity: sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==} dev: true - /lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - dev: true - - /lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - dev: true - /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -9101,12 +8318,6 @@ packages: dependencies: sourcemap-codec: 1.4.8 - /magic-string@0.30.11: - resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - dev: true - /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -9248,13 +8459,6 @@ packages: dependencies: brace-expansion: 2.0.1 - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} @@ -9282,10 +8486,6 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /muggle-string@0.3.1: - resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} - dev: true - /multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true @@ -9298,12 +8498,6 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - /nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true - /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -9644,10 +8838,6 @@ packages: no-case: 3.0.4 tslib: 2.6.2 - /path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - dev: true - /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -10429,15 +9619,6 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /postcss@8.4.40: - resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - dev: true - /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -11144,13 +10325,6 @@ packages: resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==} engines: {node: '>=10'} - /resolve@1.19.0: - resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} - dependencies: - is-core-module: 2.10.0 - path-parse: 1.0.7 - dev: true - /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true @@ -11218,14 +10392,6 @@ packages: optionalDependencies: fsevents: 2.3.3 - /rollup@3.29.4: - resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.3 - dev: true - /run-applescript@5.0.0: resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} engines: {node: '>=12'} @@ -11568,11 +10734,6 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - /source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} - engines: {node: '>=0.10.0'} - dev: true - /source-map-loader@3.0.1(webpack@5.74.0): resolution: {integrity: sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==} engines: {node: '>= 12.13.0'} @@ -12161,11 +11322,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - /tosource@2.0.0-alpha.3: - resolution: {integrity: sha512-KAB2lrSS48y91MzFPFuDg4hLbvDiyTjOVgaK7Erw+5AmZXNq4sFRVn8r6yxSLuNs15PaokrDRpS61ERY9uZOug==} - engines: {node: '>=10'} - dev: true - /tough-cookie@4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} engines: {node: '>=6'} @@ -12203,15 +11359,6 @@ packages: typescript: 4.9.5 dev: true - /ts-api-utils@1.0.3(typescript@5.5.4): - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} - engines: {node: '>=16.13.0'} - peerDependencies: - typescript: '>=4.2.0' - dependencies: - typescript: 5.5.4 - dev: true - /ts-node@10.9.1(@types/node@16.11.59)(typescript@4.9.5): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -12364,18 +11511,6 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - - /typescript@5.5.4: - resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -12429,11 +11564,6 @@ packages: dependencies: crypto-random-string: 2.0.0 - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - dev: true - /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -12543,101 +11673,15 @@ packages: spdx-expression-parse: 3.0.1 dev: true - /validator@13.12.0: - resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} - engines: {node: '>= 0.10'} - dev: true - /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - /vite-plugin-dts@3.9.1(@types/node@16.11.59)(rollup@2.79.0)(typescript@5.5.4)(vite@4.5.3): - resolution: {integrity: sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - typescript: '*' - vite: '*' - peerDependenciesMeta: - vite: - optional: true - dependencies: - '@microsoft/api-extractor': 7.43.0(@types/node@16.11.59) - '@rollup/pluginutils': 5.1.0(rollup@2.79.0) - '@vue/language-core': 1.8.27(typescript@5.5.4) - debug: 4.3.4 - kolorist: 1.8.0 - magic-string: 0.30.11 - typescript: 5.5.4 - vite: 4.5.3(@types/node@16.11.59)(sass@1.54.9) - vue-tsc: 1.8.27(typescript@5.5.4) - transitivePeerDependencies: - - '@types/node' - - rollup - - supports-color - dev: true - - /vite@4.5.3(@types/node@16.11.59)(sass@1.54.9): - resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 16.11.59 - esbuild: 0.18.20 - postcss: 8.4.40 - rollup: 3.29.4 - sass: 1.54.9 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /void-elements@3.1.0: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} dev: false - /vue-template-compiler@2.7.16: - resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} - dependencies: - de-indent: 1.0.2 - he: 1.2.0 - dev: true - - /vue-tsc@1.8.27(typescript@5.5.4): - resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==} - hasBin: true - peerDependencies: - typescript: '*' - dependencies: - '@volar/typescript': 1.11.1 - '@vue/language-core': 1.8.27(typescript@5.5.4) - semver: 7.5.4 - typescript: 5.5.4 - dev: true - /w3c-hr-time@1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} dependencies: @@ -13274,18 +12318,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - /z-schema@5.0.5: - resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} - engines: {node: '>=8.0.0'} - hasBin: true - dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 13.12.0 - optionalDependencies: - commander: 9.5.0 - dev: true - /zustand@4.1.1(react@18.2.0): resolution: {integrity: sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==} engines: {node: '>=12.7.0'} diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index 41dc0fef..789109d2 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -735,3 +735,35 @@ export interface ReactionItem { tooltip: string; is_active: boolean; } + +export interface BadgeListItem { + id: string; + name: string; + icon: string; + award_count: number; + earned: boolean; + /** 1: bronze 2: silver 3:gold */ + level: number; +} + +export interface BadgeListGroupItem { + badges: BadgeListItem[]; + group_name: string; +} + +export interface BadgeInfo extends BadgeListItem { + description: string; + earned_count: number; + is_single: boolean; +} + +export interface BadgeDetailListReq { + page: number; + page_size: number; + badge_id: string; +} + +export interface BadgeDetailListRes { + count: number; + list: BadgeInfo[]; +} diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index 9251b38c..6fb4af7c 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -19,35 +19,59 @@ import { useTranslation } from 'react-i18next'; import { FC } from 'react'; import { Card, Badge } from 'react-bootstrap'; +import { Link } from 'react-router-dom'; +import classnames from 'classnames'; + +import { Icon } from '@/components'; +import * as Type from '@/common/interface'; import { formatCount } from '@/utils'; import './index.scss'; interface IProps { - data: any; - badgePill: boolean; + data: Type.BadgeListItem; showAwardedCount?: boolean; } -const Index: FC = ({ data, badgePill, showAwardedCount = false }) => { +const Index: FC = ({ data, showAwardedCount = false }) => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); console.log(data); return ( - + - - 0 - - -
Nice Question
+ {data.earned && ( + + {t('earned')} + + )} + + {/* + {showEarned ? t('earned') : data.award_count} + */} + {data.icon.startsWith('http') ? ( + {data.name} + ) : ( + + )} + +
{data.name}
{showAwardedCount && (
- {t('x_awarded', { number: formatCount(16) })} + {t('x_awarded', { number: formatCount(data.award_count) })}
)}
-
+ ); }; diff --git a/ui/src/index.scss b/ui/src/index.scss index b174fbc5..6d3ade05 100644 --- a/ui/src/index.scss +++ b/ui/src/index.scss @@ -352,3 +352,13 @@ img[src=""] { .alert-exist { color: var(--an-alert-exist-color); } + +.bronze { + color: #CD7F32; +} +.silver { + color: #C0C0C0; +} +.gold { + color: #FFD700; +} diff --git a/ui/src/pages/Badges/Detail/components/Badge/index.tsx b/ui/src/pages/Badges/Detail/components/Badge/index.tsx new file mode 100644 index 00000000..1fc5d43d --- /dev/null +++ b/ui/src/pages/Badges/Detail/components/Badge/index.tsx @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FC } from 'react'; +import { Card, Badge } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; + +import classnames from 'classnames'; + +import * as Type from '@/common/interface'; +import { Icon } from '@/components'; +import { formatCount } from '@/utils'; + +interface IProps { + data: Type.BadgeInfo; +} + +const Index: FC = ({ data }) => { + const { t } = useTranslation('translation', { keyPrefix: 'badges' }); + + if (!data?.id) { + return null; + } + + return ( + + + {data.icon?.startsWith('http') ? ( + {data.name} + ) : ( + + )} +
+
{data.name}
+
+ + {!data.is_single && ( +
{t('can_earn_multiple')}
+ )} + + {data.award_count > 0 && data.earned_count > 0 && ( +
+ {data.award_count > 0 && ( + + {t('x_awarded', { number: formatCount(data.award_count) })} + + )} + + {data.earned_count > 0 && ( + + {t('earned_x', { number: data.earned_count })} + + )} +
+ )} +
+ + + ); +}; + +export default Index; diff --git a/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx b/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx new file mode 100644 index 00000000..df0c9204 --- /dev/null +++ b/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Card } from 'react-bootstrap'; + +const Index = () => { + return ( + + +
+ +
+
+
+
+ +
+ +
+ + + +
+
+ + + ); +}; + +export default Index; diff --git a/ui/src/pages/Badges/Detail/components/Loader/index.tsx b/ui/src/pages/Badges/Detail/components/Loader/index.tsx new file mode 100644 index 00000000..515e69af --- /dev/null +++ b/ui/src/pages/Badges/Detail/components/Loader/index.tsx @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { FC, memo } from 'react'; +import { Col } from 'react-bootstrap'; + +interface Props { + count?: number; +} + +const Index: FC = ({ count = 12 }) => { + const list = new Array(count).fill(0).map((v, i) => v + i); + return ( + <> + {list.map((v) => ( + +
+
+
+
+
+
+
+
+
+
+ + ))} + + ); +}; + +export default memo(Index); diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index 7a192a13..3e8513ae 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -17,79 +17,98 @@ * under the License. */ -import { Card, Badge, Row, Col } from 'react-bootstrap'; +import { Row, Col } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; -import { Link } from 'react-router-dom'; +import { Link, useParams, useSearchParams } from 'react-router-dom'; -import { Avatar, FormatTime } from '@/components'; -import { usePageTags } from '@/hooks'; -import { formatCount } from '@/utils'; +// import classnames from 'classnames'; + +import { Avatar, FormatTime, Pagination, Empty } from '@/components'; +import { usePageTags, useSkeletonControl } from '@/hooks'; +// import { formatCount } from '@/utils'; +import { useGetBadgeInfo, useBadgeDetailList } from '@/services'; + +import BadgeDetail from './components/Badge'; +import Loader from './components/Loader'; +import HeaderLoader from './components/HeaderLoader'; const Index = () => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); - usePageTags({ - title: t('title'), + const { badge_id = '' } = useParams(); + const [urlSearchParams] = useSearchParams(); + + const page = Number(urlSearchParams.get('page')) || 1; + const pageSize = 30; + const { data: badgeInfo, isLoading: isHeaderLoading } = + useGetBadgeInfo(badge_id); + const { data: badges, isLoading: isDetailLoading } = useBadgeDetailList({ + badge_id, + page, + page_size: pageSize, }); + const { isSkeletonShow } = useSkeletonControl(isDetailLoading); + + usePageTags({ + title: badgeInfo?.name || '', + }); + + if (badgeInfo === undefined) { + return null; + } + + console.log(badges); + return (

{t('title')}

- - - -
-
Support Expert
-
- This badge is granted for achieving the expert level of our - community support programme. This certifies that the recipient has - demonstrated a high level of skills and abilities to manage and - support multiple communities/instances. -
-
{t('can_earn_multiple')}
-
- - {t('x_awarded', { number: formatCount(16) })} - - - {t('earned_x', { number: 2 })} - -
-
-
-
+ {isHeaderLoading ? : } - {[0, 1, 2, 3, 4, 5, 6].map((item) => { - return ( - - -
- - - -
- - username + + {isSkeletonShow ? ( + + ) : ( + badges?.list?.map((item) => { + return ( + + +
+ + -
- 980 {t('x_reputation', { keyPrefix: 'personal' })} +
+ + username + +
+ 980 {t('x_reputation', { keyPrefix: 'personal' })} +
-
- - How to `go test` all tests in my project? - - - ); - })} + + How to `go test` all tests in my project? + + + ); + }) + )} + {Number(badges?.count) <= 0 && !isDetailLoading && } +
+ +
); }; diff --git a/ui/src/pages/Badges/index.tsx b/ui/src/pages/Badges/index.tsx index 84784c53..39628062 100644 --- a/ui/src/pages/Badges/index.tsx +++ b/ui/src/pages/Badges/index.tsx @@ -21,10 +21,13 @@ import { useTranslation } from 'react-i18next'; import { CardBadge } from '@/components'; import { usePageTags } from '@/hooks'; +import { useGetAllBadges } from '@/services'; const Index = () => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); + const { data: badgesList } = useGetAllBadges(); + usePageTags({ title: t('title'), }); @@ -32,12 +35,18 @@ const Index = () => { return (

{t('title')}

-
Community Badges
-
- {[0, 1, 2, 3, 4, 5, 6].map((item) => { - return ; - })} -
+ {badgesList?.map((item) => { + return ( +
+
{item.group_name}
+
+ {item.badges?.map((badge) => { + return ; + })} +
+
+ ); + })}
); }; diff --git a/ui/src/pages/Users/Personal/components/Badges/index.tsx b/ui/src/pages/Users/Personal/components/Badges/index.tsx index a7bd3e58..0ef00f39 100644 --- a/ui/src/pages/Users/Personal/components/Badges/index.tsx +++ b/ui/src/pages/Users/Personal/components/Badges/index.tsx @@ -19,10 +19,11 @@ import { FC } from 'react'; +import * as Type from '@/common/interface'; import { CardBadge } from '@/components'; interface IProps { - data: any[]; + data: Type.BadgeListItem[]; visible: boolean; } @@ -33,8 +34,8 @@ const Index: FC = ({ data, visible }) => { } return (
- {[0, 1, 2, 3, 4, 5, 6].map((item) => { - return ; + {data.map((item) => { + return ; })}
); diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 384689dc..b4dd548b 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -21,7 +21,8 @@ import { FC, memo } from 'react'; import { useTranslation } from 'react-i18next'; import { Row, Col } from 'react-bootstrap'; -import { CardBadge } from '@/components'; +// import * as Type from '@/common/interface'; +// import { CardBadge } from '@/components'; import TopList from '../TopList'; interface Props { @@ -67,11 +68,11 @@ const Index: FC = ({ visible, introduction, data }) => {
{t('recent_badges')}
-
+ {/*
{[0, 1, 2, 3, 4, 5, 6].map((item) => { return ; })} -
+
*/}
); diff --git a/ui/src/services/client/badges.ts b/ui/src/services/client/badges.ts new file mode 100644 index 00000000..c3a7bba2 --- /dev/null +++ b/ui/src/services/client/badges.ts @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import useSWR from 'swr'; +import qs from 'qs'; + +import request from '@/utils/request'; +import type * as Type from '@/common/interface'; + +export const useGetAllBadges = () => { + const apiUrl = '/answer/api/v1/badges'; + const { data, error, mutate } = useSWR, Error>( + apiUrl, + request.instance.get, + ); + return { + data, + isLoading: !data && !error, + error, + mutate, + }; +}; + +export const useGetBadgeInfo = (id: string) => { + const { data, error, mutate } = useSWR( + `/answer/api/v1/badge?id=${id}`, + request.instance.get, + ); + return { + data, + isLoading: !data && !error, + error, + mutate, + }; +}; + +export const useBadgeDetailList = (params: Type.BadgeDetailListReq) => { + const { data, error, mutate } = useSWR( + `/answer/api/v1/badge/awards/page?${qs.stringify(params)}`, + request.instance.get, + ); + return { + data, + isLoading: !data && !error, + error, + mutate, + }; +}; diff --git a/ui/src/services/client/index.ts b/ui/src/services/client/index.ts index 0d718423..005bc26d 100644 --- a/ui/src/services/client/index.ts +++ b/ui/src/services/client/index.ts @@ -30,3 +30,4 @@ export * from './revision'; export * from './user'; export * from './Oauth'; export * from './review'; +export * from './badges'; From fce712e6c7a7d907c2d576725fa46b07504a5e01 Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 12 Aug 2024 16:26:31 +0800 Subject: [PATCH 067/336] fix: bages detail add userCard conponent --- ui/src/common/interface.ts | 14 ++- .../Detail/components/HeaderLoader/index.tsx | 16 +-- .../Detail/components/UserCard/index.tsx | 97 +++++++++++++++++++ ui/src/pages/Badges/Detail/index.tsx | 28 ++---- ui/src/pages/Badges/index.tsx | 1 - ui/src/services/client/badges.ts | 4 +- ui/src/services/client/personal.ts | 8 +- 7 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 ui/src/pages/Badges/Detail/components/UserCard/index.tsx diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index 789109d2..45f957c2 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -761,9 +761,21 @@ export interface BadgeDetailListReq { page: number; page_size: number; badge_id: string; + username?: string | null; +} + +export interface BadgeDetailListItem { + created_at: number; + author_user_info: UserInfoBase; + object_type: string; + object_id: string; + url_title: string; + question_id: string; + answer_id: string; + comment_id: string; } export interface BadgeDetailListRes { count: number; - list: BadgeInfo[]; + list: BadgeDetailListItem[]; } diff --git a/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx b/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx index df0c9204..d56432e8 100644 --- a/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx +++ b/ui/src/pages/Badges/Detail/components/HeaderLoader/index.tsx @@ -22,23 +22,23 @@ import { Card } from 'react-bootstrap'; const Index = () => { return ( - +
-
-
-
-
+
+
+
+
- + - +
diff --git a/ui/src/pages/Badges/Detail/components/UserCard/index.tsx b/ui/src/pages/Badges/Detail/components/UserCard/index.tsx new file mode 100644 index 00000000..d874ceb9 --- /dev/null +++ b/ui/src/pages/Badges/Detail/components/UserCard/index.tsx @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { memo, FC } from 'react'; +import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; + +import classnames from 'classnames'; + +import { Avatar } from '@/components'; +import { formatCount } from '@/utils'; + +interface Props { + data: any; + className?: string; +} + +const Index: FC = ({ data, className = '' }) => { + const { t } = useTranslation('translation', { keyPrefix: 'badges' }); + return ( +
+ {data?.status !== 'deleted' ? ( + + + + + + ) : ( + <> + + + + + )} +
+
+ {data?.status !== 'deleted' ? ( + + {data?.display_name} + + ) : ( + {data?.display_name} + )} +
+
+ {formatCount(data?.rank)}{' '} + {t('x_reputation', { keyPrefix: 'personal' })} +
+
+
+ ); +}; + +export default memo(Index); diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index 3e8513ae..42487db3 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -23,7 +23,7 @@ import { Link, useParams, useSearchParams } from 'react-router-dom'; // import classnames from 'classnames'; -import { Avatar, FormatTime, Pagination, Empty } from '@/components'; +import { FormatTime, Pagination, Empty } from '@/components'; import { usePageTags, useSkeletonControl } from '@/hooks'; // import { formatCount } from '@/utils'; import { useGetBadgeInfo, useBadgeDetailList } from '@/services'; @@ -31,6 +31,7 @@ import { useGetBadgeInfo, useBadgeDetailList } from '@/services'; import BadgeDetail from './components/Badge'; import Loader from './components/Loader'; import HeaderLoader from './components/HeaderLoader'; +import UserCard from './components/UserCard'; const Index = () => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); @@ -46,6 +47,7 @@ const Index = () => { badge_id, page, page_size: pageSize, + username: urlSearchParams.get('username') || null, }); const { isSkeletonShow } = useSkeletonControl(isDetailLoading); @@ -65,36 +67,20 @@ const Index = () => {

{t('title')}

{isHeaderLoading ? : } - {isSkeletonShow ? ( ) : ( badges?.list?.map((item) => { return ( - + -
- - - -
- - username - -
- 980 {t('x_reputation', { keyPrefix: 'personal' })} -
-
-
+ - How to `go test` all tests in my project? + {item.url_title} ); diff --git a/ui/src/pages/Badges/index.tsx b/ui/src/pages/Badges/index.tsx index 39628062..d37f5d9a 100644 --- a/ui/src/pages/Badges/index.tsx +++ b/ui/src/pages/Badges/index.tsx @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - import { useTranslation } from 'react-i18next'; import { CardBadge } from '@/components'; diff --git a/ui/src/services/client/badges.ts b/ui/src/services/client/badges.ts index c3a7bba2..476f85d1 100644 --- a/ui/src/services/client/badges.ts +++ b/ui/src/services/client/badges.ts @@ -52,7 +52,9 @@ export const useGetBadgeInfo = (id: string) => { export const useBadgeDetailList = (params: Type.BadgeDetailListReq) => { const { data, error, mutate } = useSWR( - `/answer/api/v1/badge/awards/page?${qs.stringify(params)}`, + `/answer/api/v1/badge/awards/page?${qs.stringify(params, { + skipNulls: true, + })}`, request.instance.get, ); return { diff --git a/ui/src/services/client/personal.ts b/ui/src/services/client/personal.ts index 339f1e60..fbf38938 100644 --- a/ui/src/services/client/personal.ts +++ b/ui/src/services/client/personal.ts @@ -66,7 +66,7 @@ export const usePersonalTop = (username: string, tabName: string) => { }; export const usePersonalListByTabName = (params: ListReq, tabName: string) => { - let apiUrl = ''; + let apiUrl: string | null = ''; if (tabName === 'answers') { apiUrl = '/answer/api/v1/personal/answer/page'; } @@ -89,10 +89,14 @@ export const usePersonalListByTabName = (params: ListReq, tabName: string) => { delete params.username; apiUrl = '/answer/api/v1/personal/vote/page'; } + if (tabName === 'badges') { + delete params.order; + apiUrl = '/answer/api/v1/badge/user/awards'; + } const queryParams = qs.stringify(params, { skipNulls: true }); const { data, error, mutate } = useSWR( - tabName !== 'overview' ? `${apiUrl}?${queryParams}` : null, + tabName !== 'review' ? `${apiUrl}?${queryParams}` : null, request.instance.get, ); From 3d71bc17c843a78b71f30a94eed55600a1d3f89d Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 12 Aug 2024 17:45:03 +0800 Subject: [PATCH 068/336] fix: badge detail list styles format --- i18n/en_US.yaml | 2 +- ui/src/common/interface.ts | 1 + ui/src/components/CardBadge/index.tsx | 23 +++++++++---- .../Badges/Detail/components/Badge/index.tsx | 6 ++-- .../Detail/components/UserCard/index.tsx | 31 ++++++++--------- .../Personal/components/Badges/index.tsx | 11 +++++-- .../Personal/components/Overview/index.tsx | 33 +++++++++++++------ ui/src/pages/Users/Personal/index.tsx | 7 +++- ui/src/services/client/badges.ts | 16 +++++++++ 9 files changed, 89 insertions(+), 41 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 09596b78..420d25ba 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1743,7 +1743,7 @@ ui: earned_x: Earned x{{ number }} x_awarded: "{{ number }} awarded" can_earn_multiple: You can earn this multiple times. - + earned: Earned admin: admin_header: diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index 45f957c2..608a2465 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -744,6 +744,7 @@ export interface BadgeListItem { earned: boolean; /** 1: bronze 2: silver 3:gold */ level: number; + earned_count?: number; } export interface BadgeListGroupItem { diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index 6fb4af7c..bb42630c 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -32,23 +32,34 @@ import './index.scss'; interface IProps { data: Type.BadgeListItem; showAwardedCount?: boolean; + urlSearchParams?: string; + badgePillType?: 'earned' | 'count'; } -const Index: FC = ({ data, showAwardedCount = false }) => { +const Index: FC = ({ + data, + badgePillType = 'earned', + showAwardedCount = false, + urlSearchParams, +}) => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); console.log(data); return ( - + - {data.earned && ( + {data.earned && badgePillType === 'earned' && ( {t('earned')} )} - {/* - {showEarned ? t('earned') : data.award_count} - */} + {badgePillType === 'count' && Number(data?.earned_count) > 0 && ( + + x{data.earned_count} + + )} {data.icon.startsWith('http') ? ( {data.name} ) : ( diff --git a/ui/src/pages/Badges/Detail/components/Badge/index.tsx b/ui/src/pages/Badges/Detail/components/Badge/index.tsx index 1fc5d43d..affb73e6 100644 --- a/ui/src/pages/Badges/Detail/components/Badge/index.tsx +++ b/ui/src/pages/Badges/Detail/components/Badge/index.tsx @@ -69,16 +69,16 @@ const Index: FC = ({ data }) => {
{t('can_earn_multiple')}
)} - {data.award_count > 0 && data.earned_count > 0 && ( + {(data.award_count > 0 || data.earned_count > 0) && (
{data.award_count > 0 && ( - + {t('x_awarded', { number: formatCount(data.award_count) })} )} {data.earned_count > 0 && ( - + {t('earned_x', { number: data.earned_count })} )} diff --git a/ui/src/pages/Badges/Detail/components/UserCard/index.tsx b/ui/src/pages/Badges/Detail/components/UserCard/index.tsx index d874ceb9..116a81b3 100644 --- a/ui/src/pages/Badges/Detail/components/UserCard/index.tsx +++ b/ui/src/pages/Badges/Detail/components/UserCard/index.tsx @@ -21,20 +21,17 @@ import { memo, FC } from 'react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import classnames from 'classnames'; - import { Avatar } from '@/components'; import { formatCount } from '@/utils'; interface Props { data: any; - className?: string; } -const Index: FC = ({ data, className = '' }) => { +const Index: FC = ({ data }) => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); return ( -
+
{data?.status !== 'deleted' ? ( = ({ data, className = '' }) => { /> )} -
-
- {data?.status !== 'deleted' ? ( - - {data?.display_name} - - ) : ( - {data?.display_name} - )} -
+
+ {data?.status !== 'deleted' ? ( + + {data?.display_name} + + ) : ( + {data?.display_name} + )}
{formatCount(data?.rank)}{' '} {t('x_reputation', { keyPrefix: 'personal' })} diff --git a/ui/src/pages/Users/Personal/components/Badges/index.tsx b/ui/src/pages/Users/Personal/components/Badges/index.tsx index 0ef00f39..cd6830c9 100644 --- a/ui/src/pages/Users/Personal/components/Badges/index.tsx +++ b/ui/src/pages/Users/Personal/components/Badges/index.tsx @@ -24,10 +24,11 @@ import { CardBadge } from '@/components'; interface IProps { data: Type.BadgeListItem[]; + username: string; visible: boolean; } -const Index: FC = ({ data, visible }) => { +const Index: FC = ({ data, visible, username }) => { console.log(data); if (!visible) { return null; @@ -35,7 +36,13 @@ const Index: FC = ({ data, visible }) => { return (
{data.map((item) => { - return ; + return ( + + ); })}
); diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index b4dd548b..6b247b0c 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -22,16 +22,21 @@ import { useTranslation } from 'react-i18next'; import { Row, Col } from 'react-bootstrap'; // import * as Type from '@/common/interface'; -// import { CardBadge } from '@/components'; +import { CardBadge } from '@/components'; +import { useGetRecentAwardBadges } from '@/services'; import TopList from '../TopList'; interface Props { + username: string; visible: boolean; introduction: string; data; } -const Index: FC = ({ visible, introduction, data }) => { +const Index: FC = ({ visible, introduction, data, username }) => { const { t } = useTranslation('translation', { keyPrefix: 'personal' }); + const { data: recentBadges } = useGetRecentAwardBadges( + visible ? username : null, + ); if (!visible) { return null; } @@ -66,14 +71,22 @@ const Index: FC = ({ visible, introduction, data }) => { -
-
{t('recent_badges')}
- {/*
- {[0, 1, 2, 3, 4, 5, 6].map((item) => { - return ; - })} -
*/} -
+ {Number(recentBadges?.count) > 0 && ( +
+
{t('recent_badges')}
+
+ {recentBadges?.list?.map((item) => { + return ( + + ); + })} +
+
+ )}
); }; diff --git a/ui/src/pages/Users/Personal/index.tsx b/ui/src/pages/Users/Personal/index.tsx index 96704b85..e9516ace 100644 --- a/ui/src/pages/Users/Personal/index.tsx +++ b/ui/src/pages/Users/Personal/index.tsx @@ -102,6 +102,7 @@ const Personal: FC = () => { visible={tabName === 'overview'} introduction={userInfo?.bio_html || ''} data={topData} + username={username} /> { - + {!list?.length && !isLoading && } {count > 0 && ( diff --git a/ui/src/services/client/badges.ts b/ui/src/services/client/badges.ts index 476f85d1..7f3f8abd 100644 --- a/ui/src/services/client/badges.ts +++ b/ui/src/services/client/badges.ts @@ -64,3 +64,19 @@ export const useBadgeDetailList = (params: Type.BadgeDetailListReq) => { mutate, }; }; + +export const useGetRecentAwardBadges = (username) => { + const apiUrl = username + ? `/answer/api/v1/badge/user/awards/recent?username=${username}` + : null; + const { data, error, mutate } = useSWR< + { count: number; list: Array }, + Error + >(apiUrl, request.instance.get); + return { + data, + isLoading: !data && !error, + error, + mutate, + }; +}; From 957c299fc5b4a7c7d69d3bbbf191683cafa149a1 Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 13 Aug 2024 10:03:03 +0800 Subject: [PATCH 069/336] fix: delete log --- ui/src/components/CardBadge/index.tsx | 1 - ui/src/pages/Users/Personal/components/Badges/index.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index bb42630c..0983f108 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -43,7 +43,6 @@ const Index: FC = ({ urlSearchParams, }) => { const { t } = useTranslation('translation', { keyPrefix: 'badges' }); - console.log(data); return ( = ({ data, visible, username }) => { - console.log(data); if (!visible) { return null; } From 29f2ce3a5630d0426b9fb9be91201dbfa584a487 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 14 Aug 2024 11:23:57 +0800 Subject: [PATCH 070/336] fix: add link url path --- ui/src/pages/Badges/Detail/index.tsx | 18 +++++++++++++++--- ui/src/utils/localize.ts | 4 +--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index 42487db3..a388d496 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -71,6 +71,16 @@ const Index = () => { ) : ( badges?.list?.map((item) => { + const linkUrl = + item.object_type === 'question' + ? `/question/${item.question_id}` + : item.object_type === 'answer' + ? `/question/${item.question_id}/${item.answer_id}` + : item.object_type === 'comment' && item.answer_id + ? `/question/${item.question_id}/${item.answer_id}?commentId=${item.comment_id}` + : item.object_type === 'comment' + ? `/question/${item.question_id}?commentId=${item.comment_id}` + : ''; return ( { className="small mb-1 d-block" /> - - {item.url_title} - + {item.url_title && ( + + {item.url_title} + + )} ); }) diff --git a/ui/src/utils/localize.ts b/ui/src/utils/localize.ts index b64473a9..eea132a8 100644 --- a/ui/src/utils/localize.ts +++ b/ui/src/utils/localize.ts @@ -133,9 +133,7 @@ const localeDayjs = (langName) => { export const setupAppLanguage = async () => { const lang = getCurrentLang(); - if (!i18next.getDataByLanguage(lang)?.translation) { - await addI18nResource(lang); - } + await addI18nResource(lang); localeDayjs(lang); i18next.changeLanguage(lang); }; From ec31d18c2621a6a06604a14c5ea4bcb2e445d6c7 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 13 Aug 2024 17:42:12 +0800 Subject: [PATCH 071/336] feat(admin): Improve the badge list --- .../Admin/Badges/components/Action/index.tsx | 15 ++- ui/src/pages/Admin/Badges/index.tsx | 96 +++++++++++++------ ui/src/services/admin/badges.ts | 42 ++++++++ ui/src/services/admin/index.ts | 1 + 4 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 ui/src/services/admin/badges.ts diff --git a/ui/src/pages/Admin/Badges/components/Action/index.tsx b/ui/src/pages/Admin/Badges/components/Action/index.tsx index 77601cbb..9ec18379 100644 --- a/ui/src/pages/Admin/Badges/components/Action/index.tsx +++ b/ui/src/pages/Admin/Badges/components/Action/index.tsx @@ -23,23 +23,20 @@ import { useTranslation } from 'react-i18next'; import { Icon } from '@/components'; interface Props { - badgeData; + onSelect: (eventKey: string | null) => void; } - -const UserOperation = ({ badgeData }: Props) => { +const BadgeOperation = ({ onSelect }: Props) => { const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' }); - console.log(badgeData); - return ( - + - {t('active')} - {t('deactivate')} + {t('active')} + {t('deactivate')} {t('show_logs')} @@ -48,4 +45,4 @@ const UserOperation = ({ badgeData }: Props) => { ); }; -export default UserOperation; +export default BadgeOperation; diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 28854012..6c74f3ce 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -22,33 +22,50 @@ import { Form, Table, Stack } from 'react-bootstrap'; import { useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { QueryGroup } from '@/components'; +import classNames from 'classnames'; + +import { Empty, Icon, Pagination, QueryGroup } from '@/components'; import * as Type from '@/common/interface'; +import { useQueryBadges, updateBadgeStatus } from '@/services/admin/badges'; import Action from './components/Action'; const BadgeFilterKeys: Type.BadgeFilterBy[] = ['all', 'active', 'inactive']; -// const bgMap = { -// normal: 'text-bg-success', -// suspended: 'text-bg-danger', -// deleted: 'text-bg-danger', -// inactive: 'text-bg-secondary', -// }; +const bgMap = { + active: 'text-bg-success', + inactive: 'text-bg-secondary', +}; + +const PAGE_SIZE = 10; const Users: FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' }); const [urlSearchParams, setUrlSearchParams] = useSearchParams(); + const curPage = Number(urlSearchParams.get('page') || '1'); const curFilter = urlSearchParams.get('filter') || BadgeFilterKeys[0]; const curQuery = urlSearchParams.get('query') || ''; + const { data, isLoading, mutate } = useQueryBadges({ + page: curPage, + pageSize: PAGE_SIZE, + query: curQuery, + ...(curFilter === 'all' ? {} : { status: curFilter }), + }); + const handleFilter = (e) => { urlSearchParams.set('query', e.target.value); urlSearchParams.delete('page'); setUrlSearchParams(urlSearchParams); }; + const handleBadgeStatus = (badgeId, status) => { + updateBadgeStatus({ id: badgeId, status }).then(() => { + mutate(); + }); + }; + return ( <>

{t('title')}

@@ -85,36 +102,57 @@ const Users: FC = () => { - - - badge -
-
Nice Question
-
Question score of 10 or more.
-
- + {data?.list.map((badge) => ( + + + {badge.icon?.startsWith('http') ? ( + {badge.name} + ) : ( + + )} +
+
{badge.name}
+
{badge.description}
+
+ - Community Badges - 200 - Active - - + {badge.group_name} + {badge.award_count} + + + {t(badge.status)} + + + handleBadgeStatus(badge.id, status)} + /> + + ))} - {/* {Number(data?.count) <= 0 && !isLoading && } */} - {/*
+ {Number(data?.count) <= 0 && !isLoading && } +
-
*/} +
); }; diff --git a/ui/src/services/admin/badges.ts b/ui/src/services/admin/badges.ts new file mode 100644 index 00000000..b984164e --- /dev/null +++ b/ui/src/services/admin/badges.ts @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import qs from 'qs'; +import useSWR from 'swr'; + +import request from '@/utils/request'; +import type * as Type from '@/common/interface'; + +export const useQueryBadges = (params) => { + const apiUrl = `/answer/admin/api/badges?${qs.stringify(params)}`; + const { data, error, mutate } = useSWR( + apiUrl, + request.instance.get, + ); + return { + data, + isLoading: !data && !error, + error, + mutate, + }; +}; + +export const updateBadgeStatus = (params) => { + return request.put('/answer/admin/api/badge/status', params); +}; diff --git a/ui/src/services/admin/index.ts b/ui/src/services/admin/index.ts index ce64c511..af83d365 100644 --- a/ui/src/services/admin/index.ts +++ b/ui/src/services/admin/index.ts @@ -24,3 +24,4 @@ export * from './settings'; export * from './users'; export * from './dashboard'; export * from './plugins'; +export * from './badges'; From 04065a8dcb56b338c10feb9f5265ee470c92eee0 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 13 Aug 2024 18:25:52 +0800 Subject: [PATCH 072/336] refactor: Update query parameter name in badge list API call --- ui/src/pages/Admin/Badges/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 6c74f3ce..571f9b83 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -50,7 +50,7 @@ const Users: FC = () => { const { data, isLoading, mutate } = useQueryBadges({ page: curPage, pageSize: PAGE_SIZE, - query: curQuery, + q: curQuery, ...(curFilter === 'all' ? {} : { status: curFilter }), }); From 4afa76ba2a8233a949ef05f605416f5983f556c7 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 13 Aug 2024 18:31:47 +0800 Subject: [PATCH 073/336] refactor: update zh_CN.yaml --- i18n/zh_CN.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 94e6c97f..5612e1ab 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1407,6 +1407,7 @@ ui: questions: 问题 answers: 回答 users: 用户管理 + badges: 徽章管理 flags: 举报管理 settings: 站点设置 general: 一般 @@ -1834,6 +1835,20 @@ ui: msg: should_be_number: 输入必须是数字 number_larger_1: 数字应该大于等于 1 + badges: + action: 操作 + active: 激活 + all: 全部 + awards: 奖励 + deactivate: 取消激活 + filter: + placeholder: "按名称筛选,徽章:id" + group: 组 + inactive: 未激活 + name: 名称 + show_logs: 显示日志 + status: 状态 + title: 徽章 form: optional: (选填) empty: 不能为空 From 342c31f38cda7c671c4939c547e424284bbda4aa Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 14 Aug 2024 16:41:14 +0800 Subject: [PATCH 074/336] fix: add link url path --- ui/src/pages/Badges/Detail/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index a388d496..46f49ce2 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -60,8 +60,6 @@ const Index = () => { return null; } - console.log(badges); - return (

{t('title')}

From 3cb1be88f6fa6c5b4bb7e476e1dada0c8e0e429b Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 14 Aug 2024 14:13:28 +0800 Subject: [PATCH 075/336] refactor: Update badge description styling in Admin Badges page --- ui/src/pages/Admin/Badges/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 571f9b83..f6b8cb0d 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -127,7 +127,7 @@ const Users: FC = () => { )}
{badge.name}
-
{badge.description}
+
{badge.description}
From db1a527f955343c936b261a2832e7b071c8316d9 Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 14 Aug 2024 14:19:18 +0800 Subject: [PATCH 076/336] refactor: Update page_size parameter in badge list API call --- ui/src/pages/Admin/Badges/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index f6b8cb0d..448040a4 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -49,7 +49,7 @@ const Users: FC = () => { const { data, isLoading, mutate } = useQueryBadges({ page: curPage, - pageSize: PAGE_SIZE, + page_size: PAGE_SIZE, q: curQuery, ...(curFilter === 'all' ? {} : { status: curFilter }), }); From 45f410ca4c9b06e8f8fd3041cfce46af67698ba7 Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 16 Aug 2024 11:39:17 +0800 Subject: [PATCH 077/336] chore: Update tsconfig.json to exclude src/plugins directory --- ui/tsconfig.json | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/ui/tsconfig.json b/ui/tsconfig.json index b16f340c..ac6a549e 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -20,9 +24,20 @@ "jsx": "react-jsx", "baseUrl": "./", "paths": { - "@/*": ["src/*"], - "@i18n/*": ["../i18n/*"] + "@/*": [ + "src/*" + ], + "@i18n/*": [ + "../i18n/*" + ] } }, - "include": ["src", "node_modules/@testing-library/jest-dom", "scripts" ] -} + "include": [ + "src", + "node_modules/@testing-library/jest-dom", + "scripts" + ], + "exclude": [ + "src/plugins" + ] +} \ No newline at end of file From ac28c8871251c28fcdf9711922bc549c93ee7f10 Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 16 Aug 2024 11:41:11 +0800 Subject: [PATCH 078/336] refactor: Update badge description styling in Admin Badges page --- i18n/en_US.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 420d25ba..8b137d37 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1580,7 +1580,7 @@ ui: visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined - comma: ',' + comma: "," last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1738,6 +1738,11 @@ ui: qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges title: Badges awarded: Awarded earned_x: Earned x{{ number }} From 90cf954d8fc28103f15079c102ae4ac0a6b9cab7 Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 16 Aug 2024 11:41:57 +0800 Subject: [PATCH 079/336] refactor: Update badge description styling in Admin Badges page --- ui/src/common/interface.ts | 15 +++- ui/src/components/Modal/BadgeModal.tsx | 70 +++++++++++++++++++ ui/src/components/Modal/index.tsx | 3 +- ui/src/pages/Admin/Badges/index.tsx | 6 +- ui/src/pages/Layout/index.tsx | 8 ++- .../components/Achievements/index.scss | 5 +- .../components/Achievements/index.tsx | 27 +++++-- ui/src/services/admin/badges.ts | 8 +-- 8 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 ui/src/components/Modal/BadgeModal.tsx diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index 608a2465..a06fec28 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -220,11 +220,19 @@ export interface SetNoticeReq { notice_switch: boolean; } +export interface NotificationBadgeAward { + notification_id: string; + badge_id: string; + name: string; + icon: string; + level: number; +} export interface NotificationStatus { inbox: number; achievement: number; revision: number; can_revision: boolean; + badge_award: NotificationBadgeAward | null; } export interface QuestionDetailRes { @@ -758,13 +766,18 @@ export interface BadgeInfo extends BadgeListItem { is_single: boolean; } +export interface AdminBadgeListItem extends BadgeListItem { + group_name: string; + status: string; + description: string; +} + export interface BadgeDetailListReq { page: number; page_size: number; badge_id: string; username?: string | null; } - export interface BadgeDetailListItem { created_at: number; author_user_info: UserInfoBase; diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx new file mode 100644 index 00000000..214c1d67 --- /dev/null +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -0,0 +1,70 @@ +import { FC } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; + +import classNames from 'classnames'; + +import type * as Type from '@/common/interface'; +import { loggedUserInfoStore } from '@/stores'; +import { readNotification, useQueryNotificationStatus } from '@/services'; +import Icon from '../Icon'; + +import Modal from './Modal'; + +interface BadgeModalProps { + badge?: Type.NotificationBadgeAward | null; + visible: boolean; +} +const BadgeModal: FC = ({ badge, visible }) => { + const { t } = useTranslation('translation', { keyPrefix: 'badges.modal' }); + const { user } = loggedUserInfoStore(); + const navigate = useNavigate(); + const { data } = useQueryNotificationStatus(); + + const handleCancel = async () => { + if (!data) return; + await readNotification(badge?.notification_id); + }; + const handleConfirm = async () => { + await readNotification(badge?.notification_id); + + const url = `/badges/${badge?.badge_id}?username=${user.username}`; + navigate(url); + }; + + return ( + + {badge && ( +
+ {badge.icon?.startsWith('http') ? ( + {badge.name} + ) : ( + + )} +
{badge?.name}
+

{t('content')}

+
+ )} +
+ ); +}; + +export default BadgeModal; diff --git a/ui/src/components/Modal/index.tsx b/ui/src/components/Modal/index.tsx index 40459196..75d96842 100644 --- a/ui/src/components/Modal/index.tsx +++ b/ui/src/components/Modal/index.tsx @@ -20,6 +20,7 @@ import DefaultModal from './Modal'; import confirm, { Config } from './Confirm'; import LoginToContinueModal from './LoginToContinueModal'; +import BadgeModal from './BadgeModal'; type ModalType = typeof DefaultModal & { confirm: (config: Config) => void; @@ -32,4 +33,4 @@ Modal.confirm = function (props: Config) { export default Modal; -export { LoginToContinueModal }; +export { LoginToContinueModal, BadgeModal }; diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 448040a4..e76f90eb 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -39,7 +39,7 @@ const bgMap = { const PAGE_SIZE = 10; -const Users: FC = () => { +const Badges: FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' }); const [urlSearchParams, setUrlSearchParams] = useSearchParams(); @@ -103,7 +103,7 @@ const Users: FC = () => { {data?.list.map((badge) => ( - + {badge.icon?.startsWith('http') ? ( { ); }; -export default Users; +export default Badges; diff --git a/ui/src/pages/Layout/index.tsx b/ui/src/pages/Layout/index.tsx index 2029b0fa..e8bab279 100644 --- a/ui/src/pages/Layout/index.tsx +++ b/ui/src/pages/Layout/index.tsx @@ -33,8 +33,9 @@ import { PageTags, HttpErrorContent, } from '@/components'; -import { LoginToContinueModal } from '@/components/Modal'; +import { LoginToContinueModal, BadgeModal } from '@/components/Modal'; import { changeTheme } from '@/utils'; +import { useQueryNotificationStatus } from '@/services'; const Layout: FC = () => { const location = useLocation(); @@ -44,6 +45,7 @@ const Layout: FC = () => { }; const { code: httpStatusCode, reset: httpStatusReset } = errorCodeStore(); const { show: showLoginToContinueModal } = loginToContinueStore(); + const { data: notificationData } = useQueryNotificationStatus(); useEffect(() => { httpStatusReset(); @@ -86,6 +88,10 @@ const Layout: FC = () => {
+ diff --git a/ui/src/pages/Users/Notifications/components/Achievements/index.scss b/ui/src/pages/Users/Notifications/components/Achievements/index.scss index fb91193f..9a224921 100644 --- a/ui/src/pages/Users/Notifications/components/Achievements/index.scss +++ b/ui/src/pages/Users/Notifications/components/Achievements/index.scss @@ -18,8 +18,9 @@ */ .achievement-wrap { - .num { + .num, + .icon { width: 60px; flex: none; } -} +} \ No newline at end of file diff --git a/ui/src/pages/Users/Notifications/components/Achievements/index.tsx b/ui/src/pages/Users/Notifications/components/Achievements/index.tsx index 5f2e8f58..c171a427 100644 --- a/ui/src/pages/Users/Notifications/components/Achievements/index.tsx +++ b/ui/src/pages/Users/Notifications/components/Achievements/index.tsx @@ -24,10 +24,13 @@ import classNames from 'classnames'; import isEmpty from 'lodash/isEmpty'; import { Empty } from '@/components'; +import { loggedUserInfoStore } from '@/stores'; import './index.scss'; const Achievements = ({ data, handleReadNotification }) => { + const { user } = loggedUserInfoStore(); + if (!data) { return null; } @@ -50,6 +53,9 @@ const Achievements = ({ data, handleReadNotification }) => { case 'comment': url = `/questions/${question}/${answer}?commentId=${comment}`; break; + case 'badge_award': + url = `/badges/${item.object_info.object_map.badge_id}?username=${user.username}`; + break; default: url = ''; } @@ -60,13 +66,22 @@ const Achievements = ({ data, handleReadNotification }) => { 'd-flex border-start-0 border-end-0 py-3', !item.is_read && 'warning', )}> - {item.rank > 0 && ( -
{`+${item.rank}`}
- )} - {item.rank === 0 &&
{item.rank}
} - {item.rank < 0 && ( -
{`${item.rank}`}
+ {item.object_info.object_type === 'badge_award' ? ( +
👏
+ ) : ( + <> + {item.rank > 0 && ( +
{`+${item.rank}`}
+ )} + {item.rank === 0 && ( +
{item.rank}
+ )} + {item.rank < 0 && ( +
{`${item.rank}`}
+ )} + )} +
handleReadNotification(item.id)}> {item.object_info.title} diff --git a/ui/src/services/admin/badges.ts b/ui/src/services/admin/badges.ts index b984164e..64685bc5 100644 --- a/ui/src/services/admin/badges.ts +++ b/ui/src/services/admin/badges.ts @@ -25,10 +25,10 @@ import type * as Type from '@/common/interface'; export const useQueryBadges = (params) => { const apiUrl = `/answer/admin/api/badges?${qs.stringify(params)}`; - const { data, error, mutate } = useSWR( - apiUrl, - request.instance.get, - ); + const { data, error, mutate } = useSWR< + Type.ListResult, + Error + >(apiUrl, request.instance.get); return { data, isLoading: !data && !error, From 85516530ca1d98710f05194da0305a227318244e Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 13 Aug 2024 15:02:29 +0800 Subject: [PATCH 080/336] =?UTF-8?q?feat=EF=BC=9ASupport=20Render=20type=20?= =?UTF-8?q?plugins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/src/utils/pluginKit/index.ts | 3 ++- ui/src/utils/pluginKit/interface.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 1f7efaca..26e3a288 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -221,7 +221,8 @@ const useRenderHtmlPlugin = ( return ( plugin.activated && plugin.hooks?.useRender && - plugin.info.type === PluginType.Editor + (plugin.info.type === PluginType.Editor || + plugin.info.type === PluginType.Render) ); }) .forEach((plugin) => { diff --git a/ui/src/utils/pluginKit/interface.ts b/ui/src/utils/pluginKit/interface.ts index e1b8ab0c..462ae47b 100644 --- a/ui/src/utils/pluginKit/interface.ts +++ b/ui/src/utils/pluginKit/interface.ts @@ -27,6 +27,7 @@ export enum PluginType { Editor = 'editor', Route = 'route', Captcha = 'captcha', + Render = 'render', } export interface PluginInfo { @@ -45,7 +46,7 @@ export interface Plugin { useRender?: Array< (element: HTMLElement | RefObject | null) => void >; - useCaptcha?: (props: { captchaKey: Type.CaptchaKey; commonProps: any }) => { + useCaptcha?: (props: { captchaKey: Type.CaptchaKey; commonProps: any; }) => { getCaptcha: () => Record; check: (t: () => void) => void; handleCaptchaError: (error) => any; From 7c59d3f3cb167abdaadf0a570dec24c11efc9cc3 Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 15 Aug 2024 10:57:33 +0800 Subject: [PATCH 081/336] feat: Add useRenderPlugin to Editor component --- ui/src/components/Editor/index.tsx | 4 +++- ui/src/utils/pluginKit/index.ts | 28 +++++++++++++++++++++++++++- ui/src/utils/pluginKit/interface.ts | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/ui/src/components/Editor/index.tsx b/ui/src/components/Editor/index.tsx index dd004021..ead37653 100644 --- a/ui/src/components/Editor/index.tsx +++ b/ui/src/components/Editor/index.tsx @@ -27,7 +27,7 @@ import { import classNames from 'classnames'; -import { PluginType } from '@/utils/pluginKit'; +import { PluginType, useRenderPlugin } from '@/utils/pluginKit'; import PluginRender from '../PluginRender'; import { @@ -84,6 +84,8 @@ const MDEditor: ForwardRefRenderFunction = ( const editorRef = useRef(null); const previewRef = useRef<{ getHtml; element } | null>(null); + useRenderPlugin(previewRef.current?.element); + const editor = useEditor({ editorRef, onChange, diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 26e3a288..6d0e9878 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -232,6 +232,26 @@ const useRenderHtmlPlugin = ( }); }; +// Only for render type plugins +const useRenderPlugin = ( + element: HTMLElement | RefObject | null, +) => { + return plugins + .getPlugins() + .filter((plugin) => { + return ( + plugin.activated && + plugin.hooks?.useRender && + plugin.info.type === PluginType.Render + ); + }) + .forEach((plugin) => { + plugin.hooks?.useRender?.forEach((hook) => { + hook(element); + }); + }); +}; + // Only one captcha type plug-in can be enabled at the same time const useCaptchaPlugin = (key: Type.CaptchaKey) => { const captcha = plugins @@ -248,5 +268,11 @@ const useCaptchaPlugin = (key: Type.CaptchaKey) => { export type { Plugin, PluginInfo }; -export { useRenderHtmlPlugin, mergeRoutePlugins, useCaptchaPlugin, PluginType }; +export { + useRenderHtmlPlugin, + mergeRoutePlugins, + useCaptchaPlugin, + useRenderPlugin, + PluginType, +}; export default plugins; diff --git a/ui/src/utils/pluginKit/interface.ts b/ui/src/utils/pluginKit/interface.ts index 462ae47b..880a524a 100644 --- a/ui/src/utils/pluginKit/interface.ts +++ b/ui/src/utils/pluginKit/interface.ts @@ -46,7 +46,7 @@ export interface Plugin { useRender?: Array< (element: HTMLElement | RefObject | null) => void >; - useCaptcha?: (props: { captchaKey: Type.CaptchaKey; commonProps: any; }) => { + useCaptcha?: (props: { captchaKey: Type.CaptchaKey; commonProps: any }) => { getCaptcha: () => Record; check: (t: () => void) => void; handleCaptchaError: (error) => any; From e48a13fed51f9f14a28d914ea3ca75920dc49333 Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 22 Aug 2024 10:04:47 +0800 Subject: [PATCH 082/336] refactor: Update Chinese translation for badge activation --- i18n/zh_CN.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 5612e1ab..20782516 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1840,7 +1840,7 @@ ui: active: 激活 all: 全部 awards: 奖励 - deactivate: 取消激活 + deactivate: 停用 filter: placeholder: "按名称筛选,徽章:id" group: 组 From e4d0322a1694b026a205f0ddc3221e249fe6280a Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 22 Aug 2024 10:04:52 +0800 Subject: [PATCH 083/336] refactor: Remove unused dropdown item in BadgeOperation component --- ui/src/pages/Admin/Badges/components/Action/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/src/pages/Admin/Badges/components/Action/index.tsx b/ui/src/pages/Admin/Badges/components/Action/index.tsx index 9ec18379..b5bf8ddd 100644 --- a/ui/src/pages/Admin/Badges/components/Action/index.tsx +++ b/ui/src/pages/Admin/Badges/components/Action/index.tsx @@ -37,8 +37,6 @@ const BadgeOperation = ({ onSelect }: Props) => { {t('active')} {t('deactivate')} - - {t('show_logs')} From e6aa178062c65cd0f79671efd6ebda90219f3843 Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 22 Aug 2024 10:45:24 +0800 Subject: [PATCH 084/336] refactor: Update key prop in BadgeDetail component --- ui/src/pages/Badges/Detail/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index 46f49ce2..f8a9327a 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -80,7 +80,12 @@ const Index = () => { ? `/question/${item.question_id}?commentId=${item.comment_id}` : ''; return ( - + Date: Thu, 22 Aug 2024 10:47:44 +0800 Subject: [PATCH 085/336] refactor: Update BadgeModal component to handle badge cancellation and confirmation --- ui/src/components/Modal/BadgeModal.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index 214c1d67..32049de6 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -19,14 +19,21 @@ const BadgeModal: FC = ({ badge, visible }) => { const { t } = useTranslation('translation', { keyPrefix: 'badges.modal' }); const { user } = loggedUserInfoStore(); const navigate = useNavigate(); - const { data } = useQueryNotificationStatus(); + const { data, mutate } = useQueryNotificationStatus(); - const handleCancel = async () => { + const handle = async () => { if (!data) return; await readNotification(badge?.notification_id); + await mutate({ + ...data, + badge_award: null, + }); + }; + const handleCancel = async () => { + await handle(); }; const handleConfirm = async () => { - await readNotification(badge?.notification_id); + await handle(); const url = `/badges/${badge?.badge_id}?username=${user.username}`; navigate(url); From 7d8e679d9c969c036ea8697d225c25c843d88c15 Mon Sep 17 00:00:00 2001 From: Fen Date: Tue, 13 Aug 2024 10:29:55 +0800 Subject: [PATCH 086/336] docs: enable wiki --- .asf.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.asf.yaml b/.asf.yaml index a8baeb21..7505cd7f 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -30,7 +30,7 @@ github: - q-and-a - hacktoberfest features: - wiki: false + wiki: true issues: true projects: true discussions: false From 15531f42231471509b2a0513737546263b1a0e25 Mon Sep 17 00:00:00 2001 From: Jan Ernsting Date: Thu, 15 Aug 2024 17:31:49 +0200 Subject: [PATCH 087/336] build swagger documentation on go generate --- cmd/answer/main.go | 7 +++ docs/docs.go | 87 ++++++++++++++++++++----------- docs/swagger.json | 68 ++++++++++++++++++++---- docs/swagger.yaml | 64 ++++++++++++++--------- go.mod | 5 +- go.sum | 6 +++ internal/router/swagger_router.go | 4 -- 7 files changed, 172 insertions(+), 69 deletions(-) diff --git a/cmd/answer/main.go b/cmd/answer/main.go index ae114709..a14031ec 100644 --- a/cmd/answer/main.go +++ b/cmd/answer/main.go @@ -17,12 +17,19 @@ * under the License. */ +//go:generate go run github.com/swaggo/swag/cmd/swag init -g ./cmd/answer/main.go -d ../../ -o ../../docs + package main import ( answercmd "github.com/apache/incubator-answer/cmd" ) +// main godoc +// @title "answer" +// @description = "answer api" +// @version = "v0.0.1" +// @BasePath = "/" // @securityDefinitions.apikey ApiKeyAuth // @in header // @name Authorization diff --git a/docs/docs.go b/docs/docs.go index cf1264d1..fee91459 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,22 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - // Package docs Code generated by swaggo/swag. DO NOT EDIT package docs @@ -4410,7 +4391,7 @@ const docTemplate = `{ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetTagResp" + "$ref": "#/definitions/schema.GetTagBasicResp" } } } @@ -5380,7 +5361,7 @@ const docTemplate = `{ }, "/answer/api/v1/tags": { "get": { - "description": "get tags list", + "description": "get tags list by slug name", "produces": [ "application/json" ], @@ -5404,7 +5385,22 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handler.RespBody" + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetTagBasicResp" + } + } + } + } + ] } } } @@ -8242,6 +8238,23 @@ const docTemplate = `{ } } }, + "schema.GetTagBasicResp": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "recommend": { + "type": "boolean" + }, + "reserved": { + "type": "boolean" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.GetTagPageResp": { "type": "object", "properties": { @@ -9819,7 +9832,7 @@ const docTemplate = `{ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9828,7 +9841,7 @@ const docTemplate = `{ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9842,7 +9855,7 @@ const docTemplate = `{ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9851,7 +9864,7 @@ const docTemplate = `{ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9859,6 +9872,20 @@ const docTemplate = `{ } } }, + "schema.SiteWriteTag": { + "type": "object", + "required": [ + "slug_name" + ], + "properties": { + "display_name": { + "type": "string" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.TagItem": { "type": "object", "properties": { @@ -10783,12 +10810,12 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ - Version: "", + Version: "= \"v0.0.1\"", Host: "", - BasePath: "", + BasePath: "= \"/\"", Schemes: []string{}, - Title: "", - Description: "", + Title: "\"answer\"", + Description: "= \"answer api\"", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", diff --git a/docs/swagger.json b/docs/swagger.json index 1e93d2b0..7c103856 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,8 +1,12 @@ { "swagger": "2.0", "info": { - "contact": {} + "description": "= \"answer api\"", + "title": "\"answer\"", + "contact": {}, + "version": "= \"v0.0.1\"" }, + "basePath": "= \"/\"", "paths": { "/": { "get": { @@ -4380,7 +4384,7 @@ "data": { "type": "array", "items": { - "$ref": "#/definitions/schema.GetTagResp" + "$ref": "#/definitions/schema.GetTagBasicResp" } } } @@ -5350,7 +5354,7 @@ }, "/answer/api/v1/tags": { "get": { - "description": "get tags list", + "description": "get tags list by slug name", "produces": [ "application/json" ], @@ -5374,7 +5378,22 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handler.RespBody" + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetTagBasicResp" + } + } + } + } + ] } } } @@ -8212,6 +8231,23 @@ } } }, + "schema.GetTagBasicResp": { + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "recommend": { + "type": "boolean" + }, + "reserved": { + "type": "boolean" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.GetTagPageResp": { "type": "object", "properties": { @@ -8809,7 +8845,7 @@ "enum": [ "newest", "active", - "frequent", + "hot", "score", "unanswered" ] @@ -9789,7 +9825,7 @@ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9798,7 +9834,7 @@ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9812,7 +9848,7 @@ "recommend_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "required_tag": { @@ -9821,7 +9857,7 @@ "reserved_tags": { "type": "array", "items": { - "type": "string" + "$ref": "#/definitions/schema.SiteWriteTag" } }, "restrict_answer": { @@ -9829,6 +9865,20 @@ } } }, + "schema.SiteWriteTag": { + "type": "object", + "required": [ + "slug_name" + ], + "properties": { + "display_name": { + "type": "string" + }, + "slug_name": { + "type": "string" + } + } + }, "schema.TagItem": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 93f8116a..231b271e 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,20 +1,4 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - +basePath: = "/" definitions: constant.NotificationChannelKey: enum: @@ -983,6 +967,17 @@ definitions: terms_of_service_parsed_text: type: string type: object + schema.GetTagBasicResp: + properties: + display_name: + type: string + recommend: + type: boolean + reserved: + type: boolean + slug_name: + type: string + type: object schema.GetTagPageResp: properties: created_at: @@ -1401,7 +1396,7 @@ definitions: enum: - newest - active - - frequent + - hot - score - unanswered type: string @@ -2071,13 +2066,13 @@ definitions: properties: recommend_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array required_tag: type: boolean reserved_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array restrict_answer: type: boolean @@ -2086,17 +2081,26 @@ definitions: properties: recommend_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array required_tag: type: boolean reserved_tags: items: - type: string + $ref: '#/definitions/schema.SiteWriteTag' type: array restrict_answer: type: boolean type: object + schema.SiteWriteTag: + properties: + display_name: + type: string + slug_name: + type: string + required: + - slug_name + type: object schema.TagItem: properties: display_name: @@ -2736,6 +2740,9 @@ definitions: type: object info: contact: {} + description: = "answer api" + title: '"answer"' + version: = "v0.0.1" paths: /: get: @@ -5382,7 +5389,7 @@ paths: - properties: data: items: - $ref: '#/definitions/schema.GetTagResp' + $ref: '#/definitions/schema.GetTagBasicResp' type: array type: object security: @@ -5965,7 +5972,7 @@ paths: - Tag /answer/api/v1/tags: get: - description: get tags list + description: get tags list by slug name parameters: - collectionFormat: csv description: string collection @@ -5980,7 +5987,14 @@ paths: "200": description: OK schema: - $ref: '#/definitions/handler.RespBody' + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetTagBasicResp' + type: array + type: object summary: get tags list tags: - Tag diff --git a/go.mod b/go.mod index e1b78ad2..036a2b42 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/swaggo/files v1.0.0 github.com/swaggo/gin-swagger v1.5.3 - github.com/swaggo/swag v1.16.1 + github.com/swaggo/swag v1.16.3 github.com/tidwall/gjson v1.14.4 github.com/yuin/goldmark v1.4.13 golang.org/x/crypto v0.21.0 @@ -79,6 +79,7 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/containerd/continuity v0.4.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/cli v24.0.6+incompatible // indirect github.com/docker/docker v24.0.6+incompatible // indirect @@ -128,6 +129,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.9.2 // indirect github.com/spf13/cast v1.5.0 // indirect @@ -140,6 +142,7 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + github.com/urfave/cli/v2 v2.3.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect diff --git a/go.sum b/go.sum index 501d1e94..fb49b88b 100644 --- a/go.sum +++ b/go.sum @@ -128,6 +128,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -615,6 +616,7 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -692,6 +694,8 @@ github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89 github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= @@ -710,7 +714,9 @@ github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95 github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= diff --git a/internal/router/swagger_router.go b/internal/router/swagger_router.go index 795e8802..55f2d644 100644 --- a/internal/router/swagger_router.go +++ b/internal/router/swagger_router.go @@ -51,9 +51,5 @@ func (a *SwaggerRouter) Register(r *gin.RouterGroup) { // InitSwaggerDocs init swagger docs func (a *SwaggerRouter) InitSwaggerDocs() { - docs.SwaggerInfo.Title = "answer" - docs.SwaggerInfo.Description = "answer api" - docs.SwaggerInfo.Version = "v0.0.1" docs.SwaggerInfo.Host = fmt.Sprintf("%s%s", a.config.Host, a.config.Address) - docs.SwaggerInfo.BasePath = "/" } From 493d5c0768b1e21415e6c2f416e9febcf35be738 Mon Sep 17 00:00:00 2001 From: Jan Ernsting Date: Fri, 16 Aug 2024 08:41:04 +0200 Subject: [PATCH 088/336] requested changes --- cmd/answer/main.go | 4 ++-- docs/docs.go | 19 +++++++++++++++++++ docs/swagger.yaml | 17 +++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/cmd/answer/main.go b/cmd/answer/main.go index a14031ec..fb91f594 100644 --- a/cmd/answer/main.go +++ b/cmd/answer/main.go @@ -26,8 +26,8 @@ import ( ) // main godoc -// @title "answer" -// @description = "answer api" +// @title "apache answer" +// @description = "apache answer api" // @version = "v0.0.1" // @BasePath = "/" // @securityDefinitions.apikey ApiKeyAuth diff --git a/docs/docs.go b/docs/docs.go index fee91459..376cdf07 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Package docs Code generated by swaggo/swag. DO NOT EDIT package docs diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 231b271e..88709bed 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,3 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + basePath: = "/" definitions: constant.NotificationChannelKey: From b20e656c30b3a3dfead266c36397da78bdff4c69 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 22 Aug 2024 14:21:18 +0800 Subject: [PATCH 089/336] feat(config): add deactivate plugin config cli --- cmd/command.go | 11 ++++++++--- internal/cli/config.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/cmd/command.go b/cmd/command.go index b8d9c561..65710e6b 100644 --- a/cmd/command.go +++ b/cmd/command.go @@ -263,12 +263,17 @@ To run answer, use: } field := &cli.ConfigField{} - for _, f := range configFields { - switch f { + fmt.Println(configFields) + if len(configFields) > 0 { + switch configFields[0] { case "allow_password_login": field.AllowPasswordLogin = true + case "deactivate_plugin": + if len(configFields) > 1 { + field.DeactivatePluginSlugName = configFields[1] + } default: - fmt.Printf("field %s not support\n", f) + fmt.Printf("field %s not support\n", configFields[0]) } } err = cli.SetDefaultConfig(c.Data.Database, c.Data.Cache, field) diff --git a/internal/cli/config.go b/internal/cli/config.go index 06764e41..9ebefa1d 100644 --- a/internal/cli/config.go +++ b/internal/cli/config.go @@ -31,6 +31,8 @@ import ( type ConfigField struct { AllowPasswordLogin bool `json:"allow_password_login"` + // The slug name of plugin that you want to deactivate + DeactivatePluginSlugName string `json:"deactivate_plugin_slug_name"` } // SetDefaultConfig set default config @@ -55,6 +57,9 @@ func SetDefaultConfig(dbConf *data.Database, cacheConf *data.CacheConf, field *C if field.AllowPasswordLogin { return defaultLoginConfig(db) } + if len(field.DeactivatePluginSlugName) > 0 { + return deactivatePlugin(db, field.DeactivatePluginSlugName) + } return nil } @@ -82,3 +87,37 @@ func defaultLoginConfig(x *xorm.Engine) (err error) { } return nil } + +func deactivatePlugin(x *xorm.Engine, pluginSlugName string) (err error) { + fmt.Printf("try to deactivate plugin: %s\n", pluginSlugName) + + item := &entity.Config{Key: constant.PluginStatus} + exist, err := x.Get(item) + if err != nil { + return fmt.Errorf("get config failed: %w", err) + } + if !exist { + return nil + } + + pluginStatusMapping := make(map[string]bool) + _ = json.Unmarshal([]byte(item.Value), &pluginStatusMapping) + status, ok := pluginStatusMapping[pluginSlugName] + if !ok { + fmt.Printf("plugin %s not exist\n", pluginSlugName) + return nil + } + if !status { + fmt.Printf("plugin %s already deactivated\n", pluginSlugName) + return nil + } + + pluginStatusMapping[pluginSlugName] = false + dataByte, _ := json.Marshal(pluginStatusMapping) + item.Value = string(dataByte) + _, err = x.ID(item.ID).Cols("value").Update(item) + if err != nil { + return fmt.Errorf("update plugin status failed: %w", err) + } + return nil +} From 76d455e6de6907ff49fea25071113b4cf4782c53 Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 22 Aug 2024 14:21:47 +0800 Subject: [PATCH 090/336] refactor: Restore zh_CN.yaml --- i18n/zh_CN.yaml | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 20782516..396c2f9b 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1407,7 +1407,6 @@ ui: questions: 问题 answers: 回答 users: 用户管理 - badges: 徽章管理 flags: 举报管理 settings: 站点设置 general: 一般 @@ -1835,20 +1834,6 @@ ui: msg: should_be_number: 输入必须是数字 number_larger_1: 数字应该大于等于 1 - badges: - action: 操作 - active: 激活 - all: 全部 - awards: 奖励 - deactivate: 停用 - filter: - placeholder: "按名称筛选,徽章:id" - group: 组 - inactive: 未激活 - name: 名称 - show_logs: 显示日志 - status: 状态 - title: 徽章 form: optional: (选填) empty: 不能为空 @@ -1935,4 +1920,4 @@ ui: post_reopen: 这个帖子已被重新打开. post_list: 这个帖子已经被显示 post_unlist: 这个帖子已经被隐藏 - post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 + post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 \ No newline at end of file From 1e8072ba21951890a24c2c448638beadedf2112c Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 22 Aug 2024 14:37:49 +0800 Subject: [PATCH 091/336] refactor: Update translation for achievements --- i18n/en_US.yaml | 3 +++ .../Users/Notifications/components/Achievements/index.tsx | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 8b137d37..032ad141 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -853,6 +853,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Your Account has been Suspended until_time: "Your account was suspended until {{ time }}." diff --git a/ui/src/pages/Users/Notifications/components/Achievements/index.tsx b/ui/src/pages/Users/Notifications/components/Achievements/index.tsx index c171a427..824bb178 100644 --- a/ui/src/pages/Users/Notifications/components/Achievements/index.tsx +++ b/ui/src/pages/Users/Notifications/components/Achievements/index.tsx @@ -19,6 +19,7 @@ import { ListGroup } from 'react-bootstrap'; import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import classNames from 'classnames'; import isEmpty from 'lodash/isEmpty'; @@ -30,6 +31,7 @@ import './index.scss'; const Achievements = ({ data, handleReadNotification }) => { const { user } = loggedUserInfoStore(); + const { t } = useTranslation('translation', { keyPrefix: 'notifications' }); if (!data) { return null; @@ -87,7 +89,7 @@ const Achievements = ({ data, handleReadNotification }) => { {item.object_info.title} - {item.object_info.object_type} + {t(item.object_info.object_type)}
From 065bf980d34ea50574b713aff4e4d2f1b4d136c4 Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 22 Aug 2024 15:50:40 +0800 Subject: [PATCH 092/336] chore: Add License --- ui/src/components/CardBadge/index.tsx | 1 + ui/src/components/Modal/BadgeModal.tsx | 19 +++++++++++++++++++ ui/src/pages/Badges/index.tsx | 1 + 3 files changed, 21 insertions(+) diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index 0983f108..dd8c18e6 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ + import { useTranslation } from 'react-i18next'; import { FC } from 'react'; import { Card, Badge } from 'react-bootstrap'; diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index 32049de6..468c7f89 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + import { FC } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; diff --git a/ui/src/pages/Badges/index.tsx b/ui/src/pages/Badges/index.tsx index d37f5d9a..39628062 100644 --- a/ui/src/pages/Badges/index.tsx +++ b/ui/src/pages/Badges/index.tsx @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ + import { useTranslation } from 'react-i18next'; import { CardBadge } from '@/components'; From 82d7445e62321a6cc859df15007a486b5a70b5ad Mon Sep 17 00:00:00 2001 From: kumfo Date: Thu, 22 Aug 2024 16:13:44 +0800 Subject: [PATCH 093/336] fix: embed controller add error return --- internal/controller/embed_controller.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/controller/embed_controller.go b/internal/controller/embed_controller.go index a61bd68c..eb54f1a6 100644 --- a/internal/controller/embed_controller.go +++ b/internal/controller/embed_controller.go @@ -43,10 +43,10 @@ func NewEmbedController() *EmbedController { func (c *EmbedController) GetEmbedConfig(ctx *gin.Context) { resp := make([]*plugin.EmbedConfig, 0) - _ = plugin.CallEmbed(func(embed plugin.Embed) (err error) { + err := plugin.CallEmbed(func(embed plugin.Embed) (err error) { resp, err = embed.GetEmbedConfigs(ctx) - return nil + return err }) - handler.HandleResponse(ctx, nil, resp) + handler.HandleResponse(ctx, err, resp) } From 1af1f77a60afb2adec3034e06118c0d70610fffd Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 23 Aug 2024 11:10:31 +0800 Subject: [PATCH 094/336] feat: Add RenderController to handle rendering configuration --- cmd/wire_gen.go | 3 +- internal/controller/controller.go | 1 + internal/controller/render_controller.go | 52 ++++++++++++++++++++++++ internal/router/plugin_api_router.go | 4 ++ plugin/plugin.go | 4 ++ plugin/render.go | 39 ++++++++++++++++++ 6 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 internal/controller/render_controller.go create mode 100644 plugin/render.go diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index cc245aea..940c0dc1 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -282,7 +282,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, userCenterController := controller.NewUserCenterController(userCenterLoginService, siteInfoCommonService) captchaController := controller.NewCaptchaController() embedController := controller.NewEmbedController() - pluginAPIRouter := router.NewPluginAPIRouter(connectorController, userCenterController, captchaController, embedController) + renderController := controller.NewRenderController() + pluginAPIRouter := router.NewPluginAPIRouter(connectorController, userCenterController, captchaController, embedController, renderController) ginEngine := server.NewHTTPServer(debug, staticRouter, answerAPIRouter, swaggerRouter, uiRouter, authUserMiddleware, avatarMiddleware, shortIDMiddleware, templateRouter, pluginAPIRouter, uiConf) scheduledTaskManager := cron.NewScheduledTaskManager(siteInfoCommonService, questionService) application := newApplication(serverConf, ginEngine, scheduledTaskManager) diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 8fad918a..cbf80f7f 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -52,4 +52,5 @@ var ProviderSetController = wire.NewSet( NewMetaController, NewEmbedController, NewBadgeController, + NewRenderController, ) diff --git a/internal/controller/render_controller.go b/internal/controller/render_controller.go new file mode 100644 index 00000000..05e49d0b --- /dev/null +++ b/internal/controller/render_controller.go @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package controller + +import ( + "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/plugin" + "github.com/gin-gonic/gin" +) + +type RenderController struct { +} + +func NewRenderController() *RenderController { + return &RenderController{} +} + +// GetRenderConfig godoc +// @Summary GetRenderConfig +// @Description GetRenderConfig +// @Tags PluginRender +// @Accept json +// @Produce json +// @Router /answer/api/v1/render/config [get] +// @Success 200 {object} handler.RespBody{data=plugin.RenderConfig} +func (c *RenderController) GetRenderConfig(ctx *gin.Context) { + var resp *plugin.RenderConfig + + _ = plugin.CallRender(func(render plugin.Render) (err error) { + resp = render.GetRenderConfig(ctx) + return nil + }) + + handler.HandleResponse(ctx, nil, resp) +} diff --git a/internal/router/plugin_api_router.go b/internal/router/plugin_api_router.go index e4a85a15..e69e0b6b 100644 --- a/internal/router/plugin_api_router.go +++ b/internal/router/plugin_api_router.go @@ -29,6 +29,7 @@ type PluginAPIRouter struct { userCenterController *controller.UserCenterController captchaController *controller.CaptchaController embedController *controller.EmbedController + renderController *controller.RenderController } func NewPluginAPIRouter( @@ -36,12 +37,14 @@ func NewPluginAPIRouter( userCenterController *controller.UserCenterController, captchaController *controller.CaptchaController, embedController *controller.EmbedController, + renderController *controller.RenderController, ) *PluginAPIRouter { return &PluginAPIRouter{ connectorController: connectorController, userCenterController: userCenterController, captchaController: captchaController, embedController: embedController, + renderController: renderController, } } @@ -64,6 +67,7 @@ func (pr *PluginAPIRouter) RegisterUnAuthConnectorRouter(r *gin.RouterGroup) { // captcha plugin r.GET("/captcha/config", pr.captchaController.GetCaptchaConfig) r.GET("/embed/config", pr.embedController.GetEmbedConfig) + r.GET("/render/config", pr.renderController.GetRenderConfig) } func (pr *PluginAPIRouter) RegisterAuthUserConnectorRouter(r *gin.RouterGroup) { diff --git a/plugin/plugin.go b/plugin/plugin.go index 85286855..9c144346 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -103,6 +103,10 @@ func Register(p Base) { registerEmbed(p.(Embed)) } + if _, ok := p.(Render); ok { + registerRender(p.(Render)) + } + if _, ok := p.(CDN); ok { registerCDN(p.(CDN)) } diff --git a/plugin/render.go b/plugin/render.go new file mode 100644 index 00000000..4fc2edf6 --- /dev/null +++ b/plugin/render.go @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package plugin + +import "github.com/gin-gonic/gin" + +type RenderConfig struct { + SelectTheme string `json:"select_theme"` +} + +// select_theme + +type Render interface { + Base + GetRenderConfig(ctx *gin.Context) (renderConfig *RenderConfig) +} + +var ( + // CallReviewer is a function that calls all registered parsers + CallRender, + registerRender = MakePlugin[Render](false) +) From 6214fed8ae75ac01df5ec937348e295b032e29ed Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 23 Aug 2024 11:24:41 +0800 Subject: [PATCH 095/336] docs: Add render api --- docs/docs.go | 53 +++++++++++++++++++++++++++++++++++++++++++++-- docs/swagger.json | 53 +++++++++++++++++++++++++++++++++++++++++++++-- docs/swagger.yaml | 31 ++++++++++++++++++++++++++- 3 files changed, 132 insertions(+), 5 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index daef6851..389f3bdf 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4854,6 +4854,41 @@ const docTemplate = `{ } } }, + "/answer/api/v1/render/config": { + "get": { + "description": "GetRenderConfig", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "PluginRender" + ], + "summary": "GetRenderConfig", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/plugin.RenderConfig" + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/report": { "post": { "security": [ @@ -7420,6 +7455,14 @@ const docTemplate = `{ } } }, + "plugin.RenderConfig": { + "type": "object", + "properties": { + "select_theme": { + "type": "string" + } + } + }, "schema.AcceptAnswerReq": { "type": "object", "required": [ @@ -9257,10 +9300,16 @@ const docTemplate = `{ }, "schema.NotificationClearRequest": { "type": "object", + "required": [ + "type" + ], "properties": { "type": { - "description": "inbox achievement", - "type": "string" + "type": "string", + "enum": [ + "inbox", + "achievement" + ] } } }, diff --git a/docs/swagger.json b/docs/swagger.json index c7ad452e..3d6f07c8 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4828,6 +4828,41 @@ } } }, + "/answer/api/v1/render/config": { + "get": { + "description": "GetRenderConfig", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "PluginRender" + ], + "summary": "GetRenderConfig", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/plugin.RenderConfig" + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/report": { "post": { "security": [ @@ -7394,6 +7429,14 @@ } } }, + "plugin.RenderConfig": { + "type": "object", + "properties": { + "select_theme": { + "type": "string" + } + } + }, "schema.AcceptAnswerReq": { "type": "object", "required": [ @@ -9231,10 +9274,16 @@ }, "schema.NotificationClearRequest": { "type": "object", + "required": [ + "type" + ], "properties": { "type": { - "description": "inbox achievement", - "type": "string" + "type": "string", + "enum": [ + "inbox", + "achievement" + ] } } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 1cf29862..d2d43504 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -135,6 +135,11 @@ definitions: platform: type: string type: object + plugin.RenderConfig: + properties: + select_theme: + type: string + type: object schema.AcceptAnswerReq: properties: answer_id: @@ -1414,8 +1419,12 @@ definitions: schema.NotificationClearRequest: properties: type: - description: inbox achievement + enum: + - inbox + - achievement type: string + required: + - type type: object schema.OnCompleteAction: properties: @@ -5817,6 +5826,26 @@ paths: summary: get reasons by object type and action tags: - reason + /answer/api/v1/render/config: + get: + consumes: + - application/json + description: GetRenderConfig + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + $ref: '#/definitions/plugin.RenderConfig' + type: object + summary: GetRenderConfig + tags: + - PluginRender /answer/api/v1/report: post: consumes: From 701343e82f6b0d934f934a018332ef1df5f7f59f Mon Sep 17 00:00:00 2001 From: Jan Ernsting Date: Fri, 23 Aug 2024 09:18:56 +0200 Subject: [PATCH 096/336] Fix error on multiple make generate runs (#1087) As discussed in #1074 --------- Co-authored-by: Fen --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 9dc8c983..bcacf3e4 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,8 @@ universal: generate generate: @$(GO) get github.com/google/wire/cmd/wire@v0.5.0 @$(GO) get github.com/golang/mock/mockgen@v1.6.0 + @$(GO) get github.com/swaggo/swag/cmd/swag@v1.16.3 + @$(GO) install github.com/swaggo/swag/cmd/swag@v1.16.3 @$(GO) install github.com/google/wire/cmd/wire@v0.5.0 @$(GO) install github.com/golang/mock/mockgen@v1.6.0 @$(GO) generate ./... From 16605eafd0008ad42537ca4aacbf6e4a250c9c7e Mon Sep 17 00:00:00 2001 From: Jan Ernsting Date: Fri, 23 Aug 2024 09:18:56 +0200 Subject: [PATCH 097/336] Fix error on multiple make generate runs (#1087) As discussed in #1074 --------- Co-authored-by: Fen --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 9dc8c983..bcacf3e4 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,8 @@ universal: generate generate: @$(GO) get github.com/google/wire/cmd/wire@v0.5.0 @$(GO) get github.com/golang/mock/mockgen@v1.6.0 + @$(GO) get github.com/swaggo/swag/cmd/swag@v1.16.3 + @$(GO) install github.com/swaggo/swag/cmd/swag@v1.16.3 @$(GO) install github.com/google/wire/cmd/wire@v0.5.0 @$(GO) install github.com/golang/mock/mockgen@v1.6.0 @$(GO) generate ./... From 9082623c49a6616306260c84f99b77c1659dbb8b Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 27 Aug 2024 15:54:20 +0800 Subject: [PATCH 098/336] fix(badge): remove duplicate default badges --- internal/migrations/init.go | 21 --------------------- internal/migrations/v22.go | 5 ++++- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/internal/migrations/init.go b/internal/migrations/init.go index b74e3688..4558ef60 100644 --- a/internal/migrations/init.go +++ b/internal/migrations/init.go @@ -65,7 +65,6 @@ func (m *Mentor) InitDB() error { m.do("init version table", m.initVersionTable) m.do("init admin user", m.initAdminUser) m.do("init config", m.initConfig) - m.do("init badge", m.initBadge) m.do("init default privileges config", m.initDefaultRankPrivileges) m.do("init role", m.initRole) m.do("init power", m.initPower) @@ -128,26 +127,6 @@ func (m *Mentor) initConfig() { _, m.err = m.engine.Context(m.ctx).Insert(defaultConfigTable) } -// initBadge init badge's table and data -func (m *Mentor) initBadge() { - uniqueIDRepo := unique.NewUniqueIDRepo(&data.Data{DB: m.engine}) - _, m.err = m.engine.Context(m.ctx).Insert(defaultBadgeGroupTable) - if m.err != nil { - return - } - - for _, badge := range defaultBadgeTable { - badge.ID, m.err = uniqueIDRepo.GenUniqueIDStr(m.ctx, new(entity.Badge).TableName()) - if m.err != nil { - return - } - _, m.err = m.engine.Context(m.ctx).Insert(badge) - if m.err != nil { - return - } - } -} - func (m *Mentor) initDefaultRankPrivileges() { chooseOption := schema.DefaultPrivilegeOptions.Choose(schema.PrivilegeLevel2) for _, privilege := range chooseOption.Privileges { diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index ab7185e3..1543c6ad 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -52,11 +52,14 @@ func addBadges(ctx context.Context, x *xorm.Engine) (err error) { } for _, badge := range defaultBadgeTable { - exist, err := x.Context(ctx).Get(&entity.Badge{Name: badge.Name}) + beans := &entity.Badge{Name: badge.Name} + exist, err := x.Context(ctx).Get(beans) if err != nil { return err } if exist { + badge.ID = beans.ID + _, err = x.Context(ctx).ID(beans.ID).Update(badge) continue } badge.ID, err = uniqueIDRepo.GenUniqueIDStr(ctx, new(entity.Badge).TableName()) From 17c69c3cc55774f531ab4477e2c022b4d1d197eb Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 27 Aug 2024 16:15:10 +0800 Subject: [PATCH 099/336] fix: badges link url --- ui/src/pages/Badges/Detail/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index f8a9327a..27fe9b7e 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -71,13 +71,13 @@ const Index = () => { badges?.list?.map((item) => { const linkUrl = item.object_type === 'question' - ? `/question/${item.question_id}` + ? `/questions/${item.question_id}` : item.object_type === 'answer' - ? `/question/${item.question_id}/${item.answer_id}` + ? `/questions/${item.question_id}/${item.answer_id}` : item.object_type === 'comment' && item.answer_id - ? `/question/${item.question_id}/${item.answer_id}?commentId=${item.comment_id}` + ? `/questions/${item.question_id}/${item.answer_id}?commentId=${item.comment_id}` : item.object_type === 'comment' - ? `/question/${item.question_id}?commentId=${item.comment_id}` + ? `/questions/${item.question_id}?commentId=${item.comment_id}` : ''; return ( Date: Wed, 28 Aug 2024 15:34:40 +0800 Subject: [PATCH 100/336] refactor(badge): remove unused code --- internal/service/badge/badge_award_service.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index 02cdcf1c..0bc7be0f 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -273,13 +273,6 @@ func (bs *BadgeAwardService) GetUserRecentBadgeAwardList(ctx *gin.Context, req * return } -// validate user - -type userReq struct { - UserID string - Username string -} - func (bs *BadgeAwardService) validateUserByUsername(ctx context.Context, userName string) (userID string, err error) { var ( userInfo *schema.UserBasicInfo From 341b0ab8da56f3a5e4e6cf600e86ec71d8324f32 Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 30 Aug 2024 15:28:21 +0800 Subject: [PATCH 101/336] refactor: Remove unnecessary CSS property in Editor utils --- ui/src/components/Editor/utils/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/components/Editor/utils/index.ts b/ui/src/components/Editor/utils/index.ts index 0624418a..759033cc 100644 --- a/ui/src/components/Editor/utils/index.ts +++ b/ui/src/components/Editor/utils/index.ts @@ -98,7 +98,6 @@ export const useEditor = ({ '.cm-line': { whiteSpace: 'pre-wrap', wordWrap: 'break-word', - wordBreak: 'break-all', }, '.ͼ7, .ͼ6': { textDecoration: 'none', From 23323d9346e6189a36621b32a7792b5932352964 Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 30 Aug 2024 15:55:56 +0800 Subject: [PATCH 102/336] fix: When using base_url, some links are missing the base path --- ui/src/components/AccordionNav/index.tsx | 70 +++++++++++++------ .../Header/components/NavItems/index.tsx | 48 +++++++------ ui/src/components/QueryGroup/index.tsx | 8 ++- ui/src/components/SideNav/index.tsx | 18 ++--- 4 files changed, 86 insertions(+), 58 deletions(-) diff --git a/ui/src/components/AccordionNav/index.tsx b/ui/src/components/AccordionNav/index.tsx index 91c4d1c5..a0e666e1 100644 --- a/ui/src/components/AccordionNav/index.tsx +++ b/ui/src/components/AccordionNav/index.tsx @@ -20,7 +20,7 @@ import React, { FC, useEffect, useState } from 'react'; import { Accordion, Nav } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; -import { useNavigate, useMatch } from 'react-router-dom'; +import { useNavigate, useMatch, NavLink } from 'react-router-dom'; import classNames from 'classnames'; @@ -38,30 +38,54 @@ function MenuNode({ const { t } = useTranslation('translation', { keyPrefix: 'nav_menus' }); const isLeaf = !menu.children.length; const href = isLeaf ? `${path}${menu.path}` : '#'; - return ( - { - callback(evt, menu, href, isLeaf); - }} - href={href} - className={classNames( - 'text-nowrap d-flex flex-nowrap align-items-center w-100', - { expanding, 'link-dark': activeKey !== menu.path }, - )}> - - {menu.displayName ? menu.displayName : t(menu.name)} - - {menu.badgeContent ? ( - {menu.badgeContent} - ) : null} - {!isLeaf && ( - - )} - + {isLeaf ? ( + { + callback(evt, menu, href, isLeaf); + }} + className={classNames( + 'text-nowrap d-flex flex-nowrap align-items-center w-100', + { expanding, 'link-dark': activeKey !== menu.path }, + )}> + + {menu.displayName ? menu.displayName : t(menu.name)} + + {menu.badgeContent ? ( + {menu.badgeContent} + ) : null} + {!isLeaf && ( + + )} + + ) : ( + { + callback(evt, menu, href, isLeaf); + }} + className={classNames( + 'text-nowrap d-flex flex-nowrap align-items-center w-100', + { expanding, 'link-dark': activeKey !== menu.path }, + )}> + + {menu.displayName ? menu.displayName : t(menu.name)} + + {menu.badgeContent ? ( + {menu.badgeContent} + ) : null} + {!isLeaf && ( + + )} + + )} + {menu.children.length ? ( <> diff --git a/ui/src/components/Header/components/NavItems/index.tsx b/ui/src/components/Header/components/NavItems/index.tsx index f3368b0f..bd80729d 100644 --- a/ui/src/components/Header/components/NavItems/index.tsx +++ b/ui/src/components/Header/components/NavItems/index.tsx @@ -35,24 +35,25 @@ interface Props { const Index: FC = ({ redDot, userInfo, logOut }) => { const { t } = useTranslation(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars const navigate = useNavigate(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { agent: ucAgent } = userCenterStore(); const handleLinkClick = (evt) => { if (floppyNavigation.shouldProcessLinkClick(evt)) { evt.preventDefault(); const href = evt.currentTarget.getAttribute('href'); - navigate(href); + floppyNavigation.navigate(href, { + handler: navigate, + }); } }; return ( <> @@ -95,25 +95,31 @@ const Index: FC = ({ redDot, userInfo, logOut }) => { - 'dropdown-item'} onClick={handleLinkClick}> {t('header.nav.profile')} - - + 'dropdown-item'} onClick={handleLinkClick}> {t('header.nav.bookmark')} - - + 'dropdown-item'} onClick={handleLinkClick}> {t('header.nav.setting')} - + - logOut(e)}> + 'dropdown-item'} + onClick={(e) => logOut(e)}> {t('header.nav.logout')} - + {/* Dropdown for user center agent info */} diff --git a/ui/src/components/QueryGroup/index.tsx b/ui/src/components/QueryGroup/index.tsx index a201ae7a..9b37c6e9 100644 --- a/ui/src/components/QueryGroup/index.tsx +++ b/ui/src/components/QueryGroup/index.tsx @@ -24,6 +24,7 @@ import { useTranslation } from 'react-i18next'; import classNames from 'classnames'; +import { REACT_BASE_PATH } from '@/router/alias'; import { floppyNavigation } from '@/utils'; interface Props { @@ -82,7 +83,6 @@ const Index: FC = ({ const name = typeof btn === 'string' ? btn : btn.name; return (
From 292dfe6da70de516ca67ef3cdc592043018353d7 Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 2 Sep 2024 15:32:03 +0800 Subject: [PATCH 104/336] feat(badge): feat badge description url --- i18n/en_US.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 4de69658..1a27d804 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -539,7 +539,7 @@ backend: name: other: Autobiographer desc: - other: Filled out [profile] information. + other: Filled out profile information. certified: name: other: Certified From 90faa87e52bfee67d87e86a2426232efb906b1aa Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 28 Aug 2024 15:34:40 +0800 Subject: [PATCH 105/336] refactor(badge): remove unused code --- internal/service/badge/badge_award_service.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index 02cdcf1c..0bc7be0f 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -273,13 +273,6 @@ func (bs *BadgeAwardService) GetUserRecentBadgeAwardList(ctx *gin.Context, req * return } -// validate user - -type userReq struct { - UserID string - Username string -} - func (bs *BadgeAwardService) validateUserByUsername(ctx context.Context, userName string) (userID string, err error) { var ( userInfo *schema.UserBasicInfo From 6aa64092b625b9e8f0edb503207bd88a77335ddf Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 2 Sep 2024 15:32:03 +0800 Subject: [PATCH 106/336] feat(badge): feat badge description url --- i18n/en_US.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 032ad141..2b0a4714 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -539,7 +539,7 @@ backend: name: other: Autobiographer desc: - other: Filled out [profile] information. + other: Filled out profile information. certified: name: other: Certified From 4f80f9e97b02a7329d2c24beefe869c8a8d571aa Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 2 Sep 2024 18:12:04 +0800 Subject: [PATCH 107/336] feat(badge): badge list earned return earned total --- docs/docs.go | 6 +++--- docs/swagger.json | 6 +++--- docs/swagger.yaml | 6 +++--- internal/schema/badge_schema.go | 2 +- internal/service/badge/badge_service.go | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 389f3bdf..e5cc6f16 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -7795,7 +7795,7 @@ const docTemplate = `{ }, "earned": { "description": "badge earned count", - "type": "boolean" + "type": "integer" }, "icon": { "description": "badge icon", @@ -11472,8 +11472,8 @@ var SwaggerInfo = &swag.Spec{ Host: "", BasePath: "= \"/\"", Schemes: []string{}, - Title: "\"answer\"", - Description: "= \"answer api\"", + Title: "\"apache answer\"", + Description: "= \"apache answer api\"", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", diff --git a/docs/swagger.json b/docs/swagger.json index 3d6f07c8..5fd36907 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,8 +1,8 @@ { "swagger": "2.0", "info": { - "description": "= \"answer api\"", - "title": "\"answer\"", + "description": "= \"apache answer api\"", + "title": "\"apache answer\"", "contact": {}, "version": "= \"v0.0.1\"" }, @@ -7769,7 +7769,7 @@ }, "earned": { "description": "badge earned count", - "type": "boolean" + "type": "integer" }, "icon": { "description": "badge icon", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index d2d43504..72871edc 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -372,7 +372,7 @@ definitions: type: integer earned: description: badge earned count - type: boolean + type: integer icon: description: badge icon type: string @@ -2909,8 +2909,8 @@ definitions: type: object info: contact: {} - description: = "answer api" - title: '"answer"' + description: = "apache answer api" + title: '"apache answer"' version: = "v0.0.1" paths: /: diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index efbcd37a..1dd2e76f 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -49,7 +49,7 @@ type BadgeListInfo struct { // badge award count AwardCount int `json:"award_count" ` // badge earned count - Earned bool `json:"earned" ` + Earned int64 `json:"earned" ` // badge level Level entity.BadgeLevel `json:"level" ` } diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 031f0f15..49591adc 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -99,11 +99,11 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* for _, badge := range badges { // check is earned - earned := false + var earned int64 = 0 if len(earnedCounts) > 0 { for _, earnedCount := range earnedCounts { if badge.ID == earnedCount.BadgeID && earnedCount.EarnedCount > 0 { - earned = true + earned = earnedCount.EarnedCount break } } From 1666b9413514fc19bc24e6629927589058ea46d8 Mon Sep 17 00:00:00 2001 From: kumfo Date: Mon, 2 Sep 2024 18:26:24 +0800 Subject: [PATCH 108/336] feat(badge): badge list earned return earned total --- docs/docs.go | 2 +- docs/swagger.json | 2 +- docs/swagger.yaml | 2 +- internal/schema/badge_schema.go | 2 +- internal/service/badge/badge_service.go | 12 ++++++------ 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index e5cc6f16..a9d56ab9 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -7793,7 +7793,7 @@ const docTemplate = `{ "description": "badge award count", "type": "integer" }, - "earned": { + "earned_count": { "description": "badge earned count", "type": "integer" }, diff --git a/docs/swagger.json b/docs/swagger.json index 5fd36907..82ec1a6f 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -7767,7 +7767,7 @@ "description": "badge award count", "type": "integer" }, - "earned": { + "earned_count": { "description": "badge earned count", "type": "integer" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 72871edc..2af2900f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -370,7 +370,7 @@ definitions: award_count: description: badge award count type: integer - earned: + earned_count: description: badge earned count type: integer icon: diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index 1dd2e76f..a33fb480 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -49,7 +49,7 @@ type BadgeListInfo struct { // badge award count AwardCount int `json:"award_count" ` // badge earned count - Earned int64 `json:"earned" ` + EarnedCount int64 `json:"earned_count" ` // badge level Level entity.BadgeLevel `json:"level" ` } diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 49591adc..3ec7b5bf 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -110,12 +110,12 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* } badgesMap[badge.BadgeGroupID] = append(badgesMap[badge.BadgeGroupID], &schema.BadgeListInfo{ - ID: uid.EnShortID(badge.ID), - Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), - Icon: badge.Icon, - AwardCount: badge.AwardCount, - Earned: earned, - Level: badge.Level, + ID: uid.EnShortID(badge.ID), + Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), + Icon: badge.Icon, + AwardCount: badge.AwardCount, + EarnedCount: earned, + Level: badge.Level, }) } From 8b9f5d4448f9e4a4498631d5c6c5131f4da557d4 Mon Sep 17 00:00:00 2001 From: robin Date: Mon, 2 Sep 2024 16:35:33 +0800 Subject: [PATCH 109/336] refactor: Add links to badge names and award counts in Admin Badges page --- ui/src/pages/Admin/Badges/index.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index e76f90eb..4cadc1c3 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -19,7 +19,7 @@ import { FC } from 'react'; import { Form, Table, Stack } from 'react-bootstrap'; -import { useSearchParams } from 'react-router-dom'; +import { Link, useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import classNames from 'classnames'; @@ -126,13 +126,15 @@ const Badges: FC = () => { /> )}
-
{badge.name}
+ {badge.name}
{badge.description}
{badge.group_name} - {badge.award_count} + + {badge.award_count} + {t(badge.status)} From afaf11ffb64af31836d4d6e6f59ca2a7fb977420 Mon Sep 17 00:00:00 2001 From: robin Date: Mon, 2 Sep 2024 16:59:28 +0800 Subject: [PATCH 110/336] refactor: Update badge labels to use multiplication symbol instead of 'x' --- i18n/en_US.yaml | 4 ++-- ui/src/components/CardBadge/index.tsx | 4 ++-- ui/src/pages/Badges/Detail/components/Badge/index.tsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 2b0a4714..f7c16e64 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1748,8 +1748,8 @@ ui: confirm: View badges title: Badges awarded: Awarded - earned_x: Earned x{{ number }} - x_awarded: "{{ number }} awarded" + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" can_earn_multiple: You can earn this multiple times. earned: Earned diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index dd8c18e6..fcb1bb9d 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -57,7 +57,7 @@ const Index: FC = ({ {badgePillType === 'count' && Number(data?.earned_count) > 0 && ( - x{data.earned_count} + ×{data.earned_count} )} {data.icon.startsWith('http') ? ( @@ -78,7 +78,7 @@ const Index: FC = ({
{data.name}
{showAwardedCount && (
- {t('x_awarded', { number: formatCount(data.award_count) })} + {t('×_awarded', { number: formatCount(data.award_count) })}
)} diff --git a/ui/src/pages/Badges/Detail/components/Badge/index.tsx b/ui/src/pages/Badges/Detail/components/Badge/index.tsx index affb73e6..29da1af6 100644 --- a/ui/src/pages/Badges/Detail/components/Badge/index.tsx +++ b/ui/src/pages/Badges/Detail/components/Badge/index.tsx @@ -73,13 +73,13 @@ const Index: FC = ({ data }) => {
{data.award_count > 0 && ( - {t('x_awarded', { number: formatCount(data.award_count) })} + {t('×_awarded', { number: formatCount(data.award_count) })} )} {data.earned_count > 0 && ( - {t('earned_x', { number: data.earned_count })} + {t('earned_×', { number: data.earned_count })} )}
From 63e1da69a1b1dea1a026f7714a2b26e8356e9fbf Mon Sep 17 00:00:00 2001 From: alvin Date: Sun, 1 Sep 2024 21:32:19 +0800 Subject: [PATCH 111/336] refactor: add err handling for activeUser --- internal/service/content/user_service.go | 2 ++ .../user_external_login/user_center_login_service.go | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/service/content/user_service.go b/internal/service/content/user_service.go index 11f3bb63..974151a5 100644 --- a/internal/service/content/user_service.go +++ b/internal/service/content/user_service.go @@ -527,6 +527,7 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri } if err = us.userActivity.UserActive(ctx, userInfo.ID); err != nil { log.Error(err) + return nil, err } // In the case of three-party login, the associated users are bound @@ -660,6 +661,7 @@ func (us *UserService) UserChangeEmailVerify(ctx context.Context, content string if userInfo.MailStatus == entity.EmailStatusToBeVerified { if err = us.userActivity.UserActive(ctx, userInfo.ID); err != nil { log.Error(err) + return nil, err } } diff --git a/internal/service/user_external_login/user_center_login_service.go b/internal/service/user_external_login/user_center_login_service.go index 6089d626..5ff47bce 100644 --- a/internal/service/user_external_login/user_center_login_service.go +++ b/internal/service/user_external_login/user_center_login_service.go @@ -129,7 +129,9 @@ func (us *UserCenterLoginService) ExternalLogin( return nil, err } - us.activeUser(ctx, oldUserInfo) + if err := us.activeUser(ctx, oldUserInfo); err != nil { + return nil, err + } accessToken, _, err := us.userCommonService.CacheLoginUserInfo( ctx, oldUserInfo.ID, oldUserInfo.MailStatus, oldUserInfo.Status, oldExternalLoginUserInfo.ExternalID) @@ -181,10 +183,12 @@ func (us *UserCenterLoginService) registerNewUser(ctx context.Context, provider return userInfo, nil } -func (us *UserCenterLoginService) activeUser(ctx context.Context, oldUserInfo *entity.User) { +func (us *UserCenterLoginService) activeUser(ctx context.Context, oldUserInfo *entity.User) error { if err := us.userActivity.UserActive(ctx, oldUserInfo.ID); err != nil { log.Error(err) + return err } + return nil } func (us *UserCenterLoginService) UserCenterUserSettings(ctx context.Context, userID string) ( From ca8c4b40c653858dbcd3ad70e6c1790577bf755d Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 3 Sep 2024 11:05:03 +0800 Subject: [PATCH 112/336] refactor: Update badge labels to use multiplication symbol instead of 'x' --- ui/src/components/CardBadge/index.tsx | 10 ++++++---- ui/src/pages/Badges/Detail/components/Badge/index.tsx | 5 ++++- .../pages/Users/Personal/components/NavBar/index.tsx | 1 - 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index fcb1bb9d..a2a0bd7d 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -49,14 +49,16 @@ const Index: FC = ({ className="card text-center badge-card" to={`/badges/${data.id}${urlSearchParams ? `?${urlSearchParams}` : ''}`}> - {data.earned && badgePillType === 'earned' && ( + {Number(data?.earned_count) > 0 && badgePillType === 'earned' && ( - {t('earned')} + {`${t('earned')}${ + Number(data?.earned_count) > 1 ? ` ×${data.earned_count}` : '' + }`} )} - {badgePillType === 'count' && Number(data?.earned_count) > 0 && ( - + {badgePillType === 'count' && Number(data?.earned_count) > 1 && ( + ×{data.earned_count} )} diff --git a/ui/src/pages/Badges/Detail/components/Badge/index.tsx b/ui/src/pages/Badges/Detail/components/Badge/index.tsx index 29da1af6..a554a6bc 100644 --- a/ui/src/pages/Badges/Detail/components/Badge/index.tsx +++ b/ui/src/pages/Badges/Detail/components/Badge/index.tsx @@ -77,11 +77,14 @@ const Index: FC = ({ data }) => {
)} - {data.earned_count > 0 && ( + {data.earned_count > 1 && ( {t('earned_×', { number: data.earned_count })} )} + {data.earned_count === 1 && ( + {t('earned')} + )}
)}
diff --git a/ui/src/pages/Users/Personal/components/NavBar/index.tsx b/ui/src/pages/Users/Personal/components/NavBar/index.tsx index 5f4360ed..9c6d157a 100644 --- a/ui/src/pages/Users/Personal/components/NavBar/index.tsx +++ b/ui/src/pages/Users/Personal/components/NavBar/index.tsx @@ -60,7 +60,6 @@ const list = [ name: 'votes', }, { - role: 'self', // Only visible to author path: '/badges', name: 'badges', }, From d72cf56b8c4d2827977547cbc3f19fed9b1401f0 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 3 Sep 2024 11:58:57 +0800 Subject: [PATCH 113/336] refactor: Add text truncation to TopList component link --- ui/src/pages/Users/Personal/components/TopList/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/pages/Users/Personal/components/TopList/index.tsx b/ui/src/pages/Users/Personal/components/TopList/index.tsx index 04553428..aa896caf 100644 --- a/ui/src/pages/Users/Personal/components/TopList/index.tsx +++ b/ui/src/pages/Users/Personal/components/TopList/index.tsx @@ -38,6 +38,7 @@ const Index: FC = ({ data, type }) => { className={`${index === data.length - 1 ? '' : 'mb-2'}`} key={type === 'answer' ? item.answer_id : item.question_id}> Date: Tue, 3 Sep 2024 12:28:01 +0800 Subject: [PATCH 114/336] refactor: Update badge description rendering in Admin Badges page --- ui/src/pages/Admin/Badges/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 4cadc1c3..29661714 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -127,7 +127,12 @@ const Badges: FC = () => { )}
{badge.name} -
{badge.description}
+
From 41d63bd245cd59b3866c94bcd67c9dab6e02a192 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 3 Sep 2024 14:16:17 +0800 Subject: [PATCH 115/336] feat(badge): delete red dot when no unread notification --- .../repo/notification/notification_repo.go | 8 ++++++ .../notification/notification_service.go | 25 ++++++++++++++----- .../notification_common/notification.go | 15 +++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/internal/repo/notification/notification_repo.go b/internal/repo/notification/notification_repo.go index bd325ef2..5a2a6cc7 100644 --- a/internal/repo/notification/notification_repo.go +++ b/internal/repo/notification/notification_repo.go @@ -129,3 +129,11 @@ func (nr *notificationRepo) GetNotificationPage(ctx context.Context, searchCond } return } + +func (nr *notificationRepo) CountNotificationByUser(ctx context.Context, cond *entity.Notification) (int64, error) { + count, err := nr.data.DB.Context(ctx).Count(cond) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return count, err +} diff --git a/internal/service/notification/notification_service.go b/internal/service/notification/notification_service.go index b73d4fda..be2963fe 100644 --- a/internal/service/notification/notification_service.go +++ b/internal/service/notification/notification_service.go @@ -23,12 +23,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/internal/service/report_common" - "github.com/apache/incubator-answer/internal/service/review" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/base/handler" @@ -36,8 +30,13 @@ import ( "github.com/apache/incubator-answer/internal/base/translator" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/badge" notficationcommon "github.com/apache/incubator-answer/internal/service/notification_common" + "github.com/apache/incubator-answer/internal/service/report_common" + "github.com/apache/incubator-answer/internal/service/review" "github.com/apache/incubator-answer/internal/service/revision_common" + usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/incubator-answer/pkg/converter" "github.com/apache/incubator-answer/pkg/uid" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/log" @@ -203,6 +202,20 @@ func (ns *NotificationService) ClearIDUnRead(ctx context.Context, userID string, if err != nil { log.Errorf("remove badge award alert cache failed: %v", err) } + + amount, err := ns.notificationRepo.CountNotificationByUser(ctx, &entity.Notification{ + UserID: userID, + Type: notificationInfo.Type, + IsRead: schema.NotificationNotRead, + Status: schema.NotificationStatusNormal, + }) + if err != nil { + log.Errorf("count notification failed: %v", err) + return nil + } + if amount == 0 { + _ = ns.notificationCommon.DeleteRedDot(ctx, userID, notificationInfo.Type) + } return nil } diff --git a/internal/service/notification_common/notification.go b/internal/service/notification_common/notification.go index a3129b3a..f3732fcf 100644 --- a/internal/service/notification_common/notification.go +++ b/internal/service/notification_common/notification.go @@ -54,6 +54,7 @@ type NotificationRepo interface { GetByUserIdObjectIdTypeId(ctx context.Context, userID, objectID string, notificationType int) (*entity.Notification, bool, error) UpdateNotificationContent(ctx context.Context, notification *entity.Notification) (err error) GetById(ctx context.Context, id string) (*entity.Notification, bool, error) + CountNotificationByUser(ctx context.Context, cond *entity.Notification) (int64, error) } type NotificationCommon struct { @@ -226,6 +227,20 @@ func (ns *NotificationCommon) addRedDot(ctx context.Context, userID string, noti return nil } +func (ns *NotificationCommon) DeleteRedDot(ctx context.Context, userID string, notificationType int) error { + var key string + if notificationType == schema.NotificationTypeInbox { + key = fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeInbox, userID) + } else { + key = fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeAchievement, userID) + } + err := ns.data.Cache.Del(ctx, key) + if err != nil { + return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + return nil +} + // AddBadgeAwardAlertCache add badge award alert cache func (ns *NotificationCommon) AddBadgeAwardAlertCache(ctx context.Context, userID, notificationID, badgeID string) (err error) { key := fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeBadgeAchievement, userID) From 8a31d29ce7ddea8a256f92dbf2cef2b0da20413f Mon Sep 17 00:00:00 2001 From: lhpqaq <657407891@qq.com> Date: Tue, 3 Sep 2024 12:48:47 +0800 Subject: [PATCH 116/336] Fix ListNewestEarned in high version MySQL --- internal/repo/badge_award/badge_award_repo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 377677d1..3a04fd22 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -139,7 +139,7 @@ func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeI func (r *badgeAwardRepo) ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) { badgeAwards = make([]*entity.BadgeAwardRecent, 0) err = r.data.DB.Context(ctx). - Select("user_id, badge_id, max(created_at) created,count(*) earned_count"). + Select("any_value(user_id), badge_id, max(created_at) created,count(*) earned_count"). Where("user_id = ? AND is_badge_deleted = ? ", userID, entity.IsBadgeNotDeleted). GroupBy("badge_id"). OrderBy("created desc"). From 70acbe38e053863e02ab033ea7b896a7636f0352 Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 3 Sep 2024 14:34:58 +0800 Subject: [PATCH 117/336] fix: styles --- ui/src/components/CardBadge/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index a2a0bd7d..214e3f5d 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -79,7 +79,7 @@ const Index: FC = ({
{data.name}
{showAwardedCount && ( -
+
{t('×_awarded', { number: formatCount(data.award_count) })}
)} From 832fa688392a34627f20c6746a9b5afba4621039 Mon Sep 17 00:00:00 2001 From: SantiagoLiendro <126113529+SantiagoLiendro@users.noreply.github.com> Date: Wed, 14 Aug 2024 19:04:27 -0300 Subject: [PATCH 118/336] change in the display of emoticons --- ui/src/pages/Questions/Detail/components/Reactions/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Questions/Detail/components/Reactions/index.tsx b/ui/src/pages/Questions/Detail/components/Reactions/index.tsx index f1c84295..a98f2fd0 100644 --- a/ui/src/pages/Questions/Detail/components/Reactions/index.tsx +++ b/ui/src/pages/Questions/Detail/components/Reactions/index.tsx @@ -110,7 +110,7 @@ const Index: FC = ({ return (
{showAddCommentBtn && ( From fec34ae974f30b4707dce507a13d307d8333096a Mon Sep 17 00:00:00 2001 From: kumfo Date: Tue, 3 Sep 2024 14:43:35 +0800 Subject: [PATCH 119/336] feat(badge): delete useless field --- internal/entity/badge_award_entity.go | 1 - internal/repo/badge_award/badge_award_repo.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 5ba475cd..f18138be 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -57,7 +57,6 @@ func (BadgeEarnedCount) TableName() string { type BadgeAwardRecent struct { Created time.Time `xorm:"created"` - UserID string `xorm:"user_id"` BadgeID string `xorm:"badge_id"` AwardKey string `xorm:"award_key"` EarnedCount int64 `xorm:"earned_count"` diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 3a04fd22..64615d6d 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -139,7 +139,7 @@ func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeI func (r *badgeAwardRepo) ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) { badgeAwards = make([]*entity.BadgeAwardRecent, 0) err = r.data.DB.Context(ctx). - Select("any_value(user_id), badge_id, max(created_at) created,count(*) earned_count"). + Select("badge_id, max(created_at) created,count(*) earned_count"). Where("user_id = ? AND is_badge_deleted = ? ", userID, entity.IsBadgeNotDeleted). GroupBy("badge_id"). OrderBy("created desc"). From 86cde0e983da102f6bdb4be4ced05967ce40a668 Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 3 Sep 2024 14:45:13 +0800 Subject: [PATCH 120/336] fix: style --- ui/src/pages/Questions/Detail/components/Reactions/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Questions/Detail/components/Reactions/index.tsx b/ui/src/pages/Questions/Detail/components/Reactions/index.tsx index a98f2fd0..8fa09509 100644 --- a/ui/src/pages/Questions/Detail/components/Reactions/index.tsx +++ b/ui/src/pages/Questions/Detail/components/Reactions/index.tsx @@ -110,7 +110,7 @@ const Index: FC = ({ return (
{showAddCommentBtn && ( From a36d2e810d84835ae17c9b01787b756814fe188d Mon Sep 17 00:00:00 2001 From: kumfo Date: Tue, 3 Sep 2024 14:43:35 +0800 Subject: [PATCH 121/336] feat(badge): delete useless field --- internal/entity/badge_award_entity.go | 1 - internal/repo/badge_award/badge_award_repo.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 5ba475cd..f18138be 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -57,7 +57,6 @@ func (BadgeEarnedCount) TableName() string { type BadgeAwardRecent struct { Created time.Time `xorm:"created"` - UserID string `xorm:"user_id"` BadgeID string `xorm:"badge_id"` AwardKey string `xorm:"award_key"` EarnedCount int64 `xorm:"earned_count"` diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 3a04fd22..64615d6d 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -139,7 +139,7 @@ func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context, badgeI func (r *badgeAwardRepo) ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) { badgeAwards = make([]*entity.BadgeAwardRecent, 0) err = r.data.DB.Context(ctx). - Select("any_value(user_id), badge_id, max(created_at) created,count(*) earned_count"). + Select("badge_id, max(created_at) created,count(*) earned_count"). Where("user_id = ? AND is_badge_deleted = ? ", userID, entity.IsBadgeNotDeleted). GroupBy("badge_id"). OrderBy("created desc"). From a2c725abbbbd6d17639efd7b42c9fe2c1cd14a27 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 3 Sep 2024 14:30:49 +0800 Subject: [PATCH 122/336] refactor: Update BadgeOperation component to conditionally render dropdown items based on badge status --- ui/src/pages/Admin/Badges/components/Action/index.tsx | 11 ++++++++--- ui/src/pages/Admin/Badges/index.tsx | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ui/src/pages/Admin/Badges/components/Action/index.tsx b/ui/src/pages/Admin/Badges/components/Action/index.tsx index b5bf8ddd..023e626f 100644 --- a/ui/src/pages/Admin/Badges/components/Action/index.tsx +++ b/ui/src/pages/Admin/Badges/components/Action/index.tsx @@ -23,9 +23,10 @@ import { useTranslation } from 'react-i18next'; import { Icon } from '@/components'; interface Props { + status: string; onSelect: (eventKey: string | null) => void; } -const BadgeOperation = ({ onSelect }: Props) => { +const BadgeOperation = ({ onSelect, status }: Props) => { const { t } = useTranslation('translation', { keyPrefix: 'admin.badges' }); return ( @@ -35,8 +36,12 @@ const BadgeOperation = ({ onSelect }: Props) => { - {t('active')} - {t('deactivate')} + {status === 'inactive' && ( + {t('active')} + )} + {status === 'active' && ( + {t('deactivate')} + )} diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 29661714..9a86eed9 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -146,6 +146,7 @@ const Badges: FC = () => { handleBadgeStatus(badge.id, status)} /> From daab3eebee5e4bd8776a9424ae5f651ed7c38cae Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 3 Sep 2024 15:03:28 +0800 Subject: [PATCH 123/336] feat: Add animation to badgeModal --- ui/src/components/Modal/BadgeModal.tsx | 40 +++++- ui/src/components/Modal/Modal.tsx | 3 + ui/src/utils/animateGift.ts | 183 +++++++++++++++++++++++++ ui/src/utils/progress.ts | 77 +++++++++++ 4 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 ui/src/utils/animateGift.ts create mode 100644 ui/src/utils/progress.ts diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index 468c7f89..303c9677 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -17,7 +17,7 @@ * under the License. */ -import { FC } from 'react'; +import { FC, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; @@ -26,6 +26,7 @@ import classNames from 'classnames'; import type * as Type from '@/common/interface'; import { loggedUserInfoStore } from '@/stores'; import { readNotification, useQueryNotificationStatus } from '@/services'; +import AnimateGift from '@/utils/animateGift'; import Icon from '../Icon'; import Modal from './Modal'; @@ -34,6 +35,10 @@ interface BadgeModalProps { badge?: Type.NotificationBadgeAward | null; visible: boolean; } + +let bg1: AnimateGift; +let bg2: AnimateGift; +let timeout: NodeJS.Timeout; const BadgeModal: FC = ({ badge, visible }) => { const { t } = useTranslation('translation', { keyPrefix: 'badges.modal' }); const { user } = loggedUserInfoStore(); @@ -47,6 +52,9 @@ const BadgeModal: FC = ({ badge, visible }) => { ...data, badge_award: null, }); + clearTimeout(timeout); + bg1?.destroy(); + bg2?.destroy(); }; const handleCancel = async () => { await handle(); @@ -58,8 +66,38 @@ const BadgeModal: FC = ({ badge, visible }) => { navigate(url); }; + useEffect(() => { + const DURATION = 8000; + const LENGTH = 200; + const bgNode = document.documentElement || document.body; + + if (visible) { + const paranetNode = document.getElementById('badgeModal')?.parentNode; + + bg1 = new AnimateGift({ + elm: paranetNode, + width: bgNode.clientWidth, + height: bgNode.clientHeight, + length: LENGTH, + duration: DURATION, + isLoop: true, + }); + + timeout = setTimeout(() => { + bg2 = new AnimateGift({ + elm: paranetNode, + width: window.innerWidth, + height: window.innerHeight, + length: LENGTH, + duration: DURATION, + }); + }, DURATION / 2); + } + }, [visible]); + return ( = ({ + id = '', title = 'title', visible = false, centered = true, @@ -63,6 +65,7 @@ const Index: FC = ({ const { t } = useTranslation(); return ( = 1 && this.isLoop) { + this.start(now); + } + + return this.progress; + } + return 0; + } +} + +export default Progress; From 052b78be28622fb3452698e91137aab52b24923f Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 4 Sep 2024 10:08:07 +0800 Subject: [PATCH 124/336] fix(badge): remove red dot only when the badge notification has been read --- .../notification/notification_service.go | 18 ++-------- .../notification_common/notification.go | 36 ++++++++++++++++++- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/internal/service/notification/notification_service.go b/internal/service/notification/notification_service.go index be2963fe..0860c894 100644 --- a/internal/service/notification/notification_service.go +++ b/internal/service/notification/notification_service.go @@ -163,9 +163,7 @@ func (ns *NotificationService) countAllReviewAmount(ctx context.Context, req *sc } func (ns *NotificationService) ClearRedDot(ctx context.Context, req *schema.NotificationClearRequest) (*schema.RedDot, error) { - key := fmt.Sprintf(constant.RedDotCacheKey, req.NotificationType, req.UserID) - _ = ns.data.Cache.Del(ctx, key) - + _ = ns.notificationCommon.DeleteRedDot(ctx, req.UserID, schema.NotificationType[req.NotificationType]) resp := &schema.GetRedDot{} _ = copier.Copy(resp, req) return ns.GetRedDot(ctx, resp) @@ -203,19 +201,7 @@ func (ns *NotificationService) ClearIDUnRead(ctx context.Context, userID string, log.Errorf("remove badge award alert cache failed: %v", err) } - amount, err := ns.notificationRepo.CountNotificationByUser(ctx, &entity.Notification{ - UserID: userID, - Type: notificationInfo.Type, - IsRead: schema.NotificationNotRead, - Status: schema.NotificationStatusNormal, - }) - if err != nil { - log.Errorf("count notification failed: %v", err) - return nil - } - if amount == 0 { - _ = ns.notificationCommon.DeleteRedDot(ctx, userID, notificationInfo.Type) - } + _ = ns.notificationCommon.DecreaseRedDot(ctx, userID, notificationInfo.Type) return nil } diff --git a/internal/service/notification_common/notification.go b/internal/service/notification_common/notification.go index f3732fcf..9d08e258 100644 --- a/internal/service/notification_common/notification.go +++ b/internal/service/notification_common/notification.go @@ -220,10 +220,44 @@ func (ns *NotificationCommon) addRedDot(ctx context.Context, userID string, noti } else { key = fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeAchievement, userID) } - err := ns.data.Cache.SetInt64(ctx, key, 1, constant.RedDotCacheTime) + _, exist, err := ns.data.Cache.GetInt64(ctx, key) if err != nil { return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() } + if exist { + if _, err := ns.data.Cache.Increase(ctx, key, 1); err != nil { + return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + return nil + } + err = ns.data.Cache.SetInt64(ctx, key, 1, constant.RedDotCacheTime) + if err != nil { + return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + return nil +} + +func (ns *NotificationCommon) DecreaseRedDot(ctx context.Context, userID string, notificationType int) error { + var key string + if notificationType == schema.NotificationTypeInbox { + key = fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeInbox, userID) + } else { + key = fmt.Sprintf(constant.RedDotCacheKey, constant.NotificationTypeAchievement, userID) + } + _, exist, err := ns.data.Cache.GetInt64(ctx, key) + if err != nil { + return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + if !exist { + return nil + } + res, err := ns.data.Cache.Decrease(ctx, key, 1) + if err != nil { + return errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + if res <= 0 { + return ns.DeleteRedDot(ctx, userID, notificationType) + } return nil } From eacb79e5120f46267b78c4713358ab7bef9e8d79 Mon Sep 17 00:00:00 2001 From: ferrischi201 Date: Thu, 18 Jul 2024 14:40:03 -0400 Subject: [PATCH 125/336] feat(recommend): add tag-based recommendations in question page Filter out deleted or hidden questions and support multi databases and filter out deleted or hidden questions. For issue:1003. --- cmd/wire_gen.go | 4 +- go.mod | 4 +- go.sum | 9 +- i18n/en_US.yaml | 1 + i18n/no_NO.yaml | 1 + internal/controller/question_controller.go | 15 ++ .../repo/activity_common/activity_repo.go | 13 ++ internal/repo/question/question_repo.go | 51 +++++ internal/repo/repo_test/recommend_test.go | 215 ++++++++++++++++++ internal/router/answer_api_router.go | 1 + internal/schema/question_schema.go | 2 +- internal/service/activity_common/activity.go | 1 + internal/service/content/question_service.go | 53 ++++- internal/service/question_common/question.go | 1 + ui/src/common/interface.ts | 1 + ui/src/components/QuestionList/index.tsx | 6 +- ui/src/pages/Questions/index.tsx | 12 +- ui/src/pages/Tags/Detail/index.tsx | 1 + ui/src/services/client/question.ts | 15 ++ 19 files changed, 391 insertions(+), 15 deletions(-) create mode 100644 internal/repo/repo_test/recommend_test.go diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 4928a122..31e6d94e 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -189,12 +189,13 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, rateLimitMiddleware := middleware.NewRateLimitMiddleware(limitRepo) commentController := controller.NewCommentController(commentService, rankService, captchaService, rateLimitMiddleware) reportRepo := report.NewReportRepo(dataData, uniqueIDRepo) + tagService := tag2.NewTagService(tagRepo, tagCommonService, revisionService, followRepo, siteInfoCommonService, activityQueueService) answerActivityRepo := activity.NewAnswerActivityRepo(dataData, activityRepo, userRankRepo, notificationQueueService) answerActivityService := activity2.NewAnswerActivityService(answerActivityRepo, configService) externalNotificationService := notification.NewExternalNotificationService(dataData, userNotificationConfigRepo, followRepo, emailService, userRepo, externalNotificationQueueService, userExternalLoginRepo, siteInfoCommonService) reviewRepo := review.NewReviewRepo(dataData) reviewService := review2.NewReviewService(reviewRepo, objService, userCommon, userRepo, questionRepo, answerRepo, userRoleRelService, externalNotificationQueueService, tagCommonService, questionCommon, notificationQueueService, siteInfoCommonService) - questionService := content.NewQuestionService(questionRepo, answerRepo, tagCommonService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService) + questionService := content.NewQuestionService(activityRepo, questionRepo, answerRepo, tagCommonService, tagService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService) answerService := content.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService, reviewService) reportHandle := report_handle.NewReportHandle(questionService, answerService, commentService) reportService := report2.NewReportService(reportRepo, objService, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService) @@ -202,7 +203,6 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, contentVoteRepo := activity.NewVoteRepo(dataData, activityRepo, userRankRepo, notificationQueueService) voteService := content.NewVoteService(contentVoteRepo, configService, questionRepo, answerRepo, commentCommonRepo, objService) voteController := controller.NewVoteController(voteService, rankService, captchaService) - tagService := tag2.NewTagService(tagRepo, tagCommonService, revisionService, followRepo, siteInfoCommonService, activityQueueService) tagController := controller.NewTagController(tagService, tagCommonService, rankService) followFollowRepo := activity.NewFollowRepo(dataData, uniqueIDRepo, activityRepo) followService := follow.NewFollowService(followFollowRepo, followRepo, tagCommonRepo) diff --git a/go.mod b/go.mod index 036a2b42..8b886a09 100644 --- a/go.mod +++ b/go.mod @@ -147,8 +147,8 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.8.0 // indirect - go.uber.org/zap v1.23.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.24.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/sys v0.18.0 // indirect diff --git a/go.sum b/go.sum index fb49b88b..ead9468d 100644 --- a/go.sum +++ b/go.sum @@ -752,21 +752,20 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index a123d70d..eebfde2a 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1290,6 +1290,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified diff --git a/i18n/no_NO.yaml b/i18n/no_NO.yaml index c91f56b0..859f1cea 100644 --- a/i18n/no_NO.yaml +++ b/i18n/no_NO.yaml @@ -859,6 +859,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 1b0dee92..725a24af 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -340,6 +340,21 @@ func (qc *QuestionController) QuestionPage(ctx *gin.Context) { handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions)) } +func (qc *QuestionController) QuestionRecommendPage(ctx *gin.Context) { + req := &schema.QuestionPageReq{} + if handler.BindAndCheck(ctx, req) { + return + } + req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx) + + questions, total, err := qc.questionService.GetRecommendQuestionPage(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions)) +} + // AddQuestion add question // @Summary add question // @Description add question diff --git a/internal/repo/activity_common/activity_repo.go b/internal/repo/activity_common/activity_repo.go index 70f49962..9f0a59e4 100644 --- a/internal/repo/activity_common/activity_repo.go +++ b/internal/repo/activity_common/activity_repo.go @@ -107,6 +107,19 @@ func (ar *ActivityRepo) GetActivity(ctx context.Context, session *xorm.Session, return } +func (ar *ActivityRepo) GetUserActivitysByActivityType(ctx context.Context, userID string, activityType int) ( + activityList []*entity.Activity, err error) { + activityList = make([]*entity.Activity, 0) + err = ar.data.DB.Context(ctx).Where("user_id = ?", userID). + And("activity_type = ?", activityType). + And("cancelled = 0"). + Find(&activityList) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + func (ar *ActivityRepo) GetUserIDObjectIDActivitySum(ctx context.Context, userID, objectID string) (int, error) { sum := &entity.ActivityRankSum{} _, err := ar.data.DB.Context(ctx).Table(entity.Activity{}.TableName()). diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 83a84157..aa3694d0 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -401,6 +401,57 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, return questionList, total, err } +// GetRecommendQuestionPageByTags get recommend question page by tags +func (qr *questionRepo) GetRecommendQuestionPageByTags(ctx context.Context, userID string, tagIDs, followedQuestionIDs []string, page, pageSize int) ( + questionList []*entity.Question, total int64, err error) { + questionList = make([]*entity.Question, 0) + orderBySQL := "question.pin DESC, question.created_at DESC" + + // Please Make sure every question has at least one tag + session := qr.data.DB.Context(ctx).Select(entity.Question{}.TableName() + ".*") + + if len(tagIDs) > 0 { + session.Where("question.user_id != ?", userID). + And("question.id NOT IN (SELECT question_id FROM answer WHERE user_id = ?)", userID). + Join("INNER", "tag_rel", "question.id = tag_rel.object_id"). + And("tag_rel.status = ?", entity.TagRelStatusAvailable). + Join("INNER", "tag", "tag.id = tag_rel.tag_id"). + In("tag.id", tagIDs) + } else if len(followedQuestionIDs) == 0 { + return questionList, 0, nil + } + + if len(followedQuestionIDs) > 0 { + idStr := "'" + strings.Join(followedQuestionIDs, "','") + "'" + orderBySQL = fmt.Sprintf("CASE WHEN question.id IN (%s) THEN 0 ELSE 1 END, ", idStr) + orderBySQL + if len(tagIDs) > 0 { + // if tags provided, show followed questions and tag questions + session.Or(builder.In("question.id", followedQuestionIDs)) + } else { + // if no tags, only show followed questions + session.Where(builder.In("question.id", followedQuestionIDs)) + } + } + + session. + And("question.show = ? and question.status = ?", entity.QuestionShow, entity.QuestionStatusAvailable). + Distinct("question.id"). + OrderBy(orderBySQL) + + total, err = pager.Help(page, pageSize, &questionList, &entity.Question{}, session) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + + if handler.GetEnableShortID(ctx) { + for _, item := range questionList { + item.ID = uid.EnShortID(item.ID) + } + } + + return questionList, total, err +} + func (qr *questionRepo) AdminQuestionPage(ctx context.Context, search *schema.AdminQuestionPageReq) ([]*entity.Question, int64, error) { var ( count int64 diff --git a/internal/repo/repo_test/recommend_test.go b/internal/repo/repo_test/recommend_test.go new file mode 100644 index 00000000..6c87dfe7 --- /dev/null +++ b/internal/repo/repo_test/recommend_test.go @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package repo_test + +import ( + "context" + "testing" + + "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/repo/activity" + "github.com/apache/incubator-answer/internal/repo/activity_common" + "github.com/apache/incubator-answer/internal/repo/config" + "github.com/apache/incubator-answer/internal/repo/question" + "github.com/apache/incubator-answer/internal/repo/tag" + "github.com/apache/incubator-answer/internal/repo/tag_common" + "github.com/apache/incubator-answer/internal/repo/unique" + "github.com/apache/incubator-answer/internal/repo/user" + config2 "github.com/apache/incubator-answer/internal/service/config" + "github.com/stretchr/testify/assert" +) + +func Test_questionRepo_GetRecommend(t *testing.T) { + var ( + uniqueIDRepo = unique.NewUniqueIDRepo(testDataSource) + questionRepo = question.NewQuestionRepo(testDataSource, uniqueIDRepo) + userRepo = user.NewUserRepo(testDataSource) + tagRelRepo = tag.NewTagRelRepo(testDataSource, uniqueIDRepo) + tagRepo = tag.NewTagRepo(testDataSource, uniqueIDRepo) + tagCommenRepo = tag_common.NewTagCommonRepo(testDataSource, uniqueIDRepo) + configRepo = config.NewConfigRepo(testDataSource) + configService = config2.NewConfigService(configRepo) + activityCommonRepo = activity_common.NewActivityRepo(testDataSource, uniqueIDRepo, configService) + followRepo = activity.NewFollowRepo(testDataSource, uniqueIDRepo, activityCommonRepo) + ) + + // create question and user + user := &entity.User{ + Username: "ferrischi201", + Pass: "ferrischi201", + EMail: "ferrischi201@example.com", + MailStatus: entity.EmailStatusAvailable, + Status: entity.UserStatusAvailable, + DisplayName: "ferrischi201", + IsAdmin: false, + } + err := userRepo.AddUser(context.TODO(), user) + assert.NoError(t, err) + assert.NotEqual(t, "", user.ID) + + questions := make([]*entity.Question, 0) + // tag, unjoin, unfollow + questions = append(questions, &entity.Question{ + UserID: "1", + Title: "Valid recommendation 1", + OriginalText: "A go question", + ParsedText: "Go question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + // tag, unjoin, follow + questions = append(questions, &entity.Question{ + UserID: "1", + Title: "Valid recommendation 2", + OriginalText: "A go question", + ParsedText: "Go question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + // tag, join, unfollow + questions = append(questions, &entity.Question{ + UserID: user.ID, + Title: "Invalid recommendation 1", + OriginalText: "A go question 1", + ParsedText: "Go question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + // tag, join, follow + questions = append(questions, &entity.Question{ + UserID: user.ID, + Title: "Valid recommendation 3", + OriginalText: "A java question", + ParsedText: "Java question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + // untag, unjoin, unfollow + questions = append(questions, &entity.Question{ + UserID: "1", + Title: "Invalid recommendation 2", + OriginalText: "A go question", + ParsedText: "Go question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + // untag, unjoin, follow + questions = append(questions, &entity.Question{ + UserID: "1", + Title: "Valid recommendation 4", + OriginalText: "A go question", + ParsedText: "Go question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + // untag, join, unfollow + questions = append(questions, &entity.Question{ + UserID: user.ID, + Title: "Invalid recommendation 3", + OriginalText: "A go question 1", + ParsedText: "Go question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + // untag, join, follow + questions = append(questions, &entity.Question{ + UserID: user.ID, + Title: "Valid recommendation 5", + OriginalText: "A java question", + ParsedText: "Java question", + Status: entity.QuestionStatusAvailable, + Show: entity.QuestionShow, + }) + + for _, question := range questions { + err = questionRepo.AddQuestion(context.TODO(), question) + assert.NoError(t, err) + assert.NotEqual(t, "", question.ID) + } + + tags := []*entity.Tag{ + { + SlugName: "go", + DisplayName: "Golang", + OriginalText: "golang", + ParsedText: "

golang

", + Status: entity.TagStatusAvailable, + }, + { + SlugName: "java", + DisplayName: "Java", + OriginalText: "java", + ParsedText: "

java

", + Status: entity.TagStatusAvailable, + }, + } + err = tagCommenRepo.AddTagList(context.TODO(), tags) + assert.NoError(t, err) + + tagRels := make([]*entity.TagRel, 0) + for i, question := range questions { + tagRel := &entity.TagRel{ + TagID: tags[i/4].ID, + ObjectID: question.ID, + Status: entity.TagRelStatusAvailable, + } + tagRels = append(tagRels, tagRel) + } + err = tagRelRepo.AddTagRelList(context.TODO(), tagRels) + assert.NoError(t, err) + + followQuestionIDs := make([]string, 0) + for i := range questions { + if i%2 == 0 { + continue + } + err = followRepo.Follow(context.TODO(), questions[i].ID, user.ID) + assert.NoError(t, err) + followQuestionIDs = append(followQuestionIDs, questions[i].ID) + } + + // get recommend + questionList, total, err := questionRepo.GetRecommendQuestionPageByTags(context.TODO(), user.ID, []string{tags[0].ID}, followQuestionIDs, 1, 20) + assert.NoError(t, err) + assert.Equal(t, int64(5), total) + assert.Equal(t, 5, len(questionList)) + + // recovery + t.Cleanup(func() { + tagRelIDs := make([]int64, 0) + for i, tagRel := range tagRels { + if i%2 == 1 { + err = followRepo.FollowCancel(context.TODO(), questions[i].ID, user.ID) + assert.NoError(t, err) + } + tagRelIDs = append(tagRelIDs, tagRel.ID) + } + err = tagRelRepo.RemoveTagRelListByIDs(context.TODO(), tagRelIDs) + assert.NoError(t, err) + for _, tag := range tags { + err = tagRepo.RemoveTag(context.TODO(), tag.ID) + assert.NoError(t, err) + } + for _, q := range questions { + err = questionRepo.RemoveQuestion(context.TODO(), q.ID) + assert.NoError(t, err) + } + }) +} diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index 32854186..4434a8d6 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -159,6 +159,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) { r.GET("/question/info", a.questionController.GetQuestion) r.GET("/question/invite", a.questionController.GetQuestionInviteUserInfo) r.GET("/question/page", a.questionController.QuestionPage) + r.GET("/question/recommend/page", a.questionController.QuestionRecommendPage) r.GET("/question/similar/tag", a.questionController.SimilarQuestion) r.GET("/personal/qa/top", a.questionController.UserTop) r.GET("/personal/question/page", a.questionController.PersonalQuestionPage) diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index a4c6ee8c..2a6e5f12 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -355,7 +355,7 @@ const ( type QuestionPageReq struct { Page int `validate:"omitempty,min=1" form:"page"` PageSize int `validate:"omitempty,min=1" form:"page_size"` - OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered" form:"order"` + OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered recommend" form:"order"` Tag string `validate:"omitempty,gt=0,lte=100" form:"tag"` Username string `validate:"omitempty,gt=0,lte=100" form:"username"` InDays int `validate:"omitempty,min=1" form:"in_days"` diff --git a/internal/service/activity_common/activity.go b/internal/service/activity_common/activity.go index db565f1e..6b3557c0 100644 --- a/internal/service/activity_common/activity.go +++ b/internal/service/activity_common/activity.go @@ -37,6 +37,7 @@ type ActivityRepo interface { GetActivityTypeByObjectType(ctx context.Context, objectKey, action string) (activityType int, err error) GetActivity(ctx context.Context, session *xorm.Session, objectID, userID string, activityType int) ( existsActivity *entity.Activity, exist bool, err error) + GetUserActivitysByActivityType(ctx context.Context, userID string, activityType int) (activityList []*entity.Activity, err error) GetUserIDObjectIDActivitySum(ctx context.Context, userID, objectID string) (int, error) GetActivityTypeByConfigKey(ctx context.Context, configKey string) (activityType int, err error) AddActivity(ctx context.Context, activity *entity.Activity) (err error) diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index 6d8b37ba..83bd7bed 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -22,7 +22,6 @@ package content import ( "encoding/json" "fmt" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" "strings" "time" @@ -35,11 +34,13 @@ import ( "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/activity" + "github.com/apache/incubator-answer/internal/service/activity_common" "github.com/apache/incubator-answer/internal/service/activity_queue" + answercommon "github.com/apache/incubator-answer/internal/service/answer_common" collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" "github.com/apache/incubator-answer/internal/service/config" "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/meta_common" + metacommon "github.com/apache/incubator-answer/internal/service/meta_common" "github.com/apache/incubator-answer/internal/service/notice_queue" "github.com/apache/incubator-answer/internal/service/notification" "github.com/apache/incubator-answer/internal/service/permission" @@ -48,6 +49,7 @@ import ( "github.com/apache/incubator-answer/internal/service/revision_common" "github.com/apache/incubator-answer/internal/service/role" "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/incubator-answer/internal/service/tag" tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" usercommon "github.com/apache/incubator-answer/internal/service/user_common" "github.com/apache/incubator-answer/pkg/checker" @@ -65,9 +67,11 @@ import ( // QuestionService user service type QuestionService struct { + activityRepo activity_common.ActivityRepo questionRepo questioncommon.QuestionRepo answerRepo answercommon.AnswerRepo tagCommon *tagcommon.TagCommonService + tagService *tag.TagService questioncommon *questioncommon.QuestionCommon userCommon *usercommon.UserCommon userRepo usercommon.UserRepo @@ -87,9 +91,11 @@ type QuestionService struct { } func NewQuestionService( + activityRepo activity_common.ActivityRepo, questionRepo questioncommon.QuestionRepo, answerRepo answercommon.AnswerRepo, tagCommon *tagcommon.TagCommonService, + tagService *tag.TagService, questioncommon *questioncommon.QuestionCommon, userCommon *usercommon.UserCommon, userRepo usercommon.UserRepo, @@ -108,9 +114,11 @@ func NewQuestionService( configService *config.ConfigService, ) *QuestionService { return &QuestionService{ + activityRepo: activityRepo, questionRepo: questionRepo, answerRepo: answerRepo, tagCommon: tagCommon, + tagService: tagService, questioncommon: questioncommon, userCommon: userCommon, userRepo: userRepo, @@ -1348,6 +1356,47 @@ func (qs *QuestionService) GetQuestionPage(ctx context.Context, req *schema.Ques return questions, total, nil } +// GetRecommendQuestionPage retrieves recommended question page based on following tags and questions. +func (qs *QuestionService) GetRecommendQuestionPage(ctx context.Context, req *schema.QuestionPageReq) ( + questions []*schema.QuestionPageResp, total int64, err error) { + followingTagsResp, err := qs.tagService.GetFollowingTags(ctx, req.LoginUserID) + if err != nil { + return nil, 0, err + } + tagIDs := make([]string, 0, len(followingTagsResp)) + for _, tag := range followingTagsResp { + tagIDs = append(tagIDs, tag.TagID) + } + + activityType, err := qs.activityRepo.GetActivityTypeByObjectType(ctx, constant.QuestionObjectType, "follow") + if err != nil { + return nil, 0, err + } + activities, err := qs.activityRepo.GetUserActivitysByActivityType(ctx, req.LoginUserID, activityType) + if err != nil { + return nil, 0, err + } + + followedQuestionIDs := make([]string, 0, len(activities)) + for _, activity := range activities { + if activity.Cancelled == entity.ActivityCancelled { + continue + } + followedQuestionIDs = append(followedQuestionIDs, activity.ObjectID) + } + questionList, total, err := qs.questionRepo.GetRecommendQuestionPageByTags(ctx, req.LoginUserID, tagIDs, followedQuestionIDs, req.Page, req.PageSize) + if err != nil { + return nil, 0, err + } + + questions, err = qs.questioncommon.FormatQuestionsPage(ctx, questionList, req.LoginUserID, "frequent") + if err != nil { + return nil, 0, err + } + + return questions, total, nil +} + func (qs *QuestionService) AdminSetQuestionStatus(ctx context.Context, req *schema.AdminUpdateQuestionStatusReq) error { setStatus, ok := entity.AdminQuestionSearchStatus[req.Status] if !ok { diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index b9f2fd53..5dab1214 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -57,6 +57,7 @@ type QuestionRepo interface { GetQuestionList(ctx context.Context, question *entity.Question) (questions []*entity.Question, err error) GetQuestionPage(ctx context.Context, page, pageSize int, tagIDs []string, userID, orderCond string, inDays int, showHidden, showPending bool) ( questionList []*entity.Question, total int64, err error) + GetRecommendQuestionPageByTags(ctx context.Context, userID string, tagIDs, followedQuestionIDs []string, page, pageSize int) (questionList []*entity.Question, total int64, err error) UpdateQuestionStatus(ctx context.Context, questionID string, status int) (err error) UpdateQuestionStatusWithOutUpdateTime(ctx context.Context, question *entity.Question) (err error) RecoverQuestion(ctx context.Context, questionID string) (err error) diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index ff7c0902..093680e0 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -288,6 +288,7 @@ export interface LangsType { * @description interface for Question */ export type QuestionOrderBy = + | 'recommend' | 'newest' | 'active' | 'hot' diff --git a/ui/src/components/QuestionList/index.tsx b/ui/src/components/QuestionList/index.tsx index d9b46dd2..c41f4b9d 100644 --- a/ui/src/components/QuestionList/index.tsx +++ b/ui/src/components/QuestionList/index.tsx @@ -43,11 +43,13 @@ export const QUESTION_ORDER_KEYS: Type.QuestionOrderBy[] = [ 'hot', 'score', 'unanswered', + 'recommend', ]; interface Props { source: 'questions' | 'tag'; order?: Type.QuestionOrderBy; data; + orderList?: Type.QuestionOrderBy[]; isLoading: boolean; } @@ -55,6 +57,7 @@ const QuestionList: FC = ({ source, order, data, + orderList, isLoading = false, }) => { const { t } = useTranslation('translation', { keyPrefix: 'question' }); @@ -65,6 +68,7 @@ const QuestionList: FC = ({ const curPage = Number(urlSearchParams.get('page')) || 1; const pageSize = 20; const count = data?.count || 0; + const orderKeys = orderList || QUESTION_ORDER_KEYS; return (
@@ -75,7 +79,7 @@ const QuestionList: FC = ({ : t('x_questions', { count })} { page: curPage, order: curOrder as Type.QuestionOrderBy, }; - const { data: listData, isLoading: listLoading } = useQuestionList(reqParams); + const { data: listData, isLoading: listLoading } = + curOrder === 'recommend' + ? useQuestionRecommendList(reqParams) + : useQuestionList(reqParams); const isIndexPage = useMatch('/'); let pageTitle = t('questions', { keyPrefix: 'page_title' }); let slogan = ''; @@ -71,6 +74,11 @@ const Questions: FC = () => { source="questions" data={listData} order={curOrder} + orderList={ + loggedUser.username + ? QUESTION_ORDER_KEYS + : QUESTION_ORDER_KEYS.filter((key) => key !== 'recommend') + } isLoading={listLoading} /> diff --git a/ui/src/pages/Tags/Detail/index.tsx b/ui/src/pages/Tags/Detail/index.tsx index 42b89d5d..ac2fa937 100644 --- a/ui/src/pages/Tags/Detail/index.tsx +++ b/ui/src/pages/Tags/Detail/index.tsx @@ -176,6 +176,7 @@ const Index: FC = () => { source="tag" data={listData} order={curOrder} + orderList={QUESTION_ORDER_KEYS.slice(0, 4)} isLoading={listLoading} /> diff --git a/ui/src/services/client/question.ts b/ui/src/services/client/question.ts index 0e382c26..b62fbf1a 100644 --- a/ui/src/services/client/question.ts +++ b/ui/src/services/client/question.ts @@ -36,6 +36,21 @@ export const useQuestionList = (params: Type.QueryQuestionsReq) => { }; }; +export const useQuestionRecommendList = (params: Type.QueryQuestionsReq) => { + const apiUrl = `/answer/api/v1/question/recommend/page?${qs.stringify( + params, + )}`; + const { data, error } = useSWR( + [apiUrl], + request.instance.get, + ); + return { + data, + isLoading: !data && !error, + error, + }; +}; + export const useHotQuestions = ( params: Type.QueryQuestionsReq = { page: 1, From cf7b2f0c1a2c8b8f9de7c0d7a692940db702eb62 Mon Sep 17 00:00:00 2001 From: ferrischi201 Date: Tue, 27 Aug 2024 14:07:08 -0400 Subject: [PATCH 126/336] fix(recommend): fix for all database backend --- internal/repo/question/question_repo.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index aa3694d0..2c6e595a 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -408,7 +408,13 @@ func (qr *questionRepo) GetRecommendQuestionPageByTags(ctx context.Context, user orderBySQL := "question.pin DESC, question.created_at DESC" // Please Make sure every question has at least one tag - session := qr.data.DB.Context(ctx).Select(entity.Question{}.TableName() + ".*") + selectSQL := entity.Question{}.TableName() + ".*" + if len(followedQuestionIDs) > 0 { + idStr := "'" + strings.Join(followedQuestionIDs, "','") + "'" + selectSQL += fmt.Sprintf(", CASE WHEN question.id IN (%s) THEN 0 ELSE 1 END AS order_priority", idStr) + orderBySQL = "order_priority, " + orderBySQL + } + session := qr.data.DB.Context(ctx).Select(selectSQL) if len(tagIDs) > 0 { session.Where("question.user_id != ?", userID). @@ -422,8 +428,6 @@ func (qr *questionRepo) GetRecommendQuestionPageByTags(ctx context.Context, user } if len(followedQuestionIDs) > 0 { - idStr := "'" + strings.Join(followedQuestionIDs, "','") + "'" - orderBySQL = fmt.Sprintf("CASE WHEN question.id IN (%s) THEN 0 ELSE 1 END, ", idStr) + orderBySQL if len(tagIDs) > 0 { // if tags provided, show followed questions and tag questions session.Or(builder.In("question.id", followedQuestionIDs)) From 8142d78e107149401a4d507d9df44630bd704ffd Mon Sep 17 00:00:00 2001 From: ferrischi201 Date: Tue, 3 Sep 2024 16:02:52 -0400 Subject: [PATCH 127/336] fix(recommend): redirect unauth users from recommend page --- internal/controller/question_controller.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 725a24af..5ddc33f3 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -340,6 +340,15 @@ func (qc *QuestionController) QuestionPage(ctx *gin.Context) { handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions)) } +// QuestionRecommendPage get recommend questions by page +// @Summary get recommend questions by page +// @Description get recommend questions by page +// @Tags Question +// @Accept json +// @Produce json +// @Param data body schema.QuestionPageReq true "QuestionPageReq" +// @Success 200 {object} handler.RespBody{data=pager.PageModel{list=[]schema.QuestionPageResp}} +// @Router /answer/api/v1/question/recommend/page [get] func (qc *QuestionController) QuestionRecommendPage(ctx *gin.Context) { req := &schema.QuestionPageReq{} if handler.BindAndCheck(ctx, req) { @@ -347,6 +356,11 @@ func (qc *QuestionController) QuestionRecommendPage(ctx *gin.Context) { } req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx) + if req.LoginUserID == "" { + handler.HandleResponse(ctx, errors.Unauthorized(reason.UnauthorizedError), nil) + return + } + questions, total, err := qc.questionService.GetRecommendQuestionPage(ctx, req) if err != nil { handler.HandleResponse(ctx, err, nil) From cb5a0b7045998d8fcc583b06c7a3f65b0b6cbb59 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 4 Sep 2024 10:26:57 +0800 Subject: [PATCH 128/336] chore(lint): lint code and regenerate docs --- docs/docs.go | 74 +++++++++++++++++++++++++++++++++++++++++++---- docs/swagger.json | 74 +++++++++++++++++++++++++++++++++++++++++++---- docs/swagger.yaml | 45 ++++++++++++++++++++++++---- go.mod | 3 -- go.sum | 6 ---- 5 files changed, 176 insertions(+), 26 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 376cdf07..cf218a56 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4185,6 +4185,67 @@ const docTemplate = `{ } } }, + "/answer/api/v1/question/recommend/page": { + "get": { + "description": "get recommend questions by page", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Question" + ], + "summary": "get recommend questions by page", + "parameters": [ + { + "description": "QuestionPageReq", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.QuestionPageReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/pager.PageModel" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.QuestionPageResp" + } + } + } + } + ] + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/question/recover": { "post": { "security": [ @@ -6586,14 +6647,14 @@ const docTemplate = `{ }, "/custom.css": { "get": { - "description": "get site robots information", + "description": "get site custom CSS", "produces": [ - "application/json" + "text/css" ], "tags": [ "site" ], - "summary": "get site robots information", + "summary": "get site custom CSS", "responses": { "200": { "description": "OK", @@ -8873,7 +8934,8 @@ const docTemplate = `{ "active", "hot", "score", - "unanswered" + "unanswered", + "recommend" ] }, "page": { @@ -10833,8 +10895,8 @@ var SwaggerInfo = &swag.Spec{ Host: "", BasePath: "= \"/\"", Schemes: []string{}, - Title: "\"answer\"", - Description: "= \"answer api\"", + Title: "\"apache answer\"", + Description: "= \"apache answer api\"", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", diff --git a/docs/swagger.json b/docs/swagger.json index 7c103856..0b24c60c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,8 +1,8 @@ { "swagger": "2.0", "info": { - "description": "= \"answer api\"", - "title": "\"answer\"", + "description": "= \"apache answer api\"", + "title": "\"apache answer\"", "contact": {}, "version": "= \"v0.0.1\"" }, @@ -4159,6 +4159,67 @@ } } }, + "/answer/api/v1/question/recommend/page": { + "get": { + "description": "get recommend questions by page", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Question" + ], + "summary": "get recommend questions by page", + "parameters": [ + { + "description": "QuestionPageReq", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.QuestionPageReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/pager.PageModel" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.QuestionPageResp" + } + } + } + } + ] + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/question/recover": { "post": { "security": [ @@ -6560,14 +6621,14 @@ }, "/custom.css": { "get": { - "description": "get site robots information", + "description": "get site custom CSS", "produces": [ - "application/json" + "text/css" ], "tags": [ "site" ], - "summary": "get site robots information", + "summary": "get site custom CSS", "responses": { "200": { "description": "OK", @@ -8847,7 +8908,8 @@ "active", "hot", "score", - "unanswered" + "unanswered", + "recommend" ] }, "page": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 88709bed..eabc45bb 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1416,6 +1416,7 @@ definitions: - hot - score - unanswered + - recommend type: string page: minimum: 1 @@ -2757,8 +2758,8 @@ definitions: type: object info: contact: {} - description: = "answer api" - title: '"answer"' + description: = "apache answer api" + title: '"apache answer"' version: = "v0.0.1" paths: /: @@ -5269,6 +5270,40 @@ paths: summary: get questions by page tags: - Question + /answer/api/v1/question/recommend/page: + get: + consumes: + - application/json + description: get recommend questions by page + parameters: + - description: QuestionPageReq + in: body + name: data + required: true + schema: + $ref: '#/definitions/schema.QuestionPageReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + allOf: + - $ref: '#/definitions/pager.PageModel' + - properties: + list: + items: + $ref: '#/definitions/schema.QuestionPageResp' + type: array + type: object + type: object + summary: get recommend questions by page + tags: + - Question /answer/api/v1/question/recover: post: consumes: @@ -6708,15 +6743,15 @@ paths: - Activity /custom.css: get: - description: get site robots information + description: get site custom CSS produces: - - application/json + - text/css responses: "200": description: OK schema: type: string - summary: get site robots information + summary: get site custom CSS tags: - site /installation/base-info: diff --git a/go.mod b/go.mod index 8b886a09..e14b01b9 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,6 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/containerd/continuity v0.4.2 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/cli v24.0.6+incompatible // indirect github.com/docker/docker v24.0.6+incompatible // indirect @@ -129,7 +128,6 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.9.2 // indirect github.com/spf13/cast v1.5.0 // indirect @@ -142,7 +140,6 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect - github.com/urfave/cli/v2 v2.3.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect diff --git a/go.sum b/go.sum index ead9468d..4bf5cc08 100644 --- a/go.sum +++ b/go.sum @@ -128,7 +128,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -616,7 +615,6 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -692,8 +690,6 @@ github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO github.com/swaggo/gin-swagger v1.5.3 h1:8mWmHLolIbrhJJTflsaFoZzRBYVmEE7JZGIq08EiC0Q= github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89Yp4uA50HpI= github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= -github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= -github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= @@ -714,9 +710,7 @@ github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95 github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= From b5401915fdc8a17a419d516ac7902541b6f71933 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 4 Sep 2024 11:06:44 +0800 Subject: [PATCH 129/336] fix: badge detial not show empty --- ui/src/pages/Badges/Detail/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index 27fe9b7e..cb85a8b8 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -23,7 +23,7 @@ import { Link, useParams, useSearchParams } from 'react-router-dom'; // import classnames from 'classnames'; -import { FormatTime, Pagination, Empty } from '@/components'; +import { FormatTime, Pagination } from '@/components'; import { usePageTags, useSkeletonControl } from '@/hooks'; // import { formatCount } from '@/utils'; import { useGetBadgeInfo, useBadgeDetailList } from '@/services'; @@ -102,7 +102,6 @@ const Index = () => { }) )} - {Number(badges?.count) <= 0 && !isDetailLoading && }
Date: Wed, 4 Sep 2024 11:58:05 +0800 Subject: [PATCH 130/336] feat(badge): add trigger object id for all badge award event --- internal/controller/template_controller.go | 3 +- internal/entity/badge_award_entity.go | 2 +- internal/repo/badge/badge_event_rule.go | 9 ++--- internal/repo/badge/badge_repo.go | 9 +++++ internal/repo/badge_award/badge_award_repo.go | 20 ++++++++-- internal/schema/event_schema.go | 24 +++++++++-- internal/service/badge/badge_award_service.go | 1 + internal/service/badge/badge_service.go | 40 ++++++++++++------- internal/service/comment/comment_service.go | 9 +++-- internal/service/content/answer_service.go | 8 ++-- internal/service/content/question_service.go | 6 +-- internal/service/content/vote_service.go | 6 +-- internal/service/meta/meta_service.go | 4 +- internal/service/report/report_service.go | 6 +-- 14 files changed, 100 insertions(+), 47 deletions(-) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index a786f646..6b6a20f8 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -304,7 +304,8 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { userInfo, err := tc.userService.GetOtherUserInfoByUsername( ctx, &schema.GetOtherUserInfoByUsernameReq{Username: shareUsername}) if err == nil { - tc.eventQueueService.Send(ctx, schema.NewEvent(constant.EventUserShare, userInfo.ID)) + tc.eventQueueService.Send(ctx, schema.NewEvent(constant.EventUserShare, userInfo.ID). + QID(id, detail.UserID).AID(answerid, "")) } } encodeTitle := htmltext.UrlTitle(detail.Title) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index f18138be..339b9ca0 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -25,7 +25,7 @@ const ( IsBadgeNotDeleted = 0 IsBadgeDeleted = 1 - BadgeOnceAwardKey = "0" + BadgeEmptyAwardKey = "0" ) // BadgeAward badge_award diff --git a/internal/repo/badge/badge_event_rule.go b/internal/repo/badge/badge_event_rule.go index f107203e..11ce38a3 100644 --- a/internal/repo/badge/badge_event_rule.go +++ b/internal/repo/badge/badge_event_rule.go @@ -72,8 +72,8 @@ func NewEventRuleRepo(data *data.Data) badge.EventRuleRepo { func (br *eventRuleRepo) HandleEventWithRule(ctx context.Context, msg *schema.EventMsg) ( awards []*entity.BadgeAward) { handlers := br.EventRuleMapping[msg.EventType] - for _, h := range handlers { - t, err := h(ctx, msg) + for _, handler := range handlers { + t, err := handler(ctx, msg) if err != nil { log.Errorf("error handling badge event %+v: %v", msg, err) } else { @@ -97,7 +97,7 @@ func (br *eventRuleRepo) FirstUpdateUserProfile(ctx context.Context, continue } if len(bean.Bio) > 0 { - awards = append(awards, br.createBadgeAward(event.UserID, "", b)) + awards = append(awards, br.createBadgeAward(event.UserID, entity.BadgeEmptyAwardKey, b)) } } return awards, nil @@ -245,9 +245,6 @@ func (br *eventRuleRepo) getBadgesByHandler(ctx context.Context, handler string) } func (br *eventRuleRepo) createBadgeAward(userID, awardKey string, badge *entity.Badge) (awards *entity.BadgeAward) { - if badge.Single == entity.BadgeSingleAward { - awardKey = entity.BadgeOnceAwardKey - } return &entity.BadgeAward{ UserID: userID, BadgeID: badge.ID, diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index 80689541..d52fc122 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -140,3 +140,12 @@ func (r *badgeRepo) UpdateStatus(ctx context.Context, id string, status int8) (e return } + +// UpdateAwardCount updates the award count of a badge +func (r *badgeRepo) UpdateAwardCount(ctx context.Context, badgeID string, awardCount int) (err error) { + _, err = r.data.DB.Context(ctx).ID(badgeID).Cols("award_count").Update(&entity.Badge{AwardCount: awardCount}) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 64615d6d..c1ce1e58 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -63,9 +63,15 @@ func (r *badgeAwardRepo) AwardBadgeForUser(ctx context.Context, badgeAward *enti return nil, fmt.Errorf("badge not exist") } - old := &entity.BadgeAward{} - exist, err = session.Where("user_id = ? AND badge_id = ? AND award_key = ? AND is_badge_deleted = 0", - badgeAward.UserID, badgeAward.BadgeID, badgeAward.AwardKey).Get(old) + old := &entity.BadgeAward{ + UserID: badgeAward.UserID, + BadgeID: badgeAward.BadgeID, + IsBadgeDeleted: entity.IsBadgeNotDeleted, + } + if badgeInfo.Single != entity.BadgeSingleAward { + old.AwardKey = badgeAward.AwardKey + } + exist, err = session.Get(old) if err != nil { return nil, err } @@ -108,6 +114,14 @@ func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID str return } +func (r *badgeAwardRepo) CountByBadgeID(ctx context.Context, badgeID string) (awardCount int64, err error) { + awardCount, err = r.data.DB.Context(ctx).Count(&entity.BadgeAward{BadgeID: badgeID}) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + func (r *badgeAwardRepo) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) { err = r.data.DB.Context(ctx).Select("badge_id, count(`id`) AS earned_count").Where("user_id = ?", userID).GroupBy("badge_id").Find(&earnedCounts) return diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go index a507f269..701d5d88 100644 --- a/internal/schema/event_schema.go +++ b/internal/schema/event_schema.go @@ -19,13 +19,18 @@ package schema -import "github.com/apache/incubator-answer/internal/base/constant" +import ( + "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/incubator-answer/pkg/uid" +) // EventMsg event message type EventMsg struct { EventType constant.EventType UserID string + TriggerObjectID string + QuestionID string QuestionUserID string @@ -49,14 +54,18 @@ func NewEvent(e constant.EventType, userID string) *EventMsg { // QID get question id func (e *EventMsg) QID(questionID, userID string) *EventMsg { - e.QuestionID = questionID + if len(questionID) > 0 { + e.QuestionID = uid.DeShortID(questionID) + } e.QuestionUserID = userID return e } // AID get answer id func (e *EventMsg) AID(answerID, userID string) *EventMsg { - e.AnswerID = answerID + if len(answerID) > 0 { + e.AnswerID = uid.DeShortID(answerID) + } e.AnswerUserID = userID return e } @@ -68,6 +77,12 @@ func (e *EventMsg) CID(comment, userID string) *EventMsg { return e } +// TID get trigger object id +func (e *EventMsg) TID(triggerObjectID string) *EventMsg { + e.TriggerObjectID = triggerObjectID + return e +} + // AddExtra add extra info func (e *EventMsg) AddExtra(key, value string) *EventMsg { e.ExtraInfo[key] = value @@ -84,6 +99,9 @@ func (e *EventMsg) GetExtra(key string) string { // GetObjectID get object id func (e *EventMsg) GetObjectID() string { + if len(e.TriggerObjectID) > 0 { + return e.TriggerObjectID + } if len(e.CommentID) > 0 { return e.CommentID } diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index 0bc7be0f..feb95a65 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -42,6 +42,7 @@ type BadgeAwardRepo interface { AwardBadgeForUser(ctx context.Context, badgeAward *entity.BadgeAward) (err error) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) + CountByBadgeID(ctx context.Context, badgeID string) (awardCount int64, err error) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 3ec7b5bf..faf9b628 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -30,6 +30,7 @@ import ( "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" + "github.com/segmentfault/pacman/log" "strings" ) @@ -42,6 +43,7 @@ type BadgeRepo interface { ListInactivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) UpdateStatus(ctx context.Context, id string, status int8) (err error) + UpdateAwardCount(ctx context.Context, badgeID string, awardCount int) (err error) } type BadgeService struct { @@ -266,32 +268,42 @@ func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) // UpdateStatus update badge status func (b *BadgeService) UpdateStatus(ctx *gin.Context, req *schema.UpdateBadgeStatusReq) (err error) { - var ( - badge *entity.Badge - exists bool - ) req.ID = uid.DeShortID(req.ID) - badge, exists, err = b.badgeRepo.GetByID(ctx, req.ID) + badge, exists, err := b.badgeRepo.GetByID(ctx, req.ID) if err != nil { - return + return err } if !exists { - err = errors.BadRequest(reason.BadgeObjectNotFound) - return + return errors.BadRequest(reason.BadgeObjectNotFound) } - status, ok := schema.BadgeStatusEMap[req.Status] // check duplicate action - if badge.Status == status { - return - } - + status, ok := schema.BadgeStatusEMap[req.Status] if !ok { err = errors.BadRequest(reason.StatusInvalid) return } + if badge.Status == status { + return + } err = b.badgeRepo.UpdateStatus(ctx, req.ID, status) - return + if err != nil { + return err + } + + if status == entity.BadgeStatusActive { + count, err := b.badgeAwardRepo.CountByBadgeID(ctx, badge.ID) + if err != nil { + log.Errorf("count badge award failed: %v", err) + return nil + } + err = b.badgeRepo.UpdateAwardCount(ctx, badge.ID, int(count)) + if err != nil { + log.Errorf("update badge award count failed: %v", err) + return nil + } + } + return nil } diff --git a/internal/service/comment/comment_service.go b/internal/service/comment/comment_service.go index 75d30f9d..012149e7 100644 --- a/internal/service/comment/comment_service.go +++ b/internal/service/comment/comment_service.go @@ -192,11 +192,11 @@ func (cs *CommentService) AddComment(ctx context.Context, req *schema.AddComment switch objInfo.ObjectType { case constant.QuestionObjectType: activityMsg.ActivityTypeKey = constant.ActQuestionCommented - event = schema.NewEvent(constant.EventCommentCreate, req.UserID). + event = schema.NewEvent(constant.EventCommentCreate, req.UserID).TID(comment.ID). CID(comment.ID, comment.UserID).QID(objInfo.QuestionID, objInfo.ObjectCreatorUserID) case constant.AnswerObjectType: activityMsg.ActivityTypeKey = constant.ActAnswerCommented - event = schema.NewEvent(constant.EventCommentCreate, req.UserID). + event = schema.NewEvent(constant.EventCommentCreate, req.UserID).TID(comment.ID). CID(comment.ID, comment.UserID).AID(objInfo.AnswerID, objInfo.ObjectCreatorUserID) } cs.activityQueueService.Send(ctx, activityMsg) @@ -255,7 +255,8 @@ func (cs *CommentService) RemoveComment(ctx context.Context, req *schema.RemoveC if err != nil { return err } - cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentDelete, req.UserID).CID(req.CommentID, req.UserID)) + cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentDelete, req.UserID). + TID(req.CommentID).CID(req.CommentID, req.UserID)) return nil } @@ -288,7 +289,7 @@ func (cs *CommentService) UpdateComment(ctx context.Context, req *schema.UpdateC OriginalText: req.OriginalText, ParsedText: req.ParsedText, } - cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentUpdate, req.UserID). + cs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventCommentUpdate, req.UserID).TID(old.ID). CID(old.ID, old.UserID)) return resp, nil } diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index 496f7546..c34e9081 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -179,7 +179,7 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns OriginalObjectID: answerInfo.ID, ActivityTypeKey: constant.ActAnswerDeleted, }) - as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerDelete, req.UserID). + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerDelete, req.UserID).TID(answerInfo.ID). AID(answerInfo.ID, answerInfo.UserID)) return } @@ -301,7 +301,7 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) ( OriginalObjectID: questionInfo.ID, ActivityTypeKey: constant.ActQuestionAnswered, }) - as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerCreate, req.UserID). + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerCreate, req.UserID).TID(insertData.ID). AID(insertData.ID, insertData.UserID)) return insertData.ID, nil } @@ -391,7 +391,7 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq ActivityTypeKey: constant.ActAnswerEdited, RevisionID: revisionID, }) - as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerUpdate, req.UserID). + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventAnswerUpdate, req.UserID).TID(insertData.ID). AID(insertData.ID, insertData.UserID)) } @@ -447,7 +447,7 @@ func (as *AnswerService) AcceptAnswer(ctx context.Context, req *schema.AcceptAns } if acceptedAnswerInfo != nil { - as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionAccept, req.UserID). + as.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionAccept, req.UserID).TID(acceptedAnswerInfo.ID). QID(questionInfo.ID, questionInfo.UserID).AID(acceptedAnswerInfo.ID, acceptedAnswerInfo.UserID)) } diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index d3e952b7..9a6dd280 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -397,7 +397,7 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question qs.externalNotificationQueueService.Send(ctx, schema.CreateNewQuestionNotificationMsg(question.ID, question.Title, question.UserID, tags)) } - qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionCreate, req.UserID). + qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionCreate, req.UserID).TID(question.ID). QID(question.ID, question.UserID)) questionInfo, err = qs.GetQuestion(ctx, question.ID, question.UserID, req.QuestionPermission) @@ -560,7 +560,7 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov OriginalObjectID: questionInfo.ID, ActivityTypeKey: constant.ActQuestionDeleted, }) - qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionDelete, req.UserID). + qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionDelete, req.UserID).TID(questionInfo.ID). QID(questionInfo.ID, questionInfo.UserID)) return nil } @@ -953,7 +953,7 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest RevisionID: revisionID, OriginalObjectID: question.ID, }) - qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionUpdate, req.UserID). + qs.eventQueueService.Send(ctx, schema.NewEvent(constant.EventQuestionUpdate, req.UserID).TID(question.ID). QID(question.ID, question.UserID)) } diff --git a/internal/service/content/vote_service.go b/internal/service/content/vote_service.go index c83011a9..b4b92ddd 100644 --- a/internal/service/content/vote_service.go +++ b/internal/service/content/vote_service.go @@ -305,13 +305,13 @@ func (vs *VoteService) sendEvent(ctx context.Context, var event *schema.EventMsg switch objectInfo.ObjectType { case constant.QuestionObjectType: - event = schema.NewEvent(constant.EventQuestionVote, req.UserID). + event = schema.NewEvent(constant.EventQuestionVote, req.UserID).TID(objectInfo.QuestionID). QID(objectInfo.QuestionID, objectInfo.ObjectCreatorUserID) case constant.AnswerObjectType: - event = schema.NewEvent(constant.EventAnswerVote, req.UserID). + event = schema.NewEvent(constant.EventAnswerVote, req.UserID).TID(objectInfo.AnswerID). AID(objectInfo.AnswerID, objectInfo.ObjectCreatorUserID) case constant.CommentObjectType: - event = schema.NewEvent(constant.EventCommentVote, req.UserID). + event = schema.NewEvent(constant.EventCommentVote, req.UserID).TID(objectInfo.CommentID). CID(objectInfo.CommentID, objectInfo.ObjectCreatorUserID) default: return diff --git a/internal/service/meta/meta_service.go b/internal/service/meta/meta_service.go index 778c6ca6..b85aecf6 100644 --- a/internal/service/meta/meta_service.go +++ b/internal/service/meta/meta_service.go @@ -104,7 +104,7 @@ func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.Upda if !exist { return nil, myErrors.BadRequest(reason.AnswerNotFound) } - event = schema.NewEvent(constant.EventAnswerReact, req.UserID). + event = schema.NewEvent(constant.EventAnswerReact, req.UserID).TID(answerInfo.ID). AID(answerInfo.ID, answerInfo.UserID) } else if objectType == constant.QuestionObjectType { questionInfo, exist, err := ms.questionRepo.GetQuestion(ctx, req.ObjectID) @@ -114,7 +114,7 @@ func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.Upda if !exist { return nil, myErrors.BadRequest(reason.QuestionNotFound) } - event = schema.NewEvent(constant.EventQuestionReact, req.UserID). + event = schema.NewEvent(constant.EventQuestionReact, req.UserID).TID(questionInfo.ID). QID(questionInfo.ID, questionInfo.UserID) } else { return nil, myErrors.BadRequest(reason.ObjectNotFound) diff --git a/internal/service/report/report_service.go b/internal/service/report/report_service.go index 218423e1..2ca44855 100644 --- a/internal/service/report/report_service.go +++ b/internal/service/report/report_service.go @@ -233,13 +233,13 @@ func (rs *ReportService) sendEvent(ctx context.Context, var event *schema.EventMsg switch objectInfo.ObjectType { case constant.QuestionObjectType: - event = schema.NewEvent(constant.EventQuestionFlag, report.UserID). + event = schema.NewEvent(constant.EventQuestionFlag, report.UserID).TID(objectInfo.QuestionID). QID(objectInfo.QuestionID, objectInfo.ObjectCreatorUserID) case constant.AnswerObjectType: - event = schema.NewEvent(constant.EventAnswerFlag, report.UserID). + event = schema.NewEvent(constant.EventAnswerFlag, report.UserID).TID(objectInfo.AnswerID). AID(objectInfo.AnswerID, objectInfo.ObjectCreatorUserID) case constant.CommentObjectType: - event = schema.NewEvent(constant.EventCommentFlag, report.UserID). + event = schema.NewEvent(constant.EventCommentFlag, report.UserID).TID(objectInfo.CommentID). CID(objectInfo.CommentID, objectInfo.ObjectCreatorUserID) default: return From 323ee0e36d6e85d15f21391a920a26aca3fa2a84 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 4 Sep 2024 15:53:29 +0800 Subject: [PATCH 131/336] docs(makefile): upgrade version --- Makefile | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index bcacf3e4..8279d17a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: build clean ui -VERSION=1.3.6 +VERSION=1.4.0 BIN=answer DIR_SRC=./cmd/answer DOCKER_CMD=docker diff --git a/README.md b/README.md index 0894a413..7d753805 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ To learn more about the project, visit [answer.apache.org](https://answer.apache ### Running with docker ```bash -docker run -d -p 9080:80 -v answer-data:/data --name answer apache/answer:1.3.6 +docker run -d -p 9080:80 -v answer-data:/data --name answer apache/answer:1.4.0 ``` For more information, see [Installation](https://answer.apache.org/docs/installation). From 1a8e2fa0bd8d4db98ed896a013696baf69a204a2 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 4 Sep 2024 16:48:30 +0800 Subject: [PATCH 132/336] # Conflicts: # i18n/da_DK.yaml # i18n/de_DE.yaml # i18n/es_ES.yaml # i18n/ko_KR.yaml # i18n/pl_PL.yaml # i18n/uk_UA.yaml # i18n/vi_VN.yaml # i18n/zh_CN.yaml --- i18n/cs_CZ.yaml | 299 ++++++ i18n/cy_GB.yaml | 299 ++++++ i18n/da_DK.yaml | 2723 ++++++++++++++++++++++++++--------------------- i18n/de_DE.yaml | 341 +++++- i18n/es_ES.yaml | 299 ++++++ i18n/fa_IR.yaml | 299 ++++++ i18n/fr_FR.yaml | 299 ++++++ i18n/hi_IN.yaml | 299 ++++++ i18n/id_ID.yaml | 299 ++++++ i18n/it_IT.yaml | 299 ++++++ i18n/ja_JP.yaml | 299 ++++++ i18n/ko_KR.yaml | 307 +++++- i18n/pl_PL.yaml | 299 ++++++ i18n/pt_PT.yaml | 317 +++++- i18n/ro_RO.yaml | 299 ++++++ i18n/ru_RU.yaml | 299 ++++++ i18n/sk_SK.yaml | 299 ++++++ i18n/sv_SE.yaml | 301 +++++- i18n/te_IN.yaml | 299 ++++++ i18n/tr_TR.yaml | 299 ++++++ i18n/uk_UA.yaml | 299 ++++++ i18n/vi_VN.yaml | 383 ++++++- i18n/zh_CN.yaml | 327 +++++- i18n/zh_TW.yaml | 301 +++++- 24 files changed, 8480 insertions(+), 1304 deletions(-) diff --git a/i18n/cs_CZ.yaml b/i18n/cs_CZ.yaml index 058223c1..ccf371f0 100644 --- a/i18n/cs_CZ.yaml +++ b/i18n/cs_CZ.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Heslo nesmí obsahovat mezery. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Your Account has been Suspended until_time: "Your account was suspended until {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Users + badges: Badges profile: Profile setting: Settings logout: Log out @@ -1257,6 +1525,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified @@ -1275,12 +1544,14 @@ ui: reputation: Reputation comments: Comments votes: Votes + badges: Badges newest: Newest score: Score edit_profile: Edit profile visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes received x_answers: answers x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Next @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: Flags settings: Settings general: General @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/cy_GB.yaml b/i18n/cy_GB.yaml index c0f6a44e..f96476f2 100644 --- a/i18n/cy_GB.yaml +++ b/i18n/cy_GB.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Mae'ch Cyfrif wedi'i Atal until_time: "Cafodd eich cyfrif ei atal tan {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Users + badges: Badges profile: Profile setting: Settings logout: Log out @@ -1257,6 +1525,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified @@ -1275,12 +1544,14 @@ ui: reputation: Reputation comments: Comments votes: Votes + badges: Badges newest: Newest score: Score edit_profile: Edit profile visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes received x_answers: answers x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Next @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: Flags settings: Settings general: General @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/da_DK.yaml b/i18n/da_DK.yaml index b8548d98..ec2d8cf2 100644 --- a/i18n/da_DK.yaml +++ b/i18n/da_DK.yaml @@ -19,1736 +19,2021 @@ backend: base: success: - other: Success. + other: Gennemført. unknown: - other: Unknown error. + other: Ukendt fejl. request_format_error: - other: Request format is not valid. + other: Forespørgselsformat er ikke gyldigt. unauthorized_error: - other: Unauthorized. + other: Uautoriseret. database_error: - other: Data server error. + other: Data-server fejl. forbidden_error: - other: Forbidden. + other: Forbudt. duplicate_request_error: - other: Duplicate submission. + other: Duplilkeret indenselse. action: report: - other: Flag + other: Anmeld edit: - other: Edit + other: Rediger delete: - other: Delete + other: Slet close: - other: Close + other: Luk reopen: - other: Reopen + other: Genåbn forbidden_error: - other: Forbidden. + other: Forbudt. pin: - other: Pin + other: Fastgør hide: - other: Unlist + other: Afliste unpin: - other: Unpin + other: Frigør show: - other: List + other: Liste invite_someone_to_answer: - other: Edit + other: Rediger undelete: - other: Undelete + other: Genopret role: name: user: - other: User + other: Bruger admin: - other: Admin + other: Administrator moderator: other: Moderator description: user: - other: Default with no special access. + other: Standard uden særlig adgang. admin: - other: Have the full power to access the site. + other: Hav den fulde magt til at få adgang til webstedet. moderator: - other: Has access to all posts except admin settings. + other: Har adgang til alle indlæg undtagen administratorindstillinger. privilege: level_1: description: - other: Level 1 (less reputation required for private team, group) + other: Niveau 1 (mindre omdømme kræves for private team, gruppe) level_2: description: - other: Level 2 (low reputation required for startup community) + other: Niveau 2 (lav omdømme kræves for opstart fællesskab) level_3: description: - other: Level 3 (high reputation required for mature community) + other: Niveau 3 (højt omdømme kræves for moden fællesskab) level_custom: description: - other: Custom Level + other: Brugerdefineret Niveau rank_question_add_label: - other: Ask question + other: Stil spørgsmål rank_answer_add_label: - other: Write answer + other: Skriv svar rank_comment_add_label: - other: Write comment + other: Skriv kommentar rank_report_add_label: - other: Flag + other: Anmeld rank_comment_vote_up_label: - other: Upvote comment + other: Op-stem kommentar rank_link_url_limit_label: - other: Post more than 2 links at a time + other: Skriv mere end 2 links ad gangen rank_question_vote_up_label: - other: Upvote question + other: Op-stem spørgsmål rank_answer_vote_up_label: - other: Upvote answer + other: Op-stem svar rank_question_vote_down_label: - other: Downvote question + other: Ned-stem spørgsmål rank_answer_vote_down_label: - other: Downvote answer + other: Ned-stem svar rank_invite_someone_to_answer_label: - other: Invite someone to answer + other: Inviter nogen til at svare rank_tag_add_label: - other: Create new tag + other: Opret et nyt tag rank_tag_edit_label: - other: Edit tag description (need to review) + other: Rediger tag beskrivelse (skal gennemgås) rank_question_edit_label: - other: Edit other's question (need to review) + other: Rediger andres spørgsmål (skal gennemgås) rank_answer_edit_label: - other: Edit other's answer (need to review) + other: Redigere andres svar (skal gennemgås) rank_question_edit_without_review_label: - other: Edit other's question without review + other: Rediger andres spørgsmål uden gennemgang rank_answer_edit_without_review_label: - other: Edit other's answer without review + other: Rediger andres svar uden gennemgang rank_question_audit_label: - other: Review question edits + other: Gennemse spørgsmål redigeringer rank_answer_audit_label: - other: Review answer edits + other: Gennemgå svar redigeringer rank_tag_audit_label: - other: Review tag edits + other: Gennemse tag redigeringer rank_tag_edit_without_review_label: - other: Edit tag description without review + other: Rediger tag beskrivelse uden gennemgang rank_tag_synonym_label: - other: Manage tag synonyms + other: Administrer tag synonymer email: - other: Email + other: E-mail e_mail: - other: Email + other: E-mail password: - other: Password + other: Adgangskode pass: - other: Password + other: Adgangskode original_text: - other: This post + other: Dette indlæg email_or_password_wrong_error: - other: Email and password do not match. + other: E-mail og adgangskode stemmer ikke overens. error: common: invalid_url: - other: Invalid URL. + other: Ugyldig URL. + status_invalid: + other: Invalid status. password: space_invalid: - other: Password cannot contain spaces. + other: Adgangskoden må ikke indeholde mellemrum. admin: cannot_update_their_password: - other: You cannot modify your password. + other: Du kan ikke ændre din adgangskode. cannot_edit_their_profile: - other: You cannot modify your profile. + other: Du kan ikke ændre din profil. cannot_modify_self_status: - other: You cannot modify your status. + other: Du kan ikke ændre din status. email_or_password_wrong: - other: Email and password do not match. + other: E-mail og adgangskode stemmer ikke overens. answer: not_found: - other: Answer do not found. + other: Svar ikke fundet. cannot_deleted: - other: No permission to delete. + other: Ingen tilladelser til at slette. cannot_update: - other: No permission to update. + other: Ingen tilladelse til at opdatere. question_closed_cannot_add: - other: Questions are closed and cannot be added. + other: Spørgsmål er lukket og kan ikke tilføjes. comment: edit_without_permission: - other: Comment are not allowed to edit. + other: Kommentar er ikke tilladt at redigere. not_found: - other: Comment not found. + other: Kommentar ikke fundet. cannot_edit_after_deadline: - other: The comment time has been too long to modify. + other: Kommentaren er for gammel til at blive redigeret. email: duplicate: - other: Email already exists. + other: Email eksisterer allerede. need_to_be_verified: - other: Email should be verified. + other: E-mail skal bekræftes. verify_url_expired: - other: Email verified URL has expired, please resend the email. + other: Email bekræftet URL er udløbet. Send venligst e-mailen igen. illegal_email_domain_error: - other: Email is not allowed from that email domain. Please use another one. + other: E-mail er ikke tilladt fra dette e-mail-domæne. Brug venligst et andet. lang: not_found: - other: Language file not found. + other: Sprog-fil kunne ikke findes. object: captcha_verification_failed: - other: Captcha wrong. + other: Captcha er forkert. disallow_follow: - other: You are not allowed to follow. + other: Du har ikke tilladelse til at følge. disallow_vote: - other: You are not allowed to vote. + other: Du har ikke tilladelse til at stemme. disallow_vote_your_self: - other: You can't vote for your own post. + other: Du kan ikke stemme på dit eget indlæg. not_found: - other: Object not found. + other: Objekt ikke fundet. verification_failed: - other: Verification failed. + other: Verifikation mislykkedes. email_or_password_incorrect: - other: Email and password do not match. + other: E-mail og adgangskode stemmer ikke overens. old_password_verification_failed: - other: The old password verification failed + other: Den gamle adgangskodebekræftelse mislykkedes new_password_same_as_previous_setting: - other: The new password is the same as the previous one. + other: Den nye adgangskode er den samme som den foregående. already_deleted: - other: This post has been deleted. + other: Dette indlæg er blevet slettet. meta: object_not_found: - other: Meta object not found + other: Metaobjekt ikke fundet question: already_deleted: - other: This post has been deleted. + other: Dette indlæg er blevet slettet. under_review: - other: Your post is awaiting review. It will be visible after it has been approved. + other: Dit indlæg afventer gennemgang. Det vil være synligt, når det er blevet godkendt. not_found: - other: Question not found. + other: Spørgsmål ikke fundet. cannot_deleted: - other: No permission to delete. + other: Ingen tilladelser til at slette. cannot_close: - other: No permission to close. + other: Ingen tilladelse til at lukke. cannot_update: - other: No permission to update. + other: Ingen tilladelse til at opdatere. rank: fail_to_meet_the_condition: - other: Reputation rank fail to meet the condition. + other: Omdømmelse rang opfylder ikke betingelsen. vote_fail_to_meet_the_condition: - other: Thanks for the feedback. You need at least {{.Rank}} reputation to cast a vote. + other: Tak for feedback. Du skal mindst have {{.Rank}} ry for at afgive en stemme. no_enough_rank_to_operate: - other: You need at least {{.Rank}} reputation to do this. + other: Du skal mindst {{.Rank}} omdømme for at gøre dette. report: handle_failed: other: Report handle failed. not_found: - other: Report not found. + other: Rapport ikke fundet. tag: already_exist: - other: Tag already exists. + other: Tag findes allerede. not_found: - other: Tag not found. + other: Tag blev ikke fundet. recommend_tag_not_found: - other: Recommend tag is not exist. + other: Anbefal tag eksisterer ikke. recommend_tag_enter: - other: Please enter at least one required tag. + other: Indtast mindst et påkrævet tag. not_contain_synonym_tags: - other: Should not contain synonym tags. + other: Må ikke indeholde synonym tags. cannot_update: - other: No permission to update. + other: Ingen tilladelse til at opdatere. is_used_cannot_delete: - other: You cannot delete a tag that is in use. + other: Du kan ikke slette et tag, der er i brug. cannot_set_synonym_as_itself: - other: You cannot set the synonym of the current tag as itself. + other: Du kan ikke indstille synonymet for det nuværende tag som sig selv. smtp: config_from_name_cannot_be_email: - other: The from name cannot be a email address. + other: Fra-navnet kan ikke være en e-mail-adresse. theme: not_found: - other: Theme not found. + other: Tema ikke fundet. revision: review_underway: - other: Can't edit currently, there is a version in the review queue. + other: Kan ikke redigere i øjeblikket, der er en version i revisionskøen. no_permission: - other: No permission to revise. + other: Ingen tilladelse til at revidere. user: external_login_missing_user_id: - other: The third-party platform does not provide a unique UserID, so you cannot login, please contact the website administrator. + other: Den tredjepartsplatform giver ikke et unikt UserID, så du kan ikke logge ind, kontakt venligst webstedsadministratoren. external_login_unbinding_forbidden: - other: Please set a login password for your account before you remove this login. + other: Angiv en adgangskode til din konto, før du fjerner dette login. email_or_password_wrong: other: - other: Email and password do not match. + other: E-mail og adgangskode stemmer ikke overens. not_found: - other: User not found. + other: Bruger ikke fundet. suspended: - other: User has been suspended. + other: Brugeren er suspenderet. username_invalid: - other: Username is invalid. + other: Brugernavn er ugyldigt. username_duplicate: - other: Username is already in use. + other: Brugernavn er allerede i brug. set_avatar: - other: Avatar set failed. + other: Avatar sæt mislykkedes. cannot_update_your_role: - other: You cannot modify your role. + other: Du kan ikke ændre din rolle. not_allowed_registration: - other: Currently the site is not open for registration. + other: Webstedet er ikke åbent for registrering. not_allowed_login_via_password: - other: Currently the site is not allowed to login via password. + other: I øjeblikket er det ikke tilladt at logge ind via adgangskode. access_denied: - other: Access denied + other: Adgang nægtet page_access_denied: - other: You do not have access to this page. + other: Du har ikke adgang til denne side. add_bulk_users_format_error: - other: "Error {{.Field}} format near '{{.Content}}' at line {{.Line}}. {{.ExtraMessage}}" + other: "Fejl {{.Field}} format nær '{{.Content}}' i linje {{.Line}}. {{.ExtraMessage}}" add_bulk_users_amount_error: - other: "The number of users you add at once should be in the range of 1-{{.MaxAmount}}." + other: "Antallet af brugere du tilføjer på én gang skal være i intervallet 1 -{{.MaxAmount}}." config: read_config_failed: - other: Read config failed + other: Kunne ikke læse konfigurationen database: connection_failed: - other: Database connection failed + other: Database forbindelse mislykkedes create_table_failed: - other: Create table failed + other: Tabellen kunne ikke oprettes install: create_config_failed: - other: Can't create the config.yaml file. + other: Kan ikke oprette filen config.yaml. upload: unsupported_file_format: - other: Unsupported file format. + other: Ikke understøttet filformat. site_info: config_not_found: - other: Site config not found. + other: Site config ikke fundet. + badge: + object_not_found: + other: Badge object not found reason: spam: name: other: spam desc: - other: This post is an advertisement, or vandalism. It is not useful or relevant to the current topic. + other: Dette indlæg er en annonce eller vandalisme. Det er ikke nyttigt eller relevant for det aktuelle emne. rude_or_abusive: name: - other: rude or abusive + other: uhøflig eller misbrug desc: other: - - A reasonable person would find this content inappropriate for respectful + - En fornuftig person ville finde dette indhold upassende eller ikke respektfuldt - discourse. a_duplicate: name: - other: a duplicate + other: en duplikering desc: - other: This question has been asked before and already has an answer. + other: Dette spørgsmål er blevet stillet før og har allerede et svar. placeholder: - other: Enter the existing question link + other: Indtast linket til eksisterende spørgsmål not_a_answer: name: - other: not an answer + other: ikke et svar desc: other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + - Dette blev sendt som svar, men det forsøger ikke at besvare + - spørgsmål. Det bør muligvis være en redigering, en kommentar, et andet spørgsmål + - eller slettet helt. no_longer_needed: name: - other: no longer needed + other: ikke længere nødvendigt desc: - other: This comment is outdated, conversational or not relevant to this post. + other: Denne kommentar er forældet, samtale-agtig eller ikke relevant for dette indlæg. something: name: - other: something else + other: noget andet desc: - other: This post requires staff attention for another reason not listed above. + other: Dette indlæg kræver personalets opmærksomhed af en anden grund, som ikke er nævnt ovenfor. placeholder: - other: Let us know specifically what you are concerned about + other: Lad os vide specifikt, hvad du er bekymret over community_specific: name: - other: a community-specific reason + other: en fællesskabsspecifik årsag desc: - other: This question doesn't meet a community guideline. + other: Dette spørgsmål opfylder ikke en fællesskabsretningslinje. not_clarity: name: - other: needs details or clarity + other: kræver detaljer eller klarhed desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: Dette spørgsmål indeholder i øjeblikket flere spørgsmål i én. Det bør kun fokusere på ét problem. looks_ok: name: - other: looks OK + other: ser OK ud desc: - other: This post is good as-is and not low quality. + other: Dette indlæg er godt som er og ikke lav kvalitet. needs_edit: name: - other: needs edit, and I did it + other: har brug for redigering, og jeg gjorde det desc: - other: Improve and correct problems with this post yourself. + other: Forbedre og ret selv problemer med dette indlæg. needs_close: name: - other: needs close + other: skal lukkes desc: - other: A closed question can't answer, but still can edit, vote and comment. + other: Et lukket spørgsmål kan ikke besvares, men du kan stadig redigere, stemme og kommentere. needs_delete: name: - other: needs delete + other: skal slettes desc: - other: This post will be deleted. + other: Dette indlæg bliver slettet. question: close: duplicate: name: other: spam desc: - other: This question has been asked before and already has an answer. + other: Dette spørgsmål er blevet stillet før og har allerede et svar. guideline: name: - other: a community-specific reason + other: en fællesskabsspecifik årsag desc: - other: This question doesn't meet a community guideline. + other: Dette spørgsmål opfylder ikke en fællesskabsretningslinje. multiple: name: - other: needs details or clarity + other: kræver detaljer eller klarhed desc: other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + - Dette spørgsmål indeholder i øjeblikket flere spørgsmål i et. Det bør + - fokusere på kun ét problem. other: name: - other: something else + other: noget andet desc: - other: This post requires another reason not listed above. + other: Dette indlæg kræver en anden grund som ikke er nævnt ovenfor. operation_type: asked: - other: asked + other: spurgt answered: - other: answered + other: besvaret modified: - other: modified + other: ændret deleted_title: - other: Deleted question + other: Slettet spørgsmål questions_title: - other: Questions + other: Spørgsmål tag: tags_title: other: Tags no_description: - other: The tag has no description. + other: Tag har ingen beskrivelse. notification: action: update_question: - other: updated question + other: opdateret spørgsmål answer_the_question: - other: answered question + other: besvaret spørgsmål update_answer: - other: updated answer + other: opdateret svar accept_answer: - other: accepted answer + other: accepteret svar comment_question: - other: commented question + other: kommenteret spørgsmål comment_answer: - other: commented answer + other: kommenteret svar reply_to_you: - other: replied to you + other: svarede dig mention_you: - other: mentioned you + other: nævnte dig your_question_is_closed: - other: Your question has been closed + other: Dit spørgsmål er blevet lukket your_question_was_deleted: - other: Your question has been deleted + other: Dit spørgsmål er blevet slettet your_answer_was_deleted: - other: Your answer has been deleted + other: Dit svar er blevet slettet your_comment_was_deleted: - other: Your comment has been deleted + other: Din kommentar er slettet up_voted_question: - other: upvoted question + other: op-stemt spørgsmål down_voted_question: - other: downvoted question + other: ned-stemt spørgsmål up_voted_answer: - other: upvoted answer + other: op-stemt svar down_voted_answer: - other: downvoted answer + other: ned-stemt svar up_voted_comment: - other: upvoted comment + other: op-stemt kommentar invited_you_to_answer: - other: invited you to answer + other: inviterede dig til at svare + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: - other: "[{{.SiteName}}] Confirm your new email address" + other: "[{{.SiteName}}] Bekræft din nye e-mailadresse" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
\n{{.ChangeEmailUrl}}

\n\nIf you did not request this change, please ignore this email.\n" + other: "Bekræft din nye e-mailadresse for {{.SiteName}} ved at klikke på følgende link:
\n{{.ChangeEmailUrl}}

\n\nHvis du ikke anmodede om denne ændring, ignorér venligst denne e-mail.\n" new_answer: title: - other: "[{{.SiteName}}] {{.DisplayName}} answered your question" + other: "[{{.SiteName}}] {{.DisplayName}} besvarede dit spørgsmål" body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\nSe den på {{.SiteName}}

\n\n--
\nAfmeld" invited_you_to_answer: title: - other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" + other: "[{{.SiteName}}] {{.DisplayName}} inviterede dig til at svare" body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
I think you may know the answer.

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
Jeg tror du måske kender svaret.

\nSe den på {{.SiteName}}

\n\n--
\nAfmeld" new_comment: title: - other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" + other: "[{{.SiteName}}] {{.DisplayName}} kommenterede dit indlæg" body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\nSe den på {{.SiteName}}

\n\n--
\nAfmeld" new_question: title: - other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" + other: "[{{.SiteName}}] Nyt spørgsmål: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\nAfmeld" pass_reset: title: - other: "[{{.SiteName }}] Password reset" + other: "[{{.SiteName }}] Nulstilling af adgangskode" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

\n\nIf it was not you, you can safely ignore this email.

\n\nClick the following link to choose a new password:
\n{{.PassResetUrl}}\n" + other: "Nogen bad om at nulstille din adgangskode på {{.SiteName}}.

\n\nHvis det ikke var dig, kan du trygt ignorere denne e-mail.

\n\nKlik på følgende link for at vælge en ny adgangskode:
\n{{.PassResetUrl}}\n" register: title: - other: "[{{.SiteName}}] Confirm your new account" + other: "[{{.SiteName}}] Bekræft din nye konto" body: - other: "Welcome to {{.SiteName}}!

\n\nClick the following link to confirm and activate your new account:
\n{{.RegisterUrl}}

\n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Velkommen til {{.SiteName}}!

\n\nKlik på følgende link for at bekræfte og aktivere din nye konto:
\n{{.RegisterUrl}}

\n\nHvis ovenstående link ikke kan klikkes på, prøv at kopiere og indsætte det i adresselinjen i din webbrowser.\n" test: title: - other: "[{{.SiteName}}] Test Email" + other: "[{{.SiteName}}] Test E-Mail" body: - other: "This is a test email." + other: "Dette er en test e-mail." action_activity_type: upvote: - other: upvote + other: stem op upvoted: - other: upvoted + other: stemt op downvote: - other: downvote + other: stem ned downvoted: - other: downvoted + other: stemt ned accept: - other: accept + other: acceptér accepted: - other: accepted + other: accepteret edit: - other: edit + other: rediger review: queued_post: - other: Queued post + other: Indlæg i kø flagged_post: - other: Flagged post + other: Anmeldt indlæg suggested_post_edit: - other: Suggested edits + other: Foreslåede redigeringer reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} og {{ .Count }} mere..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: - title: How to Format + title: Sådan formaterer du desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • for at lave links

    <https://url.com>

    [Titel](https://url.com)
  • indsæt linieskift mellem paragraffer

  • _kursiv_ or **fed**

  • indskyd kode med 4 mellemrum

  • citér ved at placere > på starten af linie

  • backtick escapes `som _dette_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: - prev: Prev - next: Next + prev: Forrige + next: Næste page_title: - question: Question - questions: Questions + question: Spørgsmål + questions: Spørgsmål tag: Tag tags: Tags tag_wiki: tag wiki - create_tag: Create Tag - edit_tag: Edit Tag - ask_a_question: Add Question - edit_question: Edit Question - edit_answer: Edit Answer - search: Search - posts_containing: Posts containing - settings: Settings - notifications: Notifications - login: Log In - sign_up: Sign Up - account_recovery: Account Recovery - account_activation: Account Activation - confirm_email: Confirm Email - account_suspended: Account Suspended - admin: Admin - change_email: Modify Email + create_tag: Opret tag + edit_tag: Rediger tag + ask_a_question: Tilføj spørgsmål + edit_question: Rediger spørgsmål + edit_answer: Rediger Svar + search: Søg + posts_containing: Indlæg som indeholder + settings: Indstillinger + notifications: Notifikationer + login: Log Ind + sign_up: Tilmeld dig + account_recovery: Konto-gendannelse + account_activation: Aktivering af konto + confirm_email: Bekræft e-mail + account_suspended: Konto suspenderet + admin: Administrator + change_email: Ændre E-Mail install: Answer Installation - upgrade: Answer Upgrade - maintenance: Website Maintenance - users: Users - oauth_callback: Processing - http_404: HTTP Error 404 - http_50X: HTTP Error 500 - http_403: HTTP Error 403 - logout: Log Out + upgrade: Answer Opgradering + maintenance: Vedligeholdelse af websted + users: Brugere + oauth_callback: Behandler + http_404: HTTP Fejl 404 + http_50X: Http Fejl 500 + http_403: HTTP Fejl 403 + logout: Log Ud notifications: - title: Notifications - inbox: Inbox - achievement: Achievements - new_alerts: New alerts - all_read: Mark all as read - show_more: Show more - someone: Someone + title: Notifikationer + inbox: Indbakke + achievement: Bedrifter + new_alerts: Nye adviseringer + all_read: Markér alle som læst + show_more: Vis mere + someone: Nogen inbox_type: - all: All - posts: Posts - invites: Invites - votes: Votes + all: Alle + posts: Indlæg + invites: Invitationer + votes: Stemmer + answer: Answer + question: Question + badge_award: Badge suspended: - title: Your Account has been Suspended - until_time: "Your account was suspended until {{ time }}." - forever: This user was suspended forever. - end: You don't meet a community guideline. - contact_us: Contact us + title: Din konto er blevet suspenderet + until_time: "Din konto blev suspenderet indtil {{ time }}." + forever: Denne bruger blev suspenderet for evigt. + end: Du opfylder ikke en fællesskabsretningslinje. + contact_us: Kontakt os editor: blockquote: - text: Blockquote + text: Citatblok bold: - text: Strong + text: Fed chart: - text: Chart - flow_chart: Flow chart - sequence_diagram: Sequence diagram - class_diagram: Class diagram - state_diagram: State diagram - entity_relationship_diagram: Entity relationship diagram - user_defined_diagram: User defined diagram - gantt_chart: Gantt chart - pie_chart: Pie chart + text: Diagram + flow_chart: Flow- diagram + sequence_diagram: Sekvensdiagram + class_diagram: Klassediagram + state_diagram: Tilstands-diagram + entity_relationship_diagram: Enheds-forhold-diagram + user_defined_diagram: Brugerdefineret diagram + gantt_chart: Gantt- diagram + pie_chart: Cirkeldiagram code: - text: Code Sample - add_code: Add code sample + text: Kode-eksempel + add_code: Tilføj kodeeksempel form: fields: code: - label: Code + label: Kode msg: - empty: Code cannot be empty. + empty: Kode skal udfyldes. language: - label: Language - placeholder: Automatic detection - btn_cancel: Cancel - btn_confirm: Add + label: Sprog + placeholder: Automatisk detektering + btn_cancel: Annuller + btn_confirm: Tilføj formula: - text: Formula + text: Formel options: - inline: Inline formula - block: Block formula + inline: Indlejret formel + block: Formel blok heading: - text: Heading + text: Overskrift options: - h1: Heading 1 - h2: Heading 2 - h3: Heading 3 - h4: Heading 4 - h5: Heading 5 - h6: Heading 6 + h1: Overskrift 1 + h2: Overskrift 2 + h3: Overskrift 3 + h4: Overskrift 4 + h5: Overskrift 5 + h6: Overskrift 6 help: - text: Help + text: Hjælp hr: - text: Horizontal rule + text: Vandret streg image: - text: Image - add_image: Add image - tab_image: Upload image + text: Billede + add_image: Tilføj billede + tab_image: Upload billede form_image: fields: file: - label: Image file - btn: Select image + label: Billedfil + btn: Vælg billede msg: - empty: File cannot be empty. - only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + empty: Filen skal udfyldes. + only_image: Kun billedfiler er tilladt. + max_size: Filstørrelse må ikke overstige 4 MB. desc: - label: Description - tab_url: Image URL + label: Beskriveslse + tab_url: Billede-URL form_url: fields: url: - label: Image URL + label: Billede-URL msg: - empty: Image URL cannot be empty. + empty: Billede-URL skal udfyldes. name: - label: Description - btn_cancel: Cancel - btn_confirm: Add - uploading: Uploading + label: Beskriveslse + btn_cancel: Annuller + btn_confirm: Tilføj + uploading: Uploader indent: - text: Indent + text: Indrykning outdent: - text: Outdent + text: Udrykning italic: - text: Emphasis + text: Fremhævning link: - text: Hyperlink - add_link: Add hyperlink + text: Link + add_link: Tilføj link form: fields: url: label: URL msg: - empty: URL cannot be empty. + empty: URL må ikke være tom. name: - label: Description - btn_cancel: Cancel - btn_confirm: Add + label: Beskriveslse + btn_cancel: Annuller + btn_confirm: Tilføj ordered_list: - text: Numbered list + text: Nummereret liste unordered_list: - text: Bulleted list + text: Punktliste table: - text: Table - heading: Heading - cell: Cell + text: Tabel + heading: Overskrift + cell: Celle close_modal: - title: I am closing this post as... - btn_cancel: Cancel - btn_submit: Submit + title: Jeg lukker dette indlæg fordi... + btn_cancel: Annuller + btn_submit: Indsend remark: - empty: Cannot be empty. + empty: skal udfyldes. msg: - empty: Please select a reason. + empty: Vælg en grund. report_modal: - flag_title: I am flagging to report this post as... - close_title: I am closing this post as... - review_question_title: Review question - review_answer_title: Review answer - review_comment_title: Review comment - btn_cancel: Cancel - btn_submit: Submit + flag_title: Jeg markerer for at rapportere dette indlæg som... + close_title: Jeg lukker dette indlæg fordi... + review_question_title: Gennemgå spørgsmål + review_answer_title: Gennemgå svar + review_comment_title: Gennemgå kommentar + btn_cancel: Annuller + btn_submit: Indsend remark: - empty: Cannot be empty. + empty: skal udfyldes. msg: - empty: Please select a reason. - not_a_url: URL format is incorrect. - url_not_match: URL origin does not match the current website. + empty: Vælg en grund. + not_a_url: URL-format er forkert. + url_not_match: URL oprindelsen matcher ikke det aktuelle websted. tag_modal: - title: Create new tag + title: Opret et nyt tag form: fields: display_name: - label: Display name + label: Visnings-navn msg: - empty: Display name cannot be empty. - range: Display name up to 35 characters. + empty: Visnings-navn skal udfyldes. + range: Visnings-navn på op til 35 tegn. slug_name: - label: URL slug - desc: URL slug up to 35 characters. + label: URL-slug + desc: URL slug op til 35 tegn. msg: - empty: URL slug cannot be empty. - range: URL slug up to 35 characters. - character: URL slug contains unallowed character set. + empty: URL slug må ikke være tom. + range: URL slug op til 35 tegn. + character: URL slug indeholder ikke tilladte tegn. desc: - label: Description + label: Beskriveslse revision: label: Revision edit_summary: - label: Edit summary + label: Rediger resumé placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) - btn_cancel: Cancel - btn_submit: Submit - btn_post: Post new tag + Forklar kort dine ændringer (korrigeret stavning, fast grammatik, forbedret formatering) + btn_cancel: Annuller + btn_submit: Indsend + btn_post: Send nyt tag tag_info: - created_at: Created - edited_at: Edited - history: History + created_at: Oprettet + edited_at: Redigeret + history: Historik synonyms: - title: Synonyms - text: The following tags will be remapped to - empty: No synonyms found. - btn_add: Add a synonym - btn_edit: Edit - btn_save: Save - synonyms_text: The following tags will be remapped to + title: Synonymer + text: Følgende tags vil blive genmappet til + empty: Ingen synonymer fundet. + btn_add: Tilføj et synonym + btn_edit: Rediger + btn_save: Gem + synonyms_text: Følgende tags vil blive genmappet til delete: - title: Delete this tag + title: Slet dette tag tip_with_posts: >- -

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+

Vi tillader ikke at slette tag med indlæg.

Fjern venligst dette tag fra indlæggene først.

tip_with_synonyms: >- -

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

- tip: Are you sure you wish to delete? - close: Close +

Vi tillader ikke at slette tag med indlæg.

Fjern venligst dette tag fra indlæggene først.

+ tip: Er du sikker på, at du vil slette? + close: Luk edit_tag: - title: Edit Tag - default_reason: Edit tag - default_first_reason: Add tag - btn_save_edits: Save edits - btn_cancel: Cancel + title: Rediger tag + default_reason: Rediger tag + default_first_reason: Tilføj tag + btn_save_edits: Gem ændringer + btn_cancel: Annuller dates: long_date: MMM D - long_date_with_year: "MMM D, YYYY" - long_date_with_time: "MMM D, YYYY [at] HH:mm" - now: now - x_seconds_ago: "{{count}}s ago" - x_minutes_ago: "{{count}}m ago" - x_hours_ago: "{{count}}h ago" - hour: hour - day: day - hours: hours - days: days + long_date_with_year: "D MMMM, YYYY" + long_date_with_time: "MMM D, ÅÅÅÅ [at] HH:mm" + now: nu + x_seconds_ago: "{{count}}s siden" + x_minutes_ago: "{{count}}s siden" + x_hours_ago: "{{count}}t siden" + hour: time + day: dag + hours: timer + days: dag reaction: - heart: heart - smile: smile - frown: frown - btn_label: add or remove reactions - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} - unreact_emoji: unreact with {{ emoji }} + heart: hjerte + smile: smil + frown: rynke panden + btn_label: tilføj eller fjern reaktioner + undo_emoji: fortryd {{ emoji }} reaktion + react_emoji: reager med {{ emoji }} + unreact_emoji: ikke reager med {{ emoji }} comment: - btn_add_comment: Add comment - reply_to: Reply to - btn_reply: Reply - btn_edit: Edit - btn_delete: Delete - btn_flag: Flag - btn_save_edits: Save edits - btn_cancel: Cancel - show_more: "{{count}} more comments" + btn_add_comment: Tilføj kommentar + reply_to: Svar til + btn_reply: Svar + btn_edit: Rediger + btn_delete: Slet + btn_flag: Anmeld + btn_save_edits: Gem ændringer + btn_cancel: Annuller + show_more: "{{count}} flere kommentarer" tip_question: >- - Use comments to ask for more information or suggest improvements. Avoid answering questions in comments. + Brug kommentarer til at bede om mere information eller foreslå forbedringer. Undgå at besvare spørgsmål i kommentarer. tip_answer: >- - Use comments to reply to other users or notify them of changes. If you are adding new information, edit your post instead of commenting. - tip_vote: It adds something useful to the post + Brug kommentarer til at svare andre brugere eller give dem besked om ændringer. Hvis du tilføjer nye oplysninger, skal du redigere dit indlæg i stedet for at kommentere. + tip_vote: Det tilføjer noget nyttigt til indlægget edit_answer: - title: Edit Answer - default_reason: Edit answer - default_first_reason: Add answer + title: Rediger Svar + default_reason: Rediger svar + default_first_reason: Tilføj svar form: fields: revision: label: Revision answer: - label: Answer + label: Svar feedback: - characters: content must be at least 6 characters in length. + characters: indhold skal være mindst 6 tegn. edit_summary: - label: Edit summary + label: Rediger resumé placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) - btn_save_edits: Save edits - btn_cancel: Cancel + Forklar kort dine ændringer (korrigeret stavning, fast grammatik, forbedret formatering) + btn_save_edits: Gem ændringer + btn_cancel: Annuller tags: title: Tags sort_buttons: - popular: Popular - name: Name - newest: Newest - button_follow: Follow - button_following: Following - tag_label: questions - search_placeholder: Filter by tag name - no_desc: The tag has no description. - more: More + popular: Populære + name: Navn + newest: Nyeste + button_follow: Følg + button_following: Følger + tag_label: spørgsmål + search_placeholder: Filtrer efter tag-navn + no_desc: Tag har ingen beskrivelse. + more: Mere ask: - title: Add Question - edit_title: Edit Question - default_reason: Edit question - default_first_reason: Add question - similar_questions: Similar questions + title: Tilføj spørgsmål + edit_title: Rediger spørgsmål + default_reason: Rediger spørgsmål + default_first_reason: Tilføj spørgsmål + similar_questions: Lignende spørgsmål form: fields: revision: label: Revision title: - label: Title - placeholder: Be specific and imagine you're asking a question to another person + label: Titel + placeholder: Vær specifik og forestil dig, at du stiller et spørgsmål til en anden person msg: - empty: Title cannot be empty. - range: Title up to 150 characters + empty: Titel må ikke være tom. + range: Titel på op til 150 tegn body: - label: Body + label: Brødtekst msg: - empty: Body cannot be empty. + empty: Brødtekst skal udfyldes. tags: label: Tags msg: - empty: Tags cannot be empty. + empty: Tags må ikke være tom. answer: - label: Answer + label: Svar msg: - empty: Answer cannot be empty. + empty: Svar må ikke være tomt. edit_summary: - label: Edit summary + label: Rediger resumé placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) - btn_post_question: Post your question - btn_save_edits: Save edits - answer_question: Answer your own question - post_question&answer: Post your question and answer + Forklar kort dine ændringer (korrigeret stavning, fast grammatik, forbedret formatering) + btn_post_question: Indsend dit spørgsmål + btn_save_edits: Gem ændringer + answer_question: Besvar dit eget spørgsmål + post_question&answer: Send dit spørgsmål og svar tag_selector: - add_btn: Add tag - create_btn: Create new tag - search_tag: Search tag - hint: "Describe what your question is about, at least one tag is required." - no_result: No tags matched - tag_required_text: Required tag (at least one) + add_btn: Tilføj tag + create_btn: Opret et nyt tag + search_tag: Søg tag + hint: "Beskriv hvad dit spørgsmål handler om, mindst et tag er påkrævet." + no_result: Ingen tags matchede + tag_required_text: Påkrævet tag (mindst én) header: nav: - question: Questions + question: Spørgsmål tag: Tags - user: Users - profile: Profile - setting: Settings - logout: Log out - admin: Admin - review: Review - bookmark: Bookmarks - moderation: Moderation + user: Brugere + badges: Badges + profile: Profil + setting: Indstillinger + logout: Log Ud + admin: Administrator + review: Gennemgå + bookmark: Bogmærker + moderation: Moderering search: - placeholder: Search + placeholder: Søg footer: build_on: >- - Powered by <1> Apache Answer - the open-source software that powers Q&A communities.
Made with love © {{cc}}. + Drevet af <1> Apache Answer- open source-softwaren, der driver Q&A-fællesskaber.
Fremstillet med kærlighed ©️ {{cc}}. upload_img: - name: Change - loading: loading... + name: Skift + loading: indlæser... pic_auth_code: title: Captcha - placeholder: Type the text above + placeholder: Skriv teksten ovenfor msg: - empty: Captcha cannot be empty. + empty: Captcha må ikke være tomt. inactive: first: >- - You're almost done! We sent an activation mail to {{mail}}. Please follow the instructions in the mail to activate your account. - info: "If it doesn't arrive, check your spam folder." + Du er næsten færdig! Vi har sendt en aktiveringsmail til {{mail}}. Følg venligst instruktionerne i mailen for at aktivere din konto. + info: "Hvis det ikke ankommer, tjek din spam-mappe." another: >- - We sent another activation email to you at {{mail}}. It might take a few minutes for it to arrive; be sure to check your spam folder. - btn_name: Resend activation email - change_btn_name: Change email + Vi har sendt endnu en aktiverings-e-mail til dig på {{mail}}. Det kan tage nogen få minutter før den når frem; kontrollér også din spam-mappe. + btn_name: Send aktiverings-e-mail igen + change_btn_name: Ændre e-mail msg: - empty: Cannot be empty. + empty: skal udfyldes. resend_email: - url_label: Are you sure you want to resend the activation email? - url_text: You can also give the activation link above to the user. + url_label: Er du sikker på, at du vil sende aktiveringse-mailen? + url_text: Du kan også give aktiveringslinket ovenfor til brugeren. login: - login_to_continue: Log in to continue - info_sign: Don't have an account? <1>Sign up - info_login: Already have an account? <1>Log in - agreements: By registering, you agree to the <1>privacy policy and <3>terms of service. - forgot_pass: Forgot password? + login_to_continue: Log ind for at fortsætte + info_sign: Har du ikke en konto? <1>Tilmeld dig + info_login: Har du allerede en konto? <1>Log ind + agreements: Ved at registrere dig accepterer du <1>privacy policy og <3>terms of service . + forgot_pass: Glemt adgangskode? name: - label: Name + label: Navn msg: - empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. - character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + empty: Navn må ikke være tomt. + range: Navnet skal være mellem 4 og 30 tegn. + character: 'Skal bruge tegnsættet "a-z", "A-Z", "0-9", " - . _"' email: - label: Email + label: E-mail msg: - empty: Email cannot be empty. + empty: E-mail skal udfyldes. password: - label: Password + label: Adgangskode msg: - empty: Password cannot be empty. - different: The passwords entered on both sides are inconsistent + empty: Adgangskoden skal udfyldes. + different: De indtastede adgangskoder er ikke ens account_forgot: - page_title: Forgot Your Password - btn_name: Send me recovery email + page_title: Glemt adgangskode + btn_name: Send mig gendannelsesmail send_success: >- - If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + Hvis en konto matcher {{mail}}, vil du modtage en e-mail med instruktioner om, hvordan du nulstiller din adgangskode. email: - label: Email + label: E-mail msg: - empty: Email cannot be empty. + empty: E-mail skal udfyldes. change_email: - btn_cancel: Cancel - btn_update: Update email address + btn_cancel: Annuller + btn_update: Opdater e-mailadresse send_success: >- - If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + Hvis en konto matcher {{mail}}, vil du modtage en e-mail med instruktioner om, hvordan du nulstiller din adgangskode. email: - label: New email + label: Ny e-mail msg: - empty: Email cannot be empty. + empty: E-mail skal udfyldes. oauth: - connect: Connect with {{ auth_name }} - remove: Remove {{ auth_name }} + connect: Forbind med {{ auth_name }} + remove: Fjern {{ auth_name }} oauth_bind_email: - subtitle: Add a recovery email to your account. - btn_update: Update email address + subtitle: Tilføj en gendannelsese-mail til din konto. + btn_update: Opdater e-mailadresse email: - label: Email + label: E-mail msg: - empty: Email cannot be empty. - modal_title: Email already existes. - modal_content: This email address already registered. Are you sure you want to connect to the existing account? - modal_cancel: Change email - modal_confirm: Connect to the existing account + empty: E-mail skal udfyldes. + modal_title: Email eksisterer allerede. + modal_content: Denne e-mailadresse er allerede registreret. Er du sikker på, at du vil oprette forbindelse til den eksisterende konto? + modal_cancel: Ændre e-mail + modal_confirm: Opret forbindelse til den eksisterende konto password_reset: - page_title: Password Reset - btn_name: Reset my password + page_title: Nulstil adgangskode + btn_name: Nulstil min adgangskode reset_success: >- - You successfully changed your password; you will be redirected to the log in page. + Du har ændret din adgangskode. Du vil blive omdirigeret til siden log ind. link_invalid: >- - Sorry, this password reset link is no longer valid. Perhaps your password is already reset? - to_login: Continue to log in page + Beklager, dette link til nulstilling af adgangskode er ikke længere gyldigt. Måske er din adgangskode allerede nulstillet? + to_login: Fortsæt til log-ind siden password: - label: Password + label: Adgangskode msg: - empty: Password cannot be empty. - length: The length needs to be between 8 and 32 - different: The passwords entered on both sides are inconsistent + empty: Adgangskoden skal udfyldes. + length: Længden skal være mellem 8 og 32 tegn + different: De indtastede adgangskoder er ikke ens password_confirm: - label: Confirm new password + label: Bekræft den nye adgangskode settings: - page_title: Settings - goto_modify: Go to modify + page_title: Indstillinger + goto_modify: Gå til at ændre nav: - profile: Profile - notification: Notifications - account: Account - interface: Interface + profile: Profil + notification: Notifikationer + account: Konto + interface: Grænseflade profile: - heading: Profile - btn_name: Save + heading: Profil + btn_name: Gem display_name: - label: Display name - msg: Display name cannot be empty. - msg_range: Display name up to 30 characters. + label: Visnings-navn + msg: Visnings-navn skal udfyldes. + msg_range: Visnings-navn på op til 30 tegn. username: - label: Username - caption: People can mention you as "@username". - msg: Username cannot be empty. - msg_range: Username up to 30 characters. - character: 'Must use the character set "a-z", "0-9", " - . _"' + label: Brugernavn + caption: Man kan nævne dig som "@username". + msg: Brugernavn skal udfyldes. + msg_range: Brugernavn op til 30 tegn. + character: 'Skal bruge tegnsættet "a-z", "0-9", " - . _"' avatar: - label: Profile image + label: Profilbillede gravatar: Gravatar - gravatar_text: You can change image on - custom: Custom - custom_text: You can upload your image. + gravatar_text: Du kan ændre billede på + custom: Brugerdefineret + custom_text: Du kan uploade dit billede. default: System - msg: Please upload an avatar + msg: Upload en avatar bio: - label: About me + label: Om mig website: - label: Website + label: Websted placeholder: "https://example.com" - msg: Website incorrect format + msg: Forkert format på websted location: - label: Location - placeholder: "City, Country" + label: Placering + placeholder: "By, land" notification: - heading: Email Notifications - turn_on: Turn on + heading: Email-notifikationer + turn_on: Slå til inbox: - label: Inbox notifications - description: Answers to your questions, comments, invites, and more. + label: Notifikationer i indbakken + description: Svar på dine spørgsmål, kommentarer, invitationer og mere. all_new_question: - label: All new questions - description: Get notified of all new questions. Up to 50 questions per week. + label: Alle nye spørgsmål + description: Få besked om alle nye spørgsmål. Op til 50 spørgsmål om ugen. all_new_question_for_following_tags: - label: All new questions for following tags - description: Get notified of new questions for following tags. + label: Alle nye spørgsmål til følgende tags + description: Få besked om nye spørgsmål til følgende tags. account: - heading: Account - change_email_btn: Change email - change_pass_btn: Change password + heading: Konto + change_email_btn: Ændre e-mail + change_pass_btn: Skift adgangskode change_email_info: >- - We've sent an email to that address. Please follow the confirmation instructions. + Vi har sendt en e-mail til denne adresse. Følg venligst bekræftelsesinstruktionerne. email: - label: Email + label: E-mail new_email: - label: New email - msg: New email cannot be empty. + label: Ny e-mail + msg: Ny e-mail skal udfyldes. pass: - label: Current password - msg: Password cannot be empty. - password_title: Password + label: Nuværende adgangskode + msg: Adgangskoden skal udfyldes. + password_title: Adgangskode current_pass: - label: Current password + label: Nuværende adgangskode msg: - empty: Current password cannot be empty. - length: The length needs to be between 8 and 32. - different: The two entered passwords do not match. + empty: Nuværende adgangskode skal udfyldes. + length: Længden skal være mellem 8 og 32 tegn. + different: De to indtastede adgangskoder er ikke ens. new_pass: - label: New password + label: Ny adgangskode pass_confirm: - label: Confirm new password + label: Bekræft den nye adgangskode interface: - heading: Interface + heading: Grænseflade lang: - label: Interface language - text: User interface language. It will change when you refresh the page. + label: Grænseflade sprog + text: Brugergrænseflade sprog. Det vil ændres, når du opdaterer siden. my_logins: - title: My logins - label: Log in or sign up on this site using these accounts. - modal_title: Remove login - modal_content: Are you sure you want to remove this login from your account? - modal_confirm_btn: Remove - remove_success: Removed successfully + title: Mine log ind + label: Log ind eller tilmeld dig på dette websted ved hjælp af disse konti. + modal_title: Fjern login + modal_content: Er du sikker på, at du vil fjerne dette login fra din konto? + modal_confirm_btn: Slet + remove_success: Fjernet toast: - update: update success - update_password: Password changed successfully. - flag_success: Thanks for flagging. - forbidden_operate_self: Forbidden to operate on yourself - review: Your revision will show after review. - sent_success: Sent successfully + update: opdatering gennemført + update_password: Adgangskoden er ændret. + flag_success: Tak for at anmelde. + forbidden_operate_self: Forbudt at operere på dig selv + review: Din revision vil blive vist efter gennemgang. + sent_success: Sendt related_question: - title: Related Questions - answers: answers + title: Relaterede spørgsmål + answers: svar invite_to_answer: - title: People Asked - desc: Select people who you think might know the answer. - invite: Invite to answer - add: Add people - search: Search people + title: Inviter personer + desc: Invitér personer, som du tror, kan svare. + invite: Inviter til at svare + add: Tilføj personer + search: Søg personer question_detail: - action: Action - Asked: Asked - asked: asked - update: Modified - edit: edited - commented: commented - Views: Viewed - Follow: Follow - Following: Following - follow_tip: Follow this question to receive notifications - answered: answered - closed_in: Closed in - show_exist: Show existing question. - useful: Useful - question_useful: It is useful and clear - question_un_useful: It is unclear or not useful - question_bookmark: Bookmark this question - answer_useful: It is useful - answer_un_useful: It is not useful + action: Handling + Asked: Spurgt + asked: spurgt + update: Ændret + edit: redigeret + commented: kommenteret + Views: Set + Follow: Følg + Following: Følger + follow_tip: Følg dette spørgsmål for at modtage notifikationer + answered: besvaret + closed_in: Lukket om + show_exist: Vis eksisterende spørgsmål. + useful: Nyttigt + question_useful: Det er nyttigt og klart + question_un_useful: Det er uklart eller ikke nyttigt + question_bookmark: Bogmærk dette spørgsmål + answer_useful: Det er nyttigt + answer_un_useful: Det er ikke nyttigt answers: - title: Answers - score: Score - newest: Newest - oldest: Oldest - btn_accept: Accept - btn_accepted: Accepted + title: Svar + score: Bedømmelse + newest: Nyeste + oldest: Ældste + btn_accept: Acceptér + btn_accepted: Accepteret write_answer: - title: Your Answer - edit_answer: Edit my existing answer - btn_name: Post your answer - add_another_answer: Add another answer - confirm_title: Continue to answer - continue: Continue + title: Dit Svar + edit_answer: Redigér mit eksisterende svar + btn_name: Indsend dit svar + add_another_answer: Tilføj endnu et svar + confirm_title: Fortsæt med at svare + continue: Forsæt confirm_info: >- -

Are you sure you want to add another answer?

You could use the edit link to refine and improve your existing answer, instead.

- empty: Answer cannot be empty. - characters: content must be at least 6 characters in length. +

Er du sikker på, at du vil tilføje et andet svar?

Du kan i stedet bruge redigeringslinket til at forfine og forbedre dit eksisterende svar.

+ empty: Svar skal udfyldes. + characters: indhold skal være mindst 6 tegn. tips: - header_1: Thanks for your answer - li1_1: Please be sure to answer the question. Provide details and share your research. - li1_2: Back up any statements you make with references or personal experience. - header_2: But avoid ... - li2_1: Asking for help, seeking clarification, or responding to other answers. + header_1: Tak for dit svar + li1_1: Vær sikker på at besvare spørgsmålet. Giv oplysninger og del din forskning. + li1_2: Begrund eventuelle udsagn med referencer eller personlige erfaringer. + header_2: Men undgå... + li2_1: Spørger om hjælp, søger afklaring, eller reagerer på andre svar. reopen: - confirm_btn: Reopen - title: Reopen this post - content: Are you sure you want to reopen? + confirm_btn: Genåbn + title: Genåbn dette indlæg + content: Er du sikker på, at du vil genåbne? list: - confirm_btn: List - title: List this post - content: Are you sure you want to list? + confirm_btn: Liste + title: Sæt dette indlæg på listen + content: Er du sikker på du vil sætte på listen? unlist: - confirm_btn: Unlist - title: Unlist this post - content: Are you sure you want to unlist? + confirm_btn: Fjern fra listen + title: Fjern dette indlæg fra listen + content: Er du sikker på at du vil fjerne fra listen? pin: - title: Pin this post - content: Are you sure you wish to pinned globally? This post will appear at the top of all post lists. - confirm_btn: Pin + title: Fastgør dette indlæg + content: Er du sikker på, at du ønsker at fastgøre globalt? Dette indlæg vises øverst på alle indlægs-lister. + confirm_btn: Fastgør delete: - title: Delete this post + title: Slet dette indlæg question: >- - We do not recommend deleting questions with answers because doing so deprives future readers of this knowledge.

Repeated deletion of answered questions can result in your account being blocked from asking. Are you sure you wish to delete? + Vi anbefaler ikke, at sletter spørgsmål med svar, fordi det fratager fremtidige læsere denne viden.

Gentaget sletning af besvarede spørgsmål kan resultere i, at din konto bliver blokeret fra at spørge. Er du sikker på, at du ønsker at slette? answer_accepted: >- -

We do not recommend deleting accepted answer because doing so deprives future readers of this knowledge.

Repeated deletion of accepted answers can result in your account being blocked from answering. Are you sure you wish to delete? - other: Are you sure you wish to delete? - tip_answer_deleted: This answer has been deleted - undelete_title: Undelete this post - undelete_desc: Are you sure you wish to undelete? +

Vi anbefaler ikke at slette accepteret svar fordi det fratager fremtidige læsere denne viden.

Gentagen sletning af accepterede svar kan resultere i, at din konto bliver blokeret fra besvarelse. Er du sikker på, at du ønsker at slette? + other: Er du sikker på, at du vil slette? + tip_answer_deleted: Dette svar er blevet slettet + undelete_title: Genopret dette indlæg + undelete_desc: Er du sikker på du ønsker at genoprette? btns: - confirm: Confirm - cancel: Cancel - edit: Edit - save: Save - delete: Delete - undelete: Undelete - list: List - unlist: Unlist - unlisted: Unlisted - login: Log in - signup: Sign up - logout: Log out - verify: Verify - add_question: Add question - approve: Approve - reject: Reject - skip: Skip - discard_draft: Discard draft - pinned: Pinned - all: All - question: Question - answer: Answer - comment: Comment - refresh: Refresh - resend: Resend - deactivate: Deactivate - active: Active - suspend: Suspend - unsuspend: Unsuspend - close: Close - reopen: Reopen - ok: OK - light: Light - dark: Dark - system_setting: System setting - default: Default - reset: Reset + confirm: Bekræft + cancel: Annuller + edit: Rediger + save: Gem + delete: Slet + undelete: Genopret + list: Sæt på liste + unlist: Fjern fra liste + unlisted: Fjernet fra liste + login: Log ind + signup: Opret konto + logout: Log Ud + verify: Verificér + add_question: Tilføj spørgsmål + approve: Godkend + reject: Afvis + skip: Spring Over + discard_draft: Kassér udkast + pinned: Fastgjort + all: Alle + question: Spørgsmål + answer: Svar + comment: Kommentar + refresh: Genopfrisk + resend: Send igen + deactivate: Deaktiver + active: Aktiv + suspend: Suspendér + unsuspend: Ophæv suspendering + close: Luk + reopen: Genåbn + ok: Ok + light: Lys + dark: Mørk + system_setting: Systemindstilling + default: Standard + reset: Nulstil tag: Tag - post_lowercase: post - filter: Filter - ignore: Ignore - submit: Submit + post_lowercase: indlæg + filter: Filtrer + ignore: Ignorér + submit: Indsend normal: Normal - closed: Closed - deleted: Deleted - pending: Pending - more: More + closed: Lukket + deleted: Slettet + pending: Ventende + more: Mere search: - title: Search Results - keywords: Keywords - options: Options - follow: Follow - following: Following - counts: "{{count}} Results" - more: More + title: Søgeresultater + keywords: Nøgleord + options: Muligheder + follow: Følg + following: Følger + counts: "{{count}} Resultater" + more: Mere sort_btns: - relevance: Relevance - newest: Newest - active: Active - score: Score - more: More + relevance: Relevans + newest: Nyeste + active: Aktiv + score: Bedømmelse + more: Mere tips: - title: Advanced Search Tips - tag: "<1>[tag] search with a tag" - user: "<1>user:username search by author" - answer: "<1>answers:0 unanswered questions" - score: "<1>score:3 posts with a 3+ score" - question: "<1>is:question search questions" - is_answer: "<1>is:answer search answers" - empty: We couldn't find anything.
Try different or less specific keywords. + title: Avancerede Søgetips + tag: "<1>[tag] søgning med et tag" + user: "<1>user:username søgning efter forfatter" + answer: "<1>answers:0 ubesvarede spørgsmål" + score: "<1>score:3 indlæg med 3+ score" + question: "<1>is:question søgespørgsmål" + is_answer: "<1>is:answer søgesvar" + empty: Vi kunne ikke finde noget.
Prøv forskellige eller mindre specifikke søgeord. share: - name: Share - copy: Copy link - via: Share post via... - copied: Copied - facebook: Share to Facebook - twitter: Share to Twitter - cannot_vote_for_self: You can't vote for your own post. + name: Del + copy: Kopiér link + via: Del indlæg via... + copied: Kopieret + facebook: Del på Facebook + twitter: Del på Twitter + cannot_vote_for_self: Du kan ikke stemme på dit eget indlæg. modal_confirm: - title: Error... + title: Fejl... account_result: - success: Your new account is confirmed; you will be redirected to the home page. - link: Continue to homepage - oops: Oops! - invalid: The link you used no longer works. - confirm_new_email: Your email has been updated. + success: Din nye konto er bekræftet. Du vil blive omdirigeret til hjemmesiden. + link: Fortsæt til startside + oops: Hovsa! + invalid: Linket, du brugte, virker ikke længere. + confirm_new_email: Din e-mail er blevet opdateret. confirm_new_email_invalid: >- - Sorry, this confirmation link is no longer valid. Perhaps your email was already changed? + Beklager, dette bekræftelseslink er ikke længere gyldigt. Måske blev din e-mail allerede ændret? unsubscribe: - page_title: Unsubscribe - success_title: Unsubscribe Successful - success_desc: You have been successfully removed from this subscriber list and won't receive any further emails from us. - link: Change settings + page_title: Afmeld + success_title: Afmelding Lykkedes + success_desc: Du er blevet fjernet fra denne abonnentliste og vil ikke modtage yderligere e-mails fra os. + link: Skift indstillinger question: - following_tags: Following Tags - edit: Edit - save: Save - follow_tag_tip: Follow tags to curate your list of questions. - hot_questions: Hot Questions - all_questions: All Questions - x_questions: "{{ count }} Questions" - x_answers: "{{ count }} answers" - questions: Questions - answers: Answers - newest: Newest - active: Active - hot: Hot - score: Score - unanswered: Unanswered - modified: modified - answered: answered - asked: asked - closed: closed - follow_a_tag: Follow a tag - more: More + following_tags: Følger Tags + edit: Rediger + save: Gem + follow_tag_tip: Følg tags for at udvælge dine spørgsmål. + hot_questions: Populære Spørgsmål + all_questions: Alle Spørgsmål + x_questions: "{{ count }} Spørgsmål" + x_answers: "{{ count }} svar" + questions: Spørgsmål + answers: Svar + newest: Nyeste + active: Aktiv + hot: Populært + recommend: Recommend + score: Bedømmelse + unanswered: Ubesvaret + modified: ændret + answered: besvaret + asked: spurgt + closed: lukket + follow_a_tag: Følg et tag + more: Mere personal: - overview: Overview - answers: Answers - answer: answer - questions: Questions - question: question - bookmarks: Bookmarks - reputation: Reputation - comments: Comments - votes: Votes - newest: Newest - score: Score - edit_profile: Edit profile - visited_x_days: "Visited {{ count }} days" - viewed: Viewed - joined: Joined - last_login: Seen - about_me: About Me - about_me_empty: "// Hello, World !" - top_answers: Top Answers - top_questions: Top Questions - stats: Stats - list_empty: No posts found.
Perhaps you'd like to select a different tab? - accepted: Accepted - answered: answered - asked: asked - downvoted: downvoted + overview: Oversigt + answers: Svar + answer: svar + questions: Spørgsmål + question: spørgsmål + bookmarks: Bogmærker + reputation: Omdømme + comments: Kommentarer + votes: Stemmer + badges: Badges + newest: Nyeste + score: Bedømmelse + edit_profile: Rediger profil + visited_x_days: "Besøgte {{ count }} dage" + viewed: Set + joined: Tilmeldt + comma: "," + last_login: Set + about_me: Om Mig + about_me_empty: "// Hej, Verden!" + top_answers: Populære Svar + top_questions: Populære Spørgsmål + stats: Statistik + list_empty: Ingen indlæg fundet.
Måske vil du vælge en anden fane? + accepted: Accepteret + answered: besvaret + asked: spurgt + downvoted: nedstemt mod_short: MOD - mod_long: Moderators - x_reputation: reputation - x_votes: votes received - x_answers: answers - x_questions: questions + mod_long: Moderatorer + x_reputation: omdømme + x_votes: stemmer modtaget + x_answers: svar + x_questions: spørgsmål + recent_badges: Recent Badges install: title: Installation - next: Next - done: Done - config_yaml_error: Can't create the config.yaml file. + next: Næste + done: Udført + config_yaml_error: Kan ikke oprette filen config.yaml. lang: - label: Please choose a language + label: Vælg et sprog db_type: - label: Database engine + label: Database type db_username: - label: Username - placeholder: root - msg: Username cannot be empty. + label: Brugernavn + placeholder: rod + msg: Brugernavn skal udfyldes. db_password: - label: Password - placeholder: root - msg: Password cannot be empty. + label: Adgangskode + placeholder: rod + msg: Adgangskoden skal udfyldes. db_host: label: Database host placeholder: "db:3306" - msg: Database host cannot be empty. + msg: Database host skal udfyldes. db_name: - label: Database name + label: Database navn placeholder: answer - msg: Database name cannot be empty. + msg: Databasenavn skal udfyldes. db_file: - label: Database file + label: Databasefil placeholder: /data/answer.db - msg: Database file cannot be empty. + msg: Databasefil skal udfyldes. config_yaml: - title: Create config.yaml - label: The config.yaml file created. + title: Opret config.yaml + label: Filen config.yaml blev oprettet. desc: >- - You can create the <1>config.yaml file manually in the <1>/var/wwww/xxx/ directory and paste the following text into it. - info: After you've done that, click "Next" button. - site_information: Site Information - admin_account: Admin Account + Du kan manuelt oprette filen <1>config.yaml i mappen <1>/var/wwww/xxx/ og indsætte følgende tekst i den. + info: Når du har gjort det, skal du klikke på "Næste" knappen. + site_information: Websted Information + admin_account: Administrator Konto site_name: - label: Site name - msg: Site name cannot be empty. - msg_max_length: Site name must be at maximum 30 characters in length. + label: Websted navn + msg: Websted-navn skal udfyldes. + msg_max_length: Webstedsnavn kan ikke være længere end 30 tegn. site_url: - label: Site URL - text: The address of your site. + label: Websted URL + text: Adressen på dit websted. msg: - empty: Site URL cannot be empty. - incorrect: Site URL incorrect format. - max_length: Site URL must be at maximum 512 characters in length. + empty: Webstedets URL skal udfyldes. + incorrect: Websteds URL forkert format. + max_length: WebstedsURL skal højst være 512 tegn. contact_email: - label: Contact email - text: Email address of key contact responsible for this site. + label: Kontakt e-mail + text: E-mailadresse på nøglekontakt ansvarlig for dette websted. msg: - empty: Contact email cannot be empty. - incorrect: Contact email incorrect format. + empty: Kontakt-e-mail skal udfyldes. + incorrect: Ugyldig kontakt e-mail adresse. login_required: - label: Private - switch: Login required - text: Only logged in users can access this community. + label: Privat + switch: Log ind påkrævet + text: Kun brugere som er logget ind har adgang til dette fællesskab. admin_name: - label: Name - msg: Name cannot be empty. - character: 'Must use the character set "a-z", "0-9", " - . _"' - msg_max_length: Name must be at maximum 30 characters in length. + label: Navn + msg: Navn skal udfyldes. + character: 'Skal bruge tegnsættet "a-z", "0-9", " - . _"' + msg_max_length: Navn kan ikke være længere end 30 tegn. admin_password: - label: Password + label: Adgangskode text: >- - You will need this password to log in. Please store it in a secure location. - msg: Password cannot be empty. - msg_min_length: Password must be at least 8 characters in length. - msg_max_length: Password must be at maximum 32 characters in length. + Du skal bruge denne adgangskode for at logge ind. Opbevar den et sikkert sted. + msg: Adgangskoden skal udfyldes. + msg_min_length: Adgangskoden skal være mindst 8 tegn. + msg_max_length: Adgangskoden skal højst udgøre 32 tegn. admin_email: - label: Email - text: You will need this email to log in. + label: E-mail + text: Du skal bruge denne e-mail for at logge ind. msg: - empty: Email cannot be empty. - incorrect: Email incorrect format. - ready_title: Your site is ready + empty: E-mail skal udfyldes. + incorrect: Ugyldig e-mail adresse. + ready_title: Dit websted er klar ready_desc: >- - If you ever feel like changing more settings, visit <1>admin section; find it in the site menu. - good_luck: "Have fun, and good luck!" - warn_title: Warning + Hvis du nogensinde har lyst til at ændre flere indstillinger, kan du besøge <1>admin-sektion; find det i site-menuen. + good_luck: "Hav det sjovt, og held og lykke!" + warn_title: Advarsel warn_desc: >- - The file <1>config.yaml already exists. If you need to reset any of the configuration items in this file, please delete it first. - install_now: You may try <1>installing now. - installed: Already installed + Filen <1>config.yaml findes allerede. Hvis du har brug for at nulstille en af konfigurationselementerne i denne fil, så slet den først. + install_now: Du kan prøve <1>at installere nu. + installed: Allerede installeret installed_desc: >- - You appear to have already installed. To reinstall please clear your old database tables first. - db_failed: Database connection failed + Du synes allerede at være installeret. For at geninstallere skal du først rydde dine gamle databasetabeller. + db_failed: Database forbindelse mislykkedes db_failed_desc: >- - This either means that the database information in your <1>config.yaml file is incorrect or that contact with the database server could not be established. This could mean your host's database server is down. + Det betyder enten, at databaseinformationen i din <1>config. aml fil er forkert eller at kontakt med databaseserveren ikke kunne etableres. Dette kan betyde, at din værts databaseserver er nede. counts: - views: views - votes: votes - answers: answers - accepted: Accepted + views: visninger + votes: stemmer + answers: svar + accepted: Accepteret page_error: - http_error: HTTP Error {{ code }} - desc_403: You don't have permission to access this page. - desc_404: Unfortunately, this page doesn't exist. - desc_50X: The server encountered an error and could not complete your request. - back_home: Back to homepage + http_error: HTTP Fejl {{ code }} + desc_403: Du har ikke adgang til denne side. + desc_404: Denne side findes desværre ikke. + desc_50X: Der skete en fejl på serveren og den kunne ikke fuldføre din anmodning. + back_home: Tilbage til forsiden page_maintenance: - desc: "We are under maintenance, we'll be back soon." + desc: "Vi laver vedligeholdelse, men er snart tilbage igen." nav_menus: - dashboard: Dashboard - contents: Contents - questions: Questions - answers: Answers - users: Users - flags: Flags - settings: Settings - general: General - interface: Interface + dashboard: Kontrolpanel + contents: Indhold + questions: Spørgsmål + answers: Svar + users: Brugere + badges: Badges + flags: Anmeldelser + settings: Indstillinger + general: Generelt + interface: Brugerflade smtp: SMTP branding: Branding - legal: Legal - write: Write - tos: Terms of Service - privacy: Privacy + legal: Jura + write: Skriv + tos: Betingelser for brug + privacy: Privatliv seo: SEO - customize: Customize - themes: Themes + customize: Tilpas + themes: Temaer css_html: CSS/HTML - login: Login - privileges: Privileges + login: Log Ind + privileges: Rettigheder plugins: Plugins - installed_plugins: Installed Plugins - website_welcome: Welcome to {{site_name}} + installed_plugins: Installerede Plugins + website_welcome: Velkommen til {{site_name}} user_center: - login: Login - qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. - login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + login: Log Ind + qrcode_login_tip: Brug {{ agentName }} til at scanne QR-koden og logge ind. + login_failed_email_tip: Log ind mislykkedes, tillad denne app at få adgang til dine e-mail-oplysninger, før du prøver igen. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: - title: Admin + title: Administrator dashboard: - title: Dashboard - welcome: Welcome to Admin! - site_statistics: Site statistics - questions: "Questions:" - answers: "Answers:" - comments: "Comments:" - votes: "Votes:" - users: "Users:" - flags: "Flags:" - reviews: "Reviews:" - site_health: Site health + title: Kontrolpanel + welcome: Velkommen til Administration! + site_statistics: Statistik for webstedet + questions: "Spørgsmål:" + answers: "Svar:" + comments: "Kommentarer:" + votes: "Stemmer:" + users: "Brugere:" + flags: "Anmeldelser:" + reviews: "Gennemgange:" + site_health: Websteds sundhed version: "Version:" https: "HTTPS:" - upload_folder: "Upload folder:" - run_mode: "Running mode:" - private: Private - public: Public + upload_folder: "Upload mappe:" + run_mode: "Kørselstilstand:" + private: Privat + public: Offentlig smtp: "SMTP:" - timezone: "Timezone:" - system_info: System info + timezone: "Tidszone:" + system_info: System information go_version: "Go version:" database: "Database:" - database_size: "Database size:" - storage_used: "Storage used:" - uptime: "Uptime:" + database_size: "Database størrelse:" + storage_used: "Anvendt lagerplads:" + uptime: "Oppetid:" links: Links plugins: Plugins github: GitHub blog: Blog - contact: Contact + contact: Kontakt os forum: Forum - documents: Documents - feedback: Feedback + documents: Dokumenter + feedback: Tilbagemelding support: Support - review: Review - config: Config - update_to: Update to - latest: Latest - check_failed: Check failed - "yes": "Yes" - "no": "No" - not_allowed: Not allowed - allowed: Allowed - enabled: Enabled - disabled: Disabled - writable: Writable - not_writable: Not writable + review: Gennemgå + config: Konfiguration + update_to: Opdatér til + latest: Seneste + check_failed: Tjek mislykkedes + "yes": "Ja" + "no": "Nej" + not_allowed: Ikke tilladt + allowed: Tilladt + enabled: Aktiveret + disabled: Deaktiveret + writable: Skrivbar + not_writable: Ikke skrivbar flags: - title: Flags - pending: Pending - completed: Completed - flagged: Flagged - flagged_type: Flagged {{ type }} - created: Created - action: Action - review: Review + title: Anmeldelser + pending: Ventende + completed: Gennemført + flagged: Anmeldt + flagged_type: Anmeldt{{ type }} + created: Oprettet + action: Handling + review: Gennemgå user_role_modal: - title: Change user role to... - btn_cancel: Cancel - btn_submit: Submit + title: Skift brugerrolle til... + btn_cancel: Annuller + btn_submit: Indsend new_password_modal: - title: Set new password + title: Angiv ny adgangskode form: fields: password: - label: Password - text: The user will be logged out and need to login again. - msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + label: Adgangskode + text: Brugeren vil blive logget ud og skal logge ind igen. + msg: Adgangskoden skal være på 8- 32 tegn. + btn_cancel: Annuller + btn_submit: Indsend edit_profile_modal: - title: Edit profile + title: Rediger profil form: fields: display_name: - label: Display name - msg_range: Display name up to 30 characters. + label: Visnings-navn + msg_range: Visnings-navn på op til 30 tegn. username: - label: Username - msg_range: Username up to 30 characters. + label: Brugernavn + msg_range: Brugernavn op til 30 tegn. email: - label: Email - msg_invalid: Invalid Email Address. - edit_success: Edited successfully - btn_cancel: Cancel - btn_submit: Submit + label: E-mail + msg_invalid: Ugyldig E-Mail Adresse. + edit_success: Redigering lykkedes + btn_cancel: Annuller + btn_submit: Indsend user_modal: - title: Add new user + title: Tilføj ny bruger form: fields: users: - label: Bulk add user + label: Masse-tilføj bruger placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" - text: Separate “name, email, password” with commas. One user per line. - msg: "Please enter the user's email, one per line." + text: Adskil “navn, e-mail, adgangskode” med kommaer. Én bruger pr. linje. + msg: "Indtast venligst brugerens e-mail, en pr. linje." display_name: - label: Display name - msg: Display name must be at 4-30 characters in length. + label: Visnings-navn + msg: Vis navn skal være på 4-30 tegn. email: - label: Email - msg: Email is not valid. + label: E-mail + msg: E-mail er ugyldig. password: - label: Password - msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + label: Adgangskode + msg: Adgangskoden skal være 8- 32 tegn. + btn_cancel: Annuller + btn_submit: Indsend users: - title: Users - name: Name - email: Email - reputation: Reputation - created_at: Created Time - delete_at: Deleted Time - suspend_at: Suspended Time + title: Brugere + name: Navn + email: E-mail + reputation: Omdømme + created_at: Oprettet Tidspunkt + delete_at: Slettet Tidspunkt + suspend_at: Suspenderet Tidspunkt status: Status - role: Role - action: Action - change: Change - all: All - staff: Staff - more: More - inactive: Inactive - suspended: Suspended - deleted: Deleted + role: Rolle + action: Handling + change: Ændre + all: Alle + staff: Ansatte + more: Mere + inactive: Inaktiv + suspended: Suspenderet + deleted: Slettet normal: Normal Moderator: Moderator - Admin: Admin - User: User + Admin: Administrator + User: Bruger filter: - placeholder: "Filter by name, user:id" - set_new_password: Set new password - edit_profile: Edit profile - change_status: Change status - change_role: Change role - show_logs: Show logs - add_user: Add user + placeholder: "Filtrer efter navn, user:id" + set_new_password: Angiv ny adgangskode + edit_profile: Rediger profil + change_status: Ændre status + change_role: Ændre rolle + show_logs: Vis logfiler + add_user: Tilføj bruger deactivate_user: - title: Deactivate user - content: An inactive user must re-validate their email. + title: Deaktiver bruger + content: En inaktiv bruger skal bekræfte deres e-mail igen. delete_user: - title: Delete this user - content: Are you sure you want to delete this user? This is permanent! - remove: Remove their content - label: Remove all questions, answers, comments, etc. - text: Don’t check this if you wish to only delete the user’s account. + title: Slet denne bruger + content: Er du sikker på, at du vil slette denne bruger? Dette er permanent! + remove: Fjern deres indhold + label: Fjern alle spørgsmål, svar, kommentarer osv. + text: Tjek ikke dette, hvis du kun ønsker at slette brugerens konto. suspend_user: - title: Suspend this user - content: A suspended user can't log in. + title: Suspendér denne bruger + content: En suspenderet bruger kan ikke logge ind. questions: - page_title: Questions - unlisted: Unlisted - post: Post - votes: Votes - answers: Answers - created: Created + page_title: Spørgsmål + unlisted: Fjernet fra liste + post: Indlæg + votes: Stemmer + answers: Svar + created: Oprettet status: Status - action: Action - change: Change - pending: Pending + action: Handling + change: Ændre + pending: Ventende filter: - placeholder: "Filter by title, question:id" + placeholder: "Filtrer efter titel, question:id" answers: - page_title: Answers - post: Post - votes: Votes - created: Created + page_title: Svar + post: Indlæg + votes: Stemmer + created: Oprettet status: Status - action: Action - change: Change + action: Handling + change: Ændre filter: - placeholder: "Filter by title, answer:id" + placeholder: "Filtrer efter titel, answer:id" general: - page_title: General + page_title: Generelt name: - label: Site name - msg: Site name cannot be empty. - text: "The name of this site, as used in the title tag." + label: Websted navn + msg: Websted-navn skal udfyldes. + text: "Navnet på dette websted, som bruges i title-tagget." site_url: - label: Site URL - msg: Site url cannot be empty. - validate: Please enter a valid URL. - text: The address of your site. + label: Websted URL + msg: Websted-URL skal udfyldes. + validate: Angiv et gyldigt URL. + text: Adressen på dit websted. short_desc: - label: Short site description - msg: Short site description cannot be empty. - text: "Short description, as used in the title tag on homepage." + label: Kort beskrivelse af websted + msg: Kort beskrivelse af websted skal udfyldes. + text: "Kort beskrivelse, som anvendt i title-tag på hjemmesiden." desc: - label: Site description - msg: Site description cannot be empty. - text: "Describe this site in one sentence, as used in the meta description tag." + label: Websted beskrivelse + msg: Webstedsbeskrivelse skal udfyldes. + text: "Beskriv dette websted i en sætning, som bruges i meta description tagget." contact_email: - label: Contact email - msg: Contact email cannot be empty. - validate: Contact email is not valid. - text: Email address of key contact responsible for this site. + label: Kontakt e-mail + msg: Kontakt-e-mail skal udfyldes. + validate: Kontakt-e-mail er ugyldig. + text: E-mailadresse på nøglekontakt ansvarlig for dette websted. check_update: - label: Software updates - text: Automatically check for updates + label: Opdatering af software + text: Søg automatisk efter opdateringer interface: - page_title: Interface + page_title: Brugerflade language: - label: Interface language - msg: Interface language cannot be empty. - text: User interface language. It will change when you refresh the page. + label: Brugerflade sprog + msg: Brugerflade-sprog skal udfyldes. + text: Brugergrænseflade sprog. Det vil ændres, når du opdaterer siden. time_zone: - label: Timezone - msg: Timezone cannot be empty. - text: Choose a city in the same timezone as you. + label: Tidszone + msg: Tidszone skal udfyldes. + text: Vælg en by i samme tidszone som dig selv. smtp: page_title: SMTP from_email: - label: From email - msg: From email cannot be empty. - text: The email address which emails are sent from. + label: Fra e-mail + msg: Fra e-mail skal udfyldes. + text: E-mail-adressen som e-mails sendes fra. from_name: - label: From name - msg: From name cannot be empty. - text: The name which emails are sent from. + label: Fra navn + msg: Fra navn skal udfyldes. + text: Navnet som e-mails sendes fra. smtp_host: label: SMTP host - msg: SMTP host cannot be empty. - text: Your mail server. + msg: SMTP host skal udfyldes. + text: Din mail-server. encryption: - label: Encryption - msg: Encryption cannot be empty. - text: For most servers SSL is the recommended option. + label: Kryptering + msg: Kryptering skal udfyldes. + text: For de fleste servere er SSL den anbefalede indstilling. ssl: SSL tls: TLS - none: None + none: Ingen smtp_port: label: SMTP port - msg: SMTP port must be number 1 ~ 65535. - text: The port to your mail server. + msg: SMTP port skal være nummer 1 ~ 65535. + text: Porten til din mailserver. smtp_username: - label: SMTP username - msg: SMTP username cannot be empty. + label: SMTP brugernavn + msg: SMTP brugernavn skal udfyldes. smtp_password: - label: SMTP password - msg: SMTP password cannot be empty. + label: SMTP adgangskode + msg: SMTP adgangskode skal udfyldes. test_email_recipient: - label: Test email recipients - text: Provide email address that will receive test sends. - msg: Test email recipients is invalid + label: Test e-mail modtagere + text: Angiv e-mail-adresse, der vil modtage test-beskedder. + msg: Test e-mail modtagere er ugyldige smtp_authentication: - label: Enable authentication - title: SMTP authentication - msg: SMTP authentication cannot be empty. - "yes": "Yes" - "no": "No" + label: Aktiver autentificering + title: SMTP autentificering + msg: SMTP autentificering skal udfyldes. + "yes": "Ja" + "no": "Nej" branding: page_title: Branding logo: label: Logo - msg: Logo cannot be empty. - text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown. + msg: Logo skal udfyldes. + text: Logoet billede øverst til venstre på dit websted. Brug et bredt rektangulært billede med en højde på 56 og et breddeforhold større end 3:1. Hvis efterladt tom, vil webstedets titeltekst blive vist. mobile_logo: - label: Mobile logo - text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the "logo" setting will be used. + label: Mobil logo + text: Logoet bruges på mobile version af dit websted. Brug et bredt rektangulært billede med en højde på 56. Hvis efterladt tom, vil billedet fra indstillingen "logo" blive brugt. square_icon: - label: Square icon - msg: Square icon cannot be empty. - text: Image used as the base for metadata icons. Should ideally be larger than 512x512. + label: Kvadratisk ikon + msg: Kvadratisk ikon skal udfyldes. + text: Billede brugt som basis for metadata-ikoner. Bør være større end 512x512. favicon: label: Favicon - text: A favicon for your site. To work correctly over a CDN it must be a png. Will be resized to 32x32. If left blank, "square icon" will be used. + text: En favicon til dit websted. For at fungere korrekt over en CDN skal det være en png. Vil blive ændret til 32x32. Hvis efterladt tomt, vil "firkantet ikon" blive brugt. legal: - page_title: Legal + page_title: Jura terms_of_service: - label: Terms of service - text: "You can add terms of service content here. If you already have a document hosted elsewhere, provide the full URL here." + label: Betingelser for brug + text: "Du kan tilføje servicevilkår her. Hvis du allerede har et dokument hostet et andet sted, så angiv den fulde URL her." privacy_policy: - label: Privacy policy - text: "You can add privacy policy content here. If you already have a document hosted elsewhere, provide the full URL here." + label: Privatlivspolitik + text: "Du kan tilføje privatlivspolitik indhold her. Hvis du allerede har et dokument hostet et andet sted, så angiv den fulde URL her." write: - page_title: Write + page_title: Skriv restrict_answer: - title: Answer write - label: Each user can only write one answer for each question - text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + title: Skriv svar + label: Hver bruger kan kun skrive et svar for det samme spørgsmål + text: "Slå fra for at give brugerne mulighed for at skrive flere svar på det samme spørgsmål, hvilket kan forårsage svar at være ufokuseret." recommend_tags: - label: Recommend tags - text: "Recommend tags will show in the dropdown list by default." + label: Anbefal tags + text: "Anbefal tags vil som standard blive vist i dropdown-listen." msg: - contain_reserved: "recommended tags cannot contain reserved tags" + contain_reserved: "anbefalede tags kan ikke indeholde reserverede tags" required_tag: - title: Set required tags - label: Set “Recommend tags” as required tags - text: "Every new question must have at least one recommend tag." + title: Angiv påkrævede tags + label: Sæt “Anbefal tags” som påkrævede tags + text: "Hvert nyt spørgsmål skal have mindst et anbefalet tag." reserved_tags: - label: Reserved tags - text: "Reserved tags can only be used by moderator." + label: Reserverede tags + text: "Reserverede tags kan kun bruges af moderator." seo: page_title: SEO permalink: label: Permalink - text: Custom URL structures can improve the usability, and forward-compatibility of your links. + text: Brugerdefinerede URL-strukturer kan forbedre brugervenlighed og fremadrettet kompatibilitet af dine links. robots: label: robots.txt - text: This will permanently override any related site settings. + text: Dette vil permanent tilsidesætte eventuelle relaterede webstedsindstillinger. themes: - page_title: Themes + page_title: Temaer themes: - label: Themes - text: Select an existing theme. + label: Temaer + text: Vælg et eksisterende tema. color_scheme: - label: Color scheme + label: Farveskema navbar_style: - label: Navbar style + label: Navigations-bjælke stil primary_color: - label: Primary color - text: Modify the colors used by your themes + label: Primær farve + text: Ændre farver, der bruges af dine temaer css_and_html: - page_title: CSS and HTML + page_title: CSS og HTML custom_css: - label: Custom CSS + label: Brugerdefineret CSS text: > head: @@ -1756,168 +2041,182 @@ ui: text: > header: - label: Header + label: Overskrift text: > footer: - label: Footer - text: This will insert before </body>. + label: Sidefod + text: Dette indsættes før </body>. sidebar: - label: Sidebar - text: This will insert in sidebar. + label: Sidebjælke + text: Dette vil indsætte i sidebjælken. login: - page_title: Login + page_title: Log Ind membership: - title: Membership - label: Allow new registrations - text: Turn off to prevent anyone from creating a new account. + title: Medlemskab + label: Tillad nye registreringer + text: Slå fra for at forhindre at nogen opretter en ny konto. email_registration: - title: Email registration - label: Allow email registration - text: Turn off to prevent anyone creating new account through email. + title: E-mail-registrering + label: Tillad e-mail registrering + text: Slå fra for at forhindre, at der oprettes en ny konto via e-mail. allowed_email_domains: - title: Allowed email domains - text: Email domains that users must register accounts with. One domain per line. Ignored when empty. + title: Tilladte e-mail-domæner + text: E-mail-domæner som brugere skal registrere konti med. Et domæne pr. linje. Ignoreres når tomt. private: - title: Private - label: Login required - text: Only logged in users can access this community. + title: Privat + label: Log ind påkrævet + text: Kun brugere som er logget ind har adgang til dette fællesskab. password_login: - title: Password login - label: Allow email and password login - text: "WARNING: If turn off, you may be unable to log in if you have not previously configured other login method." + title: Adgangskode log ind + label: Tillad e-mail og adgangskode login + text: "ADVARSEL: Hvis du slår fra, kan du muligvis ikke logge ind, hvis du ikke tidligere har konfigureret en anden loginmetode." installed_plugins: - title: Installed Plugins - plugin_link: Plugins extend and expand the functionality. You may find plugins in the <1>Plugin Repository. + title: Installerede Plugins + plugin_link: Plugins udvider og udvider funktionaliteten. Du kan finde plugins i <1>Plugin Repository. filter: - all: All - active: Active - inactive: Inactive - outdated: Outdated + all: Alle + active: Aktiv + inactive: Inaktiv + outdated: Forældet plugins: label: Plugins - text: Select an existing plugin. - name: Name + text: Vælg et eksisterende plugin. + name: Navn version: Version status: Status - action: Action - deactivate: Deactivate - activate: Activate - settings: Settings + action: Handling + deactivate: Deaktiver + activate: Aktivér + settings: Indstillinger settings_users: - title: Users + title: Brugere avatar: - label: Default avatar - text: For users without a custom avatar of their own. + label: Standard avatar + text: For brugere uden en brugerdefineret avatar. gravatar_base_url: - label: Gravatar base URL - text: URL of the Gravatar provider's API base. Ignored when empty. + label: Gravatar base-URL + text: URL for Gravatar-udbyderens API-base. Ignoreres når tom. profile_editable: - title: Profile editable + title: Profil redigerbar allow_update_display_name: - label: Allow users to change their display name + label: Tillad brugere at ændre deres visningsnavn allow_update_username: - label: Allow users to change their username + label: Tillad brugere at ændre deres brugernavn allow_update_avatar: - label: Allow users to change their profile image + label: Tillad brugere at ændre deres profilbillede allow_update_bio: - label: Allow users to change their about me + label: Tillad brugere at ændre deres om-mig allow_update_website: - label: Allow users to change their website + label: Tillad brugere at ændre deres hjemmeside allow_update_location: - label: Allow users to change their location + label: Tillad brugere at ændre deres placering privilege: - title: Privileges + title: Rettigheder level: - label: Reputation required level - text: Choose the reputation required for the privileges + label: Omdømme påkrævet niveau + text: Vælg det omdømme der kræves for rettighederne msg: - should_be_number: the input should be number - number_larger_1: number should be equal or larger than 1 + should_be_number: input skal være et tal + number_larger_1: tal skal være lig med eller større end 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: - optional: (optional) - empty: cannot be empty - invalid: is invalid - btn_submit: Save - not_found_props: "Required property {{ key }} not found." - select: Select + optional: (valgfrit) + empty: skal udfyldes + invalid: er ugyldigt + btn_submit: Gem + not_found_props: "Nødvendig egenskab {{ key }} ikke fundet." + select: Vælg page_review: - review: Review - proposed: proposed - question_edit: Question edit - answer_edit: Answer edit - tag_edit: Tag edit - edit_summary: Edit summary - edit_question: Edit question - edit_answer: Edit answer - edit_tag: Edit tag - empty: No review tasks left. - approve_revision_tip: Do you approve this revision? - approve_flag_tip: Do you approve this flag? - approve_post_tip: Do you approve this post? - approve_user_tip: Do you approve this user? - suggest_edits: Suggested edits - flag_post: Flag post - flag_user: Flag user - queued_post: Queued post - queued_user: Queued user + review: Gennemgå + proposed: foreslået + question_edit: Rediger spørgsmål + answer_edit: Svar redigér + tag_edit: Tag redigér + edit_summary: Rediger resumé + edit_question: Rediger spørgsmål + edit_answer: Rediger svar + edit_tag: Rediger tag + empty: Ingen gennemgangsopgaver tilbage. + approve_revision_tip: Godkender du denne revision? + approve_flag_tip: Godkender du denne anmeldelse? + approve_post_tip: Godkender du dette indlæg? + approve_user_tip: Godkender du denne bruger? + suggest_edits: Foreslåede redigeringer + flag_post: Anmeld indlæg + flag_user: Anmeld bruger + queued_post: Indlæg i kø + queued_user: Brugere i kø filter_label: Type - reputation: reputation - flag_post_type: Flagged this post as {{ type }}. - flag_user_type: Flagged this user as {{ type }}. - edit_post: Edit post - list_post: List post - unlist_post: Unlist post + reputation: omdømme + flag_post_type: Anmeld dette indlæg som {{ type }}. + flag_user_type: Anmeldte dette indlæg som {{ type }}. + edit_post: Rediger opslag + list_post: Sæt indlæg på liste + unlist_post: Fjern indlæg fra liste timeline: - undeleted: undeleted - deleted: deleted - downvote: downvote - upvote: upvote - accept: accept - cancelled: cancelled - commented: commented - rollback: rollback - edited: edited - answered: answered - asked: asked - closed: closed - reopened: reopened - created: created - pin: pinned - unpin: unpinned - show: listed - hide: unlisted - title: "History for" - tag_title: "Timeline for" - show_votes: "Show votes" - n_or_a: N/A - title_for_question: "Timeline for" - title_for_answer: "Timeline for answer to {{ title }} by {{ author }}" - title_for_tag: "Timeline for tag" + undeleted: genskabt + deleted: slettet + downvote: stem ned + upvote: stem op + accept: acceptér + cancelled: annulleret + commented: kommenteret + rollback: tilbagerul + edited: redigeret + answered: besvaret + asked: spurgt + closed: lukket + reopened: genåbnet + created: oprettet + pin: fastgjort + unpin: frigjort + show: sat på liste + hide: fjernet fra liste + title: "Historik for" + tag_title: "Tidslinje for" + show_votes: "Vis stemmer" + n_or_a: Ikke Relevant + title_for_question: "Tidslinje for" + title_for_answer: "Tidslinje for svar på {{ title }} af {{ author }}" + title_for_tag: "Tidslinje for tag" datetime: Datetime type: Type - by: By - comment: Comment - no_data: "We couldn't find anything." + by: Af + comment: Kommentar + no_data: "Vi kunne ikke finde noget." users: - title: Users - users_with_the_most_reputation: Users with the highest reputation scores this week - users_with_the_most_vote: Users who voted the most this week - staffs: Our community staff - reputation: reputation - votes: votes + title: Brugere + users_with_the_most_reputation: Brugere med det højeste omdømme scorer denne uge + users_with_the_most_vote: Brugere, der stemte mest i denne uge + staffs: Vores fællesskabs personale + reputation: omdømme + votes: stemmer prompt: - leave_page: Are you sure you want to leave the page? - changes_not_save: Your changes may not be saved. + leave_page: Er du sikker på, at du vil forlade siden? + changes_not_save: Dine ændringer er muligvis ikke gemt. draft: - discard_confirm: Are you sure you want to discard your draft? + discard_confirm: Er du sikker på, at du vil kassere dit udkast? messages: - post_deleted: This post has been deleted. - post_pin: This post has been pinned. - post_unpin: This post has been unpinned. - post_hide_list: This post has been hidden from list. - post_show_list: This post has been shown to list. - post_reopen: This post has been reopened. - post_list: This post has been listed. - post_unlist: This post has been unlisted. - post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_deleted: Dette indlæg er blevet slettet. + post_pin: Dette indlæg er blevet fastgjort. + post_unpin: Dette indlæg er blevet frigjort. + post_hide_list: Dette indlæg er blevet skjult fra listen. + post_show_list: Dette indlæg er blevet vist på listen. + post_reopen: Dette indlæg er blevet genåbnet. + post_list: Dette indlæg er blevet listet. + post_unlist: Dette indlæg er blevet aflistet. + post_pending: Dit indlæg afventer gennemgang. Dette er en forhåndsvisning, det vil være synligt, når det er blevet godkendt. diff --git a/i18n/de_DE.yaml b/i18n/de_DE.yaml index 8888767b..4437452c 100644 --- a/i18n/de_DE.yaml +++ b/i18n/de_DE.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Ungültige URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Passwort darf keine Leerzeichen enthalten. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Seiten-Konfiguration nicht gefunden. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -415,12 +420,12 @@ backend: deleted_title: other: Gelöschte Frage questions_title: - other: Questions + other: Fragen tag: tags_title: - other: Tags + other: Schlagwörter no_description: - other: The tag has no description. + other: Diese Kategorie hat keine Beschreibung. notification: action: update_question: @@ -459,6 +464,8 @@ backend: other: positiv bewerteter Kommentar invited_you_to_answer: other: hat dich eingeladen, zu antworten + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Beiträge invites: Einladungen votes: Abstimmungen + answer: Answer + question: Question + badge_award: Badge suspended: title: Dein Konto wurde gesperrt until_time: "Dein Konto wurde bis zum {{ time }} gesperrt." @@ -778,8 +1045,8 @@ ui: smile: Lächeln frown: frown btn_label: Reaktionen hinzufügen oder entfernen - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} + undo_emoji: '{{ emoji }} Reaktion rückgängig machen' + react_emoji: mit {{ emoji }} reagieren unreact_emoji: unreact with {{ emoji }} comment: btn_add_comment: Einen Kommentar hinzufügen @@ -874,6 +1141,7 @@ ui: question: Fragen tag: Schlagwörter user: Benutzer + badges: Badges profile: Profil setting: Einstellungen logout: Ausloggen @@ -918,7 +1186,7 @@ ui: msg: empty: Der Name darf nicht leer sein. range: Die Länge des Namens sollte zwischen 4 und 30 Zeichen liegen. - character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + character: 'Muss den Zeichensatz "a-z", "A-Z", "0-9", " - . _" verwenden' email: label: E-Mail msg: @@ -1132,8 +1400,8 @@ ui: title: Diesen Beitrag auflisten content: Are you sure you want to list? unlist: - confirm_btn: Unlist - title: Unlist this post + confirm_btn: Von Liste nehmen + title: Diesen Beitrag von der Liste nehmen content: Are you sure you want to unlist? pin: title: Diesen Beitrag anpinnen @@ -1156,7 +1424,7 @@ ui: save: Speichern delete: Löschen undelete: Wiederherstellen - list: List + list: Liste unlist: Unlist unlisted: Unlisted login: Einloggen @@ -1191,11 +1459,11 @@ ui: post_lowercase: post filter: Filter ignore: Ignore - submit: Submit + submit: Absenden normal: Normal closed: Geschlossen - deleted: Deleted - pending: Pending + deleted: Gelöscht + pending: Ausstehend more: More search: title: Suchergebnisse @@ -1257,6 +1525,7 @@ ui: newest: Neueste active: Aktiv hot: Hot + recommend: Recommend score: Punktzahl unanswered: Unbeantwortet modified: geändert @@ -1275,12 +1544,14 @@ ui: reputation: Ansehen comments: Kommentare votes: Stimmen + badges: Badges newest: Neueste score: Punktzahl edit_profile: Profil bearbeiten visited_x_days: "{{ count }} Tage besucht" viewed: Gesehen joined: Beigetreten + comma: "," last_login: Gesehen about_me: Über mich about_me_empty: "// Hallo Welt !" @@ -1298,6 +1569,7 @@ ui: x_votes: Stimmen erhalten x_answers: Antworten x_questions: Fragen + recent_badges: Recent Badges install: title: Installation next: Nächste @@ -1321,7 +1593,7 @@ ui: msg: Datenbank-Host darf nicht leer sein. db_name: label: Datenbankname - placeholder: answer + placeholder: antworten msg: Der Datenbankname darf nicht leer sein. db_file: label: Datenbank-Datei @@ -1374,7 +1646,7 @@ ui: msg: empty: E-Mail darf nicht leer sein. incorrect: E-Mail falsches Format. - ready_title: Your site is ready + ready_title: Ihre Seite ist bereit ready_desc: >- Wenn du noch mehr Einstellungen ändern möchtest, besuche den <1>Admin-Bereich; du findest ihn im Seitenmenü. good_luck: "Viel Spaß und viel Glück!" @@ -1407,6 +1679,7 @@ ui: questions: Fragen answers: Antworten users: Benutzer + badges: Badges flags: Meldungen settings: Einstellungen general: Allgemein @@ -1423,19 +1696,31 @@ ui: css_html: CSS/HTML login: Anmeldung privileges: Berechtigungen - plugins: Plugins + plugins: Erweiterungen (Plugins) installed_plugins: Installierte Plugins website_welcome: Willkommen auf {{site_name}} user_center: login: Anmelden qrcode_login_tip: Bitte verwende {{ agentName }}, um den QR-Code zu scannen und dich einzuloggen. login_failed_email_tip: Anmeldung ist fehlgeschlagen. Bitte erlaube dieser App, auf deine E-Mail-Informationen zuzugreifen, bevor du es erneut versuchst. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Administrator dashboard: title: Dashboard - welcome: Welcome to Admin! + welcome: Willkommen im Admin Bereich! site_statistics: Website-Statistiken questions: "Fragen:" answers: "Antworten:" @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: kann nicht leer sein @@ -1859,13 +2158,13 @@ ui: suggest_edits: Suggested edits flag_post: Beitrag melden flag_user: Nutzer melden - queued_post: Queued post - queued_user: Queued user - filter_label: Type - reputation: reputation + queued_post: Beitrag in Warteschlange + queued_user: Benutzer in der Warteschlange + filter_label: Typ + reputation: ansehen flag_post_type: Flagged this post as {{ type }}. flag_user_type: Flagged this user as {{ type }}. - edit_post: Edit post + edit_post: Beitrag bearbeiten list_post: List post unlist_post: Unlist post timeline: diff --git a/i18n/es_ES.yaml b/i18n/es_ES.yaml index 77feaad5..e3e5097a 100644 --- a/i18n/es_ES.yaml +++ b/i18n/es_ES.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: URL no válido. + status_invalid: + other: Invalid status. password: space_invalid: other: La contraseña no puede contener espacios. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Configuración del sitio no encontrada. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: comentario votado a favor invited_you_to_answer: other: te invitó a responder + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} y {{ .Count }} más..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Publicaciones invites: Invitaciones votes: Votos + answer: Answer + question: Question + badge_award: Badge suspended: title: Tu cuenta ha sido suspendida until_time: "Tu cuenta ha sido suspendida hasta el {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Preguntas tag: Etiquetas user: Usuarios + badges: Badges profile: Perfil setting: Ajustes logout: Cerrar sesión @@ -1257,6 +1525,7 @@ ui: newest: Más reciente active: Activo hot: Hot + recommend: Recommend score: Puntuación unanswered: Sin respuesta modified: modificada @@ -1275,12 +1544,14 @@ ui: reputation: Reputación comments: Comentarios votes: Votos + badges: Badges newest: Más reciente score: Puntuación edit_profile: Editar perfil visited_x_days: "Visitado {{ count }} días" viewed: Visto joined: Unido + comma: "," last_login: Visto about_me: Sobre mí about_me_empty: "// ¡Hola Mundo!" @@ -1298,6 +1569,7 @@ ui: x_votes: votos recibidos x_answers: respuestas x_questions: preguntas + recent_badges: Recent Badges install: title: Installation next: Próximo @@ -1407,6 +1679,7 @@ ui: questions: Preguntas answers: Respuestas users: Usuarios + badges: Badges flags: Banderas settings: Ajustes general: General @@ -1430,6 +1703,18 @@ ui: login: Iniciar sesión qrcode_login_tip: Por favor utiliza {{ agentName }} para escanear el código QR e iniciar sesión. login_failed_email_tip: Error al iniciar sesión, por favor permite el acceso a tu información de correo de esta aplicación antes de intentar nuevamente. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Administrador @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: la entrada debe ser número number_larger_1: número debe ser igual o mayor que 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (opcional) empty: no puede estar en blanco diff --git a/i18n/fa_IR.yaml b/i18n/fa_IR.yaml index 2d98aec8..bbb20214 100644 --- a/i18n/fa_IR.yaml +++ b/i18n/fa_IR.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: رمز عبور نمی تواند شامل فضای خالی باشد. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: پیکربندی سایت پیدا نشد. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: نظر بدون رای invited_you_to_answer: other: برای جواب دادن دعوت شده اید + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: پست ها invites: دعوت ها votes: آراء + answer: Answer + question: Question + badge_award: Badge suspended: title: حساب شما معلق شده است until_time: "حساب شما تا تاریخ {{ time }} به حالت تعلیق درآمده است." @@ -874,6 +1141,7 @@ ui: question: سوالات tag: تگ‌ها user: کاربران + badges: Badges profile: پروفایل setting: تنظیمات logout: خروج @@ -1257,6 +1525,7 @@ ui: newest: جدیدترین active: فعال hot: Hot + recommend: Recommend score: امتیاز unanswered: بدون پاسخ modified: تغییر یافته @@ -1275,12 +1544,14 @@ ui: reputation: محبوبیت comments: نظرات votes: آراء + badges: Badges newest: جدیدترین score: امتیاز edit_profile: ویرایش پروفایل visited_x_days: "Visited {{ count }} days" viewed: مشاهده شده joined: عضو شد + comma: "," last_login: مشاهده شده about_me: درباره من about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: آرای دریافت شد x_answers: جواب ها x_questions: سوالات + recent_badges: Recent Badges install: title: Installation next: بعدی @@ -1407,6 +1679,7 @@ ui: questions: سوالات answers: پاسخ ها users: کاربران + badges: Badges flags: پرچم settings: تنظیمات general: عمومی @@ -1430,6 +1703,18 @@ ui: login: ورود qrcode_login_tip: لطفاً از {{ agentName }} برای اسکن کد QR و ورود به سیستم استفاده کنید. login_failed_email_tip: ورود ناموفق بود، لطفاً قبل از امتحان مجدد به این برنامه اجازه دهید به اطلاعات ایمیل شما دسترسی داشته باشد. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: ادمین @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/fr_FR.yaml b/i18n/fr_FR.yaml index 9ab00990..5c9bdcf5 100644 --- a/i18n/fr_FR.yaml +++ b/i18n/fr_FR.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Le mot de passe ne doit pas comporter d'espaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Configuration du site introuvable. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: vous invite à répondre + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Publications invites: Invitations votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Votre compte a été suspendu until_time: "Votre compte a été suspendu jusqu'au {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Étiquettes user: Utilisateurs + badges: Badges profile: Profil setting: Paramètres logout: Se déconnecter @@ -1257,6 +1525,7 @@ ui: newest: Les plus récents active: Actif hot: Hot + recommend: Recommend score: Score unanswered: Sans réponse modified: modifié @@ -1275,12 +1544,14 @@ ui: reputation: Réputation comments: Commentaires votes: Votes + badges: Badges newest: Les plus récents score: Score edit_profile: Éditer le profil visited_x_days: "Visité {{ count }} jours" viewed: Vu joined: Inscrit + comma: "," last_login: Vu about_me: À propos de moi about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes reçus x_answers: réponses x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Suivant @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Réponses users: Utilisateurs + badges: Badges flags: Signalements settings: Paramètres general: Général @@ -1430,6 +1703,18 @@ ui: login: Connexion qrcode_login_tip: Veuillez utiliser {{ agentName }} pour scanner le code QR et vous connecter. login_failed_email_tip: La connexion a échoué, veuillez autoriser cette application à accéder à vos informations de messagerie avant de réessayer. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optionnel) empty: ne peut pas être vide diff --git a/i18n/hi_IN.yaml b/i18n/hi_IN.yaml index b8548d98..99f90253 100644 --- a/i18n/hi_IN.yaml +++ b/i18n/hi_IN.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Your Account has been Suspended until_time: "Your account was suspended until {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Users + badges: Badges profile: Profile setting: Settings logout: Log out @@ -1257,6 +1525,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified @@ -1275,12 +1544,14 @@ ui: reputation: Reputation comments: Comments votes: Votes + badges: Badges newest: Newest score: Score edit_profile: Edit profile visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes received x_answers: answers x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Next @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: Flags settings: Settings general: General @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/id_ID.yaml b/i18n/id_ID.yaml index fb6950d6..8f26ef0e 100644 --- a/i18n/id_ID.yaml +++ b/i18n/id_ID.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Akun Anda telah ditangguhkan until_time: "Akun anda ditangguhkan sampai {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Pengguna + badges: Badges profile: Profil setting: Pengaturan logout: Keluar @@ -1257,6 +1525,7 @@ ui: newest: Terbaru active: Aktif hot: Hot + recommend: Recommend score: Nilai unanswered: Belum dijawab modified: diubah @@ -1275,12 +1544,14 @@ ui: reputation: Reputasi comments: Komentar votes: Vote + badges: Badges newest: Terbaru score: Nilai edit_profile: Edit profile visited_x_days: "Dikunjungi {{ count }} hari" viewed: Dilihat joined: Bergabung + comma: "," last_login: Dilihat about_me: Tentang Saya about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: vote diterima x_answers: jawaban x_questions: pertanyaan + recent_badges: Recent Badges install: title: Installation next: Selanjutnya @@ -1407,6 +1679,7 @@ ui: questions: Pertanyaan answers: Jawaban users: Pengguna + badges: Badges flags: Flags settings: Pengaturan general: Umum @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/it_IT.yaml b/i18n/it_IT.yaml index c2f485e1..673b67e2 100644 --- a/i18n/it_IT.yaml +++ b/i18n/it_IT.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: URL non valido. + status_invalid: + other: Invalid status. password: space_invalid: other: La password non può contenere spazi. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Configurazione del sito non trovata. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: commento approvato invited_you_to_answer: other: sei invitato a rispondere + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Messaggi invites: Inviti votes: Voti + answer: Answer + question: Question + badge_award: Badge suspended: title: Il tuo account è stato sospeso until_time: "Il tuo account è stato sospeso fino a {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Domande tag: Tags user: Utenti + badges: Badges profile: Profilo setting: Impostazioni logout: Disconnetti @@ -1257,6 +1525,7 @@ ui: newest: Più recenti active: Attivo hot: Hot + recommend: Recommend score: Punteggio unanswered: Senza risposta modified: Modificato @@ -1275,12 +1544,14 @@ ui: reputation: Reputazione comments: Commenti votes: Voti + badges: Badges newest: Più recenti score: Punteggio edit_profile: Modifica profilo visited_x_days: "{{ count }} giorni visitati" viewed: Visualizzati joined: Iscritto + comma: "," last_login: Visto about_me: Chi sono about_me_empty: "// Ciao, mondo !" @@ -1298,6 +1569,7 @@ ui: x_votes: voti ricevuti x_answers: risposte x_questions: domande + recent_badges: Recent Badges install: title: Installation next: Avanti @@ -1407,6 +1679,7 @@ ui: questions: Domande answers: Risposte users: Utenti + badges: Badges flags: Contrassegni settings: Impostazioni general: Generale @@ -1430,6 +1703,18 @@ ui: login: Accedi qrcode_login_tip: Si prega di utilizzare {{ agentName }} per scansionare il codice QR e accedere. login_failed_email_tip: Accesso non riuscito. Consenti a questa app di accedere alle tue informazioni email prima di riprovare. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Amministratore @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: l'input dovrebbe essere un numero number_larger_1: il numero dovrebbe essere uguale o superiore a 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (opzionale) empty: non può essere vuoto diff --git a/i18n/ja_JP.yaml b/i18n/ja_JP.yaml index 74d34cf8..0b8fd6d9 100644 --- a/i18n/ja_JP.yaml +++ b/i18n/ja_JP.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: 投稿 invites: 招待 votes: 投票 + answer: Answer + question: Question + badge_award: Badge suspended: title: あなたのアカウントは停止されています。 until_time: "あなたのアカウントは {{ time }} まで停止されました。" @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Users + badges: Badges profile: Profile setting: Settings logout: Log out @@ -1257,6 +1525,7 @@ ui: newest: 最新 active: 有効 hot: Hot + recommend: Recommend score: スコア unanswered: 未回答 modified: 修正済み @@ -1275,12 +1544,14 @@ ui: reputation: Reputation comments: Comments votes: Votes + badges: Badges newest: Newest score: Score edit_profile: Edit profile visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes received x_answers: 回答 x_questions: 質問 + recent_badges: Recent Badges install: title: Installation next: 次へ @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: フラグ settings: 設定 general: 一般 @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: 管理者 @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/ko_KR.yaml b/i18n/ko_KR.yaml index 9e2b9c13..efbf7dcf 100644 --- a/i18n/ko_KR.yaml +++ b/i18n/ko_KR.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: 잘못된 URL 입니다. + status_invalid: + other: Invalid status. password: space_invalid: other: 암호에는 공백을 포함할 수 없습니다. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: 사이트 설정을 찾을 수 없습니다. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -418,7 +423,7 @@ backend: other: Questions tag: tags_title: - other: Tags + other: 태그 no_description: other: The tag has no description. notification: @@ -459,6 +464,8 @@ backend: other: 댓글에 추천함 invited_you_to_answer: other: 답변에 초대함 + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: 게시물 invites: 초대 votes: 투표 + answer: Answer + question: Question + badge_award: Badge suspended: title: 계정이 정지되었습니다 until_time: "당신의 계정은 {{ time }}까지 정지되었습니다." @@ -874,6 +1141,7 @@ ui: question: 질문 tag: 태그 user: 사용자 + badges: Badges profile: 프로필 setting: 설정 logout: 로그아웃 @@ -1257,6 +1525,7 @@ ui: newest: 최신순 active: 활성순 hot: Hot + recommend: Recommend score: 평점순 unanswered: 답변이 없는 질문 modified: 수정됨 @@ -1275,12 +1544,14 @@ ui: reputation: 평판 comments: 댓글 votes: 투표 + badges: Badges newest: 최신순 score: 평점순 edit_profile: 프로필 수정 visited_x_days: "{{ count }} 일 방문함" viewed: 조회됨 joined: 가입일 + comma: "," last_login: 최근 접속 about_me: 자기 소개 about_me_empty: "// 안녕하세요, 세상아 !" @@ -1298,6 +1569,7 @@ ui: x_votes: 받은 투표 x_answers: 답변 x_questions: 질문 + recent_badges: Recent Badges install: title: 설치 next: 다음 @@ -1407,6 +1679,7 @@ ui: questions: 질문 answers: 답변 users: 사용자 + badges: Badges flags: 신고하기 settings: 설정 general: 일반 @@ -1430,6 +1703,18 @@ ui: login: 로그인 qrcode_login_tip: '{{ agentName }}을(를) 사용하여 QR 코드를 스캔하고 로그인하세요.' login_failed_email_tip: 로그인 실패, 다시 시도하기 전에 이 앱이 이메일 정보에 접근할 수 있도록 허용하세요. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: 관리자 @@ -1515,10 +1800,10 @@ ui: label: Username msg_range: Username up to 30 characters. email: - label: Email + label: 이메일 msg_invalid: Invalid Email Address. edit_success: Edited successfully - btn_cancel: Cancel + btn_cancel: 취소 btn_submit: Submit user_modal: title: 새 사용자 추가 @@ -1726,7 +2011,7 @@ ui: label: 예약된 태그 text: "Reserved tags can only be used by moderator." seo: - page_title: SEO + page_title: 검색 엔진 최적화 permalink: label: 영구 링크 text: 사용자 정의 URL 구조는 링크의 사용성과 미래 호환성을 향상시킬 수 있습니다. @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: 입력값은 숫자여야 합니다. number_larger_1: 숫자는 1 이상이어야 합니다. + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (선택 사항) empty: 비어 있을 수 없습니다 diff --git a/i18n/pl_PL.yaml b/i18n/pl_PL.yaml index 378dd09c..efbb3dce 100644 --- a/i18n/pl_PL.yaml +++ b/i18n/pl_PL.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Nieprawidłowy URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Hasło nie może zawierać spacji. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Nie znaleziono konfiguracji strony. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: komentarz upvote invited_you_to_answer: other: zaproszono Cię do odpowiedzi + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} już {{ .Count }} razy ..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posty invites: Zaproszenia votes: Głosy + answer: Answer + question: Question + badge_award: Badge suspended: title: Twoje konto zostało zawieszone until_time: "Twoje konto zostało zawieszone do {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Pytania tag: Tagi user: Użytkownicy + badges: Badges profile: Profil setting: Ustawienia logout: Wyloguj @@ -1257,6 +1525,7 @@ ui: newest: Najnowsze active: Aktywne hot: Hot + recommend: Recommend score: Ocena unanswered: Bez odpowiedzi modified: zmodyfikowane @@ -1275,12 +1544,14 @@ ui: reputation: Reputacja comments: Komentarze votes: Głosy + badges: Badges newest: Najnowsze score: Ocena edit_profile: Edytuj Profil visited_x_days: "Odwiedzone przez {{ count }} dni" viewed: Wyświetlone joined: Dołączył + comma: "," last_login: Widziano about_me: O mnie about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: otrzymane głosy x_answers: odpowiedzi x_questions: pytania + recent_badges: Recent Badges install: title: Instalacja next: Dalej @@ -1407,6 +1679,7 @@ ui: questions: Pytania answers: Odpowiedzi users: Użytkownicy + badges: Badges flags: Flagi settings: Ustawienia general: Ogólne @@ -1430,6 +1703,18 @@ ui: login: Zaloguj się qrcode_login_tip: Zeskanuj kod QR za pomocą {{ agentName }} i zaloguj się. login_failed_email_tip: Logowanie nie powiodło się, przed ponowną próbą zezwól na dostęp tej aplikacji do informacji o Twojej skrzynce pocztowej. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Administrator @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (opcjonalne) empty: nie może być puste diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index ba8f6717..3c7b090b 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -23,7 +23,7 @@ backend: unknown: other: Erro desconhecido. request_format_error: - other: Formato de solicitação não é válido. + other: Formato de solicitação inválido. unauthorized_error: other: Não autorizado. database_error: @@ -31,14 +31,14 @@ backend: forbidden_error: other: Proibido. duplicate_request_error: - other: Duplicate submission. + other: Solicitação duplicada. action: report: other: Bandeira edit: other: Editar delete: - other: Deletar + other: Excluir close: other: Fechar reopen: @@ -56,7 +56,7 @@ backend: invite_someone_to_answer: other: Editar undelete: - other: Undelete + other: Desfazer role: name: user: @@ -69,9 +69,9 @@ backend: user: other: Padrão sem acesso especial. admin: - other: Possui acesso total ao site. + other: Possui acesso total. moderator: - other: Possui acesso a todas as postagens exceto às configurações de usuários. + other: Acesso a todas as postagens, exceto configurações administrativas. privilege: level_1: description: @@ -84,7 +84,7 @@ backend: other: Nível 3 (Alta reputação necessária para a comunidade adulta) level_custom: description: - other: Custom Level + other: Nível customizado rank_question_add_label: other: Perguntar rank_answer_add_label: @@ -144,7 +144,9 @@ backend: error: common: invalid_url: - other: Invalid URL. + other: URL inválida. + status_invalid: + other: Invalid status. password: space_invalid: other: A senha não pode conter espaços. @@ -152,7 +154,7 @@ backend: cannot_update_their_password: other: Você não pode modificar sua senha. cannot_edit_their_profile: - other: You cannot modify your profile. + other: Você não pode alterar o seu perfil. cannot_modify_self_status: other: Você não pode modificar seu status email_or_password_wrong: @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Configuração do site não encontrada. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: votos positivos do comentário invited_you_to_answer: other: lhe convidou para responder + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Postagens invites: Convites votes: Votos + answer: Answer + question: Question + badge_award: Badge suspended: title: A sua conta foi suspensa until_time: "Sua conta está suspensa até {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Perguntas tag: Marcadores user: Usuários + badges: Badges profile: Perfil setting: Configurações logout: Sair @@ -1257,6 +1525,7 @@ ui: newest: Mais recente active: Ativo hot: Hot + recommend: Recommend score: Pontuação unanswered: Não Respondido modified: modificado @@ -1275,12 +1544,14 @@ ui: reputation: Reputação comments: Comentários votes: Votos + badges: Badges newest: Mais recente score: Pontuação edit_profile: Editar Perfil visited_x_days: "Visitado {{ count }} dias" viewed: Visualizado joined: Ingressou + comma: "," last_login: Visto about_me: Sobre mim about_me_empty: "// Olá, Mundo !" @@ -1298,6 +1569,7 @@ ui: x_votes: votos recebidos x_answers: respostas x_questions: perguntas + recent_badges: Recent Badges install: title: Installation next: Proximo @@ -1407,6 +1679,7 @@ ui: questions: Perguntas answers: Respostas users: Usuários + badges: Badges flags: Marcadores settings: Configurações general: Geral @@ -1430,6 +1703,18 @@ ui: login: Entrar qrcode_login_tip: Por favor, utilize {{ agentName }} para escanear o QR code para entrar. login_failed_email_tip: Falha ao entrar, por favor, permita que este aplicativo acesse a informação do seu e-mail antes de tentar novamente. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Administrador @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (opcional) empty: não pode ser vazio diff --git a/i18n/ro_RO.yaml b/i18n/ro_RO.yaml index 45ce9d9e..3f936f60 100644 --- a/i18n/ro_RO.yaml +++ b/i18n/ro_RO.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Parola nu poate conține spații. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Configurarea site-ului nu a fost găsită. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: votează comentariul invited_you_to_answer: other: te-a invitat să răspunzi + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Postări invites: Invitați votes: Voturi + answer: Answer + question: Question + badge_award: Badge suspended: title: Contul dumneavoastră a fost suspendat until_time: "Contul dumneavoastră a fost suspendat până la {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Întrebări tag: Etichete user: Utilizatori + badges: Badges profile: Profil setting: Setări logout: Deconectaţi-vă @@ -1257,6 +1525,7 @@ ui: newest: Cele mai noi active: Activ hot: Hot + recommend: Recommend score: Scor unanswered: Fără răspuns modified: modificat @@ -1275,12 +1544,14 @@ ui: reputation: Reputație comments: Comentarii votes: Voturi + badges: Badges newest: Cele mai noi score: Scor edit_profile: Editare profil visited_x_days: "{{ count }} zile vizitate" viewed: Văzute joined: Înscris + comma: "," last_login: Văzut about_me: Despre mine about_me_empty: "// Salut, Lumea !" @@ -1298,6 +1569,7 @@ ui: x_votes: voturi primite x_answers: răspunsuri x_questions: întrebări + recent_badges: Recent Badges install: title: Installation next: Înainte @@ -1407,6 +1679,7 @@ ui: questions: Întrebări answers: Răspunsuri users: Utilizatori + badges: Badges flags: Marcaj settings: Setări general: General @@ -1430,6 +1703,18 @@ ui: login: Autentifică-te qrcode_login_tip: Vă rugăm să folosiți {{ agentName }} pentru a scana codul QR și a vă autentifica. login_failed_email_tip: Autentificare eșuată. Vă rugăm să permiteți acestei aplicații să vă acceseze informațiile de e-mail înainte de a încerca din nou. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Administrator @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (opțional) empty: nu poate fi lăsat necompletat diff --git a/i18n/ru_RU.yaml b/i18n/ru_RU.yaml index 4c5c2c36..fe28a7bf 100644 --- a/i18n/ru_RU.yaml +++ b/i18n/ru_RU.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Неверная URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Пароль не должен содержать пробелы. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Конфигурация сайта не найдена. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: поддержанный комментарий invited_you_to_answer: other: пригласил вас ответить + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Посты invites: Приглашения votes: Голоса + answer: Answer + question: Question + badge_award: Badge suspended: title: Ваш аккаунт заблокирован until_time: "Ваша учетная запись была заблокирована до {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Вопросы tag: Теги user: Пользователи + badges: Badges profile: Профиль setting: Настройки logout: Выйти @@ -1257,6 +1525,7 @@ ui: newest: Последние active: Активные hot: Hot + recommend: Recommend score: Оценка unanswered: Без ответа modified: изменён @@ -1275,12 +1544,14 @@ ui: reputation: Репутация comments: Комментарии votes: Голоса + badges: Badges newest: Последние score: Оценки edit_profile: Редактировать профиль visited_x_days: "Посещено {{ count }} дней" viewed: Просмотрен joined: Присоединился + comma: "," last_login: Просмотрен(-а) about_me: О себе about_me_empty: "// Привет, Мир!" @@ -1298,6 +1569,7 @@ ui: x_votes: полученные голоса x_answers: ответы x_questions: вопросы + recent_badges: Recent Badges install: title: Installation next: Следующий @@ -1407,6 +1679,7 @@ ui: questions: Вопросы answers: Ответы users: Пользователи + badges: Badges flags: Отметить settings: Настройки general: Основные @@ -1430,6 +1703,18 @@ ui: login: Вход qrcode_login_tip: Пожалуйста, используйте {{ agentName }} для сканирования QR-кода и входа в систему. login_failed_email_tip: Не удалось войти в систему, пожалуйста, разрешите этому приложению получить доступ к вашей электронной почте, прежде чем повторять попытку. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Администратор @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (опционально) empty: не может быть пустым diff --git a/i18n/sk_SK.yaml b/i18n/sk_SK.yaml index 081d5c34..625b4a30 100644 --- a/i18n/sk_SK.yaml +++ b/i18n/sk_SK.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Váš účet bol pozastavený until_time: "Váš účet bol pozastavený do {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Otázky tag: Značky user: Užívatelia + badges: Badges profile: Profil setting: Nastavenia logout: Odhlásiť sa @@ -1257,6 +1525,7 @@ ui: newest: Najnovšie active: Aktívne hot: Hot + recommend: Recommend score: Skóre unanswered: Nezodpovedané modified: upravené @@ -1275,12 +1544,14 @@ ui: reputation: Reputácia comments: Komentáre votes: Hlasovanie + badges: Badges newest: Najnovšie score: Skóre edit_profile: Edit profile visited_x_days: "Navštívené {{ count }} dni" viewed: Videné joined: Pripojené + comma: "," last_login: Videné about_me: O mne about_me_empty: "// Dobrý deň, svet!" @@ -1298,6 +1569,7 @@ ui: x_votes: prijatých hlasov x_answers: odpovede x_questions: otázky + recent_badges: Recent Badges install: title: Installation next: Ďalšie @@ -1407,6 +1679,7 @@ ui: questions: Otázky answers: Odpovede users: Užívatelia + badges: Badges flags: Vlajky settings: Nastavenia general: Všeobecné @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Administrátor @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (voliteľné) empty: nemôže byť prázdne diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index 5f2483b7..9056b16e 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -108,7 +108,7 @@ backend: rank_invite_someone_to_answer_label: other: Invite someone to answer rank_tag_add_label: - other: Create new tag + other: Skapa ny tagg rank_tag_edit_label: other: Edit tag description (need to review) rank_question_edit_label: @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Ogiltig URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Inlägg invites: Inbjudningar votes: Röster + answer: Answer + question: Question + badge_award: Badge suspended: title: Your Account has been Suspended until_time: "Your account was suspended until {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Användare + badges: Badges profile: Profil setting: Inställningar logout: Logga ut @@ -1257,6 +1525,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified @@ -1275,12 +1544,14 @@ ui: reputation: Reputation comments: Kommentarer votes: Röster + badges: Badges newest: Newest score: Score edit_profile: Redigera profil visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: Om mig about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes received x_answers: answers x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Nästa @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Användare + badges: Badges flags: Flags settings: Inställningar general: General @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Använd {{ agentName }} för att skanna QR-koden och logga in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/te_IN.yaml b/i18n/te_IN.yaml index 49fecacf..a4920b10 100644 --- a/i18n/te_IN.yaml +++ b/i18n/te_IN.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Your Account has been Suspended until_time: "Your account was suspended until {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Users + badges: Badges profile: Profile setting: Settings logout: Log out @@ -1257,6 +1525,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified @@ -1275,12 +1544,14 @@ ui: reputation: Reputation comments: Comments votes: Votes + badges: Badges newest: Newest score: Score edit_profile: Edit profile visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes received x_answers: answers x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Next @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: Flags settings: Settings general: General @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/tr_TR.yaml b/i18n/tr_TR.yaml index 785d132b..b169b228 100644 --- a/i18n/tr_TR.yaml +++ b/i18n/tr_TR.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: Hesabınız Askıya Alındı until_time: "Your account was suspended until {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Questions tag: Tags user: Users + badges: Badges profile: Profile setting: Settings logout: Log out @@ -1257,6 +1525,7 @@ ui: newest: Newest active: Active hot: Hot + recommend: Recommend score: Score unanswered: Unanswered modified: modified @@ -1275,12 +1544,14 @@ ui: reputation: Reputation comments: Comments votes: Votes + badges: Badges newest: Newest score: Score edit_profile: Edit profile visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: About Me about_me_empty: "// Hello, World !" @@ -1298,6 +1569,7 @@ ui: x_votes: votes received x_answers: answers x_questions: questions + recent_badges: Recent Badges install: title: Installation next: Next @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: Flags settings: Settings general: General @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/uk_UA.yaml b/i18n/uk_UA.yaml index e639fa67..0f1f088f 100644 --- a/i18n/uk_UA.yaml +++ b/i18n/uk_UA.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Невірна URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Пароль не може містити пробіли. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Конфігурацію сайту не знайдено. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: запросив(-ла) вас відповісти + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Публікації invites: Запрошення votes: Голоси + answer: Answer + question: Question + badge_award: Badge suspended: title: Ваш обліковий запис було призупинено until_time: "Ваш обліковий запис призупинено до {{ time }}." @@ -874,6 +1141,7 @@ ui: question: Запитання tag: Теґи user: Користувачі + badges: Badges profile: Профіль setting: Налаштування logout: Вийти @@ -1257,6 +1525,7 @@ ui: newest: Найновіші active: Активні hot: Hot + recommend: Recommend score: Оцінка unanswered: Без відповідей modified: modified @@ -1275,12 +1544,14 @@ ui: reputation: Репутація comments: Коментарі votes: Голоси + badges: Badges newest: Найновіше score: Score edit_profile: Редагувати профіль visited_x_days: "Visited {{ count }} days" viewed: Viewed joined: Joined + comma: "," last_login: Seen about_me: Про мене about_me_empty: "// Привіт, світ!" @@ -1298,6 +1569,7 @@ ui: x_votes: отримані голоси x_answers: відповіді x_questions: запитання + recent_badges: Recent Badges install: title: Installation next: Далі @@ -1407,6 +1679,7 @@ ui: questions: Questions answers: Answers users: Users + badges: Badges flags: Відмітки settings: Settings general: General @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Admin @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (optional) empty: cannot be empty diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 46840c49..783cadaf 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -34,7 +34,7 @@ backend: other: Trùng lặp yêu cầu. action: report: - other: Gắn Cờ + other: Gắn nhãn edit: other: Chỉnh sửa delete: @@ -64,7 +64,7 @@ backend: admin: other: Quản trị viên moderator: - other: Điều hành viên + other: Người điều hành description: user: other: Mặc định không có quyền truy cập đặc biệt. @@ -94,7 +94,7 @@ backend: rank_report_add_label: other: Gắn Cờ rank_comment_vote_up_label: - other: Upvote cho một bình luận + other: Bình chọn lên cho bình luận rank_link_url_limit_label: other: Đăng nhiều hơn 2 liên kết cùng một lúc rank_question_vote_up_label: @@ -138,13 +138,15 @@ backend: pass: other: Mật khẩu original_text: - other: post này + other: Bài viết này email_or_password_wrong_error: other: Email và mật khẩu không trùng khớp. error: common: invalid_url: other: URL không tồn tại. + status_invalid: + other: Invalid status. password: space_invalid: other: Mật khẩu không thể tồn tại khoảng trắng. @@ -187,7 +189,7 @@ backend: other: Không tìm thấy file ngôn ngữ. object: captcha_verification_failed: - other: Sai Captcha. + other: Xác minh Captcha thất bại. disallow_follow: other: Bạn không được phép theo dõi. disallow_vote: @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Không tìm thấy cấu hình trang. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -415,12 +420,12 @@ backend: deleted_title: other: Câu hỏi đã xóa questions_title: - other: Questions + other: Các câu hỏi tag: tags_title: - other: Tags + other: Thẻ no_description: - other: The tag has no description. + other: Thẻ không có mô tả. notification: action: update_question: @@ -459,6 +464,8 @@ backend: other: bình luận đã bình chọn lên invited_you_to_answer: other: đã mời bạn trả lời + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -510,7 +517,7 @@ backend: downvoted: other: đã bình chọn xuống accept: - other: + other: chấp nhận accepted: other: đã chấp nhận edit: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} và {{ .Count }} thêm..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Bài đăng invites: Lời mời votes: Bình chọn + answer: Answer + question: Question + badge_award: Badge suspended: title: Tài khoản của bạn đã bị đình chỉ until_time: "Tài khoản của bạn đã bị đình chỉ cho đến {{ time }}." @@ -718,12 +985,12 @@ ui: empty: Tên hiển thị không thể trống. range: Tên hiển thị tối đa 35 ký tự. slug_name: - label: URL slug - desc: URL slug tối đa 35 ký tự. + label: Đường dẫn URL + desc: Đường dẫn tối đa 35 ký tự. msg: - empty: URL slug không thể trống. - range: URL slug tối đa 35 ký tự. - character: URL slug chứa bộ ký tự không được phép. + empty: Đường dẫn URL không thể trống. + range: Đường dẫn URL tối đa 35 ký tự. + character: Đường dẫn URL chứa bộ ký tự không được phép. desc: label: Mô tả revision: @@ -732,7 +999,7 @@ ui: label: Tóm tắt chỉnh sửa placeholder: >- Giải thích ngắn gọn các thay đổi của bạn (sửa chính tả, sửa ngữ pháp, cải thiện định dạng) - btn_cancel: + btn_cancel: Hủy btn_submit: Gửi btn_post: Đăng thẻ mới tag_info: @@ -750,9 +1017,9 @@ ui: delete: title: Xóa thẻ này tip_with_posts: >- -

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+

Chúng tôi không cho phép xóa thẻ có bài đăng.

Vui lòng xóa thẻ này khỏi các bài đăng trước.

tip_with_synonyms: >- -

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+

Chúng tôi không cho phép xóa thẻ có từ đồng nghĩa.

Vui lòng xóa các từ đồng nghĩa khỏi thẻ này trước.

tip: Bạn có chắc chắn muốn xóa không? close: Đóng edit_tag: @@ -766,9 +1033,9 @@ ui: long_date_with_year: "MMM D, YYYY" long_date_with_time: "MMM D, YYYY [at] HH:mm" now: bây giờ - x_seconds_ago: "{{count}}s trước" - x_minutes_ago: "{{count}}m trước" - x_hours_ago: "{{count}}h trước" + x_seconds_ago: "{{count}}giây trước" + x_minutes_ago: "{{count}}phút trước" + x_hours_ago: "{{count}}giờ trước" hour: giờ day: ngày hours: giờ @@ -779,8 +1046,8 @@ ui: frown: khắc nghiệt btn_label: thêm hoặc loại bỏ lại undo_emoji: trở lại {{ emoji }} lặp lại - react_emoji: react with {{ emoji }} - unreact_emoji: react with {{ emoji }} + react_emoji: biểu cảm với {{ emoji }} + unreact_emoji: hủy biểu cảm {{ emoji }} comment: btn_add_comment: Thêm bình luận reply_to: Trả lời cho @@ -838,7 +1105,7 @@ ui: label: Sửa đổi title: label: Tiêu đề - placeholder: Hãy cụ thể và tưởng tượng bạn đang hỏi một người khác + placeholder: Hãy cụ thể và tưởng tượng rằng bạn đang hỏi một người khác msg: empty: Tiêu đề không thể trống. range: Tiêu đề tối đa 150 ký tự @@ -874,6 +1141,7 @@ ui: question: Câu hỏi tag: Thẻ user: Người dùng + badges: Badges profile: Hồ sơ setting: Cài đặt logout: Đăng xuất @@ -918,7 +1186,7 @@ ui: msg: empty: Tên không thể trống. range: Độ dài của tên phải từ 4 đến 30 ký tự. - character: 'Chỉ sử dụng bộ ký tự "a-z", "0-9", " - . _"' + character: 'Chỉ sử dụng bộ ký tự "a-z", "0-9", , "A-Z", " - . _"' email: label: Email msg: @@ -993,7 +1261,7 @@ ui: msg_range: Tên hiển thị tối đa 30 ký tự. username: label: Tên người dùng - caption: Mọi người có thể nhắc đến bạn là "@username". + caption: Mọi người có thể nhắc đến bạn với "@username". msg: Tên người dùng không thể trống. msg_range: Tên người dùng tối đa 30 ký tự. character: 'Chỉ sử dụng bộ ký tự "a-z", "0-9", " - . _"' @@ -1019,7 +1287,7 @@ ui: turn_on: Bật inbox: label: Thông báo hộp thư đến - description: Các câu trả lời cho câu hỏi của bạn, bình luận, lời mời, và nhiều hơn nữa. + description: Các câu trả lời cho câu hỏi của bạn, bình luận, lời mời và nhiều hơn nữa. all_new_question: label: Tất cả câu hỏi mới description: Nhận thông báo về tất cả các câu hỏi mới. Tối đa 50 câu hỏi mỗi tuần. @@ -1074,8 +1342,8 @@ ui: title: Các câu hỏi liên quan answers: câu trả lời invite_to_answer: - title: People Asked - desc: Select people who you think might know the answer. + title: Mời mọi người + desc: Mời những người bạn nghĩ có thể trả lời. invite: Mời trả lời add: Thêm người search: Tìm kiếm người @@ -1233,8 +1501,8 @@ ui: account_result: success: Tài khoản mới của bạn đã được xác nhận; bạn sẽ được chuyển hướng đến trang chủ. link: Tiếp tục đến trang chủ - oops: Oops! - invalid: The link you used no longer works. + oops: Rất tiếc! + invalid: Liên kết bạn đã dùng không còn hoạt động nữa. confirm_new_email: Email của bạn đã được cập nhật. confirm_new_email_invalid: >- Xin lỗi, liên kết xác nhận này không còn hợp lệ. Có thể email của bạn đã được thay đổi? @@ -1256,7 +1524,8 @@ ui: answers: Câu trả lời newest: Mới nhất active: Hoạt động - hot: Hot + hot: Được nhiều quan tâm + recommend: Recommend score: Điểm unanswered: Chưa được trả lời modified: đã chỉnh sửa @@ -1275,12 +1544,14 @@ ui: reputation: Danh tiếng comments: Bình luận votes: Bình chọn + badges: Badges newest: Mới nhất score: Điểm edit_profile: Chỉnh sửa hồ sơ visited_x_days: "Đã truy cập {{ count }} ngày" viewed: Đã xem joined: Tham gia + comma: "," last_login: Đã xem about_me: Về tôi about_me_empty: "// Xin chào, Thế giới !" @@ -1298,6 +1569,7 @@ ui: x_votes: phiếu bầu nhận được x_answers: câu trả lời x_questions: câu hỏi + recent_badges: Recent Badges install: title: Cài đặt next: Tiếp theo @@ -1321,7 +1593,7 @@ ui: msg: Máy chủ cơ sở dữ liệu không thể trống. db_name: label: Tên cơ sở dữ liệu - placeholder: answer + placeholder: câu trả lời msg: Tên cơ sở dữ liệu không thể trống. db_file: label: Tệp tin Database @@ -1407,6 +1679,7 @@ ui: questions: Câu hỏi answers: Câu trả lời users: Người dùng + badges: Badges flags: Cờ settings: Cài đặt general: Chung @@ -1430,6 +1703,18 @@ ui: login: Đăng nhập qrcode_login_tip: Vui lòng sử dụng {{ agentName }} để quét mã QR và đăng nhập. login_failed_email_tip: Đăng nhập thất bại, vui lòng cho phép ứng dụng này truy cập thông tin email của bạn trước khi thử lại. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: Quản trị @@ -1509,8 +1794,8 @@ ui: form: fields: display_name: - label: Display name - msg_range: Display name up to 30 characters. + label: Tên hiển thị + msg_range: Tên hiển thị tối đa 30 ký tự. username: label: Tên người dùng msg_range: Tên người dùng tối đa 30 ký tự. @@ -1577,7 +1862,7 @@ ui: title: Xóa người dùng này content: Bạn có chắc chắn muốn xóa người dùng này không? Điều này là vĩnh viễn! remove: Xóa nội dung của họ - label: Xóa tất cả các câu hỏi, câu trả lời, bình luận, etc. + label: Xóa tất cả các câu hỏi, câu trả lời, bình luận, vv. text: Không chọn điều này nếu bạn chỉ muốn xóa tài khoản của người dùng. suspend_user: title: Đình chỉ người dùng này @@ -1710,21 +1995,21 @@ ui: write: page_title: Viết restrict_answer: - title: Answer write + title: Câu trả lời chỉnh sửa label: Each user can only write one answer for each question - text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + text: "Tắt để cho phép người dùng viết nhiều câu trả lời cho cùng một câu hỏi, điều này có thể khiến các câu trả lời bị mất trọng tâm." recommend_tags: label: Thẻ được đề xuất - text: "Recommend tags will show in the dropdown list by default." + text: "Các thẻ gợi ý sẽ hiển thị trong danh sách thả xuống theo mặc định." msg: - contain_reserved: "recommended tags cannot contain reserved tags" + contain_reserved: "các thẻ được đề xuất không được chứa thẻ dự bị" required_tag: - title: Set required tags - label: Set “Recommend tags” as required tags + title: Đặt thẻ cần thiết + label: Đặt thẻ được đề xuất là bắt buộc text: "Mỗi câu hỏi mới phải có ít nhất một thẻ được đề xuất." reserved_tags: label: Thẻ dành riêng - text: "Reserved tags can only be used by moderator." + text: "Thẻ dành riêng chỉ có thể được thêm vào một bài đăng bởi điều hành viên." seo: page_title: SEO permalink: @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: dữ liệu đầu vào phải là số number_larger_1: số phải bằng hoặc lớn hơn 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (tùy chọn) empty: không thể trống diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 396c2f9b..933dad7c 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: 无效的 URL。 + status_invalid: + other: 无效状态。 password: space_invalid: other: 密码不得含有空格。 @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: 未找到网站的该配置信息。 + badge: + object_not_found: + other: 没有找到徽章对象 reason: spam: name: @@ -415,12 +420,12 @@ backend: deleted_title: other: 删除的问题 questions_title: - other: Questions + other: 问题 tag: tags_title: - other: Tags + other: 标签 no_description: - other: The tag has no description. + other: 此标签没有描述。 notification: action: update_question: @@ -459,6 +464,8 @@ backend: other: 点赞评论 invited_you_to_answer: other: 邀请你回答 + earned_badge: + other: 你获得 "{{.BadgeName}}" 徽章 email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} 以及另外 {{ .Count }} 个..." + badge: + default_badges: + autobiographer: + name: + other: 自传作者 + desc: + other: Filled out profile information. + certified: + name: + other: 已认证 + desc: + other: 完成了我们的新用户教程。 + editor: + name: + other: 编辑者 + desc: + other: 首次帖子编辑。 + first_flag: + name: + other: 第一次举报 + desc: + other: 第一次举报一个帖子 + first_upvote: + name: + other: 第一次投票 + desc: + other: 第一次投票了一个帖子。 + first_link: + name: + other: 第一个链接 + desc: + other: 第一个脏添加了一个链接到另一个帖子。 + first_reaction: + name: + other: 第一个响应 + desc: + other: 第一次表情回应帖子 + first_share: + name: + other: 首次分享 + desc: + other: 首次分享了一个帖子。 + scholar: + name: + other: 学者 + desc: + other: 问了一个问题并接受了一个答案。 + commentator: + name: + other: 评论员 + desc: + other: 留下5条评论。 + new_user_of_the_month: + name: + other: 月度用户 + desc: + other: 本月杰出用户 + read_guidelines: + name: + other: 阅读指南 + desc: + other: 阅读[社区准则]。 + reader: + name: + other: 读者 + desc: + other: 用10个以上的答案在主题中阅读每个答案。 + welcome: + name: + other: 欢迎 + desc: + other: 获得一个点赞投票 + nice_share: + name: + other: 好分享 + desc: + other: 分享了一个拥有25个唯一访客的帖子。 + good_share: + name: + other: 好分享 + desc: + other: 分享了一个拥有300个唯一访客的帖子。 + great_share: + name: + other: 优秀的分享 + desc: + other: 分享了一个拥有1000个唯一访客的帖子。 + out_of_love: + name: + other: 失去爱好 + desc: + other: 一天内使用了50张选票。 + higher_love: + name: + other: 更高的爱好 + desc: + other: 一天内使用了50张选票。 + crazy_in_love: + name: + other: 爱情疯狂的 + desc: + other: 在 20 天内使用了50张选票。 + promoter: + name: + other: 推荐人 + desc: + other: 邀请用户。 + campaigner: + name: + other: 宣传者 + desc: + other: 邀请了3个基本用户。 + champion: + name: + other: 冠军 + desc: + other: 邀请了5个成员。 + thank_you: + name: + other: 谢谢 + desc: + other: 拥有20个投票赞成的职位并放弃了10个投票。 + gives_back: + name: + other: 返回 + desc: + other: 拥有100个投票赞成的职位并放弃了100个投票。 + empathetic: + name: + other: 情随境迁 + desc: + other: 拥有500个投票赞成的职位并放弃了1000个投票。 + enthusiast: + name: + other: 狂热 + desc: + other: 连续访问10天。 + aficionado: + name: + other: Aficionado + desc: + other: 连续访问100天。 + devotee: + name: + other: Devotee + desc: + other: 连续访问365天。 + anniversary: + name: + other: 周年纪念日 + desc: + other: 活跃成员一年至少发布一次。 + appreciated: + name: + other: 欣赏 + desc: + other: 20个员额获得1次补票。 + respected: + name: + other: 尊敬 + desc: + other: 100个员额获得2次补票。 + admired: + name: + other: 仰慕 + desc: + other: 300个员额获得5次补票。 + solved: + name: + other: 已解决 + desc: + other: 接受答案。 + guidance_counsellor: + name: + other: 指导顾问 + desc: + other: 接受答案。 + know_it_all: + name: + other: 万事通 + desc: + other: 接受50个答案。 + solution_institution: + name: + other: 解决方案机构 + desc: + other: 接受150份答复。 + nice_answer: + name: + other: 好答案 + desc: + other: 回答得分为10或以上。 + good_answer: + name: + other: 好答案 + desc: + other: 回答得分为25或更多。 + great_answer: + name: + other: 优秀答案 + desc: + other: 回答得分为50或以上。 + nice_question: + name: + other: 好问题 + desc: + other: 问题得分为10或以上。 + good_question: + name: + other: 好问题 + desc: + other: 问题得分为25或更多。 + great_question: + name: + other: 很棒的问题 + desc: + other: 问题得分为50或更多。 + popular_question: + name: + other: 热门问题 + desc: + other: 问题有500个意见。 + notable_question: + name: + other: 值得关注问题 + desc: + other: 1 000个问题。 + famous_question: + name: + other: 著名的问题 + desc: + other: 问题有5,000个意见。 + popular_link: + name: + other: 热门链接 + desc: + other: 发布了一个带有50个点击的外部链接。 + hot_link: + name: + other: 热门链接 + desc: + other: 发布了一个带有300个点击的外部链接。 + famous_link: + name: + other: 著名链接 + desc: + other: 发布了一个带有100个点击的外部链接。 + default_badge_groups: + getting_started: + name: + other: 完成初始化 + community: + name: + other: Community 专题 + posting: + name: + other: 发帖 # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: 帖子 invites: 邀请 votes: 投票 + answer: 回答 + question: 问题 + badge_award: 徽章 suspended: title: 你的账号账号已被封禁 until_time: "你的账号被封禁直到 {{ time }}。" @@ -874,6 +1141,7 @@ ui: question: 问题 tag: 标签 user: 用户 + badges: 徽章 profile: 用户主页 setting: 账号设置 logout: 退出 @@ -1233,8 +1501,8 @@ ui: account_result: success: 你的账号已通过验证,即将返回首页。 link: 返回首页 - oops: Oops! - invalid: The link you used no longer works. + oops: 糟糕! + invalid: 您使用的链接不再有效。 confirm_new_email: 你的电子邮箱已更新 confirm_new_email_invalid: >- 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了? @@ -1256,7 +1524,8 @@ ui: answers: 回答 newest: 最新 active: 活跃 - hot: 热度 + hot: 热门 + recommend: 推荐 score: 评分 unanswered: 未回答 modified: 更新于 @@ -1275,12 +1544,14 @@ ui: reputation: 声望 comments: 评论 votes: 得票 + badges: 徽章 newest: 最新 score: 评分 edit_profile: 编辑资料 visited_x_days: "已访问 {{ count }} 天" viewed: 浏览次数 joined: 加入于 + comma: "," last_login: 上次登录 about_me: 关于我 about_me_empty: "// Hello, World!" @@ -1298,6 +1569,7 @@ ui: x_votes: 得票 x_answers: 个回答 x_questions: 个问题 + recent_badges: 最近的徽章 install: title: 安装 next: 下一步 @@ -1407,6 +1679,7 @@ ui: questions: 问题 answers: 回答 users: 用户管理 + badges: 徽章 flags: 举报管理 settings: 站点设置 general: 一般 @@ -1430,6 +1703,18 @@ ui: login: 登录 qrcode_login_tip: 请使用 {{ agentName }} 扫描二维码并登录。 login_failed_email_tip: 登录失败,请允许此应用访问您的邮箱信息,然后重试。 + badges: + modal: + title: 恭喜 + content: 你赢得了一个新徽章。 + close: 关闭 + confirm: 查看徽章 + title: 徽章 + awarded: 授予的 + earned_×: 以获得 ×{{ number }} + ×_awarded: "{{ number }} 得到" + can_earn_multiple: 你可以多次获得 + earned: 获得 admin: admin_header: title: 后台管理 @@ -1509,8 +1794,8 @@ ui: form: fields: display_name: - label: Display name - msg_range: Display name up to 30 characters. + label: 显示名称 + msg_range: 显示名称不能超过 30 个字符。 username: label: 用户名 msg_range: 用户名不能超过 30 个字符。 @@ -1710,21 +1995,21 @@ ui: write: page_title: 编辑 restrict_answer: - title: Answer write + title: 回答编辑 label: 每个用户对于每个问题只能有一个回答 text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." recommend_tags: label: 推荐标签 - text: "Recommend tags will show in the dropdown list by default." + text: "推荐标签将默认显示在下拉列表中。" msg: - contain_reserved: "recommended tags cannot contain reserved tags" + contain_reserved: "推荐标签不能包含保留标签" required_tag: - title: Set required tags - label: Set “Recommend tags” as required tags + title: 设置必填标签 + label: 设置“推荐标签”为必需的标签 text: "每个新问题必须至少有一个推荐标签。" reserved_tags: label: 保留标签 - text: "Reserved tags can only be used by moderator." + text: "只有版主才能使用保留的标签。" seo: page_title: 搜索引擎优化 permalink: @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: 输入必须是数字 number_larger_1: 数字应该大于等于 1 + badges: + action: 操作 + active: 活跃的 + all: 全部 + awards: 奖项 + deactivate: 取消激活 + filter: + placeholder: 按名称筛选,或使用 badge:id + group: 组 + inactive: 未启用 + name: 名字 + show_logs: 显示日志 + status: 状态 + title: 徽章 form: optional: (选填) empty: 不能为空 diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index 6f796366..101d81f8 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -145,6 +145,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -311,6 +313,9 @@ backend: site_info: config_not_found: other: Site config not found. + badge: + object_not_found: + other: Badge object not found reason: spam: name: @@ -459,6 +464,8 @@ backend: other: upvoted comment invited_you_to_answer: other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge email_tpl: change_email: title: @@ -525,6 +532,263 @@ backend: reaction: tooltip: other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: how_to_format: @@ -579,6 +843,9 @@ ui: posts: Posts invites: Invites votes: Votes + answer: Answer + question: Question + badge_award: Badge suspended: title: 您的帳號已被停權 until_time: "你的帳號被停權至{{ time }}。" @@ -874,6 +1141,7 @@ ui: question: 問題 tag: 標籤 user: 用戶 + badges: Badges profile: 用戶主頁 setting: 帳號設置 logout: 登出 @@ -1256,7 +1524,8 @@ ui: answers: 回答 newest: 最新的 active: 活躍的 - hot: 熱門 + hot: Hot + recommend: Recommend score: 評分 unanswered: 未回答 modified: 修改於 @@ -1275,12 +1544,14 @@ ui: reputation: 聲望 comments: 評論 votes: 得票 + badges: Badges newest: 最新 score: 評分 edit_profile: Edit profile visited_x_days: "已造訪 {{ count }} 天" viewed: 閱讀次數 joined: 加入於 + comma: "," last_login: 出現時間 about_me: 關於我 about_me_empty: "// 你好, 世界 !" @@ -1298,6 +1569,7 @@ ui: x_votes: 得票 x_answers: 個回答 x_questions: 個問題 + recent_badges: Recent Badges install: title: Installation next: 下一步 @@ -1407,6 +1679,7 @@ ui: questions: 問題 answers: 回答 users: 使用者管理 + badges: Badges flags: 檢舉 settings: 設定 general: 一般 @@ -1430,6 +1703,18 @@ ui: login: Login qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned admin: admin_header: title: 後台管理 @@ -1834,6 +2119,20 @@ ui: msg: should_be_number: the input should be number number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges form: optional: (選填) empty: 不能為空 From 2dd4cc4f9215f573e1fa345c2ff08dca798c5a35 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:51:17 +0800 Subject: [PATCH 133/336] New translations en_us.yaml (Chinese Simplified) --- i18n/zh_CN.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 933dad7c..94434b9c 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1017,9 +1017,9 @@ ui: delete: title: 删除标签 tip_with_posts: >- -

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+

我们不允许 删除带有帖子的标签

请先从帖子中移除此标签。

tip_with_synonyms: >- -

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+

我们不允许 删除带有同义词的标签

请先从此标签中删除同义词。

tip: 确定要删除吗? close: 关闭 edit_tag: @@ -1997,7 +1997,7 @@ ui: restrict_answer: title: 回答编辑 label: 每个用户对于每个问题只能有一个回答 - text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + text: "用户可以使用编辑按钮优化已有的回答" recommend_tags: label: 推荐标签 text: "推荐标签将默认显示在下拉列表中。" @@ -2219,4 +2219,4 @@ ui: post_reopen: 这个帖子已被重新打开. post_list: 这个帖子已经被显示 post_unlist: 这个帖子已经被隐藏 - post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 \ No newline at end of file + post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 From 3c8aa03fd96801f92940475b0e05b14a0f9445df Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 4 Sep 2024 17:05:53 +0800 Subject: [PATCH 134/336] fix(badge): fixed badge description translation --- cmd/wire_gen.go | 2 +- i18n/en_US.yaml | 2 +- internal/schema/badge_schema.go | 18 ++---------- internal/service/badge/badge_service.go | 38 ++++++++++++++++++------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index d18355e3..537ece84 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -265,7 +265,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, eventRuleRepo := badge.NewEventRuleRepo(dataData) badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService, notificationQueueService) badgeEventService := badge2.NewBadgeEventService(dataData, eventQueueService, badgeRepo, eventRuleRepo, badgeAwardService) - badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) + badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService, siteInfoCommonService) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) controller_adminBadgeController := controller_admin.NewBadgeController(badgeService) answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController, controller_adminBadgeController) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 70318a38..02035210 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -539,7 +539,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index a33fb480..8c934ee2 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -172,20 +172,6 @@ type GetUserBadgeAwardListResp struct { Level entity.BadgeLevel `json:"level" ` } -// GetBadgeByIDResp get badge by id response -type GetBadgeByIDResp struct { - // badge id - ID string `json:"id" ` - // badge name - Name string `json:"name" ` - // badge description - Description string `json:"description" ` - // badge icon - Icon string `json:"icon" ` - // badge award count - AwardCount int `json:"award_count" ` - // badge is single or multiple - IsSingle bool `json:"is_single" ` - // badge level - Level entity.BadgeLevel `json:"level" ` +type BadgeTplData struct { + ProfileURL string } diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index faf9b628..029130ad 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -26,6 +26,7 @@ import ( "github.com/apache/incubator-answer/internal/base/translator" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/siteinfo_common" "github.com/apache/incubator-answer/pkg/converter" "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" @@ -47,10 +48,11 @@ type BadgeRepo interface { } type BadgeService struct { - badgeRepo BadgeRepo - badgeGroupRepo BadgeGroupRepo - badgeAwardRepo BadgeAwardRepo - badgeEventService *BadgeEventService + badgeRepo BadgeRepo + badgeGroupRepo BadgeGroupRepo + badgeAwardRepo BadgeAwardRepo + badgeEventService *BadgeEventService + siteInfoCommonService siteinfo_common.SiteInfoCommonService } func NewBadgeService( @@ -58,12 +60,14 @@ func NewBadgeService( badgeGroupRepo BadgeGroupRepo, badgeAwardRepo BadgeAwardRepo, badgeEventService *BadgeEventService, + siteInfoCommonService siteinfo_common.SiteInfoCommonService, ) *BadgeService { return &BadgeService{ - badgeRepo: badgeRepo, - badgeGroupRepo: badgeGroupRepo, - badgeAwardRepo: badgeAwardRepo, - badgeEventService: badgeEventService, + badgeRepo: badgeRepo, + badgeGroupRepo: badgeGroupRepo, + badgeAwardRepo: badgeAwardRepo, + badgeEventService: badgeEventService, + siteInfoCommonService: siteInfoCommonService, } } @@ -200,11 +204,18 @@ func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPa resp = make([]*schema.GetBadgeListPagedResp, len(badges)) + general, siteErr := b.siteInfoCommonService.GetSiteGeneral(ctx) + var baseURL = "" + if siteErr != nil { + baseURL = "" + } + baseURL = general.SiteUrl + for i, badge := range badges { resp[i] = &schema.GetBadgeListPagedResp{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), - Description: translator.Tr(handler.GetLangByCtx(ctx), badge.Description), + Description: translator.TrWithData(handler.GetLangByCtx(ctx), badge.Description, &schema.BadgeTplData{ProfileURL: baseURL + "/users/settings/profile"}), Icon: badge.Icon, AwardCount: badge.AwardCount, Level: badge.Level, @@ -253,10 +264,17 @@ func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) earnedTotal = b.badgeAwardRepo.CountByUserIdAndBadgeId(ctx, userID, badge.ID) } + general, siteErr := b.siteInfoCommonService.GetSiteGeneral(ctx) + var baseURL = "" + if siteErr != nil { + baseURL = "" + } + baseURL = general.SiteUrl + info = &schema.GetBadgeInfoResp{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), - Description: translator.Tr(handler.GetLangByCtx(ctx), badge.Description), + Description: translator.TrWithData(handler.GetLangByCtx(ctx), badge.Description, &schema.BadgeTplData{ProfileURL: baseURL + "/users/settings/profile"}), Icon: badge.Icon, AwardCount: badge.AwardCount, EarnedCount: earnedTotal, From fa5095261afc343575f734cfa1d705948a7d22f4 Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 4 Sep 2024 17:33:50 +0800 Subject: [PATCH 135/336] fix(badge): fixed badge description translation --- internal/service/badge/badge_service.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 029130ad..0ab538a3 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -208,8 +208,9 @@ func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPa var baseURL = "" if siteErr != nil { baseURL = "" + } else { + baseURL = general.SiteUrl } - baseURL = general.SiteUrl for i, badge := range badges { resp[i] = &schema.GetBadgeListPagedResp{ @@ -268,8 +269,9 @@ func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) var baseURL = "" if siteErr != nil { baseURL = "" + } else { + baseURL = general.SiteUrl } - baseURL = general.SiteUrl info = &schema.GetBadgeInfoResp{ ID: uid.EnShortID(badge.ID), From a1e427c8abe12df01f573907215fce79d9eae57c Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 4 Sep 2024 17:49:36 +0800 Subject: [PATCH 136/336] refactor(ui): Update i18n fields --- i18n/en_US.yaml | 1 + ui/src/pages/Admin/Badges/components/Action/index.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 70318a38..1a526b1a 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -2158,6 +2158,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate diff --git a/ui/src/pages/Admin/Badges/components/Action/index.tsx b/ui/src/pages/Admin/Badges/components/Action/index.tsx index 023e626f..cff07380 100644 --- a/ui/src/pages/Admin/Badges/components/Action/index.tsx +++ b/ui/src/pages/Admin/Badges/components/Action/index.tsx @@ -37,7 +37,7 @@ const BadgeOperation = ({ onSelect, status }: Props) => { {status === 'inactive' && ( - {t('active')} + {t('activate')} )} {status === 'active' && ( {t('deactivate')} From bd7a8c0368b657d2f4631b80cc2b93546cb71303 Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 4 Sep 2024 17:05:53 +0800 Subject: [PATCH 137/336] fix(badge): fixed badge description translation --- cmd/wire_gen.go | 2 +- i18n/en_US.yaml | 2 +- internal/schema/badge_schema.go | 18 ++---------- internal/service/badge/badge_service.go | 38 ++++++++++++++++++------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index d18355e3..537ece84 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -265,7 +265,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, eventRuleRepo := badge.NewEventRuleRepo(dataData) badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService, notificationQueueService) badgeEventService := badge2.NewBadgeEventService(dataData, eventQueueService, badgeRepo, eventRuleRepo, badgeAwardService) - badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) + badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService, siteInfoCommonService) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) controller_adminBadgeController := controller_admin.NewBadgeController(badgeService) answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController, controller_adminBadgeController) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 1a526b1a..96950369 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -539,7 +539,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index a33fb480..8c934ee2 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -172,20 +172,6 @@ type GetUserBadgeAwardListResp struct { Level entity.BadgeLevel `json:"level" ` } -// GetBadgeByIDResp get badge by id response -type GetBadgeByIDResp struct { - // badge id - ID string `json:"id" ` - // badge name - Name string `json:"name" ` - // badge description - Description string `json:"description" ` - // badge icon - Icon string `json:"icon" ` - // badge award count - AwardCount int `json:"award_count" ` - // badge is single or multiple - IsSingle bool `json:"is_single" ` - // badge level - Level entity.BadgeLevel `json:"level" ` +type BadgeTplData struct { + ProfileURL string } diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index faf9b628..029130ad 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -26,6 +26,7 @@ import ( "github.com/apache/incubator-answer/internal/base/translator" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/siteinfo_common" "github.com/apache/incubator-answer/pkg/converter" "github.com/apache/incubator-answer/pkg/uid" "github.com/gin-gonic/gin" @@ -47,10 +48,11 @@ type BadgeRepo interface { } type BadgeService struct { - badgeRepo BadgeRepo - badgeGroupRepo BadgeGroupRepo - badgeAwardRepo BadgeAwardRepo - badgeEventService *BadgeEventService + badgeRepo BadgeRepo + badgeGroupRepo BadgeGroupRepo + badgeAwardRepo BadgeAwardRepo + badgeEventService *BadgeEventService + siteInfoCommonService siteinfo_common.SiteInfoCommonService } func NewBadgeService( @@ -58,12 +60,14 @@ func NewBadgeService( badgeGroupRepo BadgeGroupRepo, badgeAwardRepo BadgeAwardRepo, badgeEventService *BadgeEventService, + siteInfoCommonService siteinfo_common.SiteInfoCommonService, ) *BadgeService { return &BadgeService{ - badgeRepo: badgeRepo, - badgeGroupRepo: badgeGroupRepo, - badgeAwardRepo: badgeAwardRepo, - badgeEventService: badgeEventService, + badgeRepo: badgeRepo, + badgeGroupRepo: badgeGroupRepo, + badgeAwardRepo: badgeAwardRepo, + badgeEventService: badgeEventService, + siteInfoCommonService: siteInfoCommonService, } } @@ -200,11 +204,18 @@ func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPa resp = make([]*schema.GetBadgeListPagedResp, len(badges)) + general, siteErr := b.siteInfoCommonService.GetSiteGeneral(ctx) + var baseURL = "" + if siteErr != nil { + baseURL = "" + } + baseURL = general.SiteUrl + for i, badge := range badges { resp[i] = &schema.GetBadgeListPagedResp{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), - Description: translator.Tr(handler.GetLangByCtx(ctx), badge.Description), + Description: translator.TrWithData(handler.GetLangByCtx(ctx), badge.Description, &schema.BadgeTplData{ProfileURL: baseURL + "/users/settings/profile"}), Icon: badge.Icon, AwardCount: badge.AwardCount, Level: badge.Level, @@ -253,10 +264,17 @@ func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) earnedTotal = b.badgeAwardRepo.CountByUserIdAndBadgeId(ctx, userID, badge.ID) } + general, siteErr := b.siteInfoCommonService.GetSiteGeneral(ctx) + var baseURL = "" + if siteErr != nil { + baseURL = "" + } + baseURL = general.SiteUrl + info = &schema.GetBadgeInfoResp{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), - Description: translator.Tr(handler.GetLangByCtx(ctx), badge.Description), + Description: translator.TrWithData(handler.GetLangByCtx(ctx), badge.Description, &schema.BadgeTplData{ProfileURL: baseURL + "/users/settings/profile"}), Icon: badge.Icon, AwardCount: badge.AwardCount, EarnedCount: earnedTotal, From dd8bdc230d98d2cbc2e37ed126535200d44d9ad4 Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 4 Sep 2024 17:33:50 +0800 Subject: [PATCH 138/336] fix(badge): fixed badge description translation --- internal/service/badge/badge_service.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 029130ad..0ab538a3 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -208,8 +208,9 @@ func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPa var baseURL = "" if siteErr != nil { baseURL = "" + } else { + baseURL = general.SiteUrl } - baseURL = general.SiteUrl for i, badge := range badges { resp[i] = &schema.GetBadgeListPagedResp{ @@ -268,8 +269,9 @@ func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) var baseURL = "" if siteErr != nil { baseURL = "" + } else { + baseURL = general.SiteUrl } - baseURL = general.SiteUrl info = &schema.GetBadgeInfoResp{ ID: uid.EnShortID(badge.ID), From c3b61df0a9248fa6ceb8828a05eb159b4654fbc1 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:48 +0800 Subject: [PATCH 139/336] New translations en_us.yaml (Vietnamese) --- i18n/vi_VN.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 783cadaf..31474724 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 2664c15910b2e3479706b1121e12e3bbdc33f216 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:50 +0800 Subject: [PATCH 140/336] New translations en_us.yaml (Swedish) --- i18n/sv_SE.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index 9056b16e..1e9f747e 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 6017cab509d4994ddf056eccbbd4696365fc80f4 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:51 +0800 Subject: [PATCH 141/336] New translations en_us.yaml (Portuguese) --- i18n/pt_PT.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index 3c7b090b..d3922da5 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 57bef7da37446c2e89ecb4b3128a29fe9fa147ab Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:52 +0800 Subject: [PATCH 142/336] New translations en_us.yaml (Romanian) --- i18n/ro_RO.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/ro_RO.yaml b/i18n/ro_RO.yaml index 3f936f60..e4d8433a 100644 --- a/i18n/ro_RO.yaml +++ b/i18n/ro_RO.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 53485964bdf4fdbf67f708ed3faa8f1163109628 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:54 +0800 Subject: [PATCH 143/336] New translations en_us.yaml (French) --- i18n/fr_FR.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/fr_FR.yaml b/i18n/fr_FR.yaml index 5c9bdcf5..0d692c11 100644 --- a/i18n/fr_FR.yaml +++ b/i18n/fr_FR.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 427ed2a856cd196dcd2d5697c8752e8975ac5f60 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:55 +0800 Subject: [PATCH 144/336] New translations en_us.yaml (Spanish) --- i18n/es_ES.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/es_ES.yaml b/i18n/es_ES.yaml index e3e5097a..80e8902e 100644 --- a/i18n/es_ES.yaml +++ b/i18n/es_ES.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From dc7a288bc430d4ead23d9bee2c62c0d662b44458 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:57 +0800 Subject: [PATCH 145/336] New translations en_us.yaml (Czech) --- i18n/cs_CZ.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/cs_CZ.yaml b/i18n/cs_CZ.yaml index ccf371f0..4f1b8a04 100644 --- a/i18n/cs_CZ.yaml +++ b/i18n/cs_CZ.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 6ca0aec7db26ff23156da56a576c23dda66d38c5 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:01:58 +0800 Subject: [PATCH 146/336] New translations en_us.yaml (Danish) --- i18n/da_DK.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/da_DK.yaml b/i18n/da_DK.yaml index ec2d8cf2..2c344bf7 100644 --- a/i18n/da_DK.yaml +++ b/i18n/da_DK.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 11bc7226ab85d35deed70ab536adc207955e1522 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:00 +0800 Subject: [PATCH 147/336] New translations en_us.yaml (German) --- i18n/de_DE.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/de_DE.yaml b/i18n/de_DE.yaml index 4437452c..91cc09cb 100644 --- a/i18n/de_DE.yaml +++ b/i18n/de_DE.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From f8c138715935726bcb65d70840318b15ecf30ebb Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:01 +0800 Subject: [PATCH 148/336] New translations en_us.yaml (Italian) --- i18n/it_IT.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/it_IT.yaml b/i18n/it_IT.yaml index 673b67e2..c9167dde 100644 --- a/i18n/it_IT.yaml +++ b/i18n/it_IT.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 5f94c05c75a43f3bb4af921e9d3605aa7b2af55a Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:03 +0800 Subject: [PATCH 149/336] New translations en_us.yaml (Japanese) --- i18n/ja_JP.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/ja_JP.yaml b/i18n/ja_JP.yaml index 0b8fd6d9..0051f4dc 100644 --- a/i18n/ja_JP.yaml +++ b/i18n/ja_JP.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 24f8b61cea4a8eeb1e861cf0ac46a96e7ff0115a Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:05 +0800 Subject: [PATCH 150/336] New translations en_us.yaml (Korean) --- i18n/ko_KR.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/ko_KR.yaml b/i18n/ko_KR.yaml index efbf7dcf..b6baf9fa 100644 --- a/i18n/ko_KR.yaml +++ b/i18n/ko_KR.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 6e8511d20d8288752d12129859a368d63f77eab4 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:07 +0800 Subject: [PATCH 151/336] New translations en_us.yaml (Polish) --- i18n/pl_PL.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/pl_PL.yaml b/i18n/pl_PL.yaml index efbb3dce..a996953a 100644 --- a/i18n/pl_PL.yaml +++ b/i18n/pl_PL.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From e7f482170356803da7c79505161be789fd6691ea Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:08 +0800 Subject: [PATCH 152/336] New translations en_us.yaml (Russian) --- i18n/ru_RU.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/ru_RU.yaml b/i18n/ru_RU.yaml index fe28a7bf..844c4fac 100644 --- a/i18n/ru_RU.yaml +++ b/i18n/ru_RU.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 748dc66c992cb78c3c5e444877d14f6503f8bc61 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:10 +0800 Subject: [PATCH 153/336] New translations en_us.yaml (Slovak) --- i18n/sk_SK.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/sk_SK.yaml b/i18n/sk_SK.yaml index 625b4a30..7b2b9f91 100644 --- a/i18n/sk_SK.yaml +++ b/i18n/sk_SK.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 40ca81ed32488c62d10de9ad9af2e9cc47b69120 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:11 +0800 Subject: [PATCH 154/336] New translations en_us.yaml (Turkish) --- i18n/tr_TR.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/tr_TR.yaml b/i18n/tr_TR.yaml index b169b228..015ebb21 100644 --- a/i18n/tr_TR.yaml +++ b/i18n/tr_TR.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From e55c78b852173e08e255b0ba8d69063d8c7518b0 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:13 +0800 Subject: [PATCH 155/336] New translations en_us.yaml (Ukrainian) --- i18n/uk_UA.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/uk_UA.yaml b/i18n/uk_UA.yaml index 0f1f088f..b8eee43b 100644 --- a/i18n/uk_UA.yaml +++ b/i18n/uk_UA.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 612936225712f344700546bfa43d8ef9732efae7 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:15 +0800 Subject: [PATCH 156/336] New translations en_us.yaml (Chinese Simplified) --- i18n/zh_CN.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 94434b9c..d5eb16c5 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: 操作 active: 活跃的 + activate: Activate all: 全部 awards: 奖项 deactivate: 取消激活 From 3285b56a629c7c70e218a9b52be4ad563bb694d4 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:16 +0800 Subject: [PATCH 157/336] New translations en_us.yaml (Chinese Traditional) --- i18n/zh_TW.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index 101d81f8..624cfbff 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From f96b66779dc7115e4753123aa1aaa77a051c54ac Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:17 +0800 Subject: [PATCH 158/336] New translations en_us.yaml (Indonesian) --- i18n/id_ID.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/id_ID.yaml b/i18n/id_ID.yaml index 8f26ef0e..50bfcb22 100644 --- a/i18n/id_ID.yaml +++ b/i18n/id_ID.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From a9c7490d94e0b29963c60c9e89794375a8101e58 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:19 +0800 Subject: [PATCH 159/336] New translations en_us.yaml (Persian) --- i18n/fa_IR.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/fa_IR.yaml b/i18n/fa_IR.yaml index bbb20214..3c992278 100644 --- a/i18n/fa_IR.yaml +++ b/i18n/fa_IR.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From ddcecaccb9acd45aaba35d17711de842569d7173 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:20 +0800 Subject: [PATCH 160/336] New translations en_us.yaml (Hindi) --- i18n/hi_IN.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/hi_IN.yaml b/i18n/hi_IN.yaml index 99f90253..ec316699 100644 --- a/i18n/hi_IN.yaml +++ b/i18n/hi_IN.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 7f8605afd7fdb92941032bd671c4b733e126c4f1 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:22 +0800 Subject: [PATCH 161/336] New translations en_us.yaml (Telugu) --- i18n/te_IN.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/te_IN.yaml b/i18n/te_IN.yaml index a4920b10..5100d720 100644 --- a/i18n/te_IN.yaml +++ b/i18n/te_IN.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From 23d2bdb5b40ebb5e833ed85721c888e79d8bc50e Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:02:23 +0800 Subject: [PATCH 162/336] New translations en_us.yaml (Welsh) --- i18n/cy_GB.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/i18n/cy_GB.yaml b/i18n/cy_GB.yaml index f96476f2..eb2d8582 100644 --- a/i18n/cy_GB.yaml +++ b/i18n/cy_GB.yaml @@ -2122,6 +2122,7 @@ ui: badges: action: Action active: Active + activate: Activate all: All awards: Awards deactivate: Deactivate From e70050d21334086f6f3ed699fb336dbe8a961925 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:48 +0800 Subject: [PATCH 163/336] New translations en_us.yaml (Vietnamese) --- i18n/vi_VN.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 31474724..888258d0 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 56f03bc0c02a1fe9ea7f541fe56f870afb8801f6 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:50 +0800 Subject: [PATCH 164/336] New translations en_us.yaml (Swedish) --- i18n/sv_SE.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index 1e9f747e..7cacadaa 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 32d1463f53d12b60a8c083dcac4c04fe67f925fa Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:52 +0800 Subject: [PATCH 165/336] New translations en_us.yaml (Portuguese) --- i18n/pt_PT.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index d3922da5..3eb74465 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From fe7620c37a3d554168dd30054bee6df28d08c0a9 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:53 +0800 Subject: [PATCH 166/336] New translations en_us.yaml (Romanian) --- i18n/ro_RO.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/ro_RO.yaml b/i18n/ro_RO.yaml index e4d8433a..77197365 100644 --- a/i18n/ro_RO.yaml +++ b/i18n/ro_RO.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 5210ef87a35783209529105f2f5c8021b4b0fb7c Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:55 +0800 Subject: [PATCH 167/336] New translations en_us.yaml (French) --- i18n/fr_FR.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/fr_FR.yaml b/i18n/fr_FR.yaml index 0d692c11..27a0a250 100644 --- a/i18n/fr_FR.yaml +++ b/i18n/fr_FR.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From d672527bee165ec1aaafcf7f712f675916368060 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:56 +0800 Subject: [PATCH 168/336] New translations en_us.yaml (Spanish) --- i18n/es_ES.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/es_ES.yaml b/i18n/es_ES.yaml index 80e8902e..b01dbb5c 100644 --- a/i18n/es_ES.yaml +++ b/i18n/es_ES.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 6b77130251f8c22e0f7b2d149e2530d19f2d7259 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:58 +0800 Subject: [PATCH 169/336] New translations en_us.yaml (Czech) --- i18n/cs_CZ.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/cs_CZ.yaml b/i18n/cs_CZ.yaml index 4f1b8a04..c9a2bad9 100644 --- a/i18n/cs_CZ.yaml +++ b/i18n/cs_CZ.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 934d2722a26fababc794c79ae42f59776f8ffafd Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:27:59 +0800 Subject: [PATCH 170/336] New translations en_us.yaml (Danish) --- i18n/da_DK.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/da_DK.yaml b/i18n/da_DK.yaml index 2c344bf7..b7e03395 100644 --- a/i18n/da_DK.yaml +++ b/i18n/da_DK.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 30d4415aa00824778e8ff038f3e23e0977da15df Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:01 +0800 Subject: [PATCH 171/336] New translations en_us.yaml (German) --- i18n/de_DE.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/de_DE.yaml b/i18n/de_DE.yaml index 91cc09cb..25c6e92c 100644 --- a/i18n/de_DE.yaml +++ b/i18n/de_DE.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 297abec7fe0792049afc52d4477c7fe61dbdbc67 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:03 +0800 Subject: [PATCH 172/336] New translations en_us.yaml (Italian) --- i18n/it_IT.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/it_IT.yaml b/i18n/it_IT.yaml index c9167dde..b2fb1dde 100644 --- a/i18n/it_IT.yaml +++ b/i18n/it_IT.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From b06d67a134f8f6b99db34c363aca2b15a430c450 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:04 +0800 Subject: [PATCH 173/336] New translations en_us.yaml (Japanese) --- i18n/ja_JP.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/ja_JP.yaml b/i18n/ja_JP.yaml index 0051f4dc..3e6433e6 100644 --- a/i18n/ja_JP.yaml +++ b/i18n/ja_JP.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 2c31c0099874a94c4ed79fd01ee2700288251404 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:06 +0800 Subject: [PATCH 174/336] New translations en_us.yaml (Korean) --- i18n/ko_KR.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/ko_KR.yaml b/i18n/ko_KR.yaml index b6baf9fa..d62e78f5 100644 --- a/i18n/ko_KR.yaml +++ b/i18n/ko_KR.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 9cfbcc000a7d65cc515b920248e9f3157a112129 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:07 +0800 Subject: [PATCH 175/336] New translations en_us.yaml (Polish) --- i18n/pl_PL.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/pl_PL.yaml b/i18n/pl_PL.yaml index a996953a..5a46601b 100644 --- a/i18n/pl_PL.yaml +++ b/i18n/pl_PL.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 5687bb3b49709dc6376abd4ca97445e1e38f85ad Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:09 +0800 Subject: [PATCH 176/336] New translations en_us.yaml (Russian) --- i18n/ru_RU.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/ru_RU.yaml b/i18n/ru_RU.yaml index 844c4fac..42c76807 100644 --- a/i18n/ru_RU.yaml +++ b/i18n/ru_RU.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 3f2fa6ca666ef16bc5d1346404b860585438ee69 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:10 +0800 Subject: [PATCH 177/336] New translations en_us.yaml (Slovak) --- i18n/sk_SK.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/sk_SK.yaml b/i18n/sk_SK.yaml index 7b2b9f91..7f801778 100644 --- a/i18n/sk_SK.yaml +++ b/i18n/sk_SK.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From c4c414663692baa240c18a42274176ed5fd39c3c Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:11 +0800 Subject: [PATCH 178/336] New translations en_us.yaml (Turkish) --- i18n/tr_TR.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/tr_TR.yaml b/i18n/tr_TR.yaml index 015ebb21..78a77a25 100644 --- a/i18n/tr_TR.yaml +++ b/i18n/tr_TR.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From f235ecc75c7ad104c863ad36178967778558aca0 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:13 +0800 Subject: [PATCH 179/336] New translations en_us.yaml (Ukrainian) --- i18n/uk_UA.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/uk_UA.yaml b/i18n/uk_UA.yaml index b8eee43b..ee7e6603 100644 --- a/i18n/uk_UA.yaml +++ b/i18n/uk_UA.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From 4d3544ff774e2fe5c68ccb27aced673bb932ef77 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:14 +0800 Subject: [PATCH 180/336] New translations en_us.yaml (Chinese Simplified) --- i18n/zh_CN.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index d5eb16c5..85fafe54 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -538,7 +538,7 @@ backend: name: other: 自传作者 desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: 已认证 @@ -2122,7 +2122,7 @@ ui: badges: action: 操作 active: 活跃的 - activate: Activate + activate: 启用 all: 全部 awards: 奖项 deactivate: 取消激活 From 7dbffca97cd3f3f226832afbfb868064babf39ac Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:16 +0800 Subject: [PATCH 181/336] New translations en_us.yaml (Chinese Traditional) --- i18n/zh_TW.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index 624cfbff..a386576a 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From f0f5d9a2aa374652b7cfbc0e04907b8656230ddd Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:17 +0800 Subject: [PATCH 182/336] New translations en_us.yaml (Indonesian) --- i18n/id_ID.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/id_ID.yaml b/i18n/id_ID.yaml index 50bfcb22..deb0a499 100644 --- a/i18n/id_ID.yaml +++ b/i18n/id_ID.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From e0241e8a6ad5ed8ca607991fa66d80a7f9ca3977 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:19 +0800 Subject: [PATCH 183/336] New translations en_us.yaml (Persian) --- i18n/fa_IR.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/fa_IR.yaml b/i18n/fa_IR.yaml index 3c992278..ffa7a81e 100644 --- a/i18n/fa_IR.yaml +++ b/i18n/fa_IR.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From efdc06d70207cfca920377d02eab8901057fe4b7 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:20 +0800 Subject: [PATCH 184/336] New translations en_us.yaml (Hindi) --- i18n/hi_IN.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/hi_IN.yaml b/i18n/hi_IN.yaml index ec316699..cb6f1645 100644 --- a/i18n/hi_IN.yaml +++ b/i18n/hi_IN.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From d05b64962598eff4da55147e236bf7969d319f6d Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:21 +0800 Subject: [PATCH 185/336] New translations en_us.yaml (Telugu) --- i18n/te_IN.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/te_IN.yaml b/i18n/te_IN.yaml index 5100d720..04158770 100644 --- a/i18n/te_IN.yaml +++ b/i18n/te_IN.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From da546a8fc9a2423017dc106571e957f7ad14ee13 Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:28:23 +0800 Subject: [PATCH 186/336] New translations en_us.yaml (Welsh) --- i18n/cy_GB.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/cy_GB.yaml b/i18n/cy_GB.yaml index eb2d8582..ebd104b0 100644 --- a/i18n/cy_GB.yaml +++ b/i18n/cy_GB.yaml @@ -538,7 +538,7 @@ backend: name: other: Autobiographer desc: - other: Filled out profile information. + other: Filled out profile information. certified: name: other: Certified From df3164a11985261dbe393d20faed342c873c014c Mon Sep 17 00:00:00 2001 From: Sunny <1147886+sunshineg@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:31:37 +0800 Subject: [PATCH 187/336] New translations en_us.yaml (Chinese Simplified) --- i18n/zh_CN.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 85fafe54..ca69257d 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -538,7 +538,7 @@ backend: name: other: 自传作者 desc: - other: Filled out profile information. + other: 填写了 个人资料 信息。 certified: name: other: 已认证 From 465f4bff60944d652a7656cc410629beb18f79d2 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 5 Sep 2024 10:40:48 +0800 Subject: [PATCH 188/336] fix(badge): resolve id when set badge object id --- internal/schema/event_schema.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go index 701d5d88..abacaed3 100644 --- a/internal/schema/event_schema.go +++ b/internal/schema/event_schema.go @@ -79,7 +79,9 @@ func (e *EventMsg) CID(comment, userID string) *EventMsg { // TID get trigger object id func (e *EventMsg) TID(triggerObjectID string) *EventMsg { - e.TriggerObjectID = triggerObjectID + if len(triggerObjectID) > 0 { + e.TriggerObjectID = uid.DeShortID(triggerObjectID) + } return e } From 3ec9cc33c0c9652275cb61299b31db62f92c0b8a Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Wed, 28 Aug 2024 13:31:49 +0800 Subject: [PATCH 189/336] feat: install page support i18n --- ui/src/i18n/init.ts | 60 +++++++++++++++++-- .../Install/components/FirstStep/index.tsx | 3 +- ui/src/pages/Install/index.tsx | 3 +- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/ui/src/i18n/init.ts b/ui/src/i18n/init.ts index 86188900..59ffaf46 100644 --- a/ui/src/i18n/init.ts +++ b/ui/src/i18n/init.ts @@ -21,7 +21,20 @@ import { initReactI18next } from 'react-i18next'; import i18next from 'i18next'; import en_US from '@i18n/en_US.yaml'; -// import zh_CN from '@i18n/zh_CN.yaml'; +import es_ES from '@i18n/es_ES.yaml'; +import pt_BR from '@i18n/pt_BR.yaml'; +import pt_PT from '@i18n/pt_PT.yaml'; +import de_DE from '@i18n/de_DE.yaml'; +import fr_FR from '@i18n/fr_FR.yaml'; +import ja_JP from '@i18n/ja_JP.yaml'; +import it_IT from '@i18n/it_IT.yaml'; +import ru_RU from '@i18n/ru_RU.yaml'; +import zh_CN from '@i18n/zh_CN.yaml'; +import zh_TW from '@i18n/zh_TW.yaml'; +import ko_KR from '@i18n/ko_KR.yaml'; +import vi_VN from '@i18n/vi_VN.yaml'; +import sk_SK from '@i18n/sk_SK.yaml'; +import fa_IR from '@i18n/fa_IR.yaml'; import { DEFAULT_LANG, LANG_RESOURCE_STORAGE_KEY } from '@/common/constants'; import Storage from '@/utils/storage'; @@ -34,9 +47,48 @@ const initResources = { en_US: { translation: en_US.ui, }, - // zh_CN: { - // translation: zh_CN.ui, - // }, + es_ES: { + translation: es_ES.ui, + }, + pt_BR: { + translation: pt_BR.ui, + }, + pt_PT: { + translation: pt_PT.ui, + }, + de_DE: { + translation: de_DE.ui, + }, + fr_FR: { + translation: fr_FR.ui, + }, + ja_JP: { + translation: ja_JP.ui, + }, + it_IT: { + translation: it_IT.ui, + }, + ru_RU: { + translation: ru_RU.ui, + }, + zh_CN: { + translation: zh_CN.ui, + }, + zh_TW: { + translation: zh_TW.ui, + }, + ko_KR: { + translation: ko_KR.ui, + }, + vi_VN: { + translation: vi_VN.ui, + }, + sk_SK: { + translation: sk_SK.ui, + }, + fa_IR: { + translation: fa_IR.ui, + }, }; const storageLang = Storage.get(LANG_RESOURCE_STORAGE_KEY); diff --git a/ui/src/pages/Install/components/FirstStep/index.tsx b/ui/src/pages/Install/components/FirstStep/index.tsx index 3f3f423f..547e91c7 100644 --- a/ui/src/pages/Install/components/FirstStep/index.tsx +++ b/ui/src/pages/Install/components/FirstStep/index.tsx @@ -32,7 +32,7 @@ interface Props { visible: boolean; } const Index: FC = ({ visible, data, changeCallback, nextCallback }) => { - const { t } = useTranslation('translation', { keyPrefix: 'install' }); + const { t, i18n } = useTranslation('translation', { keyPrefix: 'install' }); const [langs, setLangs] = useState(); @@ -65,6 +65,7 @@ const Index: FC = ({ visible, data, changeCallback, nextCallback }) => { value={data.value} isInvalid={data.isInvalid} onChange={(e) => { + i18n.changeLanguage(e.target.value); changeCallback({ lang: { value: e.target.value, diff --git a/ui/src/pages/Install/index.tsx b/ui/src/pages/Install/index.tsx index 5c8f5c84..c34a6e3d 100644 --- a/ui/src/pages/Install/index.tsx +++ b/ui/src/pages/Install/index.tsx @@ -47,7 +47,7 @@ import { } from './components'; const Index: FC = () => { - const { t } = useTranslation('translation', { keyPrefix: 'install' }); + const { t, i18n } = useTranslation('translation', { keyPrefix: 'install' }); const [step, setStep] = useState(1); const [loading, setLoading] = useState(true); const [errorData, setErrorData] = useState<{ [propName: string]: any }>({ @@ -293,6 +293,7 @@ const Index: FC = () => { useEffect(() => { configYmlCheck(); + i18n.changeLanguage(Storage.get(CURRENT_LANG_STORAGE_KEY)); }, []); if (loading) { From c751364974a98f1a1f0a70bc853432a659e59451 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Wed, 4 Sep 2024 09:10:06 +0800 Subject: [PATCH 190/336] fix: add getInstallLanguageConfig --- cmd/answer/main.go | 38 ------------- docs/docs.go | 29 ++++++++++ docs/swagger.json | 29 ++++++++++ docs/swagger.yaml | 19 +++++++ internal/install/install_controller.go | 14 +++++ internal/install/install_server.go | 1 + internal/service/mock/siteinfo_repo_mock.go | 19 ------- ui/src/i18n/init.ts | 56 ------------------- .../Install/components/FirstStep/index.tsx | 5 +- ui/src/pages/Install/index.tsx | 5 +- ui/src/services/install/index.ts | 4 ++ ui/src/utils/localize.ts | 17 ++++++ 12 files changed, 119 insertions(+), 117 deletions(-) delete mode 100644 cmd/answer/main.go diff --git a/cmd/answer/main.go b/cmd/answer/main.go deleted file mode 100644 index fb91f594..00000000 --- a/cmd/answer/main.go +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -//go:generate go run github.com/swaggo/swag/cmd/swag init -g ./cmd/answer/main.go -d ../../ -o ../../docs - -package main - -import ( - answercmd "github.com/apache/incubator-answer/cmd" -) - -// main godoc -// @title "apache answer" -// @description = "apache answer api" -// @version = "v0.0.1" -// @BasePath = "/" -// @securityDefinitions.apikey ApiKeyAuth -// @in header -// @name Authorization -func main() { - answercmd.Main() -} diff --git a/docs/docs.go b/docs/docs.go index 7f5bd871..32942b7d 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -7226,6 +7226,35 @@ const docTemplate = `{ } } }, + "/installation/language/config": { + "get": { + "description": "get installation language config mapping", + "produces": [ + "application/json" + ], + "tags": [ + "Lang" + ], + "summary": "get installation language config mapping", + "parameters": [ + { + "type": "string", + "description": "Accept-Language", + "name": "Accept-Language", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/installation/language/options": { "get": { "description": "get installation language options", diff --git a/docs/swagger.json b/docs/swagger.json index 093e0dfc..3aa86c6b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -7200,6 +7200,35 @@ } } }, + "/installation/language/config": { + "get": { + "description": "get installation language config mapping", + "produces": [ + "application/json" + ], + "tags": [ + "Lang" + ], + "summary": "get installation language config mapping", + "parameters": [ + { + "type": "string", + "description": "Accept-Language", + "name": "Accept-Language", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/installation/language/options": { "get": { "description": "get installation language options", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6d96c8a1..4188b6c0 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -7239,6 +7239,25 @@ paths: summary: init environment tags: - installation + /installation/language/config: + get: + description: get installation language config mapping + parameters: + - description: Accept-Language + in: header + name: Accept-Language + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.RespBody' + summary: get installation language config mapping + tags: + - Lang /installation/language/options: get: description: get installation language options diff --git a/internal/install/install_controller.go b/internal/install/install_controller.go index 7f57efbf..05f7daa6 100644 --- a/internal/install/install_controller.go +++ b/internal/install/install_controller.go @@ -20,6 +20,7 @@ package install import ( + "encoding/json" "net/http" "os" "path/filepath" @@ -37,6 +38,7 @@ import ( "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" + "github.com/segmentfault/pacman/i18n" "github.com/segmentfault/pacman/log" ) @@ -51,6 +53,18 @@ func LangOptions(ctx *gin.Context) { handler.HandleResponse(ctx, nil, translator.LanguageOptions) } +// GetLangMapping get installation language config mapping +// @Summary get installation language config mapping +// @Description get installation language config mapping +// @Tags Lang +// @Param Accept-Language header string true "Accept-Language" +// @Produce json +// @Success 200 {object} handler.RespBody{} +// @Router /installation/language/config [get] +func GetLangMapping(ctx *gin.Context) { + // TODO +} + // CheckConfigFileAndRedirectToInstallPage if config file not exist try to redirect to install page // @Summary if config file not exist try to redirect to install page // @Description if config file not exist try to redirect to install page diff --git a/internal/install/install_server.go b/internal/install/install_server.go index f6087fea..76a2fffe 100644 --- a/internal/install/install_server.go +++ b/internal/install/install_server.go @@ -64,6 +64,7 @@ func NewInstallHTTPServer() *gin.Engine { installApi.GET(c.UI.BaseURL+"/", CheckConfigFileAndRedirectToInstallPage) installApi.GET(c.UI.BaseURL+"/install", WebPage) installApi.GET(c.UI.BaseURL+"/50x", WebPage) + installApi.GET("/installation/language/config", GetLangMapping) installApi.GET("/installation/language/options", LangOptions) installApi.POST("/installation/db/check", CheckDatabase) installApi.POST("/installation/config-file/check", CheckConfigFile) diff --git a/internal/service/mock/siteinfo_repo_mock.go b/internal/service/mock/siteinfo_repo_mock.go index abc1fe07..cdc72b80 100644 --- a/internal/service/mock/siteinfo_repo_mock.go +++ b/internal/service/mock/siteinfo_repo_mock.go @@ -1,22 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - // Code generated by MockGen. DO NOT EDIT. // Source: ./siteinfo_service.go diff --git a/ui/src/i18n/init.ts b/ui/src/i18n/init.ts index 59ffaf46..919335cb 100644 --- a/ui/src/i18n/init.ts +++ b/ui/src/i18n/init.ts @@ -21,20 +21,6 @@ import { initReactI18next } from 'react-i18next'; import i18next from 'i18next'; import en_US from '@i18n/en_US.yaml'; -import es_ES from '@i18n/es_ES.yaml'; -import pt_BR from '@i18n/pt_BR.yaml'; -import pt_PT from '@i18n/pt_PT.yaml'; -import de_DE from '@i18n/de_DE.yaml'; -import fr_FR from '@i18n/fr_FR.yaml'; -import ja_JP from '@i18n/ja_JP.yaml'; -import it_IT from '@i18n/it_IT.yaml'; -import ru_RU from '@i18n/ru_RU.yaml'; -import zh_CN from '@i18n/zh_CN.yaml'; -import zh_TW from '@i18n/zh_TW.yaml'; -import ko_KR from '@i18n/ko_KR.yaml'; -import vi_VN from '@i18n/vi_VN.yaml'; -import sk_SK from '@i18n/sk_SK.yaml'; -import fa_IR from '@i18n/fa_IR.yaml'; import { DEFAULT_LANG, LANG_RESOURCE_STORAGE_KEY } from '@/common/constants'; import Storage from '@/utils/storage'; @@ -47,48 +33,6 @@ const initResources = { en_US: { translation: en_US.ui, }, - es_ES: { - translation: es_ES.ui, - }, - pt_BR: { - translation: pt_BR.ui, - }, - pt_PT: { - translation: pt_PT.ui, - }, - de_DE: { - translation: de_DE.ui, - }, - fr_FR: { - translation: fr_FR.ui, - }, - ja_JP: { - translation: ja_JP.ui, - }, - it_IT: { - translation: it_IT.ui, - }, - ru_RU: { - translation: ru_RU.ui, - }, - zh_CN: { - translation: zh_CN.ui, - }, - zh_TW: { - translation: zh_TW.ui, - }, - ko_KR: { - translation: ko_KR.ui, - }, - vi_VN: { - translation: vi_VN.ui, - }, - sk_SK: { - translation: sk_SK.ui, - }, - fa_IR: { - translation: fa_IR.ui, - }, }; const storageLang = Storage.get(LANG_RESOURCE_STORAGE_KEY); diff --git a/ui/src/pages/Install/components/FirstStep/index.tsx b/ui/src/pages/Install/components/FirstStep/index.tsx index 547e91c7..cb79fdfb 100644 --- a/ui/src/pages/Install/components/FirstStep/index.tsx +++ b/ui/src/pages/Install/components/FirstStep/index.tsx @@ -24,6 +24,7 @@ import { useTranslation } from 'react-i18next'; import type { LangsType, FormValue, FormDataType } from '@/common/interface'; import Progress from '../Progress'; import { getInstallLangOptions } from '@/services'; +import { setupInstallLanguage } from '@/utils/localize'; interface Props { data: FormValue; @@ -32,7 +33,7 @@ interface Props { visible: boolean; } const Index: FC = ({ visible, data, changeCallback, nextCallback }) => { - const { t, i18n } = useTranslation('translation', { keyPrefix: 'install' }); + const { t } = useTranslation('translation', { keyPrefix: 'install' }); const [langs, setLangs] = useState(); @@ -65,7 +66,7 @@ const Index: FC = ({ visible, data, changeCallback, nextCallback }) => { value={data.value} isInvalid={data.isInvalid} onChange={(e) => { - i18n.changeLanguage(e.target.value); + setupInstallLanguage(e.target.value); changeCallback({ lang: { value: e.target.value, diff --git a/ui/src/pages/Install/index.tsx b/ui/src/pages/Install/index.tsx index c34a6e3d..4b43889a 100644 --- a/ui/src/pages/Install/index.tsx +++ b/ui/src/pages/Install/index.tsx @@ -37,6 +37,7 @@ import { } from '@/utils'; import { CURRENT_LANG_STORAGE_KEY } from '@/common/constants'; import { BASE_ORIGIN } from '@/router/alias'; +import { setupInstallLanguage } from '@/utils/localize'; import { FirstStep, @@ -47,7 +48,7 @@ import { } from './components'; const Index: FC = () => { - const { t, i18n } = useTranslation('translation', { keyPrefix: 'install' }); + const { t } = useTranslation('translation', { keyPrefix: 'install' }); const [step, setStep] = useState(1); const [loading, setLoading] = useState(true); const [errorData, setErrorData] = useState<{ [propName: string]: any }>({ @@ -293,7 +294,7 @@ const Index: FC = () => { useEffect(() => { configYmlCheck(); - i18n.changeLanguage(Storage.get(CURRENT_LANG_STORAGE_KEY)); + setupInstallLanguage(Storage.get(CURRENT_LANG_STORAGE_KEY)); }, []); if (loading) { diff --git a/ui/src/services/install/index.ts b/ui/src/services/install/index.ts index 70e581a2..b4b7dc0e 100644 --- a/ui/src/services/install/index.ts +++ b/ui/src/services/install/index.ts @@ -38,3 +38,7 @@ export const installBaseInfo = (params) => { export const getInstallLangOptions = () => { return request.get('/installation/language/options'); }; + +export const getInstallLanguageConfig = () => { + return request.get('/installation/language/config'); +}; diff --git a/ui/src/utils/localize.ts b/ui/src/utils/localize.ts index eea132a8..f446922c 100644 --- a/ui/src/utils/localize.ts +++ b/ui/src/utils/localize.ts @@ -35,6 +35,7 @@ import { } from '@/common/constants'; import { getAdminLanguageOptions, + getInstallLanguageConfig, getLanguageConfig, getLanguageOptions, } from '@/services'; @@ -61,6 +62,15 @@ export const loadLanguageOptions = async (forAdmin = false) => { }; const pullLanguageConf = (res) => { + if (window.location.pathname === '/install') { + return getInstallLanguageConfig().then((langConf) => { + if (langConf && langConf.ui) { + res.resources = langConf.ui; + Storage.set(LANG_RESOURCE_STORAGE_KEY, res); + } + }); + } + return getLanguageConfig().then((langConf) => { if (langConf && langConf.ui) { res.resources = langConf.ui; @@ -68,6 +78,7 @@ const pullLanguageConf = (res) => { } }); }; + const addI18nResource = async (langName) => { const res = { lng: langName, resources: undefined }; const storageResource = Storage.get(LANG_RESOURCE_STORAGE_KEY); @@ -149,3 +160,9 @@ export const setupAppTheme = () => { const theme = getCurrentTheme(); changeTheme(theme); }; + +export const setupInstallLanguage = async (lang) => { + await addI18nResource(lang); + localeDayjs(lang); + i18next.changeLanguage(lang); +}; From fb9bece01c68b5c02fe5b3b3ef99472475685eb0 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Wed, 4 Sep 2024 09:13:20 +0800 Subject: [PATCH 191/336] fix: format code --- cmd/answer/main.go | 38 +++++++++++++++++++++ internal/service/mock/siteinfo_repo_mock.go | 19 +++++++++++ ui/src/utils/localize.ts | 4 ++- 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 cmd/answer/main.go diff --git a/cmd/answer/main.go b/cmd/answer/main.go new file mode 100644 index 00000000..fb91f594 --- /dev/null +++ b/cmd/answer/main.go @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//go:generate go run github.com/swaggo/swag/cmd/swag init -g ./cmd/answer/main.go -d ../../ -o ../../docs + +package main + +import ( + answercmd "github.com/apache/incubator-answer/cmd" +) + +// main godoc +// @title "apache answer" +// @description = "apache answer api" +// @version = "v0.0.1" +// @BasePath = "/" +// @securityDefinitions.apikey ApiKeyAuth +// @in header +// @name Authorization +func main() { + answercmd.Main() +} diff --git a/internal/service/mock/siteinfo_repo_mock.go b/internal/service/mock/siteinfo_repo_mock.go index cdc72b80..abc1fe07 100644 --- a/internal/service/mock/siteinfo_repo_mock.go +++ b/internal/service/mock/siteinfo_repo_mock.go @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Code generated by MockGen. DO NOT EDIT. // Source: ./siteinfo_service.go diff --git a/ui/src/utils/localize.ts b/ui/src/utils/localize.ts index f446922c..fcc322a5 100644 --- a/ui/src/utils/localize.ts +++ b/ui/src/utils/localize.ts @@ -162,7 +162,9 @@ export const setupAppTheme = () => { }; export const setupInstallLanguage = async (lang) => { - await addI18nResource(lang); + if (!i18next.getDataByLanguage(lang)?.translation) { + await addI18nResource(lang); + } localeDayjs(lang); i18next.changeLanguage(lang); }; From 26afc0979c07dca8cbc358031228ab9fce3421cb Mon Sep 17 00:00:00 2001 From: kumfo Date: Wed, 4 Sep 2024 10:02:03 +0800 Subject: [PATCH 192/336] feat(install): add get language mapping api --- internal/install/install_controller.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/install/install_controller.go b/internal/install/install_controller.go index 05f7daa6..ddfed6b9 100644 --- a/internal/install/install_controller.go +++ b/internal/install/install_controller.go @@ -38,7 +38,6 @@ import ( "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" - "github.com/segmentfault/pacman/i18n" "github.com/segmentfault/pacman/log" ) @@ -62,7 +61,15 @@ func LangOptions(ctx *gin.Context) { // @Success 200 {object} handler.RespBody{} // @Router /installation/language/config [get] func GetLangMapping(ctx *gin.Context) { - // TODO + t, err := translator.NewTranslator(&translator.I18n{BundleDir: cli.I18nPath}) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + trData, _ := t.Dump(handler.GetLang(ctx)) + var resp map[string]any + _ = json.Unmarshal(trData, &resp) + handler.HandleResponse(ctx, nil, resp) } // CheckConfigFileAndRedirectToInstallPage if config file not exist try to redirect to install page From 1d33c8827c4960e35459d65101f7c598b0d85e45 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Wed, 4 Sep 2024 21:13:38 +0800 Subject: [PATCH 193/336] fix: change fail --- docs/docs.go | 6 +++--- docs/swagger.json | 6 +++--- docs/swagger.yaml | 6 +++--- internal/install/install_controller.go | 6 ++++-- ui/src/services/install/index.ts | 4 ++-- ui/src/utils/localize.ts | 6 ++---- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 32942b7d..69078bf4 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -7239,9 +7239,9 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "Accept-Language", - "name": "Accept-Language", - "in": "header", + "description": "installation language", + "name": "lang", + "in": "query", "required": true } ], diff --git a/docs/swagger.json b/docs/swagger.json index 3aa86c6b..4ca27f0a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -7213,9 +7213,9 @@ "parameters": [ { "type": "string", - "description": "Accept-Language", - "name": "Accept-Language", - "in": "header", + "description": "installation language", + "name": "lang", + "in": "query", "required": true } ], diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4188b6c0..b9c36562 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -7243,9 +7243,9 @@ paths: get: description: get installation language config mapping parameters: - - description: Accept-Language - in: header - name: Accept-Language + - description: installation language + in: query + name: lang required: true type: string produces: diff --git a/internal/install/install_controller.go b/internal/install/install_controller.go index ddfed6b9..0a116569 100644 --- a/internal/install/install_controller.go +++ b/internal/install/install_controller.go @@ -38,6 +38,7 @@ import ( "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" + "github.com/segmentfault/pacman/i18n" "github.com/segmentfault/pacman/log" ) @@ -56,7 +57,7 @@ func LangOptions(ctx *gin.Context) { // @Summary get installation language config mapping // @Description get installation language config mapping // @Tags Lang -// @Param Accept-Language header string true "Accept-Language" +// @Param lang query string true "installation language" // @Produce json // @Success 200 {object} handler.RespBody{} // @Router /installation/language/config [get] @@ -66,7 +67,8 @@ func GetLangMapping(ctx *gin.Context) { handler.HandleResponse(ctx, err, nil) return } - trData, _ := t.Dump(handler.GetLang(ctx)) + lang := ctx.Query("lang") + trData, _ := t.Dump(i18n.Language(lang)) var resp map[string]any _ = json.Unmarshal(trData, &resp) handler.HandleResponse(ctx, nil, resp) diff --git a/ui/src/services/install/index.ts b/ui/src/services/install/index.ts index b4b7dc0e..47ae75fa 100644 --- a/ui/src/services/install/index.ts +++ b/ui/src/services/install/index.ts @@ -39,6 +39,6 @@ export const getInstallLangOptions = () => { return request.get('/installation/language/options'); }; -export const getInstallLanguageConfig = () => { - return request.get('/installation/language/config'); +export const getInstallLanguageConfig = (lang: string) => { + return request.get(`/installation/language/config?lang=${lang}`); }; diff --git a/ui/src/utils/localize.ts b/ui/src/utils/localize.ts index fcc322a5..0b45a222 100644 --- a/ui/src/utils/localize.ts +++ b/ui/src/utils/localize.ts @@ -63,7 +63,7 @@ export const loadLanguageOptions = async (forAdmin = false) => { const pullLanguageConf = (res) => { if (window.location.pathname === '/install') { - return getInstallLanguageConfig().then((langConf) => { + return getInstallLanguageConfig(res.lng).then((langConf) => { if (langConf && langConf.ui) { res.resources = langConf.ui; Storage.set(LANG_RESOURCE_STORAGE_KEY, res); @@ -162,9 +162,7 @@ export const setupAppTheme = () => { }; export const setupInstallLanguage = async (lang) => { - if (!i18next.getDataByLanguage(lang)?.translation) { - await addI18nResource(lang); - } + await addI18nResource(lang); localeDayjs(lang); i18next.changeLanguage(lang); }; From e7eecc05cdb461650cfdf070afcae7804492fa29 Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 6 Sep 2024 10:45:14 +0800 Subject: [PATCH 194/336] fix: badge list style --- ui/src/components/CardBadge/index.scss | 10 ---------- ui/src/components/CardBadge/index.tsx | 9 +++++++-- ui/src/pages/Badges/Detail/index.tsx | 1 + ui/src/pages/Badges/index.tsx | 11 +++++++---- .../Users/Personal/components/Badges/index.tsx | 17 ++++++++++------- .../Personal/components/Overview/index.tsx | 18 ++++++++++-------- 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/ui/src/components/CardBadge/index.scss b/ui/src/components/CardBadge/index.scss index 30c30cb1..c3021a74 100644 --- a/ui/src/components/CardBadge/index.scss +++ b/ui/src/components/CardBadge/index.scss @@ -18,19 +18,9 @@ */ .badge-card { - width: 194px; - margin: 12px; - .label { position: absolute; top: 1rem; right: 1rem; } } - - -@media screen and (max-width: 768px) { - .badge-card { - width: 163.5px; - } -} diff --git a/ui/src/components/CardBadge/index.tsx b/ui/src/components/CardBadge/index.tsx index 214e3f5d..3022ae12 100644 --- a/ui/src/components/CardBadge/index.tsx +++ b/ui/src/components/CardBadge/index.tsx @@ -50,7 +50,9 @@ const Index: FC = ({ to={`/badges/${data.id}${urlSearchParams ? `?${urlSearchParams}` : ''}`}> {Number(data?.earned_count) > 0 && badgePillType === 'earned' && ( - + {`${t('earned')}${ Number(data?.earned_count) > 1 ? ` ×${data.earned_count}` : '' }`} @@ -58,7 +60,10 @@ const Index: FC = ({ )} {badgePillType === 'count' && Number(data?.earned_count) > 1 && ( - + ×{data.earned_count} )} diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index cb85a8b8..d9337840 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -64,6 +64,7 @@ const Index = () => {

{t('title')}

{isHeaderLoading ? : } + {isSkeletonShow ? ( diff --git a/ui/src/pages/Badges/index.tsx b/ui/src/pages/Badges/index.tsx index 73cb77b0..9ca6d9a0 100644 --- a/ui/src/pages/Badges/index.tsx +++ b/ui/src/pages/Badges/index.tsx @@ -18,6 +18,7 @@ */ import { useTranslation } from 'react-i18next'; +import { Row, Col } from 'react-bootstrap'; import { CardBadge } from '@/components'; import { usePageTags } from '@/hooks'; @@ -37,15 +38,17 @@ const Index = () => {

{t('title')}

{badgesList?.map((item) => { return ( -
+
{item.group_name}
-
+ {item.badges?.map((badge) => { return ( - + + + ); })} -
+
); })} diff --git a/ui/src/pages/Users/Personal/components/Badges/index.tsx b/ui/src/pages/Users/Personal/components/Badges/index.tsx index 4243ba9e..d49b85cd 100644 --- a/ui/src/pages/Users/Personal/components/Badges/index.tsx +++ b/ui/src/pages/Users/Personal/components/Badges/index.tsx @@ -18,6 +18,7 @@ */ import { FC } from 'react'; +import { Row, Col } from 'react-bootstrap'; import * as Type from '@/common/interface'; import { CardBadge } from '@/components'; @@ -33,17 +34,19 @@ const Index: FC = ({ data, visible, username }) => { return null; } return ( -
+ {data.map((item) => { return ( - + + + ); })} -
+ ); }; diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 6b247b0c..81ed7b32 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -72,19 +72,21 @@ const Index: FC = ({ visible, introduction, data, username }) => { {Number(recentBadges?.count) > 0 && ( -
+
{t('recent_badges')}
-
+ {recentBadges?.list?.map((item) => { return ( - + + + ); })} -
+
)}
From e24a7181f2853afb43570a556af791b5bc9bcf3c Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 6 Sep 2024 10:45:50 +0800 Subject: [PATCH 195/336] fix: badge detail delete loader --- ui/src/pages/Badges/Detail/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index d9337840..cb85a8b8 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -64,7 +64,6 @@ const Index = () => {

{t('title')}

{isHeaderLoading ? : } - {isSkeletonShow ? ( From 2e67b9ca6f7c29c2b0a030958788c4a7f20e9f59 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 11 Sep 2024 16:41:45 +0800 Subject: [PATCH 196/336] fix(swagger): fix title and description on swagger docs --- cmd/answer/main.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/answer/main.go b/cmd/answer/main.go index fb91f594..9ba33b6f 100644 --- a/cmd/answer/main.go +++ b/cmd/answer/main.go @@ -26,10 +26,9 @@ import ( ) // main godoc -// @title "apache answer" -// @description = "apache answer api" -// @version = "v0.0.1" -// @BasePath = "/" +// @title Apache Answer +// @description Apache Answer API +// @BasePath / // @securityDefinitions.apikey ApiKeyAuth // @in header // @name Authorization From 6c9203a7bef9a7180a2a4b94c93a6ad0dddda4b3 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Wed, 11 Sep 2024 17:19:39 +0800 Subject: [PATCH 197/336] fix: setup install language error --- ui/src/pages/Install/components/FirstStep/index.tsx | 9 ++++++++- ui/src/pages/Install/index.tsx | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ui/src/pages/Install/components/FirstStep/index.tsx b/ui/src/pages/Install/components/FirstStep/index.tsx index cb79fdfb..3c87ac3b 100644 --- a/ui/src/pages/Install/components/FirstStep/index.tsx +++ b/ui/src/pages/Install/components/FirstStep/index.tsx @@ -25,6 +25,8 @@ import type { LangsType, FormValue, FormDataType } from '@/common/interface'; import Progress from '../Progress'; import { getInstallLangOptions } from '@/services'; import { setupInstallLanguage } from '@/utils/localize'; +import { CURRENT_LANG_STORAGE_KEY } from '@/common/constants'; +import { Storage } from '@/utils'; interface Props { data: FormValue; @@ -39,10 +41,15 @@ const Index: FC = ({ visible, data, changeCallback, nextCallback }) => { const getLangs = async () => { const res: LangsType[] = await getInstallLangOptions(); + const currentLang = Storage.get(CURRENT_LANG_STORAGE_KEY); + const selectedLang = currentLang || res[0].value; + setLangs(res); + setupInstallLanguage(selectedLang); + changeCallback({ lang: { - value: res[0].value, + value: selectedLang, isInvalid: false, errorMsg: '', }, diff --git a/ui/src/pages/Install/index.tsx b/ui/src/pages/Install/index.tsx index 4b43889a..902f23f3 100644 --- a/ui/src/pages/Install/index.tsx +++ b/ui/src/pages/Install/index.tsx @@ -280,6 +280,7 @@ const Index: FC = () => { db_connection_success: res.db_connection_success, }); if (res && res.config_file_exist) { + setupInstallLanguage(Storage.get(CURRENT_LANG_STORAGE_KEY)); if (res.db_connection_success) { setStep(6); } else { @@ -294,7 +295,6 @@ const Index: FC = () => { useEffect(() => { configYmlCheck(); - setupInstallLanguage(Storage.get(CURRENT_LANG_STORAGE_KEY)); }, []); if (loading) { From b927953ff3ffbc759e8a50996efdbe3da0ca7a96 Mon Sep 17 00:00:00 2001 From: shuai Date: Thu, 19 Sep 2024 11:17:06 +0800 Subject: [PATCH 198/336] fix: change badges detail item key --- ui/src/pages/Badges/Detail/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index cb85a8b8..c5713e2b 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -68,7 +68,7 @@ const Index = () => { {isSkeletonShow ? ( ) : ( - badges?.list?.map((item) => { + badges?.list?.map((item, index) => { const linkUrl = item.object_type === 'question' ? `/questions/${item.question_id}` @@ -84,7 +84,7 @@ const Index = () => { sm={12} md={6} lg={3} - key={item.author_user_info.id} + key={item.object_id || `${item.author_user_info.id}${index}`} className="mb-4"> Date: Thu, 19 Sep 2024 12:02:37 +0800 Subject: [PATCH 199/336] fix: fix rendering issue in badge list --- ui/src/pages/Admin/Badges/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 9a86eed9..99bafb43 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -102,7 +102,7 @@ const Badges: FC = () => { - {data?.list.map((badge) => ( + {data?.list?.map((badge) => ( {badge.icon?.startsWith('http') ? ( From 48c238785359238d1ed278dd0921476d4ebd4c66 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Wed, 18 Sep 2024 19:24:44 +0800 Subject: [PATCH 200/336] chore: sync swagger --- cmd/wire_gen.go | 5 ++--- docs/docs.go | 8 ++++---- docs/swagger.json | 9 ++++----- docs/swagger.yaml | 7 +++---- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 537ece84..f5a3f900 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -1,6 +1,3 @@ -//go:build !wireinject -// +build !wireinject - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -23,6 +20,8 @@ // Code generated by Wire. DO NOT EDIT. //go:generate go run github.com/google/wire/cmd/wire +//go:build !wireinject +// +build !wireinject package answercmd diff --git a/docs/docs.go b/docs/docs.go index 69078bf4..e461c3a9 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -11559,12 +11559,12 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ - Version: "= \"v0.0.1\"", + Version: "", Host: "", - BasePath: "= \"/\"", + BasePath: "/", Schemes: []string{}, - Title: "\"apache answer\"", - Description: "= \"apache answer api\"", + Title: "Apache Answer", + Description: "Apache Answer API", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", diff --git a/docs/swagger.json b/docs/swagger.json index 4ca27f0a..322a87ad 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,12 +1,11 @@ { "swagger": "2.0", "info": { - "description": "= \"apache answer api\"", - "title": "\"apache answer\"", - "contact": {}, - "version": "= \"v0.0.1\"" + "description": "Apache Answer API", + "title": "Apache Answer", + "contact": {} }, - "basePath": "= \"/\"", + "basePath": "/", "paths": { "/": { "get": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index b9c36562..66a594d5 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -basePath: = "/" +basePath: / definitions: constant.NotificationChannelKey: enum: @@ -2910,9 +2910,8 @@ definitions: type: object info: contact: {} - description: = "apache answer api" - title: '"apache answer"' - version: = "v0.0.1" + description: Apache Answer API + title: Apache Answer paths: /: get: From be00ce4fc52a00fff2ee88aa8b17d8310958097f Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Thu, 19 Sep 2024 13:36:30 +0800 Subject: [PATCH 201/336] fix: install plugin dependencies --- internal/cli/build.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/cli/build.go b/internal/cli/build.go index 2e59ca58..6af13c7a 100644 --- a/internal/cli/build.go +++ b/internal/cli/build.go @@ -264,9 +264,16 @@ func copyUIFiles(b *buildingMaterial) (err error) { if !dir.CheckFileExist(packageJsonPath) { continue } + + pnpmInstallCmd := b.newExecCmd("pnpm", "install") + pnpmInstallCmd.Dir = sourcePluginDir + if err = pnpmInstallCmd.Run(); err != nil { + return fmt.Errorf("failed to install plugin dependencies: %w", err) + } + localPluginDir := filepath.Join(localUIPluginDir, entry.Name()) fmt.Printf("try to copy dir from %s to %s\n", sourcePluginDir, localPluginDir) - if err = copyDirEntries(os.DirFS(sourcePluginDir), ".", localPluginDir); err != nil { + if err = copyDirEntries(os.DirFS(sourcePluginDir), ".", localPluginDir, "node_modules"); err != nil { return fmt.Errorf("failed to copy ui files: %w", err) } } From 659a3383c9c05834f3d97fda5f6ccc24eec56bb5 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Tue, 17 Sep 2024 18:37:14 +0800 Subject: [PATCH 202/336] fix: GetUserIsAdminModerator failed --- internal/service/user_common/user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/user_common/user.go b/internal/service/user_common/user.go index 084dd389..a10c4766 100644 --- a/internal/service/user_common/user.go +++ b/internal/service/user_common/user.go @@ -234,7 +234,7 @@ func (us *UserCommon) CacheLoginUserInfo(ctx context.Context, userID string, use return "", nil, err } if userCacheInfo.RoleID == role.RoleAdminID { - if err = us.authService.SetAdminUserCacheInfo(ctx, accessToken, &entity.UserCacheInfo{UserID: userID}); err != nil { + if err = us.authService.SetAdminUserCacheInfo(ctx, accessToken, userCacheInfo); err != nil { return "", nil, err } } From 211659a5bf0bd07ba4a164bade5e4f05a10c7301 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Fri, 20 Sep 2024 11:32:19 +0800 Subject: [PATCH 203/336] fix: missing url title for PermalinkQuestionIDAndTitleByShortID --- internal/controller/template_controller.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 6b6a20f8..56a38f00 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -150,7 +150,8 @@ func (tc *TemplateController) Index(ctx *gin.Context) { siteInfo.Canonical = siteInfo.General.SiteUrl UrlUseTitle := false - if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle { + if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || + siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { UrlUseTitle = true } siteInfo.Title = "" @@ -183,7 +184,8 @@ func (tc *TemplateController) QuestionList(ctx *gin.Context) { } UrlUseTitle := false - if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle { + if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || + siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { UrlUseTitle = true } siteInfo.Title = fmt.Sprintf("%s - %s", translator.Tr(handler.GetLang(ctx), constant.QuestionsTitleTrKey), siteInfo.General.Name) @@ -466,7 +468,8 @@ func (tc *TemplateController) TagInfo(ctx *gin.Context) { siteInfo.Keywords = tagInfo.DisplayName UrlUseTitle := false - if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle { + if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || + siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { UrlUseTitle = true } siteInfo.Title = fmt.Sprintf("'%s' %s - %s", tagInfo.DisplayName, translator.Tr(handler.GetLang(ctx), constant.QuestionsTitleTrKey), siteInfo.General.Name) From 94828f71d1d4c7b89f5119fc6538d1c990ffa825 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Fri, 20 Sep 2024 16:36:24 +0800 Subject: [PATCH 204/336] fix: 404 page return 200 status code --- internal/router/ui.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/router/ui.go b/internal/router/ui.go index 1d68384e..b959bcd3 100644 --- a/internal/router/ui.go +++ b/internal/router/ui.go @@ -120,10 +120,8 @@ func (a *UIRouter) Register(r *gin.Engine, baseURLPath string) { } else { c.Header("content-type", "image/vnd.microsoft.icon") filePath = UIRootFilePath + urlPath - } case "/manifest.json": - // filePath = UIRootFilePath + urlPath a.siteInfoController.GetManifestJson(c) return case "/install": @@ -154,6 +152,12 @@ func (a *UIRouter) Register(r *gin.Engine, baseURLPath string) { c.String(http.StatusOK, strings.ReplaceAll(string(file), "/static", cdnPrefix+"/static")) return } + + if filePath == UIIndexFilePath { + c.String(http.StatusNotFound, string(file)) + return + } + c.String(http.StatusOK, string(file)) }) } From 65cb30498eeef299fca0daafc1c42e56fce6ebbf Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 23 Sep 2024 14:30:22 +0800 Subject: [PATCH 205/336] ci(github): only formal tag will push the latest image --- .../build-image-for-latest-release.yml | 72 +++++++++++++++++++ .github/workflows/build-image-for-release.yml | 1 - 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-image-for-latest-release.yml diff --git a/.github/workflows/build-image-for-latest-release.yml b/.github/workflows/build-image-for-latest-release.yml new file mode 100644 index 00000000..7cc11d39 --- /dev/null +++ b/.github/workflows/build-image-for-latest-release.yml @@ -0,0 +1,72 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: Build Docker Image For Release + +on: + push: + branches: [ "main"] + tags: + - v2.* + - v1.* + - v0.* + tags-ignore: + - v2.*-RC* + - v1.*-RC* + - v0.*-RC* + # pull_request: + # branches: [ "main" ] + +jobs: + build: + if: ${{ github.repository_owner == 'apache' }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: apache/answer + tags: | + type=raw,value=latest + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + file: ./Dockerfile + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + diff --git a/.github/workflows/build-image-for-release.yml b/.github/workflows/build-image-for-release.yml index 150b1d62..6b4b2425 100644 --- a/.github/workflows/build-image-for-release.yml +++ b/.github/workflows/build-image-for-release.yml @@ -41,7 +41,6 @@ jobs: with: images: apache/answer tags: | - type=raw,value=latest type=ref,enable=true,priority=600,prefix=,suffix=,event=branch type=semver,pattern={{version}} From 4c0e669d515192782f06dd9f6e172baf326b86a2 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 23 Sep 2024 14:38:38 +0800 Subject: [PATCH 206/336] ci(github): remove tags-ignore --- .github/workflows/build-image-for-latest-release.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build-image-for-latest-release.yml b/.github/workflows/build-image-for-latest-release.yml index 7cc11d39..9fe6f450 100644 --- a/.github/workflows/build-image-for-latest-release.yml +++ b/.github/workflows/build-image-for-latest-release.yml @@ -24,10 +24,7 @@ on: - v2.* - v1.* - v0.* - tags-ignore: - - v2.*-RC* - - v1.*-RC* - - v0.*-RC* + - "!v*-RC*" # pull_request: # branches: [ "main" ] From bbf634aab7d5e55b74637654e1fb5c6705b67f3e Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 23 Sep 2024 14:40:48 +0800 Subject: [PATCH 207/336] ci(github): rename github action name --- .github/workflows/build-image-for-latest-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-image-for-latest-release.yml b/.github/workflows/build-image-for-latest-release.yml index 9fe6f450..eb9fa287 100644 --- a/.github/workflows/build-image-for-latest-release.yml +++ b/.github/workflows/build-image-for-latest-release.yml @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -name: Build Docker Image For Release +name: Build Latest Docker Image For Release on: push: From 8e6fa13c72dae18b8c516bf349928f9d3109988c Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 23 Sep 2024 14:48:46 +0800 Subject: [PATCH 208/336] CI: only formal tag will push the latest image (#1116) --- .github/workflows/build-image-for-latest-release.yml | 1 - .github/workflows/build-image-for-release.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/build-image-for-latest-release.yml b/.github/workflows/build-image-for-latest-release.yml index eb9fa287..b45e28ef 100644 --- a/.github/workflows/build-image-for-latest-release.yml +++ b/.github/workflows/build-image-for-latest-release.yml @@ -19,7 +19,6 @@ name: Build Latest Docker Image For Release on: push: - branches: [ "main"] tags: - v2.* - v1.* diff --git a/.github/workflows/build-image-for-release.yml b/.github/workflows/build-image-for-release.yml index 6b4b2425..fdbf95cd 100644 --- a/.github/workflows/build-image-for-release.yml +++ b/.github/workflows/build-image-for-release.yml @@ -19,7 +19,6 @@ name: Build Docker Image For Release on: push: - branches: [ "main"] tags: - v2.* - v1.* From 0d6ea89ad389a523b63711e9ef5e65adbe63ffad Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 23 Sep 2024 15:00:34 +0800 Subject: [PATCH 209/336] refactor(gomod): upgrade golang and dependence version --- Dockerfile | 4 +- cmd/wire_gen.go | 5 +- go.mod | 189 +-- go.sum | 1321 +++-------------- internal/service/content/user_service.go | 10 +- internal/service/user_admin/user_backyard.go | 7 +- .../user_external_login_service.go | 3 +- pkg/htmltext/htmltext.go | 15 - pkg/token/token.go | 2 +- 9 files changed, 352 insertions(+), 1204 deletions(-) diff --git a/Dockerfile b/Dockerfile index bd5f8768..6f57aa07 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,8 +15,8 @@ # specific language governing permissions and limitations # under the License. -FROM golang:1.19-alpine AS golang-builder -LABEL maintainer="aichy@sf.com" +FROM golang:1.22-alpine AS golang-builder +LABEL maintainer="linkinstar@apache.org" ARG GOPROXY # ENV GOPROXY ${GOPROXY:-direct} diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index f5a3f900..537ece84 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -1,3 +1,6 @@ +//go:build !wireinject +// +build !wireinject + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -20,8 +23,6 @@ // Code generated by Wire. DO NOT EDIT. //go:generate go run github.com/google/wire/cmd/wire -//go:build !wireinject -// +build !wireinject package answercmd diff --git a/go.mod b/go.mod index e14b01b9..615b0f73 100644 --- a/go.mod +++ b/go.mod @@ -17,154 +17,161 @@ module github.com/apache/incubator-answer -go 1.18 +go 1.22.0 require ( github.com/Chain-Zhang/pinyin v0.1.3 github.com/Machiel/slugify v1.0.1 - github.com/Masterminds/semver/v3 v3.1.1 + github.com/Masterminds/semver/v3 v3.3.0 github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267 - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/bwmarrin/snowflake v0.3.0 github.com/disintegration/imaging v1.6.2 - github.com/gin-gonic/gin v1.9.1 + github.com/gin-gonic/gin v1.10.0 github.com/go-playground/locales v0.14.1 github.com/go-playground/universal-translator v0.18.1 - github.com/go-playground/validator/v10 v10.14.0 - github.com/go-sql-driver/mysql v1.6.0 - github.com/goccy/go-json v0.10.2 + github.com/go-playground/validator/v10 v10.22.1 + github.com/go-sql-driver/mysql v1.8.1 + github.com/goccy/go-json v0.10.3 github.com/golang/mock v1.6.0 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.6.0 github.com/google/wire v0.5.0 - github.com/grokify/html-strip-tags-go v0.0.1 - github.com/jinzhu/copier v0.3.5 + github.com/grokify/html-strip-tags-go v0.1.0 + github.com/jinzhu/copier v0.4.0 github.com/jinzhu/now v1.1.5 - github.com/lib/pq v1.10.7 - github.com/microcosm-cc/bluemonday v1.0.21 - github.com/ory/dockertest/v3 v3.10.0 + github.com/lib/pq v1.10.9 + github.com/microcosm-cc/bluemonday v1.0.27 + github.com/ory/dockertest/v3 v3.11.0 github.com/robfig/cron/v3 v3.0.1 github.com/scottleedavis/go-exif-remove v0.0.0-20230314195146-7e059d593405 github.com/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20230822083413-c0075a2d401f - github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20221018072427-a15dd1434e05 - github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230516093754-b76aef1c1150 - github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20221018072427-a15dd1434e05 - github.com/segmentfault/pacman/contrib/server/http v0.0.0-20221018072427-a15dd1434e05 - github.com/spf13/cobra v1.6.1 - github.com/stretchr/testify v1.8.4 - github.com/swaggo/files v1.0.0 - github.com/swaggo/gin-swagger v1.5.3 + github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20230822083413-c0075a2d401f + github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230822083413-c0075a2d401f + github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20230822083413-c0075a2d401f + github.com/segmentfault/pacman/contrib/server/http v0.0.0-20230822083413-c0075a2d401f + github.com/spf13/cobra v1.8.1 + github.com/stretchr/testify v1.9.0 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.3 - github.com/tidwall/gjson v1.14.4 - github.com/yuin/goldmark v1.4.13 - golang.org/x/crypto v0.21.0 - golang.org/x/image v0.13.0 - golang.org/x/net v0.21.0 + github.com/tidwall/gjson v1.17.3 + github.com/yuin/goldmark v1.7.4 + golang.org/x/crypto v0.27.0 + golang.org/x/image v0.20.0 + golang.org/x/net v0.29.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.24.0 - xorm.io/builder v0.3.12 - xorm.io/xorm v1.3.2 + modernc.org/sqlite v1.33.0 + xorm.io/builder v0.3.13 + xorm.io/xorm v1.3.9 ) require ( + dario.cat/mergo v1.0.1 // indirect + filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/LinkinStars/go-i18n/v2 v2.2.2 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect - github.com/andybalholm/brotli v1.0.4 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect - github.com/bytedance/sonic v1.9.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/containerd/continuity v0.4.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v24.0.6+incompatible // indirect - github.com/docker/docker v24.0.6+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect + github.com/bytedance/sonic v1.12.2 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/containerd/continuity v0.4.3 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/docker/cli v27.2.1+incompatible // indirect + github.com/docker/docker v27.2.1+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dsoprea/go-exif v0.0.0-20190901173045-3ce78807c90f // indirect - github.com/dsoprea/go-jpeg-image-structure v0.0.0-20190422055009-d6f9ba25cf48 // indirect - github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 // indirect - github.com/dsoprea/go-png-image-structure v0.0.0-20190624104353-c9b28dcdc5c8 // indirect + github.com/dsoprea/go-exif v0.0.0-20230826092837-6579e82b732d // indirect + github.com/dsoprea/go-exif/v2 v2.0.0-20230826092837-6579e82b732d // indirect + github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 // indirect + github.com/dsoprea/go-jpeg-image-structure v0.0.0-20221012074422-4f3f7e934102 // indirect + github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect + github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect + github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d // indirect + github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-errors/errors v1.0.1 // indirect - github.com/go-openapi/jsonpointer v0.20.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/spec v0.20.9 // indirect - github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-errors/errors v1.5.1 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-viper/mapstructure/v2 v2.1.0 // indirect + github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/geo v0.0.0-20190812012225-f41920e961ce // indirect + github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/gorilla/css v1.0.0 // indirect + github.com/gorilla/css v1.0.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect - github.com/lestrrat-go/strftime v1.0.6 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/lestrrat-go/strftime v1.1.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/opencontainers/runc v1.1.9 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/runc v1.1.14 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect - github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/afero v1.9.2 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.13.0 // indirect - github.com/subosito/gotenv v1.4.1 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.10.0 // indirect - go.uber.org/zap v1.24.0 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.13.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/arch v0.10.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.25.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - lukechampine.com/uint128 v1.2.0 // indirect - modernc.org/cc/v3 v3.40.0 // indirect - modernc.org/ccgo/v3 v3.16.13 // indirect - modernc.org/libc v1.22.5 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect - modernc.org/opt v0.1.3 // indirect - modernc.org/strutil v1.1.3 // indirect - modernc.org/token v1.0.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) replace lukechampine.com/uint128 v1.1.1 => github.com/aichy126/uint128 v1.1.1 diff --git a/go.sum b/go.sum index 4bf5cc08..1a2ab6fc 100644 --- a/go.sum +++ b/go.sum @@ -1,717 +1,343 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= -gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Chain-Zhang/pinyin v0.1.3 h1:RzErNyNwVa8z2sOLCuXSOtVdY/AsARb8mBzI2p2qtnE= github.com/Chain-Zhang/pinyin v0.1.3/go.mod h1:5iHpt9p4znrnaP59/hfPMnAojajkDxQaP9io+tRMPho= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/LinkinStars/go-i18n/v2 v2.2.2 h1:ZfjpzbW13dv6btv3RALKZkpN9A+7K1JA//2QcNeWaxU= github.com/LinkinStars/go-i18n/v2 v2.2.2/go.mod h1:hLglSJ4/3M0Y7ZVcoEJI+OwqkglHCA32DdjuJJR2LbM= github.com/Machiel/slugify v1.0.1 h1:EfWSlRWstMadsgzmiV7d0yVd2IFlagWH68Q+DcYCm4E= github.com/Machiel/slugify v1.0.1/go.mod h1:fTFGn5uWEynW4CUMG7sWkYXOf1UgDxyTM3DbR6Qfg3k= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= -github.com/aichy126/uint128 v1.1.1/go.mod h1:Hke/MPGXUxOl0OXHoNcVesBL4N+XalHEJ9e1jaIbl8o= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267 h1:vDHsaEcs/Q0dwetADENtwus6W1ccaZ9h3KBTm0d2X0g= github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267/go.mod h1:Yj3yPP/vi87JjwylUTCMyd6FrOfGqP1AHk0305hDm2o= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= -github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg= +github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= +github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= -github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= -github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= -github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIrnyWmSJI70= +github.com/docker/cli v27.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= +github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dsoprea/go-exif v0.0.0-20190901173045-3ce78807c90f h1:vqfYiZ+xF0xJvl9SZ1kovmMgKjaGZIz/Hn8JDQdyd9A= github.com/dsoprea/go-exif v0.0.0-20190901173045-3ce78807c90f/go.mod h1:DmMpU91/Ax6BAwoRkjgRCr2rmgEgS4tsmatfV7M+U+c= -github.com/dsoprea/go-jpeg-image-structure v0.0.0-20190422055009-d6f9ba25cf48 h1:9zARagUAxQJjibcDy+0+koUMR6sbX38L49Bk2Vni628= +github.com/dsoprea/go-exif v0.0.0-20230826092837-6579e82b732d h1:ygcRCGNKuEiA98k7X35hknEN8RIRUF1jrz7k1rZCvsk= +github.com/dsoprea/go-exif v0.0.0-20230826092837-6579e82b732d/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs= +github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E= +github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0= +github.com/dsoprea/go-exif/v2 v2.0.0-20230826092837-6579e82b732d h1:yeH8wrJa3+8uKKDAdURHUK1ds2UvKhMqX2MiOdVeKPs= +github.com/dsoprea/go-exif/v2 v2.0.0-20230826092837-6579e82b732d/go.mod h1:oKrjk2kb3rAR5NbtSTLUMvMSbc+k8ZosI3MaVH47noc= +github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8= +github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk= +github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM= +github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 h1:YDRiMEm32T60Kpm35YzOK9ZHgjsS1Qrid+XskNcsdp8= +github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM= github.com/dsoprea/go-jpeg-image-structure v0.0.0-20190422055009-d6f9ba25cf48/go.mod h1:H1hAaFyv9cRV1ywoHvaqVoNSThBvWZ0JarRBcV+FSnE= -github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696 h1:VGFnZAcLwPpt1sHlAxml+pGLZz9A2s+K/s1YNhPC91Y= +github.com/dsoprea/go-jpeg-image-structure v0.0.0-20221012074422-4f3f7e934102 h1:P1dsxzctGkmG6Zf7gH2xrZhNXWP5/FuLDI7xbCGsWTo= +github.com/dsoprea/go-jpeg-image-structure v0.0.0-20221012074422-4f3f7e934102/go.mod h1:6+tQXZ+I62x13UZ+hemLVoZIuq/usVzvau7bqwUo9P0= github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA= -github.com/dsoprea/go-png-image-structure v0.0.0-20190624104353-c9b28dcdc5c8 h1:SVQfy5rBFZXzvGkU2MZ0RzpS912/1sJrEJ+FMmeaC9U= +github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= +github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg= +github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8= +github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E= +github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d h1:dg6UMHa50VI01WuPWXPbNJpO8QSyvIF5T5n2IZiqX3A= +github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E= github.com/dsoprea/go-png-image-structure v0.0.0-20190624104353-c9b28dcdc5c8/go.mod h1:Bf0nmcDFFRQBjZwr9qY6c0zTxKQa+Q8YWZmlYxXGxY0= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d h1:8+qI8ant/vZkNSsbwSjIR6XJfWcDVTg/qx/3pRUUZNA= +github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d/go.mod h1:yTR3tKgyk20phAFg6IE9ulMA5NjEDD2wyx+okRFLVtw= +github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8= +github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349 h1:/py11NlxDaOxkT9OKN+gXgT+QOH5xj1ZRoyusfRIlo4= +github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349/go.mod h1:KVK+/Hul09ujXAGq+42UBgCTnXkiJZRnLYdURGjQUwo= +github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= -github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= -github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= +github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= +github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/geo v0.0.0-20190812012225-f41920e961ce h1:rqIKPpIcEgiNn0KYNFYD34TbMO86l4woyhNzSP+Oegs= github.com/golang/geo v0.0.0-20190812012225-f41920e961ce/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/geo v0.0.0-20230421003525-6adc56603217 h1:HKlyj6in2JV6wVkmQ4XmG/EIm+SCYlPZ+V4GWit7Z+I= +github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1IxZfeH3/5I97CI8i5cLGsYe7xNhQGs9U= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= -github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= +github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= -github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= -github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= -github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= -github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE= -github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= -github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= -github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= -github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc= -github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= -github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= +github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= -github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ= -github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/lestrrat-go/strftime v1.1.0 h1:gMESpZy44/4pXLO/m+sL0yBd1W6LjgjrrD4a68Gapyg= +github.com/lestrrat-go/strftime v1.1.0/go.mod h1:uzeIB52CeUJenCo1syghlugshMysrqUT51HlxphXVeI= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= -github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM= -github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= -github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= -github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= +github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= +github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNGuyA= +github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/scottleedavis/go-exif-remove v0.0.0-20230314195146-7e059d593405 h1:2ieGkj4z/YPXVyQ2ayZUg3GwE1pYWd5f1RB6DzAOXKM= github.com/scottleedavis/go-exif-remove v0.0.0-20230314195146-7e059d593405/go.mod h1:rIxVzVLKlBwLxO+lC+k/I4HJfRQcemg/f/76Xmmzsec= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f h1:9f2Bjf6bdMvNyUop32wAGJCdp+Jdm/d6nKBYvFvkRo0= github.com/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f/go.mod h1:5lNp5REd8QMThmBUvR3Fi9Y3AsOB4GRq7soCB4QLqOs= github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20230822083413-c0075a2d401f h1:1KHe0uN6p798E7XJZPhZkgm/hXk5CTjisCvFMqaZSKI= github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20230822083413-c0075a2d401f/go.mod h1:rmf1TCwz67dyM+AmTwSd1BxTo2AOYHj262lP93bOZbs= -github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20221018072427-a15dd1434e05 h1:BlqTgc3/MYKG6vMI2MI+6o+7P4Gy5PXlawu185wPXAk= -github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20221018072427-a15dd1434e05/go.mod h1:prPjFam7MyZ5b3S9dcDOt2tMPz6kf7C9c243s9zSwPY= -github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230516093754-b76aef1c1150 h1:OEuW1D7RGDE0CZDr0oGMw9Eiq7fAbD9C4WMrvSixamk= -github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230516093754-b76aef1c1150/go.mod h1:7QcRmnV7OYq4hNOOCWXT5HXnN/u756JUsqIW0Bw8n9E= -github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20221018072427-a15dd1434e05 h1:jcGZU2juv0L3eFEkuZYV14ESLUlWfGMWnP0mjOfrSZc= -github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20221018072427-a15dd1434e05/go.mod h1:L4GqtXLoR73obTYqUQIzfkm8NG8pvZafxFb6KZFSSHk= -github.com/segmentfault/pacman/contrib/server/http v0.0.0-20221018072427-a15dd1434e05 h1:91is1nKNbfTOl8CvMYiFgg4c5Vmol+5mVmMV/jDXD+A= -github.com/segmentfault/pacman/contrib/server/http v0.0.0-20221018072427-a15dd1434e05/go.mod h1:UjNiOFYv1uGCq1ZCcONaKq4eE7MW3nbgpLqgl8f9N40= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20230822083413-c0075a2d401f h1:/nA4C3UfWw+3XYVBkgVMY1p3nX3uhl22hL2LW3FNcVs= +github.com/segmentfault/pacman/contrib/conf/viper v0.0.0-20230822083413-c0075a2d401f/go.mod h1:prPjFam7MyZ5b3S9dcDOt2tMPz6kf7C9c243s9zSwPY= +github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230822083413-c0075a2d401f h1:xia6AXJor4UV4T6htmHlfN7CGXZ04vlWwybVtFKJ/mA= +github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230822083413-c0075a2d401f/go.mod h1:7QcRmnV7OYq4hNOOCWXT5HXnN/u756JUsqIW0Bw8n9E= +github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20230822083413-c0075a2d401f h1:0mrzVRrQ+mz5MWQSdC1y6dwKWiewYKkpRDqNf3nOhmk= +github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20230822083413-c0075a2d401f/go.mod h1:L4GqtXLoR73obTYqUQIzfkm8NG8pvZafxFb6KZFSSHk= +github.com/segmentfault/pacman/contrib/server/http v0.0.0-20230822083413-c0075a2d401f h1:2gjiRmSj3J/F3A1A22UU1BzO4gQypEZx/4D7c7Ue4Ag= +github.com/segmentfault/pacman/contrib/server/http v0.0.0-20230822083413-c0075a2d401f/go.mod h1:UjNiOFYv1uGCq1ZCcONaKq4eE7MW3nbgpLqgl8f9N40= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= -github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= -github.com/swaggo/files v1.0.0 h1:1gGXVIeUFCS/dta17rnP0iOpr6CXFwKD7EO5ID233e4= -github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO13kc= -github.com/swaggo/gin-swagger v1.5.3 h1:8mWmHLolIbrhJJTflsaFoZzRBYVmEE7JZGIq08EiC0Q= -github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89Yp4uA50HpI= -github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -719,619 +345,150 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -gitlab.com/cznic/cc/v3 v3.40.0 h1:3yn6qVCeHjTSJio35QIhNsD5POKm7ETHXS54yKqzDEo= -gitlab.com/cznic/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= -go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= +golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= -golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw= +golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60= -modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw= -modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI= -modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag= -modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw= -modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ= -modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c= -modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo= -modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg= -modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I= -modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs= -modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8= -modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE= -modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk= -modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w= -modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE= -modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8= -modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc= -modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU= -modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE= -modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk= -modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI= -modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE= -modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg= -modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74= -modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU= -modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU= -modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc= -modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM= -modernc.org/ccgo/v3 v3.12.65/go.mod h1:D6hQtKxPNZiY6wDBtehSGKFKmyXn53F8nGTpH+POmS4= -modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ= -modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84= -modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ= -modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY= -modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w= -modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= -modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= -modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= -modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= -modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q= -modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg= -modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M= -modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU= -modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE= -modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso= -modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8= -modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8= -modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I= -modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk= -modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY= -modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE= -modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg= -modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM= -modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg= -modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo= -modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8= -modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ= -modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA= -modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM= -modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg= -modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE= -modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM= -modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU= -modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw= -modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M= -modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18= -modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8= -modernc.org/libc v1.11.70/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw= -modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw= -modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0= -modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI= -modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE= -modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY= -modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= -modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= -modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc= -modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8= -modernc.org/sqlite v1.24.0 h1:EsClRIWHGhLTCX44p+Ri/JLD+vFGo0QGjasg2/F9TlI= -modernc.org/sqlite v1.24.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY= -modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= -modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY= -modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= -xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM= -xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/xorm v1.3.2 h1:uTRRKF2jYzbZ5nsofXVUx6ncMaek+SHjWYtCXyZo1oM= -xorm.io/xorm v1.3.2/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M= +modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk= +modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo= +xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= +xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU= +xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw= diff --git a/internal/service/content/user_service.go b/internal/service/content/user_service.go index 7a839b5d..e4d3f236 100644 --- a/internal/service/content/user_service.go +++ b/internal/service/content/user_service.go @@ -24,6 +24,7 @@ import ( "encoding/json" "fmt" "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/incubator-answer/pkg/token" "time" "github.com/apache/incubator-answer/internal/base/constant" @@ -46,7 +47,6 @@ import ( "github.com/apache/incubator-answer/internal/service/user_external_login" "github.com/apache/incubator-answer/pkg/checker" "github.com/apache/incubator-answer/plugin" - "github.com/google/uuid" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "golang.org/x/crypto/bcrypt" @@ -225,7 +225,7 @@ func (us *UserService) RetrievePassWord(ctx context.Context, req *schema.UserRet Email: req.Email, UserID: userInfo.ID, } - code := uuid.NewString() + code := token.GenerateToken() verifyEmailURL := fmt.Sprintf("%s/users/password-reset?code=%s", us.getSiteUrl(ctx), code) title, body, err := us.emailService.PassResetTemplate(ctx, verifyEmailURL) if err != nil { @@ -452,7 +452,7 @@ func (us *UserService) UserRegisterByEmail(ctx context.Context, registerUserInfo Email: registerUserInfo.Email, UserID: userInfo.ID, } - code := uuid.NewString() + code := token.GenerateToken() verifyEmailURL := fmt.Sprintf("%s/users/account-activation?code=%s", us.getSiteUrl(ctx), code) title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailURL) if err != nil { @@ -502,7 +502,7 @@ func (us *UserService) UserVerifyEmailSend(ctx context.Context, userID string) e Email: userInfo.EMail, UserID: userInfo.ID, } - code := uuid.NewString() + code := token.GenerateToken() verifyEmailURL := fmt.Sprintf("%s/users/account-activation?code=%s", us.getSiteUrl(ctx), code) title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailURL) if err != nil { @@ -617,7 +617,7 @@ func (us *UserService) UserChangeEmailSendCode(ctx context.Context, req *schema. Email: req.Email, UserID: req.UserID, } - code := uuid.NewString() + code := token.GenerateToken() var title, body string verifyEmailURL := fmt.Sprintf("%s/users/confirm-new-email?code=%s", us.getSiteUrl(ctx), code) if userInfo.MailStatus == entity.EmailStatusToBeVerified { diff --git a/internal/service/user_admin/user_backyard.go b/internal/service/user_admin/user_backyard.go index dfee9bcb..52c0d630 100644 --- a/internal/service/user_admin/user_backyard.go +++ b/internal/service/user_admin/user_backyard.go @@ -30,7 +30,7 @@ import ( "github.com/apache/incubator-answer/internal/service/comment_common" "github.com/apache/incubator-answer/internal/service/export" questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/google/uuid" + "github.com/apache/incubator-answer/pkg/token" "net/mail" "strings" "time" @@ -531,7 +531,7 @@ func (us *UserAdminService) GetUserActivation(ctx context.Context, req *schema.G Email: userInfo.EMail, UserID: userInfo.ID, } - code := uuid.NewString() + code := token.GenerateToken() us.emailService.SaveCode(ctx, userInfo.ID, code, data.ToJSONString()) resp = &schema.GetUserActivationResp{ ActivationURL: fmt.Sprintf("%s/users/account-activation?code=%s", general.SiteUrl, code), @@ -558,8 +558,7 @@ func (us *UserAdminService) SendUserActivation(ctx context.Context, req *schema. Email: userInfo.EMail, UserID: userInfo.ID, } - code := uuid.NewString() - + code := token.GenerateToken() verifyEmailURL := fmt.Sprintf("%s/users/account-activation?code=%s", general.SiteUrl, code) title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailURL) if err != nil { diff --git a/internal/service/user_external_login/user_external_login_service.go b/internal/service/user_external_login/user_external_login_service.go index 3b70a535..e0afbd37 100644 --- a/internal/service/user_external_login/user_external_login_service.go +++ b/internal/service/user_external_login/user_external_login_service.go @@ -40,7 +40,6 @@ import ( "github.com/apache/incubator-answer/pkg/random" "github.com/apache/incubator-answer/pkg/token" "github.com/apache/incubator-answer/plugin" - "github.com/google/uuid" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) @@ -322,7 +321,7 @@ func (us *UserExternalLoginService) ExternalLoginBindingUserSendEmail( UserID: userInfo.ID, BindingKey: req.BindingKey, } - code := uuid.NewString() + code := token.GenerateToken() verifyEmailURL := fmt.Sprintf("%s/users/account-activation?code=%s", siteGeneral.SiteUrl, code) title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailURL) if err != nil { diff --git a/pkg/htmltext/htmltext.go b/pkg/htmltext/htmltext.go index 26afedf7..a72f9b5c 100644 --- a/pkg/htmltext/htmltext.go +++ b/pkg/htmltext/htmltext.go @@ -35,21 +35,6 @@ import ( "github.com/apache/incubator-answer/pkg/converter" ) -// min() and max() can be removed starting from Go1.21 -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - // ClearText clear HTML, get the clear text func ClearText(html string) (text string) { if len(html) == 0 { diff --git a/pkg/token/token.go b/pkg/token/token.go index 507ae9cf..f783a10d 100644 --- a/pkg/token/token.go +++ b/pkg/token/token.go @@ -23,6 +23,6 @@ import "github.com/google/uuid" // GenerateToken generate token func GenerateToken() string { - uid, _ := uuid.NewUUID() + uid, _ := uuid.NewV7() return uid.String() } From cfbe458e9af2bd6d2f48ba9e332d8ab43f327e62 Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 23 Sep 2024 16:59:14 +0800 Subject: [PATCH 210/336] fix: update axios to latest version,fix github security CVE-2024-28849 --- ui/package.json | 2 +- ui/pnpm-lock.yaml | 432 ++++++++++++++++++++++++---------------- ui/src/utils/request.ts | 15 +- 3 files changed, 269 insertions(+), 180 deletions(-) diff --git a/ui/package.json b/ui/package.json index 2344125d..cfbe04c0 100644 --- a/ui/package.json +++ b/ui/package.json @@ -20,7 +20,7 @@ "@codemirror/language-data": "^6.5.0", "@codemirror/state": "^6.4.1", "@codemirror/view": "^6.26.1", - "axios": "^0.28.1", + "axios": "^1.7.7", "bootstrap": "^5.3.2", "bootstrap-icons": "^1.10.5", "classnames": "^2.3.1", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index 0fd9c0f1..32ce67e7 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^6.26.1 version: 6.26.3 axios: - specifier: ^0.28.1 - version: 0.28.1 + specifier: ^1.7.7 + version: 1.7.7 bootstrap: specifier: ^5.3.2 version: 5.3.2(@popperjs/core@2.11.8) @@ -209,13 +209,13 @@ importers: version: 3.1.0 purgecss-webpack-plugin: specifier: ^4.1.3 - version: 4.1.3(webpack@5.89.0) + version: 4.1.3(webpack@5.94.0) react-app-rewired: specifier: ^2.2.1 version: 2.2.1(react-scripts@5.0.1) react-scripts: specifier: 5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5) + version: 5.0.1(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5) sass: specifier: ^1.54.4 version: 1.54.9 @@ -259,6 +259,13 @@ packages: dependencies: '@babel/highlight': 7.18.6 + /@babel/code-frame@7.24.7: + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.1.0 + /@babel/compat-data@7.19.1: resolution: {integrity: sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==} engines: {node: '>=6.9.0'} @@ -306,17 +313,26 @@ packages: '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 + /@babel/generator@7.25.6: + resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + /@babel/helper-annotate-as-pure@7.18.6: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.19.0 - /@babel/helper-annotate-as-pure@7.22.5: - resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + /@babel/helper-annotate-as-pure@7.24.7: + resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.25.6 /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==} @@ -414,11 +430,14 @@ packages: dependencies: '@babel/types': 7.19.0 - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + /@babel/helper-module-imports@7.24.7: + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color /@babel/helper-module-transforms@7.19.0: resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==} @@ -445,8 +464,8 @@ packages: resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==} engines: {node: '>=6.9.0'} - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + /@babel/helper-plugin-utils@7.24.8: + resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} engines: {node: '>=6.9.0'} /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.19.1): @@ -497,16 +516,16 @@ packages: resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} engines: {node: '>=6.9.0'} - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + /@babel/helper-string-parser@7.24.8: + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + /@babel/helper-validator-identifier@7.24.7: + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} /@babel/helper-validator-option@7.18.6: @@ -542,6 +561,15 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 + /@babel/highlight@7.24.7: + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.0 + /@babel/parser@7.19.1: resolution: {integrity: sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==} engines: {node: '>=6.0.0'} @@ -549,6 +577,13 @@ packages: dependencies: '@babel/types': 7.19.0 + /@babel/parser@7.25.6: + resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.25.6 + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.19.1): resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} engines: {node: '>=6.9.0'} @@ -820,14 +855,14 @@ packages: '@babel/core': 7.19.1 '@babel/helper-plugin-utils': 7.19.0 - /@babel/plugin-syntax-flow@7.23.3(@babel/core@7.19.1): - resolution: {integrity: sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==} + /@babel/plugin-syntax-flow@7.24.7(@babel/core@7.19.1): + resolution: {integrity: sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.19.1 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.24.8 /@babel/plugin-syntax-import-assertions@7.18.6(@babel/core@7.19.1): resolution: {integrity: sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==} @@ -863,14 +898,14 @@ packages: '@babel/core': 7.19.1 '@babel/helper-plugin-utils': 7.19.0 - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.19.1): - resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + /@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.19.1): + resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.19.1 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.24.8 /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.19.1): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} @@ -1244,18 +1279,20 @@ packages: '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.19.1) '@babel/types': 7.19.0 - /@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.19.1): - resolution: {integrity: sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==} + /@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.19.1): + resolution: {integrity: sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.19.1 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.19.1) - '@babel/types': 7.23.6 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.19.1) + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color /@babel/plugin-transform-react-pure-annotations@7.18.6(@babel/core@7.19.1): resolution: {integrity: sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==} @@ -1530,6 +1567,14 @@ packages: '@babel/parser': 7.19.1 '@babel/types': 7.19.0 + /@babel/template@7.25.0: + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 + /@babel/traverse@7.19.1: resolution: {integrity: sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==} engines: {node: '>=6.9.0'} @@ -1547,6 +1592,20 @@ packages: transitivePeerDependencies: - supports-color + /@babel/traverse@7.25.6: + resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + /@babel/types@7.19.0: resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==} engines: {node: '>=6.9.0'} @@ -1555,12 +1614,12 @@ packages: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - /@babel/types@7.23.6: - resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} + /@babel/types@7.25.6: + resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 /@bcoe/v8-coverage@0.2.3: @@ -2505,39 +2564,41 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.17 - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/set-array': 1.1.2 + '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.22 - dev: true + '@jridgewell/trace-mapping': 0.3.25 /@jridgewell/resolve-uri@3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + /@jridgewell/source-map@0.3.2: resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==} dependencies: '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 - /@jridgewell/source-map@0.3.5: - resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} + /@jridgewell/source-map@0.3.6: + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 dev: true /@jridgewell/sourcemap-codec@1.4.14: @@ -2548,7 +2609,6 @@ packages: /@jridgewell/sourcemap-codec@1.5.0: resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - dev: true /@jridgewell/trace-mapping@0.3.15: resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} @@ -2562,12 +2622,11 @@ packages: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 - /@jridgewell/trace-mapping@0.3.22: - resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: - '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - dev: true /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -3153,26 +3212,12 @@ packages: '@types/eslint': 8.4.6 '@types/estree': 1.0.5 - /@types/eslint-scope@3.7.7: - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - dependencies: - '@types/eslint': 8.56.2 - '@types/estree': 1.0.5 - dev: true - /@types/eslint@8.4.6: resolution: {integrity: sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==} dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 - /@types/eslint@8.56.2: - resolution: {integrity: sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==} - dependencies: - '@types/estree': 1.0.5 - '@types/json-schema': 7.0.15 - dev: true - /@types/estree@0.0.39: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} @@ -3182,6 +3227,10 @@ packages: /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + dev: true + /@types/express-serve-static-core@4.17.31: resolution: {integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==} dependencies: @@ -3641,8 +3690,8 @@ packages: '@webassemblyjs/helper-numbers': 1.11.1 '@webassemblyjs/helper-wasm-bytecode': 1.11.1 - /@webassemblyjs/ast@1.11.6: - resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==} + /@webassemblyjs/ast@1.12.1: + resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} dependencies: '@webassemblyjs/helper-numbers': 1.11.6 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 @@ -3665,8 +3714,8 @@ packages: /@webassemblyjs/helper-buffer@1.11.1: resolution: {integrity: sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==} - /@webassemblyjs/helper-buffer@1.11.6: - resolution: {integrity: sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==} + /@webassemblyjs/helper-buffer@1.12.1: + resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} dev: true /@webassemblyjs/helper-numbers@1.11.1: @@ -3699,13 +3748,13 @@ packages: '@webassemblyjs/helper-wasm-bytecode': 1.11.1 '@webassemblyjs/wasm-gen': 1.11.1 - /@webassemblyjs/helper-wasm-section@1.11.6: - resolution: {integrity: sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==} + /@webassemblyjs/helper-wasm-section@1.12.1: + resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} dependencies: - '@webassemblyjs/ast': 1.11.6 - '@webassemblyjs/helper-buffer': 1.11.6 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - '@webassemblyjs/wasm-gen': 1.11.6 + '@webassemblyjs/wasm-gen': 1.12.1 dev: true /@webassemblyjs/ieee754@1.11.1: @@ -3749,17 +3798,17 @@ packages: '@webassemblyjs/wasm-parser': 1.11.1 '@webassemblyjs/wast-printer': 1.11.1 - /@webassemblyjs/wasm-edit@1.11.6: - resolution: {integrity: sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==} + /@webassemblyjs/wasm-edit@1.12.1: + resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} dependencies: - '@webassemblyjs/ast': 1.11.6 - '@webassemblyjs/helper-buffer': 1.11.6 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - '@webassemblyjs/helper-wasm-section': 1.11.6 - '@webassemblyjs/wasm-gen': 1.11.6 - '@webassemblyjs/wasm-opt': 1.11.6 - '@webassemblyjs/wasm-parser': 1.11.6 - '@webassemblyjs/wast-printer': 1.11.6 + '@webassemblyjs/helper-wasm-section': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-opt': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/wast-printer': 1.12.1 dev: true /@webassemblyjs/wasm-gen@1.11.1: @@ -3771,10 +3820,10 @@ packages: '@webassemblyjs/leb128': 1.11.1 '@webassemblyjs/utf8': 1.11.1 - /@webassemblyjs/wasm-gen@1.11.6: - resolution: {integrity: sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==} + /@webassemblyjs/wasm-gen@1.12.1: + resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} dependencies: - '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 '@webassemblyjs/ieee754': 1.11.6 '@webassemblyjs/leb128': 1.11.6 @@ -3789,13 +3838,13 @@ packages: '@webassemblyjs/wasm-gen': 1.11.1 '@webassemblyjs/wasm-parser': 1.11.1 - /@webassemblyjs/wasm-opt@1.11.6: - resolution: {integrity: sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==} + /@webassemblyjs/wasm-opt@1.12.1: + resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} dependencies: - '@webassemblyjs/ast': 1.11.6 - '@webassemblyjs/helper-buffer': 1.11.6 - '@webassemblyjs/wasm-gen': 1.11.6 - '@webassemblyjs/wasm-parser': 1.11.6 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 dev: true /@webassemblyjs/wasm-parser@1.11.1: @@ -3808,10 +3857,10 @@ packages: '@webassemblyjs/leb128': 1.11.1 '@webassemblyjs/utf8': 1.11.1 - /@webassemblyjs/wasm-parser@1.11.6: - resolution: {integrity: sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==} + /@webassemblyjs/wasm-parser@1.12.1: + resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} dependencies: - '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/helper-api-error': 1.11.6 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 '@webassemblyjs/ieee754': 1.11.6 @@ -3825,10 +3874,10 @@ packages: '@webassemblyjs/ast': 1.11.1 '@xtuc/long': 4.2.2 - /@webassemblyjs/wast-printer@1.11.6: - resolution: {integrity: sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==} + /@webassemblyjs/wast-printer@1.12.1: + resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} dependencies: - '@webassemblyjs/ast': 1.11.6 + '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 dev: true @@ -3869,12 +3918,12 @@ packages: dependencies: acorn: 8.8.0 - /acorn-import-assertions@1.9.0(acorn@8.11.3): - resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} + /acorn-import-attributes@1.9.5(acorn@8.12.1): + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.11.3 + acorn: 8.12.1 dev: true /acorn-jsx@5.3.2(acorn@8.11.3): @@ -3909,6 +3958,12 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + /acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /acorn@8.8.0: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} engines: {node: '>=0.4.0'} @@ -4210,10 +4265,10 @@ packages: resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} engines: {node: '>=4'} - /axios@0.28.1: - resolution: {integrity: sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==} + /axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} dependencies: - follow-redirects: 1.15.2 + follow-redirects: 1.15.9 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -4495,15 +4550,15 @@ packages: node-releases: 2.0.6 update-browserslist-db: 1.0.9(browserslist@4.21.4) - /browserslist@4.22.2: - resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} + /browserslist@4.23.3: + resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001579 - electron-to-chromium: 1.4.640 - node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.22.2) + caniuse-lite: 1.0.30001663 + electron-to-chromium: 1.5.27 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.23.3) dev: true /bser@2.1.1: @@ -4600,8 +4655,8 @@ packages: /caniuse-lite@1.0.30001408: resolution: {integrity: sha512-DdUCktgMSM+1ndk9EFMZcavsGszV7zxV9O7MtOHniTa/iyAIwJCF0dFVBdU9SijJbfh29hC9bCs07wu8pjnGJQ==} - /caniuse-lite@1.0.30001579: - resolution: {integrity: sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==} + /caniuse-lite@1.0.30001663: + resolution: {integrity: sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==} dev: true /case-sensitive-paths-webpack-plugin@2.4.0: @@ -4657,6 +4712,11 @@ packages: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} engines: {node: '>=6.0'} + /chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + dev: true + /ci-info@3.4.0: resolution: {integrity: sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==} @@ -4817,7 +4877,7 @@ packages: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} dependencies: - mime-db: 1.52.0 + mime-db: 1.53.0 /compression@1.7.4: resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} @@ -5252,6 +5312,17 @@ packages: dependencies: ms: 2.1.2 + /debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + /decamelize-keys@1.1.0: resolution: {integrity: sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==} engines: {node: '>=0.10.0'} @@ -5542,8 +5613,8 @@ packages: /electron-to-chromium@1.4.256: resolution: {integrity: sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==} - /electron-to-chromium@1.4.640: - resolution: {integrity: sha512-z/6oZ/Muqk4BaE7P69bXhUhpJbUM9ZJeka43ZwxsDshKtePns4mhBlh8bU5+yrnOnz3fhG82XLzGUXazOmsWnA==} + /electron-to-chromium@1.5.27: + resolution: {integrity: sha512-o37j1vZqCoEgBuWWXLHQgTN/KDKe7zwpiY5CPeq2RvUqOyJw9xnrULzZAEVQ5p4h+zjMk7hgtOoPdnLxr7m/jw==} dev: true /emittery@0.10.2: @@ -5576,11 +5647,11 @@ packages: resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==} engines: {node: '>=10.13.0'} dependencies: - graceful-fs: 4.2.11 + graceful-fs: 4.2.10 tapable: 2.2.1 - /enhanced-resolve@5.15.0: - resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + /enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 @@ -5696,8 +5767,8 @@ packages: /es-module-lexer@0.9.3: resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} - /es-module-lexer@1.4.1: - resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} + /es-module-lexer@1.5.4: + resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} dev: true /es-set-tostringtag@2.0.2: @@ -5725,6 +5796,11 @@ packages: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + dev: true + /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -5811,7 +5887,7 @@ packages: eslint: 8.53.0 dev: true - /eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0)(jest@27.5.1)(typescript@4.9.5): + /eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0)(jest@27.5.1)(typescript@4.9.5): resolution: {integrity: sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -5829,7 +5905,7 @@ packages: babel-preset-react-app: 10.0.1 confusing-browser-globals: 1.0.11 eslint: 8.53.0 - eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0) + eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0) eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.38.0)(eslint@8.53.0) eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.38.0)(eslint@8.53.0)(jest@27.5.1)(typescript@4.9.5) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.53.0) @@ -5958,7 +6034,7 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0): + /eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0): resolution: {integrity: sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -5966,8 +6042,8 @@ packages: '@babel/plugin-transform-react-jsx': ^7.14.9 eslint: ^8.1.0 dependencies: - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.19.1) - '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.19.1) + '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.19.1) + '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.19.1) eslint: 8.53.0 lodash: 4.17.21 string-natural-compare: 3.0.1 @@ -6540,8 +6616,8 @@ packages: /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - /follow-redirects@1.15.2: - resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + /follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -7012,7 +7088,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.2 + follow-redirects: 1.15.9 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -8100,7 +8176,7 @@ packages: dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.11 + graceful-fs: 4.2.10 /jsonp@0.2.1: resolution: {integrity: sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==} @@ -8406,6 +8482,10 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + /mime-db@1.53.0: + resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==} + engines: {node: '>= 0.6'} + /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -8519,7 +8599,7 @@ packages: jsonp: 0.2.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5) + react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5) transitivePeerDependencies: - supports-color dev: false @@ -8537,8 +8617,8 @@ packages: /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + /node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} dev: true /node-releases@2.0.6: @@ -8878,9 +8958,8 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - /picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - dev: true + /picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -9727,13 +9806,13 @@ packages: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} - /purgecss-webpack-plugin@4.1.3(webpack@5.89.0): + /purgecss-webpack-plugin@4.1.3(webpack@5.94.0): resolution: {integrity: sha512-1OHS0WE935w66FjaFSlV06ycmn3/A8a6Q+iVUmmCYAujQ1HPdX+psMXUhASEW0uF1PYEpOlhMc5ApigVqYK08g==} peerDependencies: webpack: '*' dependencies: purgecss: 4.1.3 - webpack: 5.89.0 + webpack: 5.94.0 webpack-sources: 3.2.3 dev: true @@ -9830,7 +9909,7 @@ packages: peerDependencies: react-scripts: '>=2.1.3' dependencies: - react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5) + react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5) semver: 5.7.1 dev: true @@ -9993,7 +10072,7 @@ packages: react: 18.2.0 dev: false - /react-scripts@5.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5): + /react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0)(react@18.2.0)(sass@1.54.9)(ts-node@10.9.1)(typescript@4.9.5): resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==} engines: {node: '>=14.0.0'} hasBin: true @@ -10021,7 +10100,7 @@ packages: dotenv: 10.0.0 dotenv-expand: 5.1.0 eslint: 8.53.0 - eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.53.0)(jest@27.5.1)(typescript@4.9.5) + eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.24.7)(@babel/plugin-transform-react-jsx@7.25.2)(eslint@8.53.0)(jest@27.5.1)(typescript@4.9.5) eslint-webpack-plugin: 3.2.0(eslint@8.53.0)(webpack@5.74.0) file-loader: 6.2.0(webpack@5.74.0) fs-extra: 10.1.0 @@ -11196,7 +11275,7 @@ packages: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - /terser-webpack-plugin@5.3.10(webpack@5.89.0): + /terser-webpack-plugin@5.3.10(webpack@5.94.0): resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -11212,12 +11291,12 @@ packages: uglify-js: optional: true dependencies: - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 - terser: 5.27.0 - webpack: 5.89.0 + terser: 5.33.0 + webpack: 5.94.0 dev: true /terser-webpack-plugin@5.3.6(webpack@5.74.0): @@ -11253,13 +11332,13 @@ packages: commander: 2.20.3 source-map-support: 0.5.21 - /terser@5.27.0: - resolution: {integrity: sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==} + /terser@5.33.0: + resolution: {integrity: sha512-JuPVaB7s1gdFKPKTelwUyRq5Sid2A3Gko2S0PncwdBq7kN9Ti9HPWDQ06MPsEDGsZeVESjKEnyGy68quBk1w6g==} engines: {node: '>=10'} hasBin: true dependencies: - '@jridgewell/source-map': 0.3.5 - acorn: 8.11.3 + '@jridgewell/source-map': 0.3.6 + acorn: 8.12.1 commander: 2.20.3 source-map-support: 0.5.21 dev: true @@ -11588,17 +11667,6 @@ packages: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} - /update-browserslist-db@1.0.13(browserslist@4.22.2): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.22.2 - escalade: 3.1.1 - picocolors: 1.0.1 - dev: true - /update-browserslist-db@1.0.9(browserslist@4.21.4): resolution: {integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==} hasBin: true @@ -11609,6 +11677,17 @@ packages: escalade: 3.1.1 picocolors: 1.0.0 + /update-browserslist-db@1.1.0(browserslist@4.23.3): + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.3 + escalade: 3.2.0 + picocolors: 1.1.0 + dev: true + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -11711,9 +11790,17 @@ packages: /watchpack@2.4.0: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.10 + + /watchpack@2.4.2: + resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} + engines: {node: '>=10.13.0'} dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + dev: true /wbuf@1.7.3: resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} @@ -11857,8 +11944,8 @@ packages: - esbuild - uglify-js - /webpack@5.89.0: - resolution: {integrity: sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==} + /webpack@5.94.0: + resolution: {integrity: sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -11867,17 +11954,16 @@ packages: webpack-cli: optional: true dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.5 - '@webassemblyjs/ast': 1.11.6 - '@webassemblyjs/wasm-edit': 1.11.6 - '@webassemblyjs/wasm-parser': 1.11.6 - acorn: 8.11.3 - acorn-import-assertions: 1.9.0(acorn@8.11.3) - browserslist: 4.22.2 - chrome-trace-event: 1.0.3 - enhanced-resolve: 5.15.0 - es-module-lexer: 1.4.1 + '@types/estree': 1.0.6 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + acorn: 8.12.1 + acorn-import-attributes: 1.9.5(acorn@8.12.1) + browserslist: 4.23.3 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.17.1 + es-module-lexer: 1.5.4 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -11888,8 +11974,8 @@ packages: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.89.0) - watchpack: 2.4.0 + terser-webpack-plugin: 5.3.10(webpack@5.94.0) + watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: - '@swc/core' diff --git a/ui/src/utils/request.ts b/ui/src/utils/request.ts index c4070957..f4dd97af 100644 --- a/ui/src/utils/request.ts +++ b/ui/src/utils/request.ts @@ -18,7 +18,12 @@ */ import axios, { AxiosResponse } from 'axios'; -import type { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios'; +import type { + AxiosInstance, + AxiosRequestConfig, + InternalAxiosRequestConfig, + AxiosError, +} from 'axios'; import { Modal } from '@/components'; import { loggedUserInfoStore, toastStore, errorCodeStore } from '@/stores'; @@ -51,13 +56,11 @@ class Request { constructor(config: AxiosRequestConfig) { this.instance = axios.create(config); this.instance.interceptors.request.use( - (requestConfig: AxiosRequestConfig) => { + (requestConfig: InternalAxiosRequestConfig) => { const token = Storage.get(LOGGED_TOKEN_STORAGE_KEY) || ''; const lang = getCurrentLang(); - requestConfig.headers = { - Authorization: token, - 'Accept-Language': lang, - }; + requestConfig.headers.set('Authorization', token); + requestConfig.headers.set('Accept-Language', lang); return requestConfig; }, (err: AxiosError) => { From 7ff803890725fdd68b82b9f20d924ae5eea9071d Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 24 Sep 2024 10:30:13 +0800 Subject: [PATCH 211/336] fix: badge modal set zindex attribute --- ui/src/components/Modal/BadgeModal.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index 303c9677..c0cf4cc3 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -72,7 +72,10 @@ const BadgeModal: FC = ({ badge, visible }) => { const bgNode = document.documentElement || document.body; if (visible) { - const paranetNode = document.getElementById('badgeModal')?.parentNode; + const badgeModalNode = document.getElementById('badgeModal'); + const paranetNode = badgeModalNode?.parentNode; + + badgeModalNode?.setAttribute('style', 'z-index: 1'); bg1 = new AnimateGift({ elm: paranetNode, From 88dabcc4e1b57614a356d1e905ddb56cfb11d582 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 25 Sep 2024 11:12:20 +0800 Subject: [PATCH 212/336] fix: badges allow 404 --- ui/src/services/client/badges.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ui/src/services/client/badges.ts b/ui/src/services/client/badges.ts index 7f3f8abd..e1617aab 100644 --- a/ui/src/services/client/badges.ts +++ b/ui/src/services/client/badges.ts @@ -40,7 +40,10 @@ export const useGetAllBadges = () => { export const useGetBadgeInfo = (id: string) => { const { data, error, mutate } = useSWR( `/answer/api/v1/badge?id=${id}`, - request.instance.get, + (url) => + request.get(url, { + allow404: true, + }), ); return { data, @@ -51,12 +54,17 @@ export const useGetBadgeInfo = (id: string) => { }; export const useBadgeDetailList = (params: Type.BadgeDetailListReq) => { + if (!params.badge_id) return { data: null, isLoading: false, error: null }; const { data, error, mutate } = useSWR( `/answer/api/v1/badge/awards/page?${qs.stringify(params, { skipNulls: true, })}`, - request.instance.get, + (url) => + request.get(url, { + allow404: true, + }), ); + return { data, isLoading: !data && !error, From 3cf4cd62f83993717f807f1b16f34e343f698ef9 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 25 Sep 2024 12:15:16 +0800 Subject: [PATCH 213/336] fix: badge detail params change --- ui/src/pages/Badges/Detail/index.tsx | 2 +- ui/src/services/client/badges.ts | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ui/src/pages/Badges/Detail/index.tsx b/ui/src/pages/Badges/Detail/index.tsx index c5713e2b..b5daccaa 100644 --- a/ui/src/pages/Badges/Detail/index.tsx +++ b/ui/src/pages/Badges/Detail/index.tsx @@ -44,7 +44,7 @@ const Index = () => { const { data: badgeInfo, isLoading: isHeaderLoading } = useGetBadgeInfo(badge_id); const { data: badges, isLoading: isDetailLoading } = useBadgeDetailList({ - badge_id, + badge_id: badgeInfo?.id || '', page, page_size: pageSize, username: urlSearchParams.get('username') || null, diff --git a/ui/src/services/client/badges.ts b/ui/src/services/client/badges.ts index e1617aab..bc5c97bd 100644 --- a/ui/src/services/client/badges.ts +++ b/ui/src/services/client/badges.ts @@ -54,11 +54,13 @@ export const useGetBadgeInfo = (id: string) => { }; export const useBadgeDetailList = (params: Type.BadgeDetailListReq) => { - if (!params.badge_id) return { data: null, isLoading: false, error: null }; + const path = params.badge_id + ? `/answer/api/v1/badge/awards/page?${qs.stringify(params, { + skipNulls: true, + })}` + : null; const { data, error, mutate } = useSWR( - `/answer/api/v1/badge/awards/page?${qs.stringify(params, { - skipNulls: true, - })}`, + path, (url) => request.get(url, { allow404: true, From 36983898f1720b5ab3605dd1b8b3d8471e76fbb6 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 25 Sep 2024 15:57:09 +0800 Subject: [PATCH 214/336] fix: Personal homepage interface request error --- ui/src/services/client/personal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/services/client/personal.ts b/ui/src/services/client/personal.ts index fbf38938..3ccb0d46 100644 --- a/ui/src/services/client/personal.ts +++ b/ui/src/services/client/personal.ts @@ -96,7 +96,7 @@ export const usePersonalListByTabName = (params: ListReq, tabName: string) => { const queryParams = qs.stringify(params, { skipNulls: true }); const { data, error, mutate } = useSWR( - tabName !== 'review' ? `${apiUrl}?${queryParams}` : null, + tabName !== 'overview' ? `${apiUrl}?${queryParams}` : null, request.instance.get, ); From 106aeab194d92f37633c4ce3485bead8e39753d8 Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 25 Sep 2024 16:32:12 +0800 Subject: [PATCH 215/336] refactor(pluginKit): update useRender hooks to include request parameter --- ui/src/utils/pluginKit/index.ts | 5 +++-- ui/src/utils/pluginKit/interface.ts | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 6d0e9878..12cd0247 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -25,6 +25,7 @@ import type * as Type from '@/common/interface'; import { LOGGED_TOKEN_STORAGE_KEY } from '@/common/constants'; import { getPluginsStatus } from '@/services'; import Storage from '@/utils/storage'; +import request from '@/utils/request'; import { initI18nResource } from './utils'; import { Plugin, PluginInfo, PluginType } from './interface'; @@ -227,7 +228,7 @@ const useRenderHtmlPlugin = ( }) .forEach((plugin) => { plugin.hooks?.useRender?.forEach((hook) => { - hook(element); + hook(element, request); }); }); }; @@ -247,7 +248,7 @@ const useRenderPlugin = ( }) .forEach((plugin) => { plugin.hooks?.useRender?.forEach((hook) => { - hook(element); + hook(element, request); }); }); }; diff --git a/ui/src/utils/pluginKit/interface.ts b/ui/src/utils/pluginKit/interface.ts index 880a524a..d946ed6e 100644 --- a/ui/src/utils/pluginKit/interface.ts +++ b/ui/src/utils/pluginKit/interface.ts @@ -20,6 +20,7 @@ import { NamedExoticComponent, FC, RefObject } from 'react'; import type * as Type from '@/common/interface'; +import Request from '@/utils/request'; export enum PluginType { Connector = 'connector', @@ -44,7 +45,10 @@ export interface Plugin { i18nConfig?; hooks?: { useRender?: Array< - (element: HTMLElement | RefObject | null) => void + ( + element: HTMLElement | RefObject | null, + request?: typeof Request, + ) => void >; useCaptcha?: (props: { captchaKey: Type.CaptchaKey; commonProps: any }) => { getCaptcha: () => Record; From b9064e3eee83015876dc5a248112afd68b244c50 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 25 Sep 2024 17:34:38 +0800 Subject: [PATCH 216/336] fix: set default theme color constance --- ui/src/common/constants.ts | 2 ++ ui/src/components/CustomizeTheme/index.tsx | 5 ++++- ui/src/pages/Admin/Themes/index.tsx | 5 +++-- ui/src/stores/themeSetting.ts | 3 ++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ui/src/common/constants.ts b/ui/src/common/constants.ts index d52f2b87..303926fb 100644 --- a/ui/src/common/constants.ts +++ b/ui/src/common/constants.ts @@ -650,3 +650,5 @@ export const SYSTEM_AVATAR_OPTIONS = [ ]; export const TAG_SLUG_NAME_MAX_LENGTH = 35; + +export const DEFAULT_THEME_COLOR = '#0033ff'; diff --git a/ui/src/components/CustomizeTheme/index.tsx b/ui/src/components/CustomizeTheme/index.tsx index ff49e550..b142540b 100644 --- a/ui/src/components/CustomizeTheme/index.tsx +++ b/ui/src/components/CustomizeTheme/index.tsx @@ -24,6 +24,7 @@ import Color from 'color'; import { shiftColor, tintColor, shadeColor } from '@/utils'; import { themeSettingStore } from '@/stores'; +import { DEFAULT_THEME_COLOR } from '@/common/constants'; const Index: FC = () => { const { theme, theme_config } = themeSettingStore((_) => _); @@ -34,7 +35,9 @@ const Index: FC = () => { const setThemeColor = () => { const themeMetaNode = document.querySelector('meta[name="theme-color"]'); if (themeMetaNode) { - const themeColor = primaryColor ? primaryColor.hex() : '#0033ff'; + const themeColor = primaryColor + ? primaryColor.hex() + : DEFAULT_THEME_COLOR; themeMetaNode.setAttribute('content', themeColor); } }; diff --git a/ui/src/pages/Admin/Themes/index.tsx b/ui/src/pages/Admin/Themes/index.tsx index 0d219816..b5dc2ebd 100644 --- a/ui/src/pages/Admin/Themes/index.tsx +++ b/ui/src/pages/Admin/Themes/index.tsx @@ -27,6 +27,7 @@ import { useToast } from '@/hooks'; import { handleFormError, scrollToElementTop } from '@/utils'; import { themeSettingStore } from '@/stores'; import { setupAppTheme } from '@/utils/localize'; +import { DEFAULT_THEME_COLOR } from '@/common/constants'; const Index: FC = () => { const { t } = useTranslation('translation', { @@ -67,7 +68,7 @@ const Index: FC = () => { type: 'string', title: t('primary_color.label'), description: t('primary_color.text'), - default: '#0033FF', + default: DEFAULT_THEME_COLOR, }, }, }; @@ -103,7 +104,7 @@ const Index: FC = () => { const resetPrimaryScheme = () => { const formMeta = { ...formData }; - formMeta.primary_color.value = '#0033FF'; + formMeta.primary_color.value = DEFAULT_THEME_COLOR; setFormData({ ...formMeta }); }; diff --git a/ui/src/stores/themeSetting.ts b/ui/src/stores/themeSetting.ts index d0788cc8..dde9c91e 100644 --- a/ui/src/stores/themeSetting.ts +++ b/ui/src/stores/themeSetting.ts @@ -20,6 +20,7 @@ import create from 'zustand'; import { AdminSettingsTheme } from '@/common/interface'; +import { DEFAULT_THEME_COLOR } from '@/common/constants'; interface IType { theme: AdminSettingsTheme['theme']; @@ -36,7 +37,7 @@ const store = create((set) => ({ theme_config: { default: { navbar_style: 'colored', - primary_color: '#0033FF', + primary_color: DEFAULT_THEME_COLOR, }, }, update: (params) => From f8fd872bde03d71dd34af1c779deb82e186738c3 Mon Sep 17 00:00:00 2001 From: shuai Date: Thu, 26 Sep 2024 11:15:52 +0800 Subject: [PATCH 217/336] update: tag styles change --- ui/src/common/color.scss | 30 +++++++--------------- ui/src/components/CustomizeTheme/index.tsx | 24 ----------------- ui/src/index.scss | 27 ++++++++----------- 3 files changed, 19 insertions(+), 62 deletions(-) diff --git a/ui/src/common/color.scss b/ui/src/common/color.scss index 1a96b31d..16a7a297 100644 --- a/ui/src/common/color.scss +++ b/ui/src/common/color.scss @@ -110,31 +110,19 @@ /** tag **/ .badge-tag { - background: rgba($blue-900, 0.5); - color: $blue-300; - &:hover { - color: $blue-300; - background: $blue-900; - } - } - .badge-tag-required { background: $gray-800; - color:$gray-300; - border: 1px solid $gray-600; + color: $gray-300; &:hover { - color: $gray-300; - background: $gray-700; - } - } - .badge-tag-reserved { - color: $orange-300; - background: rgba($orange-900, 0.5); - border: 1px solid $orange-900; - &:hover { - color: $orange-300; - background: rgba($orange-900, 1); + background: $gray-600; } } + .badge-tag-reserved { + color: $orange-200; + background: $orange-800; + &:hover { + background: $orange-700; + } + } } diff --git a/ui/src/components/CustomizeTheme/index.tsx b/ui/src/components/CustomizeTheme/index.tsx index b142540b..46e3dd57 100644 --- a/ui/src/components/CustomizeTheme/index.tsx +++ b/ui/src/components/CustomizeTheme/index.tsx @@ -143,31 +143,7 @@ const Index: FC = () => { .link-primary:hover, .link-primary:focus { color: ${shadeColor(primaryColor, 0.8).hex()}!important; } - .badge-tag:not(.badge-tag-reserved, .badge-tag-required) { - background-color: rgba(${tintColor(primaryColor, 0.2) - .rgb() - .array() - .join(',')}, .5); - color: ${shadeColor(primaryColor, 0.6).hex()} - } - .badge-tag:not(.badge-tag-reserved, .badge-tag-required):hover { - background-color: ${tintColor(primaryColor, 0.2).hex()}; - } - [data-bs-theme="dark"] .badge-tag:not(.badge-tag-reserved):not(.badge-tag-required) { - background-color: rgba(${shadeColor(primaryColor, 0.2) - .rgb() - .array() - .join(',')}, .5) !important; - color: ${tintColor(primaryColor, 0.4).hex()} !important; - } - [data-bs-theme="dark"] .badge-tag:not(.badge-tag-reserved, .badge-tag-required):hover { - background-color: rgba(${tintColor( - primaryColor, - 0.4, - ).hex()}, 0.8) !important; - color: ${tintColor(primaryColor, 0.6).hex()} !important; - } `} )} diff --git a/ui/src/index.scss b/ui/src/index.scss index 6d3ade05..6da6d336 100644 --- a/ui/src/index.scss +++ b/ui/src/index.scss @@ -87,33 +87,26 @@ img[src=""] { .badge-tag { display: inline-block; font-size: 14px; - background: rgba($blue-100, 0.5); + background: $gray-200; padding: 0 7px 1px; - color: $blue-700; + color: $gray-700; + font-weight: 400; border: 1px solid transparent; &:hover { - color: $blue-700; - background: $blue-100; - } -} - -.badge-tag-required { - background: $gray-200; - color: $gray-700; - border: 1px solid $gray-400; - &:hover { - color: $gray-700; background: $gray-300; } } +.badge-tag-required { + font-weight: 700; +} + .badge-tag-reserved { - background: rgba($orange-100, 0.5); + background: $orange-100; color: $orange-700; - border: 1px solid $orange-100; + border: 1px solid transparent; &:hover { - color: $orange-700; - background: rgba($orange-100, 1); + background: $orange-200; } } From e062cbcb0efabede1a71c9e1c881076dc24fc7a6 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 26 Sep 2024 16:25:00 +0800 Subject: [PATCH 218/336] refactor(gomod): replace pinyin dependency --- docs/release/LICENSE | 2 +- ...ang-pinyin.txt => LICENSE-mozillazg-go-pinyin.txt} | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/service/user_common/user.go | 9 ++------- pkg/htmltext/htmltext.go | 11 +++-------- 6 files changed, 11 insertions(+), 21 deletions(-) rename docs/release/licenses/{LICENSE-Chain-Zhang-pinyin.txt => LICENSE-mozillazg-go-pinyin.txt} (95%) diff --git a/docs/release/LICENSE b/docs/release/LICENSE index 26c12b2b..65e5642d 100644 --- a/docs/release/LICENSE +++ b/docs/release/LICENSE @@ -246,7 +246,7 @@ The following components are provided under the MIT License. See project link fo (MIT License) react-router (https://github.com/remix-run/react-router) [link](./licenses/LICENSE-remix-run-react-router.txt) (MIT License) swr (https://github.com/vercel/swr) [link](./licenses/LICENSE-vercel-swr.txt) (MIT License) zustand (https://github.com/pmndrs/zustand) [link](./licenses/LICENSE-pmndrs-zustand.txt) - (MIT License) Chain-Zhang-pinyin (https://github.com/Chain-Zhang/pinyin) [link](./licenses/LICENSE-Chain-Zhang-pinyin.txt) + (MIT License) mozillazg-go-pinyin (https://github.com/mozillazg/go-pinyin) [link](./licenses/LICENSE-mozillazg-go-pinyin.txt) (MIT License) Machiel-slugify (https://github.com/Machiel/slugify) [link](./licenses/LICENSE-Machiel-slugify.txt) (MIT License) Masterminds-semver (https://github.com/Masterminds/semver) [link](./licenses/LICENSE-Masterminds-semver.txt) (MIT License) anargu-gin-brotli (https://github.com/anargu/gin-brotli) [link](./licenses/LICENSE-anargu-gin-brotli.txt) diff --git a/docs/release/licenses/LICENSE-Chain-Zhang-pinyin.txt b/docs/release/licenses/LICENSE-mozillazg-go-pinyin.txt similarity index 95% rename from docs/release/licenses/LICENSE-Chain-Zhang-pinyin.txt rename to docs/release/licenses/LICENSE-mozillazg-go-pinyin.txt index c98d6a49..8a7780fc 100644 --- a/docs/release/licenses/LICENSE-Chain-Zhang-pinyin.txt +++ b/docs/release/licenses/LICENSE-mozillazg-go-pinyin.txt @@ -1,6 +1,6 @@ -MIT License +The MIT License (MIT) -Copyright (c) 2019 Chain Zhang +Copyright (c) 2016 mozillazg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/go.mod b/go.mod index 615b0f73..84689ef9 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,6 @@ module github.com/apache/incubator-answer go 1.22.0 require ( - github.com/Chain-Zhang/pinyin v0.1.3 github.com/Machiel/slugify v1.0.1 github.com/Masterminds/semver/v3 v3.3.0 github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267 @@ -41,6 +40,7 @@ require ( github.com/jinzhu/now v1.1.5 github.com/lib/pq v1.10.9 github.com/microcosm-cc/bluemonday v1.0.27 + github.com/mozillazg/go-pinyin v0.20.0 github.com/ory/dockertest/v3 v3.11.0 github.com/robfig/cron/v3 v3.0.1 github.com/scottleedavis/go-exif-remove v0.0.0-20230314195146-7e059d593405 diff --git a/go.sum b/go.sum index 1a2ab6fc..c8e314f1 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Chain-Zhang/pinyin v0.1.3 h1:RzErNyNwVa8z2sOLCuXSOtVdY/AsARb8mBzI2p2qtnE= -github.com/Chain-Zhang/pinyin v0.1.3/go.mod h1:5iHpt9p4znrnaP59/hfPMnAojajkDxQaP9io+tRMPho= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/LinkinStars/go-i18n/v2 v2.2.2 h1:ZfjpzbW13dv6btv3RALKZkpN9A+7K1JA//2QcNeWaxU= @@ -241,6 +239,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ= +github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/internal/service/user_common/user.go b/internal/service/user_common/user.go index a10c4766..7980044e 100644 --- a/internal/service/user_common/user.go +++ b/internal/service/user_common/user.go @@ -26,7 +26,6 @@ import ( "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/pkg/converter" - "github.com/Chain-Zhang/pinyin" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" @@ -35,6 +34,7 @@ import ( "github.com/apache/incubator-answer/internal/service/siteinfo_common" "github.com/apache/incubator-answer/pkg/checker" "github.com/apache/incubator-answer/pkg/random" + "github.com/mozillazg/go-pinyin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) @@ -181,12 +181,7 @@ func (us *UserCommon) FormatUserBasicInfo(ctx context.Context, userInfo *entity. func (us *UserCommon) MakeUsername(ctx context.Context, displayName string) (username string, err error) { // Chinese processing if has := checker.IsChinese(displayName); has { - str, err := pinyin.New(displayName).Split("").Mode(pinyin.WithoutTone).Convert() - if err != nil { - return "", errors.BadRequest(reason.UsernameInvalid) - } else { - displayName = str - } + displayName = strings.Join(pinyin.LazyConvert(displayName, nil), "") } username = strings.ReplaceAll(displayName, " ", "-") diff --git a/pkg/htmltext/htmltext.go b/pkg/htmltext/htmltext.go index a72f9b5c..77ca2fba 100644 --- a/pkg/htmltext/htmltext.go +++ b/pkg/htmltext/htmltext.go @@ -27,12 +27,11 @@ import ( "strings" "unicode/utf8" - "github.com/Chain-Zhang/pinyin" "github.com/Machiel/slugify" - strip "github.com/grokify/html-strip-tags-go" - "github.com/apache/incubator-answer/pkg/checker" "github.com/apache/incubator-answer/pkg/converter" + strip "github.com/grokify/html-strip-tags-go" + "github.com/mozillazg/go-pinyin" ) // ClearText clear HTML, get the clear text @@ -97,11 +96,7 @@ func convertChinese(content string) string { if !has { return content } - str, err := pinyin.New(content).Split("-").Mode(pinyin.WithoutTone).Convert() - if err != nil { - return content - } - return str + return strings.Join(pinyin.LazyConvert(content, nil), "-") } func cutLongTitle(title string) string { From 6817fafcca55343070f0b677c2692a258eda0796 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 26 Sep 2024 16:25:00 +0800 Subject: [PATCH 219/336] refactor(gomod): replace pinyin dependency --- docs/release/LICENSE | 2 +- ...ang-pinyin.txt => LICENSE-mozillazg-go-pinyin.txt} | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- internal/service/user_common/user.go | 9 ++------- pkg/htmltext/htmltext.go | 11 +++-------- 6 files changed, 11 insertions(+), 21 deletions(-) rename docs/release/licenses/{LICENSE-Chain-Zhang-pinyin.txt => LICENSE-mozillazg-go-pinyin.txt} (95%) diff --git a/docs/release/LICENSE b/docs/release/LICENSE index 26c12b2b..65e5642d 100644 --- a/docs/release/LICENSE +++ b/docs/release/LICENSE @@ -246,7 +246,7 @@ The following components are provided under the MIT License. See project link fo (MIT License) react-router (https://github.com/remix-run/react-router) [link](./licenses/LICENSE-remix-run-react-router.txt) (MIT License) swr (https://github.com/vercel/swr) [link](./licenses/LICENSE-vercel-swr.txt) (MIT License) zustand (https://github.com/pmndrs/zustand) [link](./licenses/LICENSE-pmndrs-zustand.txt) - (MIT License) Chain-Zhang-pinyin (https://github.com/Chain-Zhang/pinyin) [link](./licenses/LICENSE-Chain-Zhang-pinyin.txt) + (MIT License) mozillazg-go-pinyin (https://github.com/mozillazg/go-pinyin) [link](./licenses/LICENSE-mozillazg-go-pinyin.txt) (MIT License) Machiel-slugify (https://github.com/Machiel/slugify) [link](./licenses/LICENSE-Machiel-slugify.txt) (MIT License) Masterminds-semver (https://github.com/Masterminds/semver) [link](./licenses/LICENSE-Masterminds-semver.txt) (MIT License) anargu-gin-brotli (https://github.com/anargu/gin-brotli) [link](./licenses/LICENSE-anargu-gin-brotli.txt) diff --git a/docs/release/licenses/LICENSE-Chain-Zhang-pinyin.txt b/docs/release/licenses/LICENSE-mozillazg-go-pinyin.txt similarity index 95% rename from docs/release/licenses/LICENSE-Chain-Zhang-pinyin.txt rename to docs/release/licenses/LICENSE-mozillazg-go-pinyin.txt index c98d6a49..8a7780fc 100644 --- a/docs/release/licenses/LICENSE-Chain-Zhang-pinyin.txt +++ b/docs/release/licenses/LICENSE-mozillazg-go-pinyin.txt @@ -1,6 +1,6 @@ -MIT License +The MIT License (MIT) -Copyright (c) 2019 Chain Zhang +Copyright (c) 2016 mozillazg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/go.mod b/go.mod index 615b0f73..84689ef9 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,6 @@ module github.com/apache/incubator-answer go 1.22.0 require ( - github.com/Chain-Zhang/pinyin v0.1.3 github.com/Machiel/slugify v1.0.1 github.com/Masterminds/semver/v3 v3.3.0 github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267 @@ -41,6 +40,7 @@ require ( github.com/jinzhu/now v1.1.5 github.com/lib/pq v1.10.9 github.com/microcosm-cc/bluemonday v1.0.27 + github.com/mozillazg/go-pinyin v0.20.0 github.com/ory/dockertest/v3 v3.11.0 github.com/robfig/cron/v3 v3.0.1 github.com/scottleedavis/go-exif-remove v0.0.0-20230314195146-7e059d593405 diff --git a/go.sum b/go.sum index 1a2ab6fc..c8e314f1 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,6 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Chain-Zhang/pinyin v0.1.3 h1:RzErNyNwVa8z2sOLCuXSOtVdY/AsARb8mBzI2p2qtnE= -github.com/Chain-Zhang/pinyin v0.1.3/go.mod h1:5iHpt9p4znrnaP59/hfPMnAojajkDxQaP9io+tRMPho= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/LinkinStars/go-i18n/v2 v2.2.2 h1:ZfjpzbW13dv6btv3RALKZkpN9A+7K1JA//2QcNeWaxU= @@ -241,6 +239,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ= +github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/internal/service/user_common/user.go b/internal/service/user_common/user.go index a10c4766..7980044e 100644 --- a/internal/service/user_common/user.go +++ b/internal/service/user_common/user.go @@ -26,7 +26,6 @@ import ( "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/pkg/converter" - "github.com/Chain-Zhang/pinyin" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" @@ -35,6 +34,7 @@ import ( "github.com/apache/incubator-answer/internal/service/siteinfo_common" "github.com/apache/incubator-answer/pkg/checker" "github.com/apache/incubator-answer/pkg/random" + "github.com/mozillazg/go-pinyin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) @@ -181,12 +181,7 @@ func (us *UserCommon) FormatUserBasicInfo(ctx context.Context, userInfo *entity. func (us *UserCommon) MakeUsername(ctx context.Context, displayName string) (username string, err error) { // Chinese processing if has := checker.IsChinese(displayName); has { - str, err := pinyin.New(displayName).Split("").Mode(pinyin.WithoutTone).Convert() - if err != nil { - return "", errors.BadRequest(reason.UsernameInvalid) - } else { - displayName = str - } + displayName = strings.Join(pinyin.LazyConvert(displayName, nil), "") } username = strings.ReplaceAll(displayName, " ", "-") diff --git a/pkg/htmltext/htmltext.go b/pkg/htmltext/htmltext.go index a72f9b5c..77ca2fba 100644 --- a/pkg/htmltext/htmltext.go +++ b/pkg/htmltext/htmltext.go @@ -27,12 +27,11 @@ import ( "strings" "unicode/utf8" - "github.com/Chain-Zhang/pinyin" "github.com/Machiel/slugify" - strip "github.com/grokify/html-strip-tags-go" - "github.com/apache/incubator-answer/pkg/checker" "github.com/apache/incubator-answer/pkg/converter" + strip "github.com/grokify/html-strip-tags-go" + "github.com/mozillazg/go-pinyin" ) // ClearText clear HTML, get the clear text @@ -97,11 +96,7 @@ func convertChinese(content string) string { if !has { return content } - str, err := pinyin.New(content).Split("-").Mode(pinyin.WithoutTone).Convert() - if err != nil { - return content - } - return str + return strings.Join(pinyin.LazyConvert(content, nil), "-") } func cutLongTitle(title string) string { From d6fa819fa191dbe3cf041c05722d4f3df6b35d66 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Fri, 27 Sep 2024 14:02:38 +0800 Subject: [PATCH 220/336] refactor(gomod): downgrade dependency --- go.mod | 2 +- go.sum | 530 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 527 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 84689ef9..34ceb7ad 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 modernc.org/sqlite v1.33.0 xorm.io/builder v0.3.13 - xorm.io/xorm v1.3.9 + xorm.io/xorm v1.3.2 ) require ( diff --git a/go.sum b/go.sum index c8e314f1..62b94f92 100644 --- a/go.sum +++ b/go.sum @@ -1,34 +1,62 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= +gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/LinkinStars/go-i18n/v2 v2.2.2 h1:ZfjpzbW13dv6btv3RALKZkpN9A+7K1JA//2QcNeWaxU= github.com/LinkinStars/go-i18n/v2 v2.2.2/go.mod h1:hLglSJ4/3M0Y7ZVcoEJI+OwqkglHCA32DdjuJJR2LbM= github.com/Machiel/slugify v1.0.1 h1:EfWSlRWstMadsgzmiV7d0yVd2IFlagWH68Q+DcYCm4E= github.com/Machiel/slugify v1.0.1/go.mod h1:fTFGn5uWEynW4CUMG7sWkYXOf1UgDxyTM3DbR6Qfg3k= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/aichy126/uint128 v1.1.1/go.mod h1:Hke/MPGXUxOl0OXHoNcVesBL4N+XalHEJ9e1jaIbl8o= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267 h1:vDHsaEcs/Q0dwetADENtwus6W1ccaZ9h3KBTm0d2X0g= github.com/anargu/gin-brotli v0.0.0-20220116052358-12bf532d5267/go.mod h1:Yj3yPP/vi87JjwylUTCMyd6FrOfGqP1AHk0305hDm2o= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg= @@ -36,21 +64,39 @@ github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKz github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIrnyWmSJI70= @@ -90,8 +136,20 @@ github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3 github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349 h1:/py11NlxDaOxkT9OKN+gXgT+QOH5xj1ZRoyusfRIlo4= github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349/go.mod h1:KVK+/Hul09ujXAGq+42UBgCTnXkiJZRnLYdURGjQUwo= github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -99,6 +157,7 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -111,6 +170,12 @@ github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWE github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -131,77 +196,194 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/geo v0.0.0-20190812012225-f41920e961ce/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20230421003525-6adc56603217 h1:HKlyj6in2JV6wVkmQ4XmG/EIm+SCYlPZ+V4GWit7Z+I= github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1IxZfeH3/5I97CI8i5cLGsYe7xNhQGs9U= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= +github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= +github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= +github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE= +github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= +github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= +github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc= +github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -214,19 +396,47 @@ github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkL github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA= github.com/lestrrat-go/strftime v1.1.0 h1:gMESpZy44/4pXLO/m+sL0yBd1W6LjgjrrD4a68Gapyg= github.com/lestrrat-go/strftime v1.1.0/go.mod h1:uzeIB52CeUJenCo1syghlugshMysrqUT51HlxphXVeI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= -github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -237,47 +447,106 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ= github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNGuyA= github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scottleedavis/go-exif-remove v0.0.0-20230314195146-7e059d593405 h1:2ieGkj4z/YPXVyQ2ayZUg3GwE1pYWd5f1RB6DzAOXKM= github.com/scottleedavis/go-exif-remove v0.0.0-20230314195146-7e059d593405/go.mod h1:rIxVzVLKlBwLxO+lC+k/I4HJfRQcemg/f/76Xmmzsec= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f h1:9f2Bjf6bdMvNyUop32wAGJCdp+Jdm/d6nKBYvFvkRo0= github.com/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f/go.mod h1:5lNp5REd8QMThmBUvR3Fi9Y3AsOB4GRq7soCB4QLqOs= github.com/segmentfault/pacman/contrib/cache/memory v0.0.0-20230822083413-c0075a2d401f h1:1KHe0uN6p798E7XJZPhZkgm/hXk5CTjisCvFMqaZSKI= @@ -290,25 +559,45 @@ github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20230822083413-c0075a2d401 github.com/segmentfault/pacman/contrib/log/zap v0.0.0-20230822083413-c0075a2d401f/go.mod h1:L4GqtXLoR73obTYqUQIzfkm8NG8pvZafxFb6KZFSSHk= github.com/segmentfault/pacman/contrib/server/http v0.0.0-20230822083413-c0075a2d401f h1:2gjiRmSj3J/F3A1A22UU1BzO4gQypEZx/4D7c7Ue4Ag= github.com/segmentfault/pacman/contrib/server/http v0.0.0-20230822083413-c0075a2d401f/go.mod h1:UjNiOFYv1uGCq1ZCcONaKq4eE7MW3nbgpLqgl8f9N40= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -332,12 +621,15 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -345,41 +637,92 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw= golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -393,7 +736,12 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -401,17 +749,37 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -419,46 +787,95 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -471,24 +888,129 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60= +modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw= +modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI= +modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag= +modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw= +modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ= +modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c= +modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo= +modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg= +modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I= +modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs= +modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8= +modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE= +modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk= +modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w= +modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE= +modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8= +modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc= +modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU= +modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE= +modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk= +modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI= +modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE= +modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg= +modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74= +modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU= +modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU= +modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc= +modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM= +modernc.org/ccgo/v3 v3.12.65/go.mod h1:D6hQtKxPNZiY6wDBtehSGKFKmyXn53F8nGTpH+POmS4= +modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ= +modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84= +modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ= +modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY= +modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w= +modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a h1:CfbpOLEo2IwNzJdMvE8aiRbPMxoTpgAJeyePh0SmO8M= modernc.org/gc/v3 v3.0.0-20240801135723-a856999a2e4a/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= +modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q= +modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg= +modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M= +modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU= +modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE= +modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso= +modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8= +modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8= +modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I= +modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk= +modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY= +modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE= +modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg= +modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM= +modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg= +modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo= +modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8= +modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ= +modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA= +modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM= +modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg= +modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE= +modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM= +modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU= +modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw= +modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M= +modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18= +modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8= +modernc.org/libc v1.11.70/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw= +modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw= +modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0= +modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI= +modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE= +modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY= +modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc= +modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8= modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk= modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo= xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU= -xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw= +xorm.io/xorm v1.3.2 h1:uTRRKF2jYzbZ5nsofXVUx6ncMaek+SHjWYtCXyZo1oM= +xorm.io/xorm v1.3.2/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw= From 0db889af38bff70cc010f13cfa626549007c4f60 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Mon, 7 Oct 2024 11:46:39 +0800 Subject: [PATCH 221/336] fix: fix typo in plugin --- plugin/embed.go | 2 +- plugin/render.go | 2 +- plugin/search.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/embed.go b/plugin/embed.go index e853c8c2..772599ce 100644 --- a/plugin/embed.go +++ b/plugin/embed.go @@ -32,7 +32,7 @@ type Embed interface { } var ( - // CallReviewer is a function that calls all registered parsers + // CallEmbed is a function that calls all registered parsers CallEmbed, registerEmbed = MakePlugin[Embed](false) ) diff --git a/plugin/render.go b/plugin/render.go index 4fc2edf6..d36fd86d 100644 --- a/plugin/render.go +++ b/plugin/render.go @@ -33,7 +33,7 @@ type Render interface { } var ( - // CallReviewer is a function that calls all registered parsers + // CallRender is a function that calls all registered parsers CallRender, registerRender = MakePlugin[Render](false) ) diff --git a/plugin/search.go b/plugin/search.go index 719d4294..02b5fba8 100644 --- a/plugin/search.go +++ b/plugin/search.go @@ -124,7 +124,7 @@ type SearchSyncer interface { } var ( - // CallUserCenter is a function that calls all registered parsers + // CallSearch is a function that calls all registered parsers CallSearch, registerSearch = MakePlugin[Search](false) ) From a0f24b3cbff380da4661910a4a60e98d26067994 Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 25 Sep 2024 16:32:12 +0800 Subject: [PATCH 222/336] refactor(pluginKit): update useRender hooks to include request parameter --- ui/src/utils/pluginKit/index.ts | 5 +++-- ui/src/utils/pluginKit/interface.ts | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 6d0e9878..12cd0247 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -25,6 +25,7 @@ import type * as Type from '@/common/interface'; import { LOGGED_TOKEN_STORAGE_KEY } from '@/common/constants'; import { getPluginsStatus } from '@/services'; import Storage from '@/utils/storage'; +import request from '@/utils/request'; import { initI18nResource } from './utils'; import { Plugin, PluginInfo, PluginType } from './interface'; @@ -227,7 +228,7 @@ const useRenderHtmlPlugin = ( }) .forEach((plugin) => { plugin.hooks?.useRender?.forEach((hook) => { - hook(element); + hook(element, request); }); }); }; @@ -247,7 +248,7 @@ const useRenderPlugin = ( }) .forEach((plugin) => { plugin.hooks?.useRender?.forEach((hook) => { - hook(element); + hook(element, request); }); }); }; diff --git a/ui/src/utils/pluginKit/interface.ts b/ui/src/utils/pluginKit/interface.ts index 880a524a..d946ed6e 100644 --- a/ui/src/utils/pluginKit/interface.ts +++ b/ui/src/utils/pluginKit/interface.ts @@ -20,6 +20,7 @@ import { NamedExoticComponent, FC, RefObject } from 'react'; import type * as Type from '@/common/interface'; +import Request from '@/utils/request'; export enum PluginType { Connector = 'connector', @@ -44,7 +45,10 @@ export interface Plugin { i18nConfig?; hooks?: { useRender?: Array< - (element: HTMLElement | RefObject | null) => void + ( + element: HTMLElement | RefObject | null, + request?: typeof Request, + ) => void >; useCaptcha?: (props: { captchaKey: Type.CaptchaKey; commonProps: any }) => { getCaptcha: () => Record; From 88b52d86aba4be37ebc385a7df9c6455022a9b6e Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 9 Oct 2024 16:30:42 +0800 Subject: [PATCH 223/336] fix: Optimize badge animation effect --- ui/src/components/Modal/BadgeModal.tsx | 43 ++++++++++++++++++++------ ui/src/utils/animateGift.ts | 4 ++- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index c0cf4cc3..9c77e9d4 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -66,19 +66,15 @@ const BadgeModal: FC = ({ badge, visible }) => { navigate(url); }; - useEffect(() => { + const initAnimation = () => { const DURATION = 8000; const LENGTH = 200; const bgNode = document.documentElement || document.body; + const parentNode = document.getElementById('badgeModal')?.parentNode; - if (visible) { - const badgeModalNode = document.getElementById('badgeModal'); - const paranetNode = badgeModalNode?.parentNode; - - badgeModalNode?.setAttribute('style', 'z-index: 1'); - + if (parentNode) { bg1 = new AnimateGift({ - elm: paranetNode, + elm: parentNode, width: bgNode.clientWidth, height: bgNode.clientHeight, length: LENGTH, @@ -88,7 +84,7 @@ const BadgeModal: FC = ({ badge, visible }) => { timeout = setTimeout(() => { bg2 = new AnimateGift({ - elm: paranetNode, + elm: parentNode, width: window.innerWidth, height: window.innerHeight, length: LENGTH, @@ -96,6 +92,35 @@ const BadgeModal: FC = ({ badge, visible }) => { }); }, DURATION / 2); } + }; + + const destroyAnimation = () => { + console.log('destroyAnimation'); + clearTimeout(timeout); + bg1?.destroy(); + bg2?.destroy(); + }; + + useEffect(() => { + if (visible) { + initAnimation(); + } else { + destroyAnimation(); + } + + const handleVisibilityChange = () => { + if (document.visibilityState === 'visible') { + initAnimation(); + } else { + destroyAnimation(); + } + }; + document.addEventListener('visibilitychange', handleVisibilityChange); + + return () => { + document.removeEventListener('visibilitychange', handleVisibilityChange); + destroyAnimation(); + }; }, [visible]); return ( diff --git a/ui/src/utils/animateGift.ts b/ui/src/utils/animateGift.ts index c53b2f76..70137eca 100644 --- a/ui/src/utils/animateGift.ts +++ b/ui/src/utils/animateGift.ts @@ -178,6 +178,8 @@ export default class Confetti { } destroy() { - this.parent.removeChild(this.canvas); + if (this.parent.contains(this.canvas)) { + this.parent.removeChild(this.canvas); + } } } From 500c774f31c15bb98dbbcba00ebbc1df34d5f9f2 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 9 Oct 2024 17:48:10 +0800 Subject: [PATCH 224/336] fix: Some contents of en_us.yaml have newline errors --- i18n/en_US.yaml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 96950369..bf8f3813 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -327,9 +327,7 @@ backend: name: other: rude or abusive desc: - other: - A reasonable person would find this content inappropriate for respectful - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -341,10 +339,7 @@ backend: name: other: not an answer desc: - other: - This was posted as an answer, but it does not attempt to answer the - question. It should possibly be an edit, a comment, another question, - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -403,9 +398,7 @@ backend: name: other: needs details or clarity desc: - other: - This question currently includes multiple questions in one. It should - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else From 62d2d2a8b356043ca1eb5ff8c4d6d46c9c76c7c4 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 8 Oct 2024 16:50:14 +0800 Subject: [PATCH 225/336] refactor(pluginKit): improve plugin registration process --- ui/src/utils/pluginKit/index.ts | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 12cd0247..920b0a3c 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -49,12 +49,12 @@ class Plugins { constructor() { this.registerBuiltin(); - this.registerPlugins(); - - getPluginsStatus().then((plugins) => { - this.registeredPlugins = plugins; - this.activatePlugins(plugins); - }); + this.registerPlugins() + .then(getPluginsStatus) + .then((plugins) => { + this.registeredPlugins = plugins; + this.activatePlugins(plugins); + }); } validate(plugin: Plugin) { @@ -75,6 +75,15 @@ class Plugins { return true; } + async loadPlugins() { + return Promise.all( + Object.keys(allPlugins).map(async (key) => { + const plugin = await allPlugins[key](); + return plugin; + }), + ); + } + registerBuiltin() { Object.keys(builtin).forEach((key) => { const plugin = builtin[key]; @@ -86,9 +95,13 @@ class Plugins { } registerPlugins() { - Object.keys(allPlugins).forEach((key) => { - const plugin = allPlugins[key]; - this.register(plugin); + return new Promise((resolve) => { + this.loadPlugins().then((plugins) => { + plugins.forEach((plugin) => { + this.register(plugin); + }); + resolve(true); + }); }); } From 9479f1f80172cee4e61a376c96a8269fc2cc6c83 Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 8 Oct 2024 16:52:36 +0800 Subject: [PATCH 226/336] chore(ui): Dynamically import plugins --- ui/scripts/plugin.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/scripts/plugin.js b/ui/scripts/plugin.js index d554df8f..a3f09df5 100644 --- a/ui/scripts/plugin.js +++ b/ui/scripts/plugin.js @@ -63,7 +63,8 @@ function addPluginToIndexTs(packageName) { const indexTsContent = fs.readFileSync(indexTsPath, 'utf-8'); const lines = indexTsContent.split('\n'); const ComponentName = pascalize(packageName); - const importLine = `export { default as ${ComponentName} } from '${packageName}';`; + + const importLine = `export const load${ComponentName} = () => import('${packageName}').then(module => module.default);`; if (!lines.includes(importLine)) { lines.push(importLine); } From dc61ab7e830512f02c06d2418e35ace7fdff2406 Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 9 Oct 2024 12:16:54 +0800 Subject: [PATCH 227/336] refactor(pluginKit): update plugin registration process --- ui/scripts/plugin.js | 12 +++++++++--- ui/src/utils/pluginKit/index.ts | 26 +++++++++++++++----------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/ui/scripts/plugin.js b/ui/scripts/plugin.js index a3f09df5..ede9f13f 100644 --- a/ui/scripts/plugin.js +++ b/ui/scripts/plugin.js @@ -19,6 +19,7 @@ const path = require('path'); const fs = require('fs'); +const yaml = require('js-yaml'); const pluginPath = path.join(__dirname, '../src/plugins'); const pluginFolders = fs.readdirSync(pluginPath); @@ -64,10 +65,15 @@ function addPluginToIndexTs(packageName) { const lines = indexTsContent.split('\n'); const ComponentName = pascalize(packageName); - const importLine = `export const load${ComponentName} = () => import('${packageName}').then(module => module.default);`; - if (!lines.includes(importLine)) { + const importLine = `const load${ComponentName} = () => import('${packageName}').then(module => module.default);`; + const info = yaml.load(fs.readFileSync(path.join(pluginPath, packageName, 'info.yaml'), 'utf8')); + const exportLine = `export const ${info.slug_name} = load${ComponentName}`; + + if (!lines.includes(exportLine)) { lines.push(importLine); + lines.push(exportLine); } + fs.writeFileSync(indexTsPath, lines.join('\n')); } @@ -75,7 +81,7 @@ const pluginLength = pluginFolders.filter((folder) => { const pluginFolder = path.join(pluginPath, folder); const stat = fs.statSync(pluginFolder); return stat.isDirectory() && folder !== 'builtin'; -}).length +}).length; if (pluginLength > 0) { resetIndexTs(); diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 920b0a3c..a57b53ed 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -49,12 +49,11 @@ class Plugins { constructor() { this.registerBuiltin(); - this.registerPlugins() - .then(getPluginsStatus) - .then((plugins) => { - this.registeredPlugins = plugins; - this.activatePlugins(plugins); - }); + + getPluginsStatus().then((plugins) => { + this.registeredPlugins = plugins.filter((p) => p.enabled); + this.registerPlugins(); + }); } validate(plugin: Plugin) { @@ -95,13 +94,17 @@ class Plugins { } registerPlugins() { + const plugins = this.registeredPlugins.map((p) => { + const func = allPlugins[p.slug_name]; + + return func; + }); return new Promise((resolve) => { - this.loadPlugins().then((plugins) => { - plugins.forEach((plugin) => { - this.register(plugin); - }); - resolve(true); + plugins.forEach(async (p) => { + const plugin = await p(); + this.register(plugin); }); + resolve(true); }); } @@ -113,6 +116,7 @@ class Plugins { if (plugin.i18nConfig) { initI18nResource(plugin.i18nConfig); } + plugin.activated = true; this.plugins.push(plugin); } From 84a49321f19da0bab26820a72d4c7d71a2cc6387 Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 9 Oct 2024 14:21:51 +0800 Subject: [PATCH 228/336] chore(ui): update pre-install script in package.json --- ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/package.json b/ui/package.json index 2344125d..51cd29d1 100644 --- a/ui/package.json +++ b/ui/package.json @@ -8,7 +8,7 @@ "build": "node ./scripts/env.js && react-app-rewired build", "lint": "eslint . --cache --fix --ext .ts,.tsx", "prettier": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}' --config ./.prettierrc.json", - "pre-install": "node ./scripts/preinstall.js && pnpm install", + "pre-install": "pnpm install && node ./scripts/preinstall.js", "prepare": "pnpm build:packages", "pre-commit": "lint-staged", "build:packages": "pnpm -r --filter=./src/plugins/* run build", From 95b9af557f1d40eebf58d5433b44c2e57d39640d Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 10 Oct 2024 10:37:36 +0800 Subject: [PATCH 229/336] refactor(pluginKit): update addPluginToIndexTs function to include pluginFolder parameter --- ui/scripts/plugin.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/scripts/plugin.js b/ui/scripts/plugin.js index ede9f13f..7ad3d7c5 100644 --- a/ui/scripts/plugin.js +++ b/ui/scripts/plugin.js @@ -59,14 +59,14 @@ function addPluginToPackageJson(packageName) { ); } -function addPluginToIndexTs(packageName) { +function addPluginToIndexTs(packageName, pluginFolder) { const indexTsPath = path.join(pluginPath, 'index.ts'); const indexTsContent = fs.readFileSync(indexTsPath, 'utf-8'); const lines = indexTsContent.split('\n'); const ComponentName = pascalize(packageName); const importLine = `const load${ComponentName} = () => import('${packageName}').then(module => module.default);`; - const info = yaml.load(fs.readFileSync(path.join(pluginPath, packageName, 'info.yaml'), 'utf8')); + const info = yaml.load(fs.readFileSync(path.join(pluginFolder, 'info.yaml'), 'utf8')); const exportLine = `export const ${info.slug_name} = load${ComponentName}`; if (!lines.includes(exportLine)) { @@ -101,6 +101,6 @@ pluginFolders.forEach((folder) => { const packageName = packageJson.name; addPluginToPackageJson(packageName); - addPluginToIndexTs(packageName); + addPluginToIndexTs(packageName, pluginFolder); } }); From 59080727cf4ff074953f0cafc96ed73f4de2c789 Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 10 Oct 2024 17:47:36 +0800 Subject: [PATCH 230/336] refactor(ui): update pre-install script in package.json --- ui/package.json | 2 +- ui/scripts/importPlugins.js | 68 ++++++++++++++++++++++++ ui/scripts/{plugin.js => loadPlugins.js} | 30 +---------- ui/scripts/preinstall.js | 2 +- 4 files changed, 71 insertions(+), 31 deletions(-) create mode 100644 ui/scripts/importPlugins.js rename ui/scripts/{plugin.js => loadPlugins.js} (76%) diff --git a/ui/package.json b/ui/package.json index 51cd29d1..3d9c2614 100644 --- a/ui/package.json +++ b/ui/package.json @@ -8,7 +8,7 @@ "build": "node ./scripts/env.js && react-app-rewired build", "lint": "eslint . --cache --fix --ext .ts,.tsx", "prettier": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}' --config ./.prettierrc.json", - "pre-install": "pnpm install && node ./scripts/preinstall.js", + "pre-install": "node ./scripts/importPlugins.js && pnpm install && node ./scripts/preinstall.js ", "prepare": "pnpm build:packages", "pre-commit": "lint-staged", "build:packages": "pnpm -r --filter=./src/plugins/* run build", diff --git a/ui/scripts/importPlugins.js b/ui/scripts/importPlugins.js new file mode 100644 index 00000000..0862a015 --- /dev/null +++ b/ui/scripts/importPlugins.js @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +const path = require('path'); +const fs = require('fs'); + +const pluginPath = path.join(__dirname, '../src/plugins'); +const pluginFolders = fs.readdirSync(pluginPath); + +function resetPackageJson() { + const packageJsonPath = path.join(__dirname, '..', 'package.json'); + const packageJsonContent = require(packageJsonPath); + const dependencies = packageJsonContent.dependencies; + for (const key in dependencies) { + if (dependencies[key].startsWith('workspace')) { + delete dependencies[key]; + } + } + fs.writeFileSync( + packageJsonPath, + JSON.stringify(packageJsonContent, null, 2), + ); +} + +function addPluginToPackageJson(packageName) { + const packageJsonPath = path.join(__dirname, '..', 'package.json'); + const packageJsonContent = require(packageJsonPath); + packageJsonContent.dependencies[packageName] = 'workspace:*'; + + fs.writeFileSync( + packageJsonPath, + JSON.stringify(packageJsonContent, null, 2), + ); +} + + +resetPackageJson(); + +pluginFolders.forEach((folder) => { + const pluginFolder = path.join(pluginPath, folder); + const stat = fs.statSync(pluginFolder); + + if (stat.isDirectory() && folder !== 'builtin') { + if (!fs.existsSync(path.join(pluginFolder, 'index.ts'))) { + return; + } + const packageJson = require(path.join(pluginFolder, 'package.json')); + const packageName = packageJson.name; + + addPluginToPackageJson(packageName); + } +}); \ No newline at end of file diff --git a/ui/scripts/plugin.js b/ui/scripts/loadPlugins.js similarity index 76% rename from ui/scripts/plugin.js rename to ui/scripts/loadPlugins.js index 7ad3d7c5..77b5fe5d 100644 --- a/ui/scripts/plugin.js +++ b/ui/scripts/loadPlugins.js @@ -28,37 +28,11 @@ function pascalize(str) { return str.split(/[_-]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(''); } -function resetPackageJson() { - const packageJsonPath = path.join(__dirname, '..', 'package.json'); - const packageJsonContent = require(packageJsonPath); - const dependencies = packageJsonContent.dependencies; - for (const key in dependencies) { - if (dependencies[key].startsWith('workspace')) { - delete dependencies[key]; - } - } - fs.writeFileSync( - packageJsonPath, - JSON.stringify(packageJsonContent, null, 2), - ); -} - function resetIndexTs() { const indexTsPath = path.join(pluginPath, 'index.ts'); fs.writeFileSync(indexTsPath, ''); } -function addPluginToPackageJson(packageName) { - const packageJsonPath = path.join(__dirname, '..', 'package.json'); - const packageJsonContent = require(packageJsonPath); - packageJsonContent.dependencies[packageName] = 'workspace:*'; - - fs.writeFileSync( - packageJsonPath, - JSON.stringify(packageJsonContent, null, 2), - ); -} - function addPluginToIndexTs(packageName, pluginFolder) { const indexTsPath = path.join(pluginPath, 'index.ts'); const indexTsContent = fs.readFileSync(indexTsPath, 'utf-8'); @@ -87,8 +61,6 @@ if (pluginLength > 0) { resetIndexTs(); } -resetPackageJson(); - pluginFolders.forEach((folder) => { const pluginFolder = path.join(pluginPath, folder); const stat = fs.statSync(pluginFolder); @@ -100,7 +72,7 @@ pluginFolders.forEach((folder) => { const packageJson = require(path.join(pluginFolder, 'package.json')); const packageName = packageJson.name; - addPluginToPackageJson(packageName); addPluginToIndexTs(packageName, pluginFolder); } }); + diff --git a/ui/scripts/preinstall.js b/ui/scripts/preinstall.js index e3608091..94de3f32 100644 --- a/ui/scripts/preinstall.js +++ b/ui/scripts/preinstall.js @@ -19,7 +19,7 @@ // There is a bug when using npm to install: the execution of preinstall is after install, so when this prompt is displayed, the dependent packages have already been installed. -require('./plugin'); +require('./loadPlugins'); if (!/pnpm/.test(process.env.npm_execpath)) { console.warn( From df507a9de5a772d8bf432a9a0c9887a8a249873f Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 11 Oct 2024 10:38:37 +0800 Subject: [PATCH 231/336] refactor(pluginKit): remove unused loadPlugins function --- ui/src/utils/pluginKit/index.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index a57b53ed..8e19d881 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -74,15 +74,6 @@ class Plugins { return true; } - async loadPlugins() { - return Promise.all( - Object.keys(allPlugins).map(async (key) => { - const plugin = await allPlugins[key](); - return plugin; - }), - ); - } - registerBuiltin() { Object.keys(builtin).forEach((key) => { const plugin = builtin[key]; From ad4771364140679dde67670602db6d735544b879 Mon Sep 17 00:00:00 2001 From: robin Date: Fri, 11 Oct 2024 11:21:29 +0800 Subject: [PATCH 232/336] refactor(ui): update pluginKit refresh method --- ui/src/pages/Admin/Plugins/Installed/index.tsx | 2 +- ui/src/utils/pluginKit/index.ts | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ui/src/pages/Admin/Plugins/Installed/index.tsx b/ui/src/pages/Admin/Plugins/Installed/index.tsx index 82e0618b..868b827a 100644 --- a/ui/src/pages/Admin/Plugins/Installed/index.tsx +++ b/ui/src/pages/Admin/Plugins/Installed/index.tsx @@ -66,7 +66,7 @@ const Users: FC = () => { plugin_slug_name: plugin.slug_name, }).then(() => { updatePlugins(); - PluginKit.changePluginActiveStatus(plugin.slug_name, !plugin.enabled); + PluginKit.refresh(); if (plugin.have_config) { emitPluginChange('refreshConfigurablePlugins'); } diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 8e19d881..f53fdb4c 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -48,6 +48,10 @@ class Plugins { registeredPlugins: Type.ActivatedPlugin[] = []; constructor() { + this.init(); + } + + init() { this.registerBuiltin(); getPluginsStatus().then((plugins) => { @@ -56,6 +60,11 @@ class Plugins { }); } + refresh() { + this.plugins = []; + this.init(); + } + validate(plugin: Plugin) { if (!plugin) { return false; @@ -123,13 +132,6 @@ class Plugins { }); } - changePluginActiveStatus(slug_name: string, active: boolean) { - const plugin = this.getPlugin(slug_name); - if (plugin) { - plugin.activated = active; - } - } - getPlugin(slug_name: string) { return this.plugins.find((p) => p.info.slug_name === slug_name); } From 057f66cf318eb06826e44eff56e2018758549421 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Thu, 10 Oct 2024 09:40:35 +0800 Subject: [PATCH 233/336] style: Improve the display of personal page when there is no information --- i18n/en_US.yaml | 1 + i18n/zh_CN.yaml | 1 + .../Personal/components/Overview/index.tsx | 41 +++++++++++-------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index bf8f3813..e5f23fe2 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1585,6 +1585,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index ca69257d..1f51ffd0 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1559,6 +1559,7 @@ ui: top_questions: 高分问题 stats: 状态 list_empty: 没有找到相关的内容。
试试看其他选项卡? + content_empty: 没有找到相关的内容。 accepted: 已采纳 answered: 回答于 asked: 提问于 diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 6b247b0c..7f937f68 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -49,31 +49,34 @@ const Index: FC = ({ visible, introduction, data, username }) => { dangerouslySetInnerHTML={{ __html: introduction }} /> ) : ( -
{t('about_me_empty')}
+
{t('about_me_empty')}
)} - - - {data?.answer?.length > 0 && ( - <> -
{t('top_answers')}
- - + 0 || data?.question?.length > 0 ? 'mb-4' : '' + }> + +
{t('top_answers')}
+ {data?.answer?.length > 0 ? ( + + ) : ( +
{t('content_empty')}
)} - {data?.question?.length > 0 && ( - <> -
{t('top_questions')}
- - +
{t('top_questions')}
+ {data?.question?.length > 0 ? ( + + ) : ( +
{t('content_empty')}
)}
- {Number(recentBadges?.count) > 0 && ( -
-
{t('recent_badges')}
+
+
{t('recent_badges')}
+ {Number(recentBadges?.count) > 0 ? (
{recentBadges?.list?.map((item) => { return ( @@ -85,8 +88,10 @@ const Index: FC = ({ visible, introduction, data, username }) => { ); })}
-
- )} + ) : ( +
{t('content_empty')}
+ )} +
); }; From 3e91f03b406f1759b8036df81e96c00d6b65dbb5 Mon Sep 17 00:00:00 2001 From: zahash Date: Thu, 10 Oct 2024 10:22:54 +0530 Subject: [PATCH 234/336] change minimum username length to 2 instead of 4 --- internal/schema/user_schema.go | 2 +- pkg/checker/username.go | 2 +- ui/src/pages/Users/Register/components/SignUpForm/index.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/schema/user_schema.go b/internal/schema/user_schema.go index 13971708..95837d96 100644 --- a/internal/schema/user_schema.go +++ b/internal/schema/user_schema.go @@ -198,7 +198,7 @@ type UserEmailLoginReq struct { // UserRegisterReq user register request type UserRegisterReq struct { - Name string `validate:"required,gt=3,lte=30" json:"name"` + Name string `validate:"required,gte=2,lte=30" json:"name"` Email string `validate:"required,email,gt=0,lte=500" json:"e_mail" ` Pass string `validate:"required,gte=8,lte=32" json:"pass"` CaptchaID string `json:"captcha_id"` diff --git a/pkg/checker/username.go b/pkg/checker/username.go index 9593ccf9..4ab39d91 100644 --- a/pkg/checker/username.go +++ b/pkg/checker/username.go @@ -22,7 +22,7 @@ package checker import "regexp" var ( - usernameReg = regexp.MustCompile(`^[a-z0-9._-]{4,30}$`) + usernameReg = regexp.MustCompile(`^[a-z0-9._-]{2,30}$`) ) func IsInvalidUsername(username string) bool { diff --git a/ui/src/pages/Users/Register/components/SignUpForm/index.tsx b/ui/src/pages/Users/Register/components/SignUpForm/index.tsx index 97499ebf..bffa4465 100644 --- a/ui/src/pages/Users/Register/components/SignUpForm/index.tsx +++ b/ui/src/pages/Users/Register/components/SignUpForm/index.tsx @@ -55,7 +55,7 @@ const Index: React.FC = ({ callback }) => { const updateUser = userStore((state) => state.update); const emailCaptcha = useCaptchaPlugin('email'); - const nameRegex = /^[\w.-\s]{4,30}$/; + const nameRegex = /^[\w.-\s]{2,30}$/; const handleChange = (params: FormDataType) => { setFormData({ ...formData, ...params }); @@ -72,7 +72,7 @@ const Index: React.FC = ({ callback }) => { isInvalid: true, errorMsg: t('name.msg.empty'), }; - } else if (name.value.length < 4 || name.value.length > 30) { + } else if (name.value.length < 2 || name.value.length > 30) { bol = false; formData.name = { value: name.value, From 18c802ae096a5f5a8de87c67f09bcdd8964ee32a Mon Sep 17 00:00:00 2001 From: zahash Date: Thu, 10 Oct 2024 18:06:06 +0530 Subject: [PATCH 235/336] change i18n strings --- i18n/af_ZA.yaml | 4 ++-- i18n/ar_SA.yaml | 4 ++-- i18n/az_AZ.yaml | 4 ++-- i18n/bal_BA.yaml | 4 ++-- i18n/ban_ID.yaml | 4 ++-- i18n/bn_BD.yaml | 4 ++-- i18n/bs_BA.yaml | 4 ++-- i18n/ca_ES.yaml | 4 ++-- i18n/cs_CZ.yaml | 4 ++-- i18n/cy_GB.yaml | 4 ++-- i18n/da_DK.yaml | 4 ++-- i18n/de_DE.yaml | 4 ++-- i18n/el_GR.yaml | 4 ++-- i18n/en_US.yaml | 4 ++-- i18n/es_ES.yaml | 4 ++-- i18n/fa_IR.yaml | 4 ++-- i18n/fi_FI.yaml | 4 ++-- i18n/fr_FR.yaml | 6 +++--- i18n/he_IL.yaml | 4 ++-- i18n/hi_IN.yaml | 4 ++-- i18n/hu_HU.yaml | 4 ++-- i18n/hy_AM.yaml | 4 ++-- i18n/id_ID.yaml | 4 ++-- i18n/it_IT.yaml | 4 ++-- i18n/ja_JP.yaml | 4 ++-- i18n/ko_KR.yaml | 2 +- i18n/nl_NL.yaml | 4 ++-- i18n/no_NO.yaml | 4 ++-- i18n/pl_PL.yaml | 4 ++-- i18n/pt_BR.yaml | 2 +- i18n/pt_PT.yaml | 4 ++-- i18n/ro_RO.yaml | 4 ++-- i18n/ru_RU.yaml | 4 ++-- i18n/sk_SK.yaml | 4 ++-- i18n/sq_AL.yaml | 4 ++-- i18n/sr_SP.yaml | 4 ++-- i18n/sv_SE.yaml | 4 ++-- i18n/te_IN.yaml | 4 ++-- i18n/tr_TR.yaml | 4 ++-- i18n/uk_UA.yaml | 4 ++-- i18n/vi_VN.yaml | 4 ++-- i18n/zh_CN.yaml | 4 ++-- i18n/zh_TW.yaml | 4 ++-- 43 files changed, 85 insertions(+), 85 deletions(-) diff --git a/i18n/af_ZA.yaml b/i18n/af_ZA.yaml index efef6068..e6dfdddd 100644 --- a/i18n/af_ZA.yaml +++ b/i18n/af_ZA.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/ar_SA.yaml b/i18n/ar_SA.yaml index c91f56b0..abeb316d 100644 --- a/i18n/ar_SA.yaml +++ b/i18n/ar_SA.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/az_AZ.yaml b/i18n/az_AZ.yaml index a667823b..7dd6a0e8 100644 --- a/i18n/az_AZ.yaml +++ b/i18n/az_AZ.yaml @@ -612,7 +612,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1123,7 +1123,7 @@ ui: fields: display_name: label: Display Name - msg: display_name must be at 4 - 30 characters in length. + msg: display_name must be at 2 - 30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/bal_BA.yaml b/i18n/bal_BA.yaml index a667823b..7dd6a0e8 100644 --- a/i18n/bal_BA.yaml +++ b/i18n/bal_BA.yaml @@ -612,7 +612,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1123,7 +1123,7 @@ ui: fields: display_name: label: Display Name - msg: display_name must be at 4 - 30 characters in length. + msg: display_name must be at 2 - 30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/ban_ID.yaml b/i18n/ban_ID.yaml index a667823b..7dd6a0e8 100644 --- a/i18n/ban_ID.yaml +++ b/i18n/ban_ID.yaml @@ -612,7 +612,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1123,7 +1123,7 @@ ui: fields: display_name: label: Display Name - msg: display_name must be at 4 - 30 characters in length. + msg: display_name must be at 2 - 30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/bn_BD.yaml b/i18n/bn_BD.yaml index a667823b..7dd6a0e8 100644 --- a/i18n/bn_BD.yaml +++ b/i18n/bn_BD.yaml @@ -612,7 +612,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1123,7 +1123,7 @@ ui: fields: display_name: label: Display Name - msg: display_name must be at 4 - 30 characters in length. + msg: display_name must be at 2 - 30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/bs_BA.yaml b/i18n/bs_BA.yaml index a667823b..7dd6a0e8 100644 --- a/i18n/bs_BA.yaml +++ b/i18n/bs_BA.yaml @@ -612,7 +612,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1123,7 +1123,7 @@ ui: fields: display_name: label: Display Name - msg: display_name must be at 4 - 30 characters in length. + msg: display_name must be at 2 - 30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/ca_ES.yaml b/i18n/ca_ES.yaml index c91f56b0..abeb316d 100644 --- a/i18n/ca_ES.yaml +++ b/i18n/ca_ES.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/cs_CZ.yaml b/i18n/cs_CZ.yaml index c9a2bad9..0a54c51a 100644 --- a/i18n/cs_CZ.yaml +++ b/i18n/cs_CZ.yaml @@ -1185,7 +1185,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/cy_GB.yaml b/i18n/cy_GB.yaml index ebd104b0..c3b3b55a 100644 --- a/i18n/cy_GB.yaml +++ b/i18n/cy_GB.yaml @@ -1185,7 +1185,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/da_DK.yaml b/i18n/da_DK.yaml index b7e03395..d707d355 100644 --- a/i18n/da_DK.yaml +++ b/i18n/da_DK.yaml @@ -1185,7 +1185,7 @@ ui: label: Navn msg: empty: Navn må ikke være tomt. - range: Navnet skal være mellem 4 og 30 tegn. + range: Navnet skal være mellem 2 og 30 tegn. character: 'Skal bruge tegnsættet "a-z", "A-Z", "0-9", " - . _"' email: label: E-mail @@ -1816,7 +1816,7 @@ ui: msg: "Indtast venligst brugerens e-mail, en pr. linje." display_name: label: Visnings-navn - msg: Vis navn skal være på 4-30 tegn. + msg: Vis navn skal være på 2-30 tegn. email: label: E-mail msg: E-mail er ugyldig. diff --git a/i18n/de_DE.yaml b/i18n/de_DE.yaml index 25c6e92c..d780b438 100644 --- a/i18n/de_DE.yaml +++ b/i18n/de_DE.yaml @@ -1185,7 +1185,7 @@ ui: label: Name msg: empty: Der Name darf nicht leer sein. - range: Die Länge des Namens sollte zwischen 4 und 30 Zeichen liegen. + range: Die Länge des Namens sollte zwischen 2 und 30 Zeichen liegen. character: 'Muss den Zeichensatz "a-z", "A-Z", "0-9", " - . _" verwenden' email: label: E-Mail @@ -1816,7 +1816,7 @@ ui: msg: "Bitte gib die E-Mail des Nutzers ein, eine pro Zeile." display_name: label: Anzeigename - msg: Der Anzeigename muss zwischen 4 und 30 Zeichen lang sein. + msg: Der Anzeigename muss zwischen 2 und 30 Zeichen lang sein. email: label: E-Mail msg: Die E-Mail ist nicht gültig. diff --git a/i18n/el_GR.yaml b/i18n/el_GR.yaml index c91f56b0..abeb316d 100644 --- a/i18n/el_GR.yaml +++ b/i18n/el_GR.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index e5f23fe2..dea08198 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1198,7 +1198,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1849,7 +1849,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/es_ES.yaml b/i18n/es_ES.yaml index b01dbb5c..ff3853d1 100644 --- a/i18n/es_ES.yaml +++ b/i18n/es_ES.yaml @@ -1185,7 +1185,7 @@ ui: label: Nombre msg: empty: El nombre no puede estar vacío. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Correo electrónico @@ -1816,7 +1816,7 @@ ui: msg: "Por favor, introduzca el correo electrónico del usuario, uno por línea." display_name: label: Nombre público - msg: El nombre público debe tener entre 4 y 30 caracteres de longitud. + msg: El nombre público debe tener entre 2 y 30 caracteres de longitud. email: label: Correo msg: El correo no es válido. diff --git a/i18n/fa_IR.yaml b/i18n/fa_IR.yaml index ffa7a81e..274b97d5 100644 --- a/i18n/fa_IR.yaml +++ b/i18n/fa_IR.yaml @@ -1185,7 +1185,7 @@ ui: label: نام msg: empty: نام نمی‌تواند خالی باشد. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: ایمیل @@ -1816,7 +1816,7 @@ ui: msg: "لطفا ایمیل کاربر را در هر خط یکی وارد کنید." display_name: label: نمایش نام - msg: نام نمایشی باید 4 تا 30 کاراکتر باشد. + msg: نام نمایشی باید 2 تا 30 کاراکتر باشد. email: label: ایمیل msg: ایمیل معتبر نمی‌باشد diff --git a/i18n/fi_FI.yaml b/i18n/fi_FI.yaml index c91f56b0..abeb316d 100644 --- a/i18n/fi_FI.yaml +++ b/i18n/fi_FI.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/fr_FR.yaml b/i18n/fr_FR.yaml index 27a0a250..c7bf5fce 100644 --- a/i18n/fr_FR.yaml +++ b/i18n/fr_FR.yaml @@ -1185,7 +1185,7 @@ ui: label: Nom msg: empty: Le nom ne peut pas être vide. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1610,7 +1610,7 @@ ui: site_name: label: Nom du site msg: Le nom ne peut pas être vide. - msg_max_length: Le nom affiché doit avoir une longueur de 4 à 30 caractères. + msg_max_length: Le nom affiché doit avoir une longueur de 2 à 30 caractères. site_url: label: URL du site text: L'adresse de ce site. @@ -1816,7 +1816,7 @@ ui: msg: "Veuillez entrer l'email de l'utilisateur, un par ligne." display_name: label: Nom affiché - msg: Le nom affiché doit avoir une longueur de 4 à 30 caractères. + msg: Le nom affiché doit avoir une longueur de 2 à 30 caractères. email: label: Email msg: L'email n'est pas valide. diff --git a/i18n/he_IL.yaml b/i18n/he_IL.yaml index c91f56b0..abeb316d 100644 --- a/i18n/he_IL.yaml +++ b/i18n/he_IL.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/hi_IN.yaml b/i18n/hi_IN.yaml index cb6f1645..78a23394 100644 --- a/i18n/hi_IN.yaml +++ b/i18n/hi_IN.yaml @@ -1185,7 +1185,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/hu_HU.yaml b/i18n/hu_HU.yaml index c91f56b0..abeb316d 100644 --- a/i18n/hu_HU.yaml +++ b/i18n/hu_HU.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/hy_AM.yaml b/i18n/hy_AM.yaml index a667823b..7dd6a0e8 100644 --- a/i18n/hy_AM.yaml +++ b/i18n/hy_AM.yaml @@ -612,7 +612,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1123,7 +1123,7 @@ ui: fields: display_name: label: Display Name - msg: display_name must be at 4 - 30 characters in length. + msg: display_name must be at 2 - 30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/id_ID.yaml b/i18n/id_ID.yaml index deb0a499..11da0521 100644 --- a/i18n/id_ID.yaml +++ b/i18n/id_ID.yaml @@ -1185,7 +1185,7 @@ ui: label: Nama msg: empty: Nama tidak boleh kosong. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/it_IT.yaml b/i18n/it_IT.yaml index b2fb1dde..1c9f8a85 100644 --- a/i18n/it_IT.yaml +++ b/i18n/it_IT.yaml @@ -1185,7 +1185,7 @@ ui: label: Nome msg: empty: Il nome non può essere vuoto. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: E-mail @@ -1816,7 +1816,7 @@ ui: msg: "Inserisci l'email dell'utente, una per riga." display_name: label: Nome da visualizzare - msg: Il nome visualizzato deve avere una lunghezza compresa tra 4 e 30 caratteri. + msg: Il nome visualizzato deve avere una lunghezza compresa tra 2 e 30 caratteri. email: label: E-mail msg: L'email non è valida. diff --git a/i18n/ja_JP.yaml b/i18n/ja_JP.yaml index 3e6433e6..887ba790 100644 --- a/i18n/ja_JP.yaml +++ b/i18n/ja_JP.yaml @@ -1185,7 +1185,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: メールアドレス @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/ko_KR.yaml b/i18n/ko_KR.yaml index d62e78f5..fba3d7d9 100644 --- a/i18n/ko_KR.yaml +++ b/i18n/ko_KR.yaml @@ -1816,7 +1816,7 @@ ui: msg: "사용자의 이메일을 입력하세요. 한 줄에 한 명씩 입력하세요." display_name: label: 표시 이름 - msg: 표시 이름은 4-30자여야 합니다. + msg: 표시 이름은 2-30자여야 합니다. email: label: 이메일 msg: 이메일이 유효하지 않습니다. diff --git a/i18n/nl_NL.yaml b/i18n/nl_NL.yaml index c91f56b0..abeb316d 100644 --- a/i18n/nl_NL.yaml +++ b/i18n/nl_NL.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/no_NO.yaml b/i18n/no_NO.yaml index 859f1cea..f62c3757 100644 --- a/i18n/no_NO.yaml +++ b/i18n/no_NO.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1137,7 +1137,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/pl_PL.yaml b/i18n/pl_PL.yaml index 5a46601b..7e885b92 100644 --- a/i18n/pl_PL.yaml +++ b/i18n/pl_PL.yaml @@ -1185,7 +1185,7 @@ ui: label: Imię msg: empty: Imię nie może być puste. - range: Długość nazwy powinna wynosić od 4 do 30 znaków. + range: Długość nazwy powinna wynosić od 2 do 30 znaków. character: 'Możesz użyć dozwolone znaki "a-z", "A-Z", "0-9", " - . _"' email: label: Adres e-mail @@ -1816,7 +1816,7 @@ ui: msg: "Podaj adresy e-mail użytkowników, jeden w każdej linii." display_name: label: Nazwa wyświetlana - msg: Wyświetlana nazwa musi mieć od 4 do 30 znaków. + msg: Wyświetlana nazwa musi mieć od 2 do 30 znaków. email: label: E-mail msg: Email nie jest prawidłowy. diff --git a/i18n/pt_BR.yaml b/i18n/pt_BR.yaml index 4210d5bd..3afde1b7 100644 --- a/i18n/pt_BR.yaml +++ b/i18n/pt_BR.yaml @@ -1133,7 +1133,7 @@ ui: fields: display_name: label: Nome de exibição - msg: Nome de exibição deve ser 4-30 caracteres em comprimento. + msg: Nome de exibição deve ser 2-30 caracteres em comprimento. email: label: Email msg: Email não é válido. diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index 3eb74465..d95385e1 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -1185,7 +1185,7 @@ ui: label: Nome msg: empty: Nome não pode ser vazio. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: E-mail @@ -1816,7 +1816,7 @@ ui: msg: "Por favor insira o e-mail do usuário, um por linha." display_name: label: Nome de exibição - msg: O nome de exibição deve ter de 4 a 30 caracteres. + msg: O nome de exibição deve ter de 2 a 30 caracteres. email: label: E-mail msg: E-mail inválido. diff --git a/i18n/ro_RO.yaml b/i18n/ro_RO.yaml index 77197365..c73eb566 100644 --- a/i18n/ro_RO.yaml +++ b/i18n/ro_RO.yaml @@ -1185,7 +1185,7 @@ ui: label: Nume msg: empty: Câmpul Nume trebuie completat. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: E-mail @@ -1816,7 +1816,7 @@ ui: msg: "Te rugăm să introduci e-mailul utilizatorului, câte unul pe linie." display_name: label: Nume afișat - msg: Numele afișat trebuie să aibă între 4 și 30 de caractere. + msg: Numele afișat trebuie să aibă între 2 și 30 de caractere. email: label: E-mail msg: E-mail nu este validă. diff --git a/i18n/ru_RU.yaml b/i18n/ru_RU.yaml index 42c76807..9adf491a 100644 --- a/i18n/ru_RU.yaml +++ b/i18n/ru_RU.yaml @@ -1185,7 +1185,7 @@ ui: label: Имя пользователя msg: empty: Имя пользователя не должно быть пустым. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email адрес @@ -1816,7 +1816,7 @@ ui: msg: "Пожалуйста, введите адрес электронной почты пользователя, по одному на строку." display_name: label: Отображаемое имя - msg: Отображаемое имя должно содержать не менее 4-30 символов. + msg: Отображаемое имя должно содержать не менее 2-30 символов. email: label: Email msg: Некорректный email. diff --git a/i18n/sk_SK.yaml b/i18n/sk_SK.yaml index 7f801778..eac4f204 100644 --- a/i18n/sk_SK.yaml +++ b/i18n/sk_SK.yaml @@ -1185,7 +1185,7 @@ ui: label: Prihlasovacie meno msg: empty: Prihlasovacie meno nemôže byť prázdne. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: E-mail @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/sq_AL.yaml b/i18n/sq_AL.yaml index a667823b..7dd6a0e8 100644 --- a/i18n/sq_AL.yaml +++ b/i18n/sq_AL.yaml @@ -612,7 +612,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1123,7 +1123,7 @@ ui: fields: display_name: label: Display Name - msg: display_name must be at 4 - 30 characters in length. + msg: display_name must be at 2 - 30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/sr_SP.yaml b/i18n/sr_SP.yaml index c91f56b0..abeb316d 100644 --- a/i18n/sr_SP.yaml +++ b/i18n/sr_SP.yaml @@ -619,7 +619,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Name must between 4 to 30 characters in length. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1136,7 +1136,7 @@ ui: fields: display_name: label: Display Name - msg: Display Name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index 7cacadaa..36b59fe6 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -1185,7 +1185,7 @@ ui: label: Namn msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: E-postadress @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Visningsnamn - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/te_IN.yaml b/i18n/te_IN.yaml index 04158770..638a1870 100644 --- a/i18n/te_IN.yaml +++ b/i18n/te_IN.yaml @@ -1185,7 +1185,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/tr_TR.yaml b/i18n/tr_TR.yaml index 78a77a25..656da997 100644 --- a/i18n/tr_TR.yaml +++ b/i18n/tr_TR.yaml @@ -1185,7 +1185,7 @@ ui: label: Name msg: empty: Name cannot be empty. - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: Email @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. diff --git a/i18n/uk_UA.yaml b/i18n/uk_UA.yaml index ee7e6603..58a538e2 100644 --- a/i18n/uk_UA.yaml +++ b/i18n/uk_UA.yaml @@ -1185,7 +1185,7 @@ ui: label: Ім’я msg: empty: Ім'я не може бути порожнім. - range: Довжина імені має бути від 4 до 30 символів. + range: Довжина імені має бути від 2 до 30 символів. character: 'Необхідно використовувати набір символів "a-z", "A-Z", "0-9", " - . _"' email: label: Електронна пошта @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Ім'я для відображення - msg: Ім'я для відображення повинно мати довжину від 4 до 30 символів. + msg: Ім'я для відображення повинно мати довжину від 2 до 30 символів. email: label: Email msg: Email is not valid. diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 888258d0..59f56978 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -1185,7 +1185,7 @@ ui: label: Tên msg: empty: Tên không thể trống. - range: Độ dài của tên phải từ 4 đến 30 ký tự. + range: Độ dài của tên phải từ 2 đến 30 ký tự. character: 'Chỉ sử dụng bộ ký tự "a-z", "0-9", , "A-Z", " - . _"' email: label: Email @@ -1816,7 +1816,7 @@ ui: msg: "Vui lòng nhập email của người dùng, một dòng mỗi người." display_name: label: Tên hiển thị - msg: Tên hiển thị phải có từ 4 đến 30 ký tự. + msg: Tên hiển thị phải có từ 2 đến 30 ký tự. email: label: Email msg: Email không hợp lệ. diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 1f51ffd0..889d4da2 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1185,7 +1185,7 @@ ui: label: 名字 msg: empty: 名字不能为空 - range: 名字应该在 4 到 30 个字符之间 + range: 名字应该在 2 到 30 个字符之间 character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' email: label: 邮箱 @@ -1817,7 +1817,7 @@ ui: msg: "请输入用户的邮箱,每行一个。" display_name: label: 显示名称 - msg: 显示名称长度必须为 4-30 个字符 + msg: 显示名称长度必须为 2-30 个字符 email: label: 邮箱 msg: 邮箱无效。 diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index a386576a..32938f4d 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -1185,7 +1185,7 @@ ui: label: 名稱 msg: empty: 名稱不能為空 - range: Length of name should between 4 to 30 characters. + range: Name must be between 2 to 30 characters in length. character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' email: label: 郵箱 @@ -1816,7 +1816,7 @@ ui: msg: "Please enter the user's email, one per line." display_name: label: Display name - msg: Display name must be at 4-30 characters in length. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Email is not valid. From bd0d9fda22d1172f211422d13f33e4c567118e33 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Fri, 11 Oct 2024 10:09:55 +0800 Subject: [PATCH 236/336] docs: regenerate docs --- docs/docs.go | 3 ++- docs/swagger.json | 3 ++- docs/swagger.yaml | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index e461c3a9..80f4a0d8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -11456,7 +11456,8 @@ const docTemplate = `{ }, "name": { "type": "string", - "maxLength": 30 + "maxLength": 30, + "minLength": 2 }, "pass": { "type": "string", diff --git a/docs/swagger.json b/docs/swagger.json index 322a87ad..5690e67b 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -11429,7 +11429,8 @@ }, "name": { "type": "string", - "maxLength": 30 + "maxLength": 30, + "minLength": 2 }, "pass": { "type": "string", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 66a594d5..6a0ab449 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2844,6 +2844,7 @@ definitions: type: string name: maxLength: 30 + minLength: 2 type: string pass: maxLength: 32 From 3eb9822c0906aa67a08a62f03bb9b10b841b420f Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 27 Sep 2024 23:42:28 +0800 Subject: [PATCH 237/336] feat(question): support linking question --- docs/docs.go | 84 +++++++++ docs/swagger.json | 84 +++++++++ docs/swagger.yaml | 51 ++++++ i18n/en_US.yaml | 6 +- i18n/zh_CN.yaml | 5 +- internal/controller/question_controller.go | 22 +++ internal/entity/question_link_entity.go | 44 +++++ internal/migrations/init_data.go | 1 + internal/migrations/migrations.go | 1 + internal/migrations/v23.go | 31 ++++ internal/repo/answer/answer_repo.go | 18 ++ internal/repo/question/question_repo.go | 167 ++++++++++++++++++ internal/router/answer_api_router.go | 1 + internal/schema/question_schema.go | 14 ++ internal/service/answer_common/answer.go | 1 + internal/service/content/answer_service.go | 114 +++++++++++- internal/service/content/question_service.go | 145 ++++++++++++++- internal/service/question_common/question.go | 5 + pkg/checker/question_link.go | 107 +++++++++++ pkg/checker/question_link_test.go | 141 +++++++++++++++ ui/src/components/QuestionList/index.tsx | 2 +- .../components/LinkedQuestions/index.tsx | 126 +++++++++++++ .../Questions/Detail/components/index.tsx | 2 + ui/src/pages/Questions/Detail/index.tsx | 3 + ui/src/pages/Questions/Linked/index.tsx | 95 ++++++++++ ui/src/router/routes.ts | 4 + ui/src/services/client/question.ts | 17 ++ 27 files changed, 1285 insertions(+), 6 deletions(-) create mode 100644 internal/entity/question_link_entity.go create mode 100644 internal/migrations/v23.go create mode 100644 pkg/checker/question_link.go create mode 100644 pkg/checker/question_link_test.go create mode 100644 ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx create mode 100644 ui/src/pages/Questions/Linked/index.tsx diff --git a/docs/docs.go b/docs/docs.go index 80f4a0d8..424bd669 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4462,6 +4462,90 @@ const docTemplate = `{ } } }, + "/answer/api/v1/question/link": { + "get": { + "description": "get question link", + "tags": [ + "Question" + ], + "summary": "get question link", + "parameters": [ + { + "minimum": 1, + "type": "integer", + "name": "in_days", + "in": "query" + }, + { + "enum": [ + "newest", + "active", + "hot", + "score", + "unanswered", + "recommend" + ], + "type": "string", + "name": "order", + "in": "query" + }, + { + "minimum": 1, + "type": "integer", + "name": "page", + "in": "query" + }, + { + "maximum": 100, + "minimum": 1, + "type": "integer", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "name": "question_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/pager.PageModel" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.QuestionPageResp" + } + } + } + } + ] + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/question/operation": { "put": { "security": [ diff --git a/docs/swagger.json b/docs/swagger.json index 5690e67b..7ec493b2 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4435,6 +4435,90 @@ } } }, + "/answer/api/v1/question/link": { + "get": { + "description": "get question link", + "tags": [ + "Question" + ], + "summary": "get question link", + "parameters": [ + { + "minimum": 1, + "type": "integer", + "name": "in_days", + "in": "query" + }, + { + "enum": [ + "newest", + "active", + "hot", + "score", + "unanswered", + "recommend" + ], + "type": "string", + "name": "order", + "in": "query" + }, + { + "minimum": 1, + "type": "integer", + "name": "page", + "in": "query" + }, + { + "maximum": 100, + "minimum": 1, + "type": "integer", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "name": "question_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/definitions/pager.PageModel" + }, + { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.QuestionPageResp" + } + } + } + } + ] + } + } + } + ] + } + } + } + } + }, "/answer/api/v1/question/operation": { "put": { "security": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 6a0ab449..4622e964 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -5586,6 +5586,57 @@ paths: summary: update question invite user tags: - Question + /answer/api/v1/question/link: + get: + description: get question link + parameters: + - in: query + minimum: 1 + name: in_days + type: integer + - enum: + - newest + - active + - hot + - score + - unanswered + - recommend + in: query + name: order + type: string + - in: query + minimum: 1 + name: page + type: integer + - in: query + maximum: 100 + minimum: 1 + name: page_size + type: integer + - in: query + name: question_id + required: true + type: string + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + allOf: + - $ref: '#/definitions/pager.PageModel' + - properties: + list: + items: + $ref: '#/definitions/schema.QuestionPageResp' + type: array + type: object + type: object + summary: get question link + tags: + - Question /answer/api/v1/question/operation: put: consumes: diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index dea08198..f47bca72 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -789,7 +789,8 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

  • link question or answer: #10010000000000001

  • +
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • - -

    • 添加链接

      <https://url.com>

      [标题](https://url.com)
    • 段落之间使用空行分隔

    • _斜体_ 或者 **粗体**

    • 使用 4 个空格缩进代码

    • 在行首添加 > 表示引用

    • 反引号进行转义 `像 _这样_`

    • 使用 ``` 创建代码块

      ```
      这是代码块
      ```
    +
    • 引用问题或答案: #10010000000000001

    • 添加链接

      <https://url.com>

      [标题](https://url.com)
    • 段落之间使用空行分隔

    • _斜体_ 或者 **粗体**

    • 使用 4 个空格缩进代码

    • 在行首添加 > 表示引用

    • 反引号进行转义 `像 _这样_`

    • 使用 ``` 创建代码块

      ```
      这是代码块
      ```
    pagination: prev: 上一页 next: 下一页 @@ -1341,6 +1341,9 @@ ui: related_question: title: 相关问题 answers: 个回答 + linked_question: + title: 关联问题 + no_linked_question: 没有关联的问题。 invite_to_answer: title: 受邀人 desc: 邀请你认为可能知道答案的人。 diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 5ddc33f3..8f349855 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -974,3 +974,25 @@ func (qc *QuestionController) AdminUpdateQuestionStatus(ctx *gin.Context) { err := qc.questionService.AdminSetQuestionStatus(ctx, req) handler.HandleResponse(ctx, err, nil) } + +// GetQuestionLink get question link +// @Summary get question link +// @Description get question link +// @Tags Question +// @Param data query schema.GetQuestionLinkReq true "GetQuestionLinkReq" +// @Success 200 {object} handler.RespBody{data=pager.PageModel{list=[]schema.QuestionPageResp}} +// @Router /answer/api/v1/question/link [get] +func (qc *QuestionController) GetQuestionLink(ctx *gin.Context) { + req := &schema.GetQuestionLinkReq{} + if handler.BindAndCheck(ctx, req) { + return + } + req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx) + req.QuestionID = uid.DeShortID(req.QuestionID) + questions, total, err := qc.questionService.GetQuestionLink(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions)) +} diff --git a/internal/entity/question_link_entity.go b/internal/entity/question_link_entity.go new file mode 100644 index 00000000..825e7595 --- /dev/null +++ b/internal/entity/question_link_entity.go @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package entity + +import ( + "time" +) + +const ( + QuestionLinkStatusAvailable = 1 + QuestionLinkStatusDeleted = 2 +) + +type QuestionLink struct { + ID string `xorm:"not null pk autoincr BIGINT(20) id"` + CreatedAt time.Time `xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` + UpdatedAt time.Time `xorm:"updated_at TIMESTAMP"` + FromQuestionID string `xorm:"not null default 0 BIGINT(20) index from_question_id"` + FromAnswerID string `xorm:"BIGINT(20) from_answer_id"` + ToQuestionID string `xorm:"not null default 0 BIGINT(20) index to_question_id"` + ToAnswerID string `xorm:"BIGINT(20) to_answer_id"` + Status int `xorm:"not null default 1 INT(11) status"` +} + +func (QuestionLink) TableName() string { + return "question_link" +} diff --git a/internal/migrations/init_data.go b/internal/migrations/init_data.go index 50a5651b..b0143b33 100644 --- a/internal/migrations/init_data.go +++ b/internal/migrations/init_data.go @@ -52,6 +52,7 @@ var ( &entity.Meta{}, &entity.Notification{}, &entity.Question{}, + &entity.QuestionLink{}, &entity.Report{}, &entity.Revision{}, &entity.SiteInfo{}, diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index a32e851a..81a54ae7 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -98,6 +98,7 @@ var migrations = []Migration{ NewMigration("v1.3.0", "add review", addReview, false), NewMigration("v1.3.6", "add hot score to question table", addQuestionHotScore, true), NewMigration("v1.4.0", "add badge/badge_group/badge_award table", addBadges, true), + NewMigration("v1.4.1", "add question link", addQuestionLink, true), } func GetMigrations() []Migration { diff --git a/internal/migrations/v23.go b/internal/migrations/v23.go new file mode 100644 index 00000000..8b8a3370 --- /dev/null +++ b/internal/migrations/v23.go @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package migrations + +import ( + "context" + + "github.com/apache/incubator-answer/internal/entity" + "xorm.io/xorm" +) + +func addQuestionLink(ctx context.Context, x *xorm.Engine) (err error) { + return x.Context(ctx).Sync(new(entity.QuestionLink)) +} diff --git a/internal/repo/answer/answer_repo.go b/internal/repo/answer/answer_repo.go index 79dac140..f59d6006 100644 --- a/internal/repo/answer/answer_repo.go +++ b/internal/repo/answer/answer_repo.go @@ -270,6 +270,24 @@ func (ar *answerRepo) GetByID(ctx context.Context, answerID string) (*entity.Ans return &resp, has, nil } +func (ar *answerRepo) GetByIDs(ctx context.Context, answerIDs ...string) ([]*entity.Answer, error) { + for idx, answerID := range answerIDs { + answerIDs[idx] = uid.DeShortID(answerID) + } + var resp = make([]*entity.Answer, 0) + err := ar.data.DB.Context(ctx).In("id", answerIDs).Find(&resp) + if err != nil { + return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + if handler.GetEnableShortID(ctx) { + for _, item := range resp { + item.ID = uid.EnShortID(item.ID) + item.QuestionID = uid.EnShortID(item.QuestionID) + } + } + return resp, nil +} + func (ar *answerRepo) GetCountByQuestionID(ctx context.Context, questionID string) (int64, error) { questionID = uid.DeShortID(questionID) var resp = new(entity.Answer) diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 2c6e595a..30370281 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -611,3 +611,170 @@ func (qr *questionRepo) RemoveAllUserQuestion(ctx context.Context, userID string } return nil } + +// LinkQuestion batch insert question link +func (qr *questionRepo) LinkQuestion(ctx context.Context, link ...*entity.QuestionLink) (err error) { + // Batch retrieve all links + var links []*entity.QuestionLink + for _, l := range link { + l.FromQuestionID = uid.DeShortID(l.FromQuestionID) + l.ToQuestionID = uid.DeShortID(l.ToQuestionID) + l.FromAnswerID = uid.DeShortID(l.FromAnswerID) + l.ToAnswerID = uid.DeShortID(l.ToAnswerID) + links = append(links, l) + } + // Retrieve existing records from the database + var existLinks []*entity.QuestionLink + session := qr.data.DB.Context(ctx) + for _, link := range links { + session = session.Or(builder.Eq{ + "from_question_id": link.FromQuestionID, + "to_question_id": link.ToQuestionID, + "from_answer_id": link.FromAnswerID, + "to_answer_id": link.ToAnswerID, + }) + } + err = session.Find(&existLinks) + if err != nil { + return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + + // Optimize separation of records that need to be updated or inserted using a map + existMap := make(map[string]*entity.QuestionLink) + for _, el := range existLinks { + key := fmt.Sprintf("%s:%s:%s:%s", el.FromQuestionID, el.ToQuestionID, el.FromAnswerID, el.ToAnswerID) + existMap[key] = el + } + + var updateLinks []*entity.QuestionLink + var insertLinks []*entity.QuestionLink + for _, link := range links { + key := fmt.Sprintf("%s:%s:%s:%s", link.FromQuestionID, link.ToQuestionID, link.FromAnswerID, link.ToAnswerID) + if el, exist := existMap[key]; exist { + if el.Status == entity.QuestionLinkStatusDeleted { + el.Status = entity.QuestionLinkStatusAvailable + el.UpdatedAt = time.Now() + updateLinks = append(updateLinks, el) + } + } else { + link.Status = entity.QuestionLinkStatusAvailable + link.CreatedAt = time.Now() + link.UpdatedAt = time.Now() + insertLinks = append(insertLinks, link) + } + } + + // Batch update + if len(updateLinks) > 0 { + for _, link := range updateLinks { + _, err = qr.data.DB.Context(ctx).ID(link.ID).Cols("status").Update(&entity.QuestionLink{Status: entity.QuestionLinkStatusAvailable}) + if err != nil { + return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + } + } + + // Batch insert + if len(insertLinks) > 0 { + _, err = qr.data.DB.Context(ctx).Insert(insertLinks) + if err != nil { + return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + } + + return +} + +// RecoverQuestionLink batch recover question link +func (qr *questionRepo) RecoverQuestionLink(ctx context.Context, links ...*entity.QuestionLink) (err error) { + return qr.UpdateQuestionLinkStatus(ctx, entity.QuestionLinkStatusAvailable, links...) +} + +// RemoveQuestionLink batch remove question link +func (qr *questionRepo) RemoveQuestionLink(ctx context.Context, links ...*entity.QuestionLink) (err error) { + return qr.UpdateQuestionLinkStatus(ctx, entity.QuestionLinkStatusDeleted, links...) +} + +// UpdateQuestionLinkStatus update question link status +func (qr *questionRepo) UpdateQuestionLinkStatus(ctx context.Context, status int, links ...*entity.QuestionLink) (err error) { + if len(links) == 0 { + return nil + } + + session := qr.data.DB.Context(ctx).Cols("status") + for _, link := range links { + eq := builder.Eq{} + if link.FromQuestionID != "" { + eq["from_question_id"] = uid.DeShortID(link.FromQuestionID) + } + if link.FromAnswerID != "" { + eq["from_answer_id"] = uid.DeShortID(link.FromAnswerID) + } + if link.ToQuestionID != "" { + eq["to_question_id"] = uid.DeShortID(link.ToQuestionID) + } + if link.ToAnswerID != "" { + eq["to_answer_id"] = uid.DeShortID(link.ToAnswerID) + } + session = session.Or(eq) + } + _, err = session.Update(&entity.QuestionLink{Status: status}) + if err != nil { + return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + +// GetQuestionLink get linked question to questionID +func (qr *questionRepo) GetQuestionLink(ctx context.Context, page, pageSize int, questionID string, orderCond string, inDays int) (questionList []*entity.Question, total int64, err error) { + questionList = make([]*entity.Question, 0) + questionID = uid.DeShortID(questionID) + questionStatus := []int{entity.QuestionStatusAvailable, entity.QuestionStatusPending} + if questionID == "0" { + return nil, 0, errors.InternalServer(reason.DatabaseError).WithError( + fmt.Errorf("questionID is empty"), + ).WithStack() + } + + session := qr.data.DB.Context(ctx). + Table("question_link"). + Join("INNER", "question", "question_link.from_question_id = question.id"). + Where("question_link.to_question_id = ? AND question.show = ?", questionID, entity.QuestionShow). + Distinct("question.id"). + Where("question_link.status = ?", entity.QuestionLinkStatusAvailable). + Select("question.*"). + In("question.status", questionStatus) + + switch orderCond { + case "newest": + session.OrderBy("question.pin desc,question.created_at DESC") + case "active": + if inDays == 0 { + session.And("question.created_at > ?", time.Now().AddDate(0, 0, -180)) + } + session.And("question.post_update_time > ?", time.Now().AddDate(0, 0, -90)) + session.OrderBy("question.pin desc,question.post_update_time DESC, question.updated_at DESC") + case "hot": + session.OrderBy("question.pin desc,question.hot_score DESC") + case "score": + session.OrderBy("question.pin desc,question.vote_count DESC, question.view_count DESC") + case "unanswered": + session.Where("question.answer_count = 0") + session.OrderBy("question.pin desc,question.created_at DESC") + } + + if page > 0 && pageSize > 0 { + session.Limit(pageSize, (page-1)*pageSize) + } + + total, err = pager.Help(page, pageSize, &questionList, &entity.Question{}, session) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + if handler.GetEnableShortID(ctx) { + for _, item := range questionList { + item.ID = uid.EnShortID(item.ID) + } + } + return +} diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index cca997bd..2927afef 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -169,6 +169,7 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) { r.GET("/question/similar/tag", a.questionController.SimilarQuestion) r.GET("/personal/qa/top", a.questionController.UserTop) r.GET("/personal/question/page", a.questionController.PersonalQuestionPage) + r.GET("/question/link", a.questionController.GetQuestionLink) // comment r.GET("/comment/page", a.commentController.GetCommentWithPage) diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index 2a6e5f12..7c605765 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -498,3 +498,17 @@ type PersonalCollectionPageReq struct { PageSize int `validate:"omitempty,min=1" form:"page_size"` UserID string `json:"-"` } + +type GetQuestionLinkReq struct { + Page int `validate:"omitempty,min=1" form:"page"` + PageSize int `validate:"omitempty,min=1,max=100" form:"page_size"` + QuestionID string `validate:"required" form:"question_id"` + OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered recommend" form:"order"` + InDays int `validate:"omitempty,min=1" form:"in_days"` + + LoginUserID string `json:"-"` +} + +type GetQuestionLinkResp struct { + QuestionPageResp +} diff --git a/internal/service/answer_common/answer.go b/internal/service/answer_common/answer.go index 1517b22d..45b11886 100644 --- a/internal/service/answer_common/answer.go +++ b/internal/service/answer_common/answer.go @@ -39,6 +39,7 @@ type AnswerRepo interface { GetAnswerPage(ctx context.Context, page, pageSize int, answer *entity.Answer) (answerList []*entity.Answer, total int64, err error) UpdateAcceptedStatus(ctx context.Context, acceptedAnswerID string, questionID string) error GetByID(ctx context.Context, answerID string) (*entity.Answer, bool, error) + GetByIDs(ctx context.Context, answerIDs ...string) ([]*entity.Answer, error) GetCountByQuestionID(ctx context.Context, questionID string) (int64, error) GetCountByUserID(ctx context.Context, userID string) (int64, error) GetIDsByUserIDAndQuestionID(ctx context.Context, userID string, questionID string) ([]string, error) diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index c34e9081..e8842891 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -22,9 +22,11 @@ package content import ( "context" "encoding/json" - "github.com/apache/incubator-answer/internal/service/event_queue" + "strings" "time" + "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" @@ -42,6 +44,7 @@ import ( "github.com/apache/incubator-answer/internal/service/revision_common" "github.com/apache/incubator-answer/internal/service/role" usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/incubator-answer/pkg/checker" "github.com/apache/incubator-answer/pkg/converter" "github.com/apache/incubator-answer/pkg/htmltext" "github.com/apache/incubator-answer/pkg/token" @@ -166,6 +169,17 @@ func (as *AnswerService) RemoveAnswer(ctx context.Context, req *schema.RemoveAns if err != nil { log.Error("user IncreaseAnswerCount error", err.Error()) } + err = as.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: answerInfo.QuestionID, + FromAnswerID: answerInfo.ID, + }, &entity.QuestionLink{ + ToQuestionID: answerInfo.QuestionID, + ToAnswerID: answerInfo.ID, + }) + if err != nil { + log.Error("RemoveQuestionLink error", err.Error()) + } + // #2372 In order to simplify the process and complexity, as well as to consider if it is in-house, // facing the problem of recovery. //err = as.answerActivityService.DeleteAnswer(ctx, answerInfo.ID, answerInfo.CreatedAt, answerInfo.VoteCount) @@ -199,6 +213,15 @@ func (as *AnswerService) RecoverAnswer(ctx context.Context, req *schema.RecoverA if err = as.answerRepo.RecoverAnswer(ctx, req.AnswerID); err != nil { return err } + if err = as.questionRepo.RecoverQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: answerInfo.QuestionID, + FromAnswerID: answerInfo.ID, + }, &entity.QuestionLink{ + ToQuestionID: answerInfo.QuestionID, + ToAnswerID: answerInfo.ID, + }); err != nil { + return err + } if err = as.questionCommon.UpdateAnswerCount(ctx, answerInfo.QuestionID); err != nil { log.Errorf("update answer count failed: %s", err.Error()) @@ -251,6 +274,15 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) ( if err := as.answerRepo.UpdateAnswerStatus(ctx, insertData.ID, insertData.Status); err != nil { return "", err } + if insertData.Status == entity.AnswerStatusAvailable { + insertData.ParsedText, err = as.updateAnswerLink(ctx, insertData) + if err != nil { + return "", err + } + if err = as.answerRepo.UpdateAnswer(ctx, insertData, []string{"parsed_text"}); err != nil { + return "", err + } + } err = as.questionCommon.UpdateAnswerCount(ctx, req.QuestionID) if err != nil { log.Error("IncreaseAnswerCount error", err.Error()) @@ -366,6 +398,10 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq if !canUpdate { revisionDTO.Status = entity.RevisionUnreviewedStatus } else { + insertData.ParsedText, err = as.updateAnswerLink(ctx, insertData) + if err != nil { + return "", err + } if err = as.answerRepo.UpdateAnswer(ctx, insertData, []string{"original_text", "parsed_text", "updated_at", "last_edit_user_id"}); err != nil { return "", err } @@ -710,3 +746,79 @@ func (as *AnswerService) notificationAnswerTheQuestion(ctx context.Context, externalNotificationMsg.NewAnswerTemplateRawData = rawData as.externalNotificationQueueService.Send(ctx, externalNotificationMsg) } + +func (as *AnswerService) updateAnswerLink(ctx context.Context, answer *entity.Answer) (string, error) { + err := as.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: uid.DeShortID(answer.QuestionID), + FromAnswerID: uid.DeShortID(answer.ID), + }) + retParsedText := answer.ParsedText + if err != nil { + return retParsedText, err + } + links := checker.GetQuestionLink(answer.OriginalText) + // validate links + questionLinks := make([]*entity.QuestionLink, 0) + answerCache := make(map[string]string) + questionCache := make(map[string]string) + answerIDList := make([]string, 0) + questionIDList := make([]string, 0) + for _, link := range links { + if link.AnswerID != "" { + answerIDList = append(answerIDList, link.AnswerID) + } + if link.QuestionID != "" { + questionIDList = append(questionIDList, link.QuestionID) + } + } + answerInfoList, err := as.answerRepo.GetByIDs(ctx, answerIDList...) + if err != nil { + return answer.ParsedText, err + } + for _, answer := range answerInfoList { + answerCache[answer.ID] = answer.QuestionID + } + questionInfoList, err := as.questionRepo.FindByID(ctx, questionIDList) + if err != nil { + return answer.ParsedText, err + } + for _, question := range questionInfoList { + questionCache[question.ID] = question.ParsedText + } + + for _, link := range links { + if link.QuestionID != "" { + if _, ok := questionCache[link.QuestionID]; !ok { + continue + } + } + if link.AnswerID != "" { + if _, ok := answerCache[link.AnswerID]; !ok { + continue + } + if link.QuestionID == "" { + link.QuestionID = answerCache[link.AnswerID] + } + } + + questionLinks = append(questionLinks, &entity.QuestionLink{ + FromQuestionID: uid.DeShortID(answer.QuestionID), + FromAnswerID: uid.DeShortID(answer.ID), + ToQuestionID: uid.DeShortID(link.QuestionID), + ToAnswerID: uid.DeShortID(link.AnswerID), + }) + + if link.QuestionID != "" { + retParsedText = strings.Replace(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"", -1) + } + if link.AnswerID != "" { + questionID := answerCache[link.AnswerID] + retParsedText = strings.Replace(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"", -1) + } + } + if err = as.questionRepo.LinkQuestion(ctx, questionLinks...); err != nil { + return retParsedText, err + } + + return retParsedText, nil +} diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index 9a6dd280..a57d3fac 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -22,10 +22,11 @@ package content import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/service/event_queue" "strings" "time" + "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/pager" @@ -347,6 +348,16 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question if err := qs.questionRepo.UpdateQuestionStatus(ctx, question.ID, question.Status); err != nil { return nil, err } + if question.Status == entity.QuestionStatusAvailable { + question.ParsedText, err = qs.updateQuestionLink(ctx, question) + if err != nil { + return nil, err + } + err = qs.questionRepo.UpdateQuestion(ctx, question, []string{"parsed_text"}) + if err != nil { + return nil, err + } + } objectTagData := schema.TagChange{} objectTagData.ObjectID = question.ID objectTagData.Tags = req.Tags @@ -425,6 +436,14 @@ func (qs *QuestionService) OperationQuestion(ctx context.Context, req *schema.Op switch req.Operation { case schema.QuestionOperationHide: questionInfo.Show = entity.QuestionHide + err = qs.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: questionInfo.ID, + }, &entity.QuestionLink{ + ToQuestionID: questionInfo.ID, + }) + if err != nil { + return + } err = qs.tagCommon.HideTagRelListByObjectID(ctx, req.ID) if err != nil { return err @@ -435,6 +454,14 @@ func (qs *QuestionService) OperationQuestion(ctx context.Context, req *schema.Op } case schema.QuestionOperationShow: questionInfo.Show = entity.QuestionShow + err = qs.questionRepo.RecoverQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: questionInfo.ID, + }, &entity.QuestionLink{ + ToQuestionID: questionInfo.ID, + }) + if err != nil { + return + } err = qs.tagCommon.ShowTagRelListByObjectID(ctx, req.ID) if err != nil { return err @@ -553,6 +580,14 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov // if err != nil { // log.Errorf("user DeleteQuestion rank rollback error %s", err.Error()) // } + err = qs.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: questionInfo.ID, + }, &entity.QuestionLink{ + ToQuestionID: questionInfo.ID, + }) + if err != nil { + return + } qs.activityQueueService.Send(ctx, &schema.ActivityMsg{ UserID: questionInfo.UserID, TriggerUserID: converter.StringToInt64(req.UserID), @@ -677,6 +712,14 @@ func (qs *QuestionService) RecoverQuestion(ctx context.Context, req *schema.Ques log.Errorf("update tag's question count failed, %v", err) } } + err = qs.questionRepo.RecoverQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: questionInfo.ID, + }, &entity.QuestionLink{ + ToQuestionID: questionInfo.ID, + }) + if err != nil { + return + } qs.activityQueueService.Send(ctx, &schema.ActivityMsg{ UserID: req.UserID, @@ -921,6 +964,10 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest //Direct modification revisionDTO.Status = entity.RevisionReviewPassStatus //update question to db + question.ParsedText, err = qs.updateQuestionLink(ctx, question) + if err != nil { + return questionInfo, err + } saveerr := qs.questionRepo.UpdateQuestion(ctx, question, []string{"title", "original_text", "parsed_text", "updated_at", "post_update_time", "last_edit_user_id"}) if saveerr != nil { return questionInfo, saveerr @@ -930,7 +977,7 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest objectTagData.Tags = req.Tags objectTagData.UserID = req.UserID tagerr := qs.ChangeTag(ctx, &objectTagData) - if err != nil { + if tagerr != nil { return questionInfo, tagerr } } @@ -1573,3 +1620,97 @@ func (qs *QuestionService) SitemapCron(ctx context.Context) { ctx = context.WithValue(ctx, constant.ShortIDFlag, siteSeo.IsShortLink()) qs.questioncommon.SitemapCron(ctx) } + +func (qs *QuestionService) updateQuestionLink(ctx context.Context, questionInfo *entity.Question) (string, error) { + err := qs.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: questionInfo.ID, + FromAnswerID: "0", + }) + if err != nil { + return questionInfo.ParsedText, err + } + retParsedText := questionInfo.ParsedText + links := checker.GetQuestionLink(questionInfo.OriginalText) + // validate links + questionLinks := make([]*entity.QuestionLink, 0) + answerCache := make(map[string]string) + questionCache := make(map[string]string) + answerIDList := make([]string, 0) + questionIDList := make([]string, 0) + for _, link := range links { + if link.AnswerID != "" { + answerIDList = append(answerIDList, link.AnswerID) + } + if link.QuestionID != "" { + questionIDList = append(questionIDList, link.QuestionID) + } + } + answerInfoList, err := qs.answerRepo.GetByIDs(ctx, answerIDList...) + if err != nil { + return questionInfo.ParsedText, err + } + for _, answer := range answerInfoList { + answerCache[answer.ID] = answer.QuestionID + } + questionInfoList, err := qs.questionRepo.FindByID(ctx, questionIDList) + if err != nil { + return questionInfo.ParsedText, err + } + for _, question := range questionInfoList { + questionCache[question.ID] = question.ParsedText + } + + for _, link := range links { + if link.QuestionID != "" { + if _, ok := questionCache[link.QuestionID]; !ok { + continue + } + } + if link.AnswerID != "" { + if _, ok := answerCache[link.AnswerID]; !ok { + continue + } + if link.QuestionID == "" { + link.QuestionID = answerCache[link.AnswerID] + } + } + + questionLinks = append(questionLinks, &entity.QuestionLink{ + FromQuestionID: uid.DeShortID(questionInfo.ID), + FromAnswerID: "0", + ToQuestionID: uid.DeShortID(link.QuestionID), + ToAnswerID: uid.DeShortID(link.AnswerID), + }) + + if link.QuestionID != "" { + retParsedText = strings.Replace(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"", -1) + } + if link.AnswerID != "" { + questionID := answerCache[link.AnswerID] + retParsedText = strings.Replace(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"", -1) + } + } + if err = qs.questionRepo.LinkQuestion(ctx, questionLinks...); err != nil { + return retParsedText, err + } + + return retParsedText, nil +} + +func (qs *QuestionService) GetQuestionLink(ctx context.Context, req *schema.GetQuestionLinkReq) ( + questions []*schema.QuestionPageResp, total int64, err error) { + if req.OrderCond == schema.QuestionOrderCondHot { + req.InDays = schema.HotInDays + } + + questionList, total, err := qs.questionRepo.GetQuestionLink(ctx, req.Page, req.PageSize, req.QuestionID, req.OrderCond, req.InDays) + if err != nil { + return nil, 0, err + } + + questions, err = qs.questioncommon.FormatQuestionsPage(ctx, questionList, req.LoginUserID, req.OrderCond) + if err != nil { + return nil, 0, err + } + return questions, total, nil +} diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index 5dab1214..f242b3f8 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -75,6 +75,11 @@ type QuestionRepo interface { SitemapQuestions(ctx context.Context, page, pageSize int) (questionIDList []*schema.SiteMapQuestionInfo, err error) RemoveAllUserQuestion(ctx context.Context, userID string) (err error) UpdateSearch(ctx context.Context, questionID string) (err error) + LinkQuestion(ctx context.Context, link ...*entity.QuestionLink) (err error) + RemoveQuestionLink(ctx context.Context, link ...*entity.QuestionLink) (err error) + RecoverQuestionLink(ctx context.Context, link ...*entity.QuestionLink) (err error) + UpdateQuestionLinkStatus(ctx context.Context, status int, links ...*entity.QuestionLink) (err error) + GetQuestionLink(ctx context.Context, page, pageSize int, questionID string, orderCond string, inDays int) (questions []*entity.Question, total int64, err error) } // QuestionCommon user service diff --git a/pkg/checker/question_link.go b/pkg/checker/question_link.go new file mode 100644 index 00000000..5907affa --- /dev/null +++ b/pkg/checker/question_link.go @@ -0,0 +1,107 @@ +package checker + +import ( + "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/incubator-answer/pkg/obj" +) + +const ( + QuestionLinkTypeURL = 1 + QuestionLinkTypeID = 2 +) + +type QuestionLink struct { + LinkType int + QuestionID string + AnswerID string +} + +func GetQuestionLink(content string) []QuestionLink { + uniqueIDs := make(map[string]struct{}) + var questionLinks []QuestionLink + + // use two pointer to find the link + left, right := 0, 0 + for right < len(content) { + // find "/questions/" or "#" + if right+11 < len(content) && content[right:right+11] == "/questions/" { + left = right + right += 11 + processURL(content, &left, &right, uniqueIDs, &questionLinks) + } else if content[right] == '#' { + left = right + 1 + right = left + processID(content, &left, &right, uniqueIDs, &questionLinks) + } else { + right++ + } + } + + return questionLinks +} + +func processURL(content string, left, right *int, uniqueIDs map[string]struct{}, questionLinks *[]QuestionLink) { + for *right < len(content) && isDigit(content[*right]) { + *right++ + } + questionID := content[*left+len("/questions/") : *right] + + answerID := "" + if *right < len(content) && content[*right] == '/' { + *left = *right + 1 + *right = *left + for *right < len(content) && isDigit(content[*right]) { + *right++ + } + answerID = content[*left:*right] + } + + addUniqueID(questionID, answerID, QuestionLinkTypeURL, uniqueIDs, questionLinks) +} + +func processID(content string, left, right *int, uniqueIDs map[string]struct{}, questionLinks *[]QuestionLink) { + for *right < len(content) && isDigit(content[*right]) { + *right++ + } + id := content[*left:*right] + addUniqueID(id, "", QuestionLinkTypeID, uniqueIDs, questionLinks) +} + +func isDigit(c byte) bool { + return c >= '0' && c <= '9' +} + +func addUniqueID(questionID, answerID string, linkType int, uniqueIDs map[string]struct{}, questionLinks *[]QuestionLink) { + if questionID == "" && answerID == "" { + return + } + + isAdd := false + if answerID != "" { + if objectType, err := obj.GetObjectTypeStrByObjectID(answerID); err == nil && objectType == constant.AnswerObjectType { + if _, ok := uniqueIDs[answerID]; !ok { + uniqueIDs[answerID] = struct{}{} + isAdd = true + } + } + } + + if objectType, err := obj.GetObjectTypeStrByObjectID(questionID); err == nil { + if _, ok := uniqueIDs[questionID]; !ok { + uniqueIDs[questionID] = struct{}{} + isAdd = true + if objectType == constant.AnswerObjectType { + answerID = questionID + questionID = "" + } + } + } + + if isAdd { + *questionLinks = append(*questionLinks, QuestionLink{ + LinkType: linkType, + QuestionID: questionID, + AnswerID: answerID, + }) + } +} diff --git a/pkg/checker/question_link_test.go b/pkg/checker/question_link_test.go new file mode 100644 index 00000000..9d734126 --- /dev/null +++ b/pkg/checker/question_link_test.go @@ -0,0 +1,141 @@ +package checker_test + +import ( + "testing" + + "github.com/apache/incubator-answer/pkg/checker" + "github.com/stretchr/testify/assert" +) + +func TestGetQuestionLink(t *testing.T) { + // Step 1: Test empty content + t.Run("Empty content", func(t *testing.T) { + links := checker.GetQuestionLink("") + assert.Empty(t, links) + }) + + // Step 2: Test content without link or ID + t.Run("Content without link or ID", func(t *testing.T) { + links := checker.GetQuestionLink("This is a random text") + assert.Empty(t, links) + }) + + // Step 3: Test content with valid question link + t.Run("Valid question link", func(t *testing.T) { + links := checker.GetQuestionLink("Check this question: https://example.com/questions/10010000000000060") + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000060", + AnswerID: "", + }, + }, links) + }) + + // Step 4: Test content with valid question and answer link + t.Run("Valid question and answer link", func(t *testing.T) { + links := checker.GetQuestionLink("Check this answer: https://example.com/questions/10010000000000060/10020000000000060?from=copy") + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000060", + AnswerID: "10020000000000060", + }, + }, links) + }) + + // Step 5: Test content with #questionID + t.Run("Content with #questionID", func(t *testing.T) { + links := checker.GetQuestionLink("This is question #10010000000000060") + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeID, + QuestionID: "10010000000000060", + AnswerID: "", + }, + }, links) + }) + + // Step 6: Test content with #answerID + t.Run("Content with #answerID", func(t *testing.T) { + links := checker.GetQuestionLink("This is answer #10020000000000060") + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeID, + QuestionID: "", + AnswerID: "10020000000000060", + }, + }, links) + }) + + // Step 7: Test invalid question ID + t.Run("Invalid question ID", func(t *testing.T) { + links := checker.GetQuestionLink("https://example.com/questions/invalid") + assert.Empty(t, links) + }) + + // Step 8: Test invalid answer ID + t.Run("Invalid answer ID", func(t *testing.T) { + links := checker.GetQuestionLink("https://example.com/questions/10010000000000060/invalid") + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000060", + AnswerID: "", + }, + }, links) + }) + + // Step 9: Test content with multiple links and IDs + t.Run("Multiple links and IDs", func(t *testing.T) { + content := "Question #10010000000000060 and https://example.com/questions/10010000000000060/10020000000000061 and https://example.com/questions/10010000000000065/10020000000000066 and another #10020000000000066" + links := checker.GetQuestionLink(content) + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeID, + QuestionID: "10010000000000060", + AnswerID: "", + }, + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000060", + AnswerID: "10020000000000061", + }, + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000065", + AnswerID: "10020000000000066", + }, + }, links) + }) + + // Step 11: Test URL with www prefix + t.Run("URL with www prefix", func(t *testing.T) { + links := checker.GetQuestionLink("Check this question: https://www.example.com/questions/10010000000000060") + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000060", + AnswerID: "", + }, + }, links) + }) + + // Step 12: Test URL without protocol + t.Run("URL without protocol", func(t *testing.T) { + links := checker.GetQuestionLink("Check this question: example.com/questions/10010000000000060") + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000060", + AnswerID: "", + }, + }, links) + }) + + // Step 14: Test error id + t.Run("Error id", func(t *testing.T) { + links := checker.GetQuestionLink("https://example.com/questions/10110000000000060") + assert.Empty(t, links) + }) +} diff --git a/ui/src/components/QuestionList/index.tsx b/ui/src/components/QuestionList/index.tsx index c41f4b9d..066711bb 100644 --- a/ui/src/components/QuestionList/index.tsx +++ b/ui/src/components/QuestionList/index.tsx @@ -46,7 +46,7 @@ export const QUESTION_ORDER_KEYS: Type.QuestionOrderBy[] = [ 'recommend', ]; interface Props { - source: 'questions' | 'tag'; + source: 'questions' | 'tag' | 'linked'; order?: Type.QuestionOrderBy; data; orderList?: Type.QuestionOrderBy[]; diff --git a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx new file mode 100644 index 00000000..a3a7a67a --- /dev/null +++ b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { memo, FC } from 'react'; +import { Card, ListGroup } from 'react-bootstrap'; +import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; + +import { Icon } from '@/components'; +import { useQuestionLink } from '@/services'; +import { pathFactory } from '@/router/pathFactory'; + +interface Props { + id: string; +} +const Index: FC = ({ id }) => { + const { t } = useTranslation('translation', { + keyPrefix: 'linked_question', + }); + const { t: t2 } = useTranslation('translation', { + keyPrefix: 'related_question', + }); + + const { data, isLoading } = useQuestionLink({ + question_id: id, + page: 1, + page_size: 5, + }); + + if (isLoading) { + return null; + } + + if (!data || !data.list) { + return ( + + + {t('title')} + + {t('more', { keyPrefix: 'btns' })} + + + +
    + {t('no_linked_question')} +
    +
    +
    + ); + } + + return ( + + + {t('title')} + + {t('more', { keyPrefix: 'btns' })} + + + + {data.list.map((item) => { + return ( + +
    {item.title}
    + {item.answer_count > 0 && ( +
    0 + ? 'link-success' + : 'link-secondary' + }`}> + 0 + ? 'check-circle-fill' + : 'chat-square-text-fill' + } + className="me-1" + /> + + {item.answer_count} {t2('answers')} + +
    + )} +
    + ); + })} + {data.list.length === 0 ? ( +
    + {t('no_linked_question')} +
    + ) : null} +
    +
    + ); +}; + +export default memo(Index); diff --git a/ui/src/pages/Questions/Detail/components/index.tsx b/ui/src/pages/Questions/Detail/components/index.tsx index 1cfe75ee..ee665790 100644 --- a/ui/src/pages/Questions/Detail/components/index.tsx +++ b/ui/src/pages/Questions/Detail/components/index.tsx @@ -25,6 +25,7 @@ import WriteAnswer from './WriteAnswer'; import Alert from './Alert'; import ContentLoader from './ContentLoader'; import InviteToAnswer from './InviteToAnswer'; +import LinkedQuestions from './LinkedQuestions'; export { Question, @@ -35,4 +36,5 @@ export { Alert, ContentLoader, InviteToAnswer, + LinkedQuestions, }; diff --git a/ui/src/pages/Questions/Detail/index.tsx b/ui/src/pages/Questions/Detail/index.tsx index 0ab02514..8c8921b8 100644 --- a/ui/src/pages/Questions/Detail/index.tsx +++ b/ui/src/pages/Questions/Detail/index.tsx @@ -47,6 +47,7 @@ import { Alert, ContentLoader, InviteToAnswer, + LinkedQuestions, } from './components'; import './index.scss'; @@ -230,6 +231,7 @@ const Index = () => { }); const showInviteToAnswer = question?.id; + const showLinkedQuestions = question?.id && question.id !== ''; let canInvitePeople = false; if (showInviteToAnswer && Array.isArray(question.extends_actions)) { const inviteAct = question.extends_actions.find((op) => { @@ -305,6 +307,7 @@ const Index = () => { readOnly={!canInvitePeople} /> ) : null} + {showLinkedQuestions ? : null} diff --git a/ui/src/pages/Questions/Linked/index.tsx b/ui/src/pages/Questions/Linked/index.tsx new file mode 100644 index 00000000..14224d77 --- /dev/null +++ b/ui/src/pages/Questions/Linked/index.tsx @@ -0,0 +1,95 @@ +import { FC } from 'react'; +import { Row, Col } from 'react-bootstrap'; +import { useParams, useSearchParams, Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; + +import { usePageTags } from '@/hooks'; +import { useQuestionLink } from '@/services'; +import * as Type from '@/common/interface'; +import { + QuestionList, + CustomSidebar, + HotQuestions, + FollowingTags, +} from '@/components'; +import { userCenter, floppyNavigation } from '@/utils'; +import { QUESTION_ORDER_KEYS } from '@/components/QuestionList'; +import { + loggedUserInfoStore, + siteInfoStore, + loginSettingStore, +} from '@/stores'; + +const LinkedQuestions: FC = () => { + const { qid } = useParams<{ qid: string }>(); + const { t } = useTranslation('translation', { keyPrefix: 'linked_question' }); + const { t: t2 } = useTranslation('translation'); + const { user: loggedUser } = loggedUserInfoStore((_) => _); + const [urlSearchParams] = useSearchParams(); + const curPage = Number(urlSearchParams.get('page')) || 1; + const curOrder = (urlSearchParams.get('order') || + QUESTION_ORDER_KEYS[0]) as Type.QuestionOrderBy; + const pageSize = 10; + const { siteInfo } = siteInfoStore(); + const { data: listData, isLoading: listLoading } = useQuestionLink({ + question_id: qid || '', + page: curPage, + page_size: pageSize, + }); + const { login: loginSetting } = loginSettingStore(); + + usePageTags({ + title: t('title'), + }); + + return ( + + + key !== 'recommend') + } + isLoading={listLoading} + /> + + + + {!loggedUser.username && ( +
    +
    +
    + {t2('website_welcome', { + site_name: siteInfo.name, + })} +
    +

    {siteInfo.description}

    + + {t('login', { keyPrefix: 'btns' })} + + {loginSetting.allow_new_registrations ? ( + + {t('signup', { keyPrefix: 'btns' })} + + ) : null} +
    +
    + )} + {loggedUser.access_token && } + + +
    + ); +}; + +export default LinkedQuestions; diff --git a/ui/src/router/routes.ts b/ui/src/router/routes.ts index aa31266e..b89f312c 100644 --- a/ui/src/router/routes.ts +++ b/ui/src/router/routes.ts @@ -107,6 +107,10 @@ const routes: RouteNode[] = [ path: 'questions/:qid/:slugPermalink/:aid', page: 'pages/Questions/Detail', }, + { + path: 'questions/linked/:qid', + page: 'pages/Questions/Linked', + }, { path: '/search', page: 'pages/Search', diff --git a/ui/src/services/client/question.ts b/ui/src/services/client/question.ts index b62fbf1a..34d1e75c 100644 --- a/ui/src/services/client/question.ts +++ b/ui/src/services/client/question.ts @@ -119,3 +119,20 @@ export const unDeleteQuestion = (qid) => { question_id: qid, }); }; + +export const useQuestionLink = (params: { + question_id: string; + page: number; + page_size: number; +}) => { + const apiUrl = `/answer/api/v1/question/link?${qs.stringify(params)}`; + const { data, error } = useSWR( + [apiUrl, params], + request.instance.get, + ); + return { + data, + isLoading: !data && !error, + error, + }; +}; From f575aa9b5f7ff053b78f4b07e3bc1f19f90b7644 Mon Sep 17 00:00:00 2001 From: Sonui Date: Sat, 28 Sep 2024 00:00:06 +0800 Subject: [PATCH 238/336] docs: add Apache License headers to source files --- pkg/checker/question_link.go | 19 +++++++++++++++++++ pkg/checker/question_link_test.go | 19 +++++++++++++++++++ ui/src/pages/Questions/Linked/index.tsx | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/pkg/checker/question_link.go b/pkg/checker/question_link.go index 5907affa..ca8327b6 100644 --- a/pkg/checker/question_link.go +++ b/pkg/checker/question_link.go @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package checker import ( diff --git a/pkg/checker/question_link_test.go b/pkg/checker/question_link_test.go index 9d734126..6b9f9483 100644 --- a/pkg/checker/question_link_test.go +++ b/pkg/checker/question_link_test.go @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package checker_test import ( diff --git a/ui/src/pages/Questions/Linked/index.tsx b/ui/src/pages/Questions/Linked/index.tsx index 14224d77..fa0e0bdb 100644 --- a/ui/src/pages/Questions/Linked/index.tsx +++ b/ui/src/pages/Questions/Linked/index.tsx @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + import { FC } from 'react'; import { Row, Col } from 'react-bootstrap'; import { useParams, useSearchParams, Link } from 'react-router-dom'; From d0d275a6c4bcd109428d1d60fe8fb7936261eef5 Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 4 Oct 2024 20:25:41 +0800 Subject: [PATCH 239/336] style: move questionLink function to common service --- .../Detail/components/LinkedQuestions/index.tsx | 4 ++-- ui/src/services/client/question.ts | 17 ----------------- ui/src/services/common.ts | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx index a3a7a67a..8e5a57dd 100644 --- a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx +++ b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx @@ -23,7 +23,7 @@ import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Icon } from '@/components'; -import { useQuestionLink } from '@/services'; +import { questionLink } from '@/services'; import { pathFactory } from '@/router/pathFactory'; interface Props { @@ -37,7 +37,7 @@ const Index: FC = ({ id }) => { keyPrefix: 'related_question', }); - const { data, isLoading } = useQuestionLink({ + const { data, isLoading } = questionLink({ question_id: id, page: 1, page_size: 5, diff --git a/ui/src/services/client/question.ts b/ui/src/services/client/question.ts index 34d1e75c..b62fbf1a 100644 --- a/ui/src/services/client/question.ts +++ b/ui/src/services/client/question.ts @@ -119,20 +119,3 @@ export const unDeleteQuestion = (qid) => { question_id: qid, }); }; - -export const useQuestionLink = (params: { - question_id: string; - page: number; - page_size: number; -}) => { - const apiUrl = `/answer/api/v1/question/link?${qs.stringify(params)}`; - const { data, error } = useSWR( - [apiUrl, params], - request.instance.get, - ); - return { - data, - isLoading: !data && !error, - error, - }; -}; diff --git a/ui/src/services/common.ts b/ui/src/services/common.ts index dff52cb7..ad0d99e0 100644 --- a/ui/src/services/common.ts +++ b/ui/src/services/common.ts @@ -199,6 +199,23 @@ export const questionDetail = (id: string) => { ); }; +export const questionLink = (params: { + question_id: string; + page: number; + page_size: number; +}) => { + const apiUrl = `/answer/api/v1/question/link?${qs.stringify(params)}`; + const { data, error } = useSWR( + [apiUrl, params], + request.instance.get, + ); + return { + data, + isLoading: !data && !error, + error, + }; +}; + export const getAnswers = (params: Type.AnswersReq) => { const apiUrl = `/answer/api/v1/answer/page?${qs.stringify(params)}`; return request.get>(apiUrl); From 6f576c29ea503dace1da02cb8dd1c930819b65d1 Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 4 Oct 2024 20:26:55 +0800 Subject: [PATCH 240/336] feat: add title to question linked page --- ui/src/pages/Questions/Linked/index.tsx | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ui/src/pages/Questions/Linked/index.tsx b/ui/src/pages/Questions/Linked/index.tsx index fa0e0bdb..aabba7bb 100644 --- a/ui/src/pages/Questions/Linked/index.tsx +++ b/ui/src/pages/Questions/Linked/index.tsx @@ -17,13 +17,13 @@ * under the License. */ -import { FC } from 'react'; +import { FC, useState } from 'react'; import { Row, Col } from 'react-bootstrap'; import { useParams, useSearchParams, Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { usePageTags } from '@/hooks'; -import { useQuestionLink } from '@/services'; +import { questionLink, questionDetail } from '@/services'; import * as Type from '@/common/interface'; import { QuestionList, @@ -50,13 +50,21 @@ const LinkedQuestions: FC = () => { QUESTION_ORDER_KEYS[0]) as Type.QuestionOrderBy; const pageSize = 10; const { siteInfo } = siteInfoStore(); - const { data: listData, isLoading: listLoading } = useQuestionLink({ + const { data: listData, isLoading: listLoading } = questionLink({ question_id: qid || '', page: curPage, page_size: pageSize, }); const { login: loginSetting } = loginSettingStore(); - + const [questionTitle, setQuestionTitle] = useState(''); + questionDetail(qid || '') + .then((res) => { + setQuestionTitle(res.title); + }) + .catch((err) => { + console.error('get question detail failed:', err); + setQuestionTitle(`#${qid}`); + }); usePageTags({ title: t('title'), }); @@ -64,6 +72,11 @@ const LinkedQuestions: FC = () => { return ( +

    Linked Questions

    +

    + Questions linked to/from  + {questionTitle} +

    Date: Fri, 4 Oct 2024 23:42:50 +0800 Subject: [PATCH 241/336] perf: skip link addition for same question id --- internal/service/content/answer_service.go | 10 +++++++--- internal/service/content/question_service.go | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index e8842891..71e4e3d9 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -801,20 +801,24 @@ func (as *AnswerService) updateAnswerLink(ctx context.Context, answer *entity.An } } - questionLinks = append(questionLinks, &entity.QuestionLink{ + addLink := &entity.QuestionLink{ FromQuestionID: uid.DeShortID(answer.QuestionID), FromAnswerID: uid.DeShortID(answer.ID), ToQuestionID: uid.DeShortID(link.QuestionID), ToAnswerID: uid.DeShortID(link.AnswerID), - }) - + } if link.QuestionID != "" { retParsedText = strings.Replace(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"", -1) } if link.AnswerID != "" { questionID := answerCache[link.AnswerID] + addLink.ToQuestionID = questionID retParsedText = strings.Replace(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"", -1) } + if addLink.FromQuestionID == addLink.ToQuestionID { + continue + } + questionLinks = append(questionLinks, addLink) } if err = as.questionRepo.LinkQuestion(ctx, questionLinks...); err != nil { return retParsedText, err diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index a57d3fac..308d52bc 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -1675,20 +1675,25 @@ func (qs *QuestionService) updateQuestionLink(ctx context.Context, questionInfo } } - questionLinks = append(questionLinks, &entity.QuestionLink{ + addLink := &entity.QuestionLink{ FromQuestionID: uid.DeShortID(questionInfo.ID), FromAnswerID: "0", ToQuestionID: uid.DeShortID(link.QuestionID), ToAnswerID: uid.DeShortID(link.AnswerID), - }) + } if link.QuestionID != "" { retParsedText = strings.Replace(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"", -1) } if link.AnswerID != "" { questionID := answerCache[link.AnswerID] + addLink.ToQuestionID = questionID retParsedText = strings.Replace(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"", -1) } + if addLink.FromQuestionID == addLink.ToQuestionID { + continue + } + questionLinks = append(questionLinks, addLink) } if err = qs.questionRepo.LinkQuestion(ctx, questionLinks...); err != nil { return retParsedText, err From b328a2b496486ceb2ce31acdc116f645551aa55d Mon Sep 17 00:00:00 2001 From: Sonui Date: Tue, 8 Oct 2024 13:23:37 +0800 Subject: [PATCH 242/336] style: use ReplaceAll instead of Replace --- internal/service/content/answer_service.go | 4 ++-- internal/service/content/question_service.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index 71e4e3d9..bd70fc93 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -808,12 +808,12 @@ func (as *AnswerService) updateAnswerLink(ctx context.Context, answer *entity.An ToAnswerID: uid.DeShortID(link.AnswerID), } if link.QuestionID != "" { - retParsedText = strings.Replace(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"", -1) + retParsedText = strings.ReplaceAll(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"") } if link.AnswerID != "" { questionID := answerCache[link.AnswerID] addLink.ToQuestionID = questionID - retParsedText = strings.Replace(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"", -1) + retParsedText = strings.ReplaceAll(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"") } if addLink.FromQuestionID == addLink.ToQuestionID { continue diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index 308d52bc..d2692d8c 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -1683,12 +1683,12 @@ func (qs *QuestionService) updateQuestionLink(ctx context.Context, questionInfo } if link.QuestionID != "" { - retParsedText = strings.Replace(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"", -1) + retParsedText = strings.ReplaceAll(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"") } if link.AnswerID != "" { questionID := answerCache[link.AnswerID] addLink.ToQuestionID = questionID - retParsedText = strings.Replace(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"", -1) + retParsedText = strings.ReplaceAll(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"") } if addLink.FromQuestionID == addLink.ToQuestionID { continue From 62b9104a68077a9fd5c92c3a66a89ac2ed5e10fa Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 11 Oct 2024 00:49:15 +0800 Subject: [PATCH 243/336] fix: support short id --- pkg/checker/question_link.go | 24 +++++++++++++++--------- pkg/checker/question_link_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/pkg/checker/question_link.go b/pkg/checker/question_link.go index ca8327b6..36f850d6 100644 --- a/pkg/checker/question_link.go +++ b/pkg/checker/question_link.go @@ -22,6 +22,7 @@ package checker import ( "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/incubator-answer/pkg/uid" ) const ( @@ -60,7 +61,7 @@ func GetQuestionLink(content string) []QuestionLink { } func processURL(content string, left, right *int, uniqueIDs map[string]struct{}, questionLinks *[]QuestionLink) { - for *right < len(content) && isDigit(content[*right]) { + for *right < len(content) && (isDigit(content[*right]) || isLetter(content[*right])) { *right++ } questionID := content[*left+len("/questions/") : *right] @@ -69,7 +70,7 @@ func processURL(content string, left, right *int, uniqueIDs map[string]struct{}, if *right < len(content) && content[*right] == '/' { *left = *right + 1 *right = *left - for *right < len(content) && isDigit(content[*right]) { + for *right < len(content) && (isDigit(content[*right]) || isLetter(content[*right])) { *right++ } answerID = content[*left:*right] @@ -79,7 +80,7 @@ func processURL(content string, left, right *int, uniqueIDs map[string]struct{}, } func processID(content string, left, right *int, uniqueIDs map[string]struct{}, questionLinks *[]QuestionLink) { - for *right < len(content) && isDigit(content[*right]) { + for *right < len(content) && (isDigit(content[*right]) || isLetter(content[*right])) { *right++ } id := content[*left:*right] @@ -90,14 +91,19 @@ func isDigit(c byte) bool { return c >= '0' && c <= '9' } -func addUniqueID(questionID, answerID string, linkType int, uniqueIDs map[string]struct{}, questionLinks *[]QuestionLink) { - if questionID == "" && answerID == "" { - return - } +func isLetter(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} +func addUniqueID(questionID, answerID string, linkType int, uniqueIDs map[string]struct{}, questionLinks *[]QuestionLink) { isAdd := false if answerID != "" { - if objectType, err := obj.GetObjectTypeStrByObjectID(answerID); err == nil && objectType == constant.AnswerObjectType { + objectType, err := obj.GetObjectTypeStrByObjectID(uid.DeShortID(answerID)) + if err != nil { + answerID = "" + } + + if objectType == constant.AnswerObjectType { if _, ok := uniqueIDs[answerID]; !ok { uniqueIDs[answerID] = struct{}{} isAdd = true @@ -105,7 +111,7 @@ func addUniqueID(questionID, answerID string, linkType int, uniqueIDs map[string } } - if objectType, err := obj.GetObjectTypeStrByObjectID(questionID); err == nil { + if objectType, err := obj.GetObjectTypeStrByObjectID(uid.DeShortID(questionID)); err == nil { if _, ok := uniqueIDs[questionID]; !ok { uniqueIDs[questionID] = struct{}{} isAdd = true diff --git a/pkg/checker/question_link_test.go b/pkg/checker/question_link_test.go index 6b9f9483..bc4eb615 100644 --- a/pkg/checker/question_link_test.go +++ b/pkg/checker/question_link_test.go @@ -157,4 +157,28 @@ func TestGetQuestionLink(t *testing.T) { links := checker.GetQuestionLink("https://example.com/questions/10110000000000060") assert.Empty(t, links) }) + + // step 15: SEO options + t.Run("SEO options", func(t *testing.T) { + content := ` + URL1: http://localhost:3000/questions/D1I2 + URL2: http://localhost:3000/questions/D1I2/hello + URL3: http://localhost:3000/questions/10010000000000068 + URL4: http://localhost:3000/questions/10010000000000068/hello + ERROR URL: http://localhost:3000/questions/AAAA/BBBB + ` + links := checker.GetQuestionLink(content) + assert.Equal(t, []checker.QuestionLink{ + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "D1I2", + AnswerID: "", + }, + { + LinkType: checker.QuestionLinkTypeURL, + QuestionID: "10010000000000068", + AnswerID: "", + }, + }, links) + }) } From 74368ec9d4490fac5f4f35c579b4e91410fc0d8d Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 11 Oct 2024 00:55:10 +0800 Subject: [PATCH 244/336] perf: optimize question link processing --- internal/service/content/answer_service.go | 86 +-------------- internal/service/content/question_service.go | 85 +-------------- internal/service/question_common/question.go | 108 +++++++++++++++++++ 3 files changed, 112 insertions(+), 167 deletions(-) diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index bd70fc93..d4983c3c 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -22,7 +22,6 @@ package content import ( "context" "encoding/json" - "strings" "time" "github.com/apache/incubator-answer/internal/service/event_queue" @@ -44,7 +43,6 @@ import ( "github.com/apache/incubator-answer/internal/service/revision_common" "github.com/apache/incubator-answer/internal/service/role" usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/checker" "github.com/apache/incubator-answer/pkg/converter" "github.com/apache/incubator-answer/pkg/htmltext" "github.com/apache/incubator-answer/pkg/token" @@ -275,7 +273,7 @@ func (as *AnswerService) Insert(ctx context.Context, req *schema.AnswerAddReq) ( return "", err } if insertData.Status == entity.AnswerStatusAvailable { - insertData.ParsedText, err = as.updateAnswerLink(ctx, insertData) + insertData.ParsedText, err = as.questionCommon.UpdateQuestionLink(ctx, insertData.QuestionID, insertData.ID, insertData.ParsedText, insertData.OriginalText) if err != nil { return "", err } @@ -398,7 +396,7 @@ func (as *AnswerService) Update(ctx context.Context, req *schema.AnswerUpdateReq if !canUpdate { revisionDTO.Status = entity.RevisionUnreviewedStatus } else { - insertData.ParsedText, err = as.updateAnswerLink(ctx, insertData) + insertData.ParsedText, err = as.questionCommon.UpdateQuestionLink(ctx, insertData.QuestionID, insertData.ID, insertData.ParsedText, insertData.OriginalText) if err != nil { return "", err } @@ -746,83 +744,3 @@ func (as *AnswerService) notificationAnswerTheQuestion(ctx context.Context, externalNotificationMsg.NewAnswerTemplateRawData = rawData as.externalNotificationQueueService.Send(ctx, externalNotificationMsg) } - -func (as *AnswerService) updateAnswerLink(ctx context.Context, answer *entity.Answer) (string, error) { - err := as.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ - FromQuestionID: uid.DeShortID(answer.QuestionID), - FromAnswerID: uid.DeShortID(answer.ID), - }) - retParsedText := answer.ParsedText - if err != nil { - return retParsedText, err - } - links := checker.GetQuestionLink(answer.OriginalText) - // validate links - questionLinks := make([]*entity.QuestionLink, 0) - answerCache := make(map[string]string) - questionCache := make(map[string]string) - answerIDList := make([]string, 0) - questionIDList := make([]string, 0) - for _, link := range links { - if link.AnswerID != "" { - answerIDList = append(answerIDList, link.AnswerID) - } - if link.QuestionID != "" { - questionIDList = append(questionIDList, link.QuestionID) - } - } - answerInfoList, err := as.answerRepo.GetByIDs(ctx, answerIDList...) - if err != nil { - return answer.ParsedText, err - } - for _, answer := range answerInfoList { - answerCache[answer.ID] = answer.QuestionID - } - questionInfoList, err := as.questionRepo.FindByID(ctx, questionIDList) - if err != nil { - return answer.ParsedText, err - } - for _, question := range questionInfoList { - questionCache[question.ID] = question.ParsedText - } - - for _, link := range links { - if link.QuestionID != "" { - if _, ok := questionCache[link.QuestionID]; !ok { - continue - } - } - if link.AnswerID != "" { - if _, ok := answerCache[link.AnswerID]; !ok { - continue - } - if link.QuestionID == "" { - link.QuestionID = answerCache[link.AnswerID] - } - } - - addLink := &entity.QuestionLink{ - FromQuestionID: uid.DeShortID(answer.QuestionID), - FromAnswerID: uid.DeShortID(answer.ID), - ToQuestionID: uid.DeShortID(link.QuestionID), - ToAnswerID: uid.DeShortID(link.AnswerID), - } - if link.QuestionID != "" { - retParsedText = strings.ReplaceAll(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"") - } - if link.AnswerID != "" { - questionID := answerCache[link.AnswerID] - addLink.ToQuestionID = questionID - retParsedText = strings.ReplaceAll(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"") - } - if addLink.FromQuestionID == addLink.ToQuestionID { - continue - } - questionLinks = append(questionLinks, addLink) - } - if err = as.questionRepo.LinkQuestion(ctx, questionLinks...); err != nil { - return retParsedText, err - } - - return retParsedText, nil -} diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index d2692d8c..7cfd39a0 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -349,7 +349,7 @@ func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.Question return nil, err } if question.Status == entity.QuestionStatusAvailable { - question.ParsedText, err = qs.updateQuestionLink(ctx, question) + question.ParsedText, err = qs.questioncommon.UpdateQuestionLink(ctx, question.ID, "", question.ParsedText, question.OriginalText) if err != nil { return nil, err } @@ -964,7 +964,7 @@ func (qs *QuestionService) UpdateQuestion(ctx context.Context, req *schema.Quest //Direct modification revisionDTO.Status = entity.RevisionReviewPassStatus //update question to db - question.ParsedText, err = qs.updateQuestionLink(ctx, question) + question.ParsedText, err = qs.questioncommon.UpdateQuestionLink(ctx, question.ID, "", question.ParsedText, question.OriginalText) if err != nil { return questionInfo, err } @@ -1621,87 +1621,6 @@ func (qs *QuestionService) SitemapCron(ctx context.Context) { qs.questioncommon.SitemapCron(ctx) } -func (qs *QuestionService) updateQuestionLink(ctx context.Context, questionInfo *entity.Question) (string, error) { - err := qs.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ - FromQuestionID: questionInfo.ID, - FromAnswerID: "0", - }) - if err != nil { - return questionInfo.ParsedText, err - } - retParsedText := questionInfo.ParsedText - links := checker.GetQuestionLink(questionInfo.OriginalText) - // validate links - questionLinks := make([]*entity.QuestionLink, 0) - answerCache := make(map[string]string) - questionCache := make(map[string]string) - answerIDList := make([]string, 0) - questionIDList := make([]string, 0) - for _, link := range links { - if link.AnswerID != "" { - answerIDList = append(answerIDList, link.AnswerID) - } - if link.QuestionID != "" { - questionIDList = append(questionIDList, link.QuestionID) - } - } - answerInfoList, err := qs.answerRepo.GetByIDs(ctx, answerIDList...) - if err != nil { - return questionInfo.ParsedText, err - } - for _, answer := range answerInfoList { - answerCache[answer.ID] = answer.QuestionID - } - questionInfoList, err := qs.questionRepo.FindByID(ctx, questionIDList) - if err != nil { - return questionInfo.ParsedText, err - } - for _, question := range questionInfoList { - questionCache[question.ID] = question.ParsedText - } - - for _, link := range links { - if link.QuestionID != "" { - if _, ok := questionCache[link.QuestionID]; !ok { - continue - } - } - if link.AnswerID != "" { - if _, ok := answerCache[link.AnswerID]; !ok { - continue - } - if link.QuestionID == "" { - link.QuestionID = answerCache[link.AnswerID] - } - } - - addLink := &entity.QuestionLink{ - FromQuestionID: uid.DeShortID(questionInfo.ID), - FromAnswerID: "0", - ToQuestionID: uid.DeShortID(link.QuestionID), - ToAnswerID: uid.DeShortID(link.AnswerID), - } - - if link.QuestionID != "" { - retParsedText = strings.ReplaceAll(retParsedText, "#"+link.QuestionID, "#"+link.QuestionID+"") - } - if link.AnswerID != "" { - questionID := answerCache[link.AnswerID] - addLink.ToQuestionID = questionID - retParsedText = strings.ReplaceAll(retParsedText, "#"+link.AnswerID, "#"+link.AnswerID+"") - } - if addLink.FromQuestionID == addLink.ToQuestionID { - continue - } - questionLinks = append(questionLinks, addLink) - } - if err = qs.questionRepo.LinkQuestion(ctx, questionLinks...); err != nil { - return retParsedText, err - } - - return retParsedText, nil -} - func (qs *QuestionService) GetQuestionLink(ctx context.Context, req *schema.GetQuestionLinkReq) ( questions []*schema.QuestionPageResp, total int64, err error) { if req.OrderCond == schema.QuestionOrderCondHot { diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index f242b3f8..63c8f5a2 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -22,7 +22,9 @@ package questioncommon import ( "context" "encoding/json" + "fmt" "math" + "strings" "time" "github.com/apache/incubator-answer/internal/base/constant" @@ -687,3 +689,109 @@ func (qs *QuestionCommon) ShowFormatWithTag(ctx context.Context, data *entity.Qu info.Tags = Tags return info } + +func (qs *QuestionCommon) UpdateQuestionLink(ctx context.Context, questionID, answerID, parsedText, originalText string) (string, error) { + err := qs.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: uid.DeShortID(questionID), + FromAnswerID: uid.DeShortID(answerID), + }) + if err != nil { + return parsedText, err + } + + links := checker.GetQuestionLink(originalText) + if len(links) == 0 { + return parsedText, nil + } + + // get answer ids and question ids + answerIDs := make([]string, 0, len(links)) + questionIDs := make([]string, 0, len(links)) + for _, link := range links { + if link.AnswerID != "" { + answerIDs = append(answerIDs, link.AnswerID) + } + if link.QuestionID != "" { + questionIDs = append(questionIDs, link.QuestionID) + } + } + + // get answer info and build cache + answerInfoList, err := qs.answerRepo.GetByIDs(ctx, answerIDs...) + if err != nil { + return parsedText, err + } + answerCache := make(map[string]string, len(answerInfoList)) + for _, ans := range answerInfoList { + answerID := uid.DeShortID(ans.ID) + questionID := ans.QuestionID + answerCache[answerID] = questionID + } + + // get question info and build cache + questionInfoList, err := qs.questionRepo.FindByID(ctx, questionIDs) + if err != nil { + return parsedText, err + } + questionCache := make(map[string]struct{}, len(questionInfoList)) + for _, q := range questionInfoList { + questionID := uid.DeShortID(q.ID) + questionCache[questionID] = struct{}{} + } + + // process links and generate new QuestionLink + validLinks := make([]*entity.QuestionLink, 0, len(links)) + for _, link := range links { + linkQuestionID := uid.DeShortID(link.QuestionID) + linkAnswerID := uid.DeShortID(link.AnswerID) + // validate question id + if _, exists := questionCache[linkQuestionID]; linkQuestionID != "0" && !exists { + continue + } + + // validate answer id + if linkAnswerID != "0" { + linkedQuestionID, exists := answerCache[linkAnswerID] + if !exists { + continue + } + // if question id is empty, get it from answer cache + if link.QuestionID == "" { + link.QuestionID = linkedQuestionID + } + } + + // build new link + newLink := &entity.QuestionLink{ + FromQuestionID: uid.DeShortID(questionID), + FromAnswerID: uid.DeShortID(answerID), + ToQuestionID: uid.DeShortID(link.QuestionID), + ToAnswerID: uid.DeShortID(link.AnswerID), + } + // replace link in parsed text + if link.QuestionID != "" { + htmlLink := fmt.Sprintf("#%s", link.QuestionID, link.QuestionID) + parsedText = strings.ReplaceAll(parsedText, "#"+link.QuestionID, htmlLink) + } + if link.AnswerID != "" { + linkedQuestionID := answerCache[linkAnswerID] + htmlLink := fmt.Sprintf("#%s", linkedQuestionID, link.AnswerID, link.AnswerID) + parsedText = strings.ReplaceAll(parsedText, "#"+link.AnswerID, htmlLink) + newLink.ToQuestionID = uid.DeShortID(linkedQuestionID) + } + // avoid link to self + if newLink.FromQuestionID != newLink.ToQuestionID { + validLinks = append(validLinks, newLink) + } + } + + // add new links to repo + if len(validLinks) > 0 { + err = qs.questionRepo.LinkQuestion(ctx, validLinks...) + if err != nil { + return parsedText, err + } + } + + return parsedText, nil +} From fe60e5e5db23c495eb1ef6e6101b9ac87b16e6fa Mon Sep 17 00:00:00 2001 From: Sonui Date: Fri, 11 Oct 2024 01:02:16 +0800 Subject: [PATCH 245/336] perf: optimize question linked display processing --- .../components/LinkedQuestions/index.tsx | 37 ++++--------------- ui/src/pages/Questions/Linked/index.tsx | 6 +-- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx index 8e5a57dd..f02adb35 100644 --- a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx +++ b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx @@ -37,36 +37,14 @@ const Index: FC = ({ id }) => { keyPrefix: 'related_question', }); - const { data, isLoading } = questionLink({ + const { data } = questionLink({ question_id: id, page: 1, page_size: 5, }); - if (isLoading) { - return null; - } - if (!data || !data.list) { - return ( - - - {t('title')} - - {t('more', { keyPrefix: 'btns' })} - - - -
    - {t('no_linked_question')} -
    -
    -
    - ); + return null; } return ( @@ -78,8 +56,8 @@ const Index: FC = ({ id }) => { - {data.list.map((item) => { - return ( + {data.list.length > 0 ? ( + data.list.map((item) => ( = ({ id }) => {
)} - ); - })} - {data.list.length === 0 ? ( + )) + ) : (
= ({ id }) => { }}> {t('no_linked_question')}
- ) : null} + )} ); diff --git a/ui/src/pages/Questions/Linked/index.tsx b/ui/src/pages/Questions/Linked/index.tsx index aabba7bb..70a62ec1 100644 --- a/ui/src/pages/Questions/Linked/index.tsx +++ b/ui/src/pages/Questions/Linked/index.tsx @@ -72,11 +72,11 @@ const LinkedQuestions: FC = () => { return ( -

Linked Questions

-

+

Linked Questions

+
Questions linked to/from  {questionTitle} -

+
Date: Sat, 12 Oct 2024 10:43:18 +0800 Subject: [PATCH 246/336] refactor(ui): Update linked question UI text --- i18n/en_US.yaml | 1 + ui/src/pages/Questions/Linked/index.tsx | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index f47bca72..8c3c3ddd 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1362,6 +1362,7 @@ ui: answers: answers linked_question: title: Linked Questions + description: Questions linked to no_linked_question: No questions linked from this question. invite_to_answer: title: Invite People diff --git a/ui/src/pages/Questions/Linked/index.tsx b/ui/src/pages/Questions/Linked/index.tsx index 70a62ec1..981e8c4e 100644 --- a/ui/src/pages/Questions/Linked/index.tsx +++ b/ui/src/pages/Questions/Linked/index.tsx @@ -72,9 +72,9 @@ const LinkedQuestions: FC = () => { return ( -

Linked Questions

+

{t('title')}

- Questions linked to/from  + {t('description')}  {questionTitle}
Date: Sat, 12 Oct 2024 15:15:34 +0800 Subject: [PATCH 247/336] refactor(utils): Refactor plugin registration in Plugins class --- ui/src/utils/pluginKit/index.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index f53fdb4c..66d5c376 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -94,11 +94,13 @@ class Plugins { } registerPlugins() { - const plugins = this.registeredPlugins.map((p) => { - const func = allPlugins[p.slug_name]; + const plugins = this.registeredPlugins + .map((p) => { + const func = allPlugins[p.slug_name]; - return func; - }); + return func; + }) + .filter((p) => p); return new Promise((resolve) => { plugins.forEach(async (p) => { const plugin = await p(); From 4c9e37fa6e2af4a6cd6bf41ccea0cdb0634210ec Mon Sep 17 00:00:00 2001 From: Anan <1449891717@qq.com> Date: Sat, 28 Sep 2024 05:07:54 +0000 Subject: [PATCH 248/336] Add importer plugin type --- .../controller/plugin_importer_controller.go | 209 ++++++++++++++++++ internal/router/plugin_api_router.go | 5 + plugin/importer.go | 56 +++++ plugin/plugin.go | 4 + 4 files changed, 274 insertions(+) create mode 100644 internal/controller/plugin_importer_controller.go create mode 100644 plugin/importer.go diff --git a/internal/controller/plugin_importer_controller.go b/internal/controller/plugin_importer_controller.go new file mode 100644 index 00000000..90532acf --- /dev/null +++ b/internal/controller/plugin_importer_controller.go @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package controller + +import ( + "bytes" + "io" + + "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/middleware" + "github.com/apache/incubator-answer/internal/base/reason" + "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/incubator-answer/internal/base/validator" + "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/content" + "github.com/apache/incubator-answer/internal/service/permission" + "github.com/apache/incubator-answer/internal/service/rank" + usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/incubator-answer/plugin" + "github.com/gin-gonic/gin" + "github.com/segmentfault/pacman/errors" + "github.com/segmentfault/pacman/log" +) + +type ImporterController struct { + // userRepo *usercommon.UserRepo + questionService *content.QuestionService + rankService *rank.RankService + rateLimitMiddleware *middleware.RateLimitMiddleware + userCommon *usercommon.UserCommon +} + +func NewImporterController( + questionService *content.QuestionService, + rankService *rank.RankService, + rateLimitMiddleware *middleware.RateLimitMiddleware, + userCommon *usercommon.UserCommon, +) *ImporterController { + return &ImporterController{ + questionService: questionService, + rankService: rankService, + rateLimitMiddleware: rateLimitMiddleware, + userCommon: userCommon, + } +} + +// ImportCommand godoc +// @Summary ImportCommand +// @Description ImportCommand +// @Tags PluginImporter +// @Accept json +// @Produce json +// @Router /answer/api/v1/importer/command [post] +// @Success 200 {object} handler.RespBody{data=[]plugin.importStatus} +func (ipc *ImporterController) ImportCommand(ctx *gin.Context) { + questionInfo := &plugin.QuestionImporterInfo{} + if !plugin.ImporterEnabled() { + log.Errorf("error: plugin is not enabled") + ctx.JSON(200, gin.H{"text": "plugin is not enabled"}) + return + } + body, err := io.ReadAll(ctx.Request.Body) + ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + cmd := ctx.PostForm("command") + if cmd != "/ask" { + log.Errorf("error: Invalid command") + ctx.JSON(200, gin.H{"text": "Invalid command"}) + return + } + _ = plugin.CallImporter(func(importer plugin.Importer) error { + ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + questionInfo, err = importer.GetQuestion(ctx) + return nil + }) + if err != nil { + log.Errorf("error: %v", err) + ctx.JSON(200, gin.H{"text": err.Error()}) + return + } + + req := &schema.QuestionAdd{} + errFields := make([]*validator.FormErrorField, 0) + // errFields := handler.BindAndCheckReturnErr(ctx, req) + if ctx.IsAborted() { + return + } + + // reject, rejectKey := ipc.rateLimitMiddleware.DuplicateRequestRejection(ctx, req) + // if reject { + // return + // } + user_info, exist, err := ipc.userCommon.GetByEmail(ctx, questionInfo.UserEmail) + if err != nil { + log.Errorf("error: %v", err) + ctx.JSON(200, gin.H{"text": err.Error()}) + return + } + if !exist { + log.Errorf("error: User Email not found") + ctx.JSON(200, gin.H{"text": "User Email not found"}) + return + } + + // defer func() { + // // If status is not 200 means that the bad request has been returned, so the record should be cleared + // if ctx.Writer.Status() != http.StatusOK { + // ipc.rateLimitMiddleware.DuplicateRequestClear(ctx, rejectKey) + // } + // }() + req.UserID = user_info.ID + req.Title = questionInfo.Title + req.Content = questionInfo.Content + req.HTML = "

" + questionInfo.Content + "

" + req.Tags = make([]*schema.TagItem, len(questionInfo.Tags)) + for i, tag := range questionInfo.Tags { + req.Tags[i] = &schema.TagItem{ + SlugName: tag, + DisplayName: tag, + } + } + canList, requireRanks, err := ipc.rankService.CheckOperationPermissionsForRanks(ctx, req.UserID, []string{ + permission.QuestionAdd, + permission.QuestionEdit, + permission.QuestionDelete, + permission.QuestionClose, + permission.QuestionReopen, + permission.TagUseReservedTag, + permission.TagAdd, + permission.LinkUrlLimit, + }) + if err != nil { + log.Errorf("error: %v", err) + ctx.JSON(200, gin.H{"text": err.Error()}) + return + } + req.CanAdd = canList[0] + req.CanEdit = canList[1] + req.CanDelete = canList[2] + req.CanClose = canList[3] + req.CanReopen = canList[4] + req.CanUseReservedTag = canList[5] + req.CanAddTag = canList[6] + if !req.CanAdd { + ctx.JSON(200, gin.H{"text": "No permission to add question"}) + log.Errorf("error: %v", err) + return + } + hasNewTag, err := ipc.questionService.HasNewTag(ctx, req.Tags) + if err != nil { + log.Errorf("error: %v", err) + ctx.JSON(200, gin.H{"text": err.Error()}) + return + } + if !req.CanAddTag && hasNewTag { + lang := handler.GetLang(ctx) + msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: requireRanks[6]}) + log.Errorf("error: %v", msg) + ctx.JSON(200, gin.H{"text": msg}) + return + } + + errList, err := ipc.questionService.CheckAddQuestion(ctx, req) + if err != nil { + errlist, ok := errList.([]*validator.FormErrorField) + if ok { + errFields = append(errFields, errlist...) + } + } + if len(errFields) > 0 { + handler.HandleResponse(ctx, errors.BadRequest(reason.RequestFormatError), errFields) + log.Errorf("error: RequestFormatError") + ctx.JSON(200, gin.H{"text": "RequestFormatError"}) + return + } + req.UserAgent = ctx.GetHeader("User-Agent") + req.IP = ctx.ClientIP() + resp, err := ipc.questionService.AddQuestion(ctx, req) + if err != nil { + errlist, ok := resp.([]*validator.FormErrorField) + if ok { + errFields = append(errFields, errlist...) + } + } + + if len(errFields) > 0 { + log.Errorf("error: RequestFormatError") + ctx.JSON(200, gin.H{"text": "RequestFormatError"}) + return + } + + ctx.JSON(200, gin.H{"text": "Add Question Successfully"}) +} diff --git a/internal/router/plugin_api_router.go b/internal/router/plugin_api_router.go index e69e0b6b..22a13b85 100644 --- a/internal/router/plugin_api_router.go +++ b/internal/router/plugin_api_router.go @@ -30,6 +30,7 @@ type PluginAPIRouter struct { captchaController *controller.CaptchaController embedController *controller.EmbedController renderController *controller.RenderController + importerController *controller.ImporterController } func NewPluginAPIRouter( @@ -38,6 +39,7 @@ func NewPluginAPIRouter( captchaController *controller.CaptchaController, embedController *controller.EmbedController, renderController *controller.RenderController, + importerController *controller.ImporterController, ) *PluginAPIRouter { return &PluginAPIRouter{ connectorController: connectorController, @@ -68,6 +70,9 @@ func (pr *PluginAPIRouter) RegisterUnAuthConnectorRouter(r *gin.RouterGroup) { r.GET("/captcha/config", pr.captchaController.GetCaptchaConfig) r.GET("/embed/config", pr.embedController.GetEmbedConfig) r.GET("/render/config", pr.renderController.GetRenderConfig) + + // importer plugin + r.POST("/importer/answer", pr.importerController.ImportCommand) } func (pr *PluginAPIRouter) RegisterAuthUserConnectorRouter(r *gin.RouterGroup) { diff --git a/plugin/importer.go b/plugin/importer.go new file mode 100644 index 00000000..79a84c50 --- /dev/null +++ b/plugin/importer.go @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package plugin + +import "github.com/gin-gonic/gin" + +type QuestionImporterInfo struct { + Title string `json:"title"` + Content string `json:"content"` + Tags []string `json:"tags"` + UserEmail string `json:"user_email"` +} + +type Importer interface { + Base + GetQuestion(ctx *gin.Context) (questionInfo *QuestionImporterInfo, err error) +} + +var ( + // CallImporter is a function that calls all registered parsers + CallImporter, + registerImporter = MakePlugin[Importer](false) +) + +func ImporterEnabled() (enabled bool) { + _ = CallImporter(func(fn Importer) error { + enabled = true + return nil + }) + return +} +func GetImporter() (ip Importer, ok bool) { + _ = CallImporter(func(fn Importer) error { + ip = fn + ok = true + return nil + }) + return +} diff --git a/plugin/plugin.go b/plugin/plugin.go index 9c144346..2e4bf749 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -110,6 +110,10 @@ func Register(p Base) { if _, ok := p.(CDN); ok { registerCDN(p.(CDN)) } + + if _, ok := p.(Importer); ok { + registerImporter(p.(Importer)) + } } type Stack[T Base] struct { From 5aad9e95b572ae82ec12cfe9e2bab9dd52d7e51d Mon Sep 17 00:00:00 2001 From: Anan <1449891717@qq.com> Date: Tue, 15 Oct 2024 04:49:08 +0000 Subject: [PATCH 249/336] Add importer service --- cmd/wire_gen.go | 4 +- internal/router/plugin_api_router.go | 5 - .../importer/importer_service.go} | 390 ++++++++---------- .../plugin_common/plugin_common_service.go | 11 + plugin/importer.go | 10 +- 5 files changed, 203 insertions(+), 217 deletions(-) rename internal/{controller/plugin_importer_controller.go => service/importer/importer_service.go} (54%) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 537ece84..1ffa75ca 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -111,6 +111,7 @@ import ( "github.com/apache/incubator-answer/internal/service/user_common" user_external_login2 "github.com/apache/incubator-answer/internal/service/user_external_login" user_notification_config2 "github.com/apache/incubator-answer/internal/service/user_notification_config" + "github.com/apache/incubator-answer/internal/service/importer" "github.com/segmentfault/pacman" "github.com/segmentfault/pacman/log" ) @@ -253,7 +254,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, roleController := controller_admin.NewRoleController(roleService) pluginConfigRepo := plugin_config.NewPluginConfigRepo(dataData) pluginUserConfigRepo := plugin_config.NewPluginUserConfigRepo(dataData) - pluginCommonService := plugin_common.NewPluginCommonService(pluginConfigRepo, pluginUserConfigRepo, configService, dataData) + importerService := importer.NewImporterService(questionService, rankService, userCommon) + pluginCommonService := plugin_common.NewPluginCommonService(pluginConfigRepo, pluginUserConfigRepo, configService, dataData, importerService) pluginController := controller_admin.NewPluginController(pluginCommonService) permissionController := controller.NewPermissionController(rankService) userPluginController := controller.NewUserPluginController(pluginCommonService) diff --git a/internal/router/plugin_api_router.go b/internal/router/plugin_api_router.go index 22a13b85..e69e0b6b 100644 --- a/internal/router/plugin_api_router.go +++ b/internal/router/plugin_api_router.go @@ -30,7 +30,6 @@ type PluginAPIRouter struct { captchaController *controller.CaptchaController embedController *controller.EmbedController renderController *controller.RenderController - importerController *controller.ImporterController } func NewPluginAPIRouter( @@ -39,7 +38,6 @@ func NewPluginAPIRouter( captchaController *controller.CaptchaController, embedController *controller.EmbedController, renderController *controller.RenderController, - importerController *controller.ImporterController, ) *PluginAPIRouter { return &PluginAPIRouter{ connectorController: connectorController, @@ -70,9 +68,6 @@ func (pr *PluginAPIRouter) RegisterUnAuthConnectorRouter(r *gin.RouterGroup) { r.GET("/captcha/config", pr.captchaController.GetCaptchaConfig) r.GET("/embed/config", pr.embedController.GetEmbedConfig) r.GET("/render/config", pr.renderController.GetRenderConfig) - - // importer plugin - r.POST("/importer/answer", pr.importerController.ImportCommand) } func (pr *PluginAPIRouter) RegisterAuthUserConnectorRouter(r *gin.RouterGroup) { diff --git a/internal/controller/plugin_importer_controller.go b/internal/service/importer/importer_service.go similarity index 54% rename from internal/controller/plugin_importer_controller.go rename to internal/service/importer/importer_service.go index 90532acf..668a2bf9 100644 --- a/internal/controller/plugin_importer_controller.go +++ b/internal/service/importer/importer_service.go @@ -1,209 +1,181 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package controller - -import ( - "bytes" - "io" - - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/plugin" - "github.com/gin-gonic/gin" - "github.com/segmentfault/pacman/errors" - "github.com/segmentfault/pacman/log" -) - -type ImporterController struct { - // userRepo *usercommon.UserRepo - questionService *content.QuestionService - rankService *rank.RankService - rateLimitMiddleware *middleware.RateLimitMiddleware - userCommon *usercommon.UserCommon -} - -func NewImporterController( - questionService *content.QuestionService, - rankService *rank.RankService, - rateLimitMiddleware *middleware.RateLimitMiddleware, - userCommon *usercommon.UserCommon, -) *ImporterController { - return &ImporterController{ - questionService: questionService, - rankService: rankService, - rateLimitMiddleware: rateLimitMiddleware, - userCommon: userCommon, - } -} - -// ImportCommand godoc -// @Summary ImportCommand -// @Description ImportCommand -// @Tags PluginImporter -// @Accept json -// @Produce json -// @Router /answer/api/v1/importer/command [post] -// @Success 200 {object} handler.RespBody{data=[]plugin.importStatus} -func (ipc *ImporterController) ImportCommand(ctx *gin.Context) { - questionInfo := &plugin.QuestionImporterInfo{} - if !plugin.ImporterEnabled() { - log.Errorf("error: plugin is not enabled") - ctx.JSON(200, gin.H{"text": "plugin is not enabled"}) - return - } - body, err := io.ReadAll(ctx.Request.Body) - ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body)) - cmd := ctx.PostForm("command") - if cmd != "/ask" { - log.Errorf("error: Invalid command") - ctx.JSON(200, gin.H{"text": "Invalid command"}) - return - } - _ = plugin.CallImporter(func(importer plugin.Importer) error { - ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body)) - questionInfo, err = importer.GetQuestion(ctx) - return nil - }) - if err != nil { - log.Errorf("error: %v", err) - ctx.JSON(200, gin.H{"text": err.Error()}) - return - } - - req := &schema.QuestionAdd{} - errFields := make([]*validator.FormErrorField, 0) - // errFields := handler.BindAndCheckReturnErr(ctx, req) - if ctx.IsAborted() { - return - } - - // reject, rejectKey := ipc.rateLimitMiddleware.DuplicateRequestRejection(ctx, req) - // if reject { - // return - // } - user_info, exist, err := ipc.userCommon.GetByEmail(ctx, questionInfo.UserEmail) - if err != nil { - log.Errorf("error: %v", err) - ctx.JSON(200, gin.H{"text": err.Error()}) - return - } - if !exist { - log.Errorf("error: User Email not found") - ctx.JSON(200, gin.H{"text": "User Email not found"}) - return - } - - // defer func() { - // // If status is not 200 means that the bad request has been returned, so the record should be cleared - // if ctx.Writer.Status() != http.StatusOK { - // ipc.rateLimitMiddleware.DuplicateRequestClear(ctx, rejectKey) - // } - // }() - req.UserID = user_info.ID - req.Title = questionInfo.Title - req.Content = questionInfo.Content - req.HTML = "

" + questionInfo.Content + "

" - req.Tags = make([]*schema.TagItem, len(questionInfo.Tags)) - for i, tag := range questionInfo.Tags { - req.Tags[i] = &schema.TagItem{ - SlugName: tag, - DisplayName: tag, - } - } - canList, requireRanks, err := ipc.rankService.CheckOperationPermissionsForRanks(ctx, req.UserID, []string{ - permission.QuestionAdd, - permission.QuestionEdit, - permission.QuestionDelete, - permission.QuestionClose, - permission.QuestionReopen, - permission.TagUseReservedTag, - permission.TagAdd, - permission.LinkUrlLimit, - }) - if err != nil { - log.Errorf("error: %v", err) - ctx.JSON(200, gin.H{"text": err.Error()}) - return - } - req.CanAdd = canList[0] - req.CanEdit = canList[1] - req.CanDelete = canList[2] - req.CanClose = canList[3] - req.CanReopen = canList[4] - req.CanUseReservedTag = canList[5] - req.CanAddTag = canList[6] - if !req.CanAdd { - ctx.JSON(200, gin.H{"text": "No permission to add question"}) - log.Errorf("error: %v", err) - return - } - hasNewTag, err := ipc.questionService.HasNewTag(ctx, req.Tags) - if err != nil { - log.Errorf("error: %v", err) - ctx.JSON(200, gin.H{"text": err.Error()}) - return - } - if !req.CanAddTag && hasNewTag { - lang := handler.GetLang(ctx) - msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: requireRanks[6]}) - log.Errorf("error: %v", msg) - ctx.JSON(200, gin.H{"text": msg}) - return - } - - errList, err := ipc.questionService.CheckAddQuestion(ctx, req) - if err != nil { - errlist, ok := errList.([]*validator.FormErrorField) - if ok { - errFields = append(errFields, errlist...) - } - } - if len(errFields) > 0 { - handler.HandleResponse(ctx, errors.BadRequest(reason.RequestFormatError), errFields) - log.Errorf("error: RequestFormatError") - ctx.JSON(200, gin.H{"text": "RequestFormatError"}) - return - } - req.UserAgent = ctx.GetHeader("User-Agent") - req.IP = ctx.ClientIP() - resp, err := ipc.questionService.AddQuestion(ctx, req) - if err != nil { - errlist, ok := resp.([]*validator.FormErrorField) - if ok { - errFields = append(errFields, errlist...) - } - } - - if len(errFields) > 0 { - log.Errorf("error: RequestFormatError") - ctx.JSON(200, gin.H{"text": "RequestFormatError"}) - return - } - - ctx.JSON(200, gin.H{"text": "Add Question Successfully"}) -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package importer + +import ( + "context" + "fmt" + + "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/reason" + "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/incubator-answer/internal/base/validator" + "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/content" + "github.com/apache/incubator-answer/internal/service/permission" + "github.com/apache/incubator-answer/internal/service/rank" + usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/incubator-answer/plugin" + "github.com/gin-gonic/gin" + "github.com/segmentfault/pacman/errors" + "github.com/segmentfault/pacman/log" +) + +// ImporterService importer service +type ImporterService struct { + questionService *content.QuestionService + rankService *rank.RankService + userCommon *usercommon.UserCommon +} + +// NewRankService new rank service +func NewImporterService( + questionService *content.QuestionService, + rankService *rank.RankService, + userCommon *usercommon.UserCommon) *ImporterService { + return &ImporterService{ + questionService: questionService, + rankService: rankService, + userCommon: userCommon, + } +} + +type ImporterFunc struct { + importerService *ImporterService +} + +func (ipfunc *ImporterFunc) AddQuestion(ctx context.Context, questionInfo plugin.QuestionImporterInfo) { + println("Hello, World123!") + ipfunc.importerService.AddQuestion123(ctx, questionInfo) +} + +func (ip *ImporterService) NewImporterFunc() plugin.ImporterFunc { + return &ImporterFunc{importerService: ip} +} + +func (ip *ImporterService) AddQuestion123(ctx context.Context, questionInfo plugin.QuestionImporterInfo) { + fmt.Println("Call from func (ip *ImporterService) AddQuestion123(*****)") + // body, err := io.ReadAll(ctx.Request.Body) + // ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + fmt.Println("ImportPush") + + // if err != nil { + // log.Errorf("error: %v", err) + // return + // } + req := &schema.QuestionAdd{} + errFields := make([]*validator.FormErrorField, 0) + // reject, rejectKey := ipc.rateLimitMiddleware.DuplicateRequestRejection(ctx, req) + // if reject { + // return + // } + user_info, exist, err := ip.userCommon.GetByEmail(ctx, questionInfo.UserEmail) + if err != nil { + log.Errorf("error: %v", err) + return + } + if !exist { + log.Errorf("error: User Email not found") + return + } + + // defer func() { + // // If status is not 200 means that the bad request has been returned, so the record should be cleared + // if ctx.Writer.Status() != http.StatusOK { + // ipc.rateLimitMiddleware.DuplicateRequestClear(ctx, rejectKey) + // } + // }() + req.UserID = user_info.ID + req.Title = questionInfo.Title + req.Content = questionInfo.Content + req.HTML = "

" + questionInfo.Content + "

" + req.Tags = make([]*schema.TagItem, len(questionInfo.Tags)) + for i, tag := range questionInfo.Tags { + req.Tags[i] = &schema.TagItem{ + SlugName: tag, + DisplayName: tag, + } + } + canList, requireRanks, err := ip.rankService.CheckOperationPermissionsForRanks(ctx, req.UserID, []string{ + permission.QuestionAdd, + permission.QuestionEdit, + permission.QuestionDelete, + permission.QuestionClose, + permission.QuestionReopen, + permission.TagUseReservedTag, + permission.TagAdd, + permission.LinkUrlLimit, + }) + if err != nil { + log.Errorf("error: %v", err) + return + } + req.CanAdd = canList[0] + req.CanEdit = canList[1] + req.CanDelete = canList[2] + req.CanClose = canList[3] + req.CanReopen = canList[4] + req.CanUseReservedTag = canList[5] + req.CanAddTag = canList[6] + if !req.CanAdd { + log.Errorf("error: %v", err) + return + } + hasNewTag, err := ip.questionService.HasNewTag(ctx.(*gin.Context), req.Tags) + if err != nil { + log.Errorf("error: %v", err) + return + } + if !req.CanAddTag && hasNewTag { + lang := handler.GetLang(ctx.(*gin.Context)) + msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: requireRanks[6]}) + log.Errorf("error: %v", msg) + return + } + + errList, err := ip.questionService.CheckAddQuestion(ctx, req) + if err != nil { + errlist, ok := errList.([]*validator.FormErrorField) + if ok { + errFields = append(errFields, errlist...) + } + } + if len(errFields) > 0 { + handler.HandleResponse(ctx.(*gin.Context), errors.BadRequest(reason.RequestFormatError), errFields) + log.Errorf("error: RequestFormat Error") + return + } + ginCtx := ctx.(*gin.Context) + req.UserAgent = ginCtx.GetHeader("User-Agent") + req.IP = ginCtx.ClientIP() + resp, err := ip.questionService.AddQuestion(ctx, req) + if err != nil { + errlist, ok := resp.([]*validator.FormErrorField) + if ok { + errFields = append(errFields, errlist...) + } + } + + if len(errFields) > 0 { + log.Errorf("error: RequestFormatError") + return + } + log.Info("Add Question Successfully") +} diff --git a/internal/service/plugin_common/plugin_common_service.go b/internal/service/plugin_common/plugin_common_service.go index d064fa99..4f7cb30a 100644 --- a/internal/service/plugin_common/plugin_common_service.go +++ b/internal/service/plugin_common/plugin_common_service.go @@ -22,6 +22,7 @@ package plugin_common import ( "context" "encoding/json" + "fmt" "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/repo/search_sync" @@ -34,6 +35,7 @@ import ( "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/config" + "github.com/apache/incubator-answer/internal/service/importer" "github.com/apache/incubator-answer/plugin" ) @@ -56,6 +58,7 @@ type PluginCommonService struct { pluginConfigRepo PluginConfigRepo pluginUserConfigRepo PluginUserConfigRepo data *data.Data + importerService *importer.ImporterService } // NewPluginCommonService new report service @@ -64,6 +67,7 @@ func NewPluginCommonService( pluginUserConfigRepo PluginUserConfigRepo, configService *config.ConfigService, data *data.Data, + importerService *importer.ImporterService, ) *PluginCommonService { p := &PluginCommonService{ @@ -71,6 +75,7 @@ func NewPluginCommonService( pluginConfigRepo: pluginConfigRepo, pluginUserConfigRepo: pluginUserConfigRepo, data: data, + importerService: importerService, } p.initPluginData() return p @@ -99,6 +104,11 @@ func (ps *PluginCommonService) UpdatePluginConfig(ctx context.Context, req *sche } return nil }) + _ = plugin.CallImporter(func(importer plugin.Importer) error { + fmt.Println("更新时注册Importer") + importer.RegisterImporterFunc(ctx, ps.importerService.NewImporterFunc()) + return nil + }) return nil } @@ -126,6 +136,7 @@ func (ps *PluginCommonService) GetUserPluginConfig(ctx context.Context, req *sch } func (ps *PluginCommonService) initPluginData() { + fmt.Println("init plugin data") // init plugin status pluginStatus, err := ps.configService.GetStringValue(context.TODO(), constant.PluginStatus) if err != nil { diff --git a/plugin/importer.go b/plugin/importer.go index 79a84c50..4c25d72b 100644 --- a/plugin/importer.go +++ b/plugin/importer.go @@ -19,7 +19,9 @@ package plugin -import "github.com/gin-gonic/gin" +import ( + "context" +) type QuestionImporterInfo struct { Title string `json:"title"` @@ -30,7 +32,11 @@ type QuestionImporterInfo struct { type Importer interface { Base - GetQuestion(ctx *gin.Context) (questionInfo *QuestionImporterInfo, err error) + RegisterImporterFunc(ctx context.Context, importer ImporterFunc) +} + +type ImporterFunc interface { + AddQuestion(ctx context.Context, questionInfo QuestionImporterInfo) } var ( From 73c7a22900834db26684b8b6060272da9b9c81ee Mon Sep 17 00:00:00 2001 From: Anan <1449891717@qq.com> Date: Wed, 16 Oct 2024 01:57:58 +0000 Subject: [PATCH 250/336] Fix importer --- cmd/wire_gen.go | 2 +- internal/service/importer/importer_service.go | 40 +++++++------------ .../plugin_common/plugin_common_service.go | 1 - plugin/importer.go | 2 +- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 1ffa75ca..29e0a441 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -79,6 +79,7 @@ import ( "github.com/apache/incubator-answer/internal/service/collection_common" comment2 "github.com/apache/incubator-answer/internal/service/comment" "github.com/apache/incubator-answer/internal/service/comment_common" + "github.com/apache/incubator-answer/internal/service/importer" config2 "github.com/apache/incubator-answer/internal/service/config" "github.com/apache/incubator-answer/internal/service/content" "github.com/apache/incubator-answer/internal/service/dashboard" @@ -111,7 +112,6 @@ import ( "github.com/apache/incubator-answer/internal/service/user_common" user_external_login2 "github.com/apache/incubator-answer/internal/service/user_external_login" user_notification_config2 "github.com/apache/incubator-answer/internal/service/user_notification_config" - "github.com/apache/incubator-answer/internal/service/importer" "github.com/segmentfault/pacman" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/importer/importer_service.go b/internal/service/importer/importer_service.go index 668a2bf9..d775ee76 100644 --- a/internal/service/importer/importer_service.go +++ b/internal/service/importer/importer_service.go @@ -21,7 +21,6 @@ package importer import ( "context" - "fmt" "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/reason" @@ -61,27 +60,19 @@ type ImporterFunc struct { importerService *ImporterService } -func (ipfunc *ImporterFunc) AddQuestion(ctx context.Context, questionInfo plugin.QuestionImporterInfo) { - println("Hello, World123!") - ipfunc.importerService.AddQuestion123(ctx, questionInfo) +func (ipfunc *ImporterFunc) AddQuestion(ctx context.Context, questionInfo plugin.QuestionImporterInfo) (err error) { + ipfunc.importerService.ImportQuestion(ctx, questionInfo) + return nil } func (ip *ImporterService) NewImporterFunc() plugin.ImporterFunc { return &ImporterFunc{importerService: ip} } -func (ip *ImporterService) AddQuestion123(ctx context.Context, questionInfo plugin.QuestionImporterInfo) { - fmt.Println("Call from func (ip *ImporterService) AddQuestion123(*****)") - // body, err := io.ReadAll(ctx.Request.Body) - // ctx.Request.Body = io.NopCloser(bytes.NewBuffer(body)) - fmt.Println("ImportPush") - - // if err != nil { - // log.Errorf("error: %v", err) - // return - // } +func (ip *ImporterService) ImportQuestion(ctx context.Context, questionInfo plugin.QuestionImporterInfo) (err error) { req := &schema.QuestionAdd{} errFields := make([]*validator.FormErrorField, 0) + // To limit rate, remove the following code from comment: Part 1/2 // reject, rejectKey := ipc.rateLimitMiddleware.DuplicateRequestRejection(ctx, req) // if reject { // return @@ -89,13 +80,14 @@ func (ip *ImporterService) AddQuestion123(ctx context.Context, questionInfo plug user_info, exist, err := ip.userCommon.GetByEmail(ctx, questionInfo.UserEmail) if err != nil { log.Errorf("error: %v", err) - return + return err } if !exist { log.Errorf("error: User Email not found") - return + return err } + // To limit rate, remove the following code from comment: Part 2/2 // defer func() { // // If status is not 200 means that the bad request has been returned, so the record should be cleared // if ctx.Writer.Status() != http.StatusOK { @@ -125,7 +117,7 @@ func (ip *ImporterService) AddQuestion123(ctx context.Context, questionInfo plug }) if err != nil { log.Errorf("error: %v", err) - return + return err } req.CanAdd = canList[0] req.CanEdit = canList[1] @@ -136,18 +128,18 @@ func (ip *ImporterService) AddQuestion123(ctx context.Context, questionInfo plug req.CanAddTag = canList[6] if !req.CanAdd { log.Errorf("error: %v", err) - return + return err } hasNewTag, err := ip.questionService.HasNewTag(ctx.(*gin.Context), req.Tags) if err != nil { log.Errorf("error: %v", err) - return + return err } if !req.CanAddTag && hasNewTag { lang := handler.GetLang(ctx.(*gin.Context)) msg := translator.TrWithData(lang, reason.NoEnoughRankToOperate, &schema.PermissionTrTplData{Rank: requireRanks[6]}) log.Errorf("error: %v", msg) - return + return errors.BadRequest(msg) } errList, err := ip.questionService.CheckAddQuestion(ctx, req) @@ -158,9 +150,7 @@ func (ip *ImporterService) AddQuestion123(ctx context.Context, questionInfo plug } } if len(errFields) > 0 { - handler.HandleResponse(ctx.(*gin.Context), errors.BadRequest(reason.RequestFormatError), errFields) - log.Errorf("error: RequestFormat Error") - return + return errors.BadRequest(reason.RequestFormatError) } ginCtx := ctx.(*gin.Context) req.UserAgent = ginCtx.GetHeader("User-Agent") @@ -172,10 +162,10 @@ func (ip *ImporterService) AddQuestion123(ctx context.Context, questionInfo plug errFields = append(errFields, errlist...) } } - if len(errFields) > 0 { log.Errorf("error: RequestFormatError") - return + return errors.BadRequest(reason.RequestFormatError) } log.Info("Add Question Successfully") + return nil } diff --git a/internal/service/plugin_common/plugin_common_service.go b/internal/service/plugin_common/plugin_common_service.go index 4f7cb30a..920a8a03 100644 --- a/internal/service/plugin_common/plugin_common_service.go +++ b/internal/service/plugin_common/plugin_common_service.go @@ -105,7 +105,6 @@ func (ps *PluginCommonService) UpdatePluginConfig(ctx context.Context, req *sche return nil }) _ = plugin.CallImporter(func(importer plugin.Importer) error { - fmt.Println("更新时注册Importer") importer.RegisterImporterFunc(ctx, ps.importerService.NewImporterFunc()) return nil }) diff --git a/plugin/importer.go b/plugin/importer.go index 4c25d72b..3893d54a 100644 --- a/plugin/importer.go +++ b/plugin/importer.go @@ -36,7 +36,7 @@ type Importer interface { } type ImporterFunc interface { - AddQuestion(ctx context.Context, questionInfo QuestionImporterInfo) + AddQuestion(ctx context.Context, questionInfo QuestionImporterInfo) (err error) } var ( From 2fd6ac37d08039254e98b386edb9ed3dfb416d18 Mon Sep 17 00:00:00 2001 From: Anan <1449891717@qq.com> Date: Wed, 16 Oct 2024 02:57:27 +0000 Subject: [PATCH 251/336] Fix err --- internal/service/importer/importer_service.go | 6 +++--- internal/service/plugin_common/plugin_common_service.go | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/internal/service/importer/importer_service.go b/internal/service/importer/importer_service.go index d775ee76..82572f85 100644 --- a/internal/service/importer/importer_service.go +++ b/internal/service/importer/importer_service.go @@ -77,14 +77,13 @@ func (ip *ImporterService) ImportQuestion(ctx context.Context, questionInfo plug // if reject { // return // } - user_info, exist, err := ip.userCommon.GetByEmail(ctx, questionInfo.UserEmail) + userInfo, exist, err := ip.userCommon.GetByEmail(ctx, questionInfo.UserEmail) if err != nil { log.Errorf("error: %v", err) return err } if !exist { log.Errorf("error: User Email not found") - return err } // To limit rate, remove the following code from comment: Part 2/2 @@ -94,7 +93,7 @@ func (ip *ImporterService) ImportQuestion(ctx context.Context, questionInfo plug // ipc.rateLimitMiddleware.DuplicateRequestClear(ctx, rejectKey) // } // }() - req.UserID = user_info.ID + req.UserID = userInfo.ID req.Title = questionInfo.Title req.Content = questionInfo.Content req.HTML = "

" + questionInfo.Content + "

" @@ -162,6 +161,7 @@ func (ip *ImporterService) ImportQuestion(ctx context.Context, questionInfo plug errFields = append(errFields, errlist...) } } + if len(errFields) > 0 { log.Errorf("error: RequestFormatError") return errors.BadRequest(reason.RequestFormatError) diff --git a/internal/service/plugin_common/plugin_common_service.go b/internal/service/plugin_common/plugin_common_service.go index 920a8a03..ea6701bd 100644 --- a/internal/service/plugin_common/plugin_common_service.go +++ b/internal/service/plugin_common/plugin_common_service.go @@ -22,7 +22,6 @@ package plugin_common import ( "context" "encoding/json" - "fmt" "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/repo/search_sync" @@ -135,7 +134,6 @@ func (ps *PluginCommonService) GetUserPluginConfig(ctx context.Context, req *sch } func (ps *PluginCommonService) initPluginData() { - fmt.Println("init plugin data") // init plugin status pluginStatus, err := ps.configService.GetStringValue(context.TODO(), constant.PluginStatus) if err != nil { From 1e82b043824d95ec86b235d39ef1c87b105f1915 Mon Sep 17 00:00:00 2001 From: Anan <1449891717@qq.com> Date: Wed, 16 Oct 2024 03:07:25 +0000 Subject: [PATCH 252/336] Fix line87 --- internal/service/importer/importer_service.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/service/importer/importer_service.go b/internal/service/importer/importer_service.go index 82572f85..2b53f7e3 100644 --- a/internal/service/importer/importer_service.go +++ b/internal/service/importer/importer_service.go @@ -21,6 +21,7 @@ package importer import ( "context" + "fmt" "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/reason" @@ -83,7 +84,7 @@ func (ip *ImporterService) ImportQuestion(ctx context.Context, questionInfo plug return err } if !exist { - log.Errorf("error: User Email not found") + return fmt.Errorf("User not found") } // To limit rate, remove the following code from comment: Part 2/2 From 2372950563c937413969d168a0dc68aa8b8c1765 Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 16 Oct 2024 16:06:06 +0800 Subject: [PATCH 253/336] refactor(ui): LinkedQuestions component to handle empty data --- .../Questions/Detail/components/LinkedQuestions/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx index f02adb35..c5d92cbe 100644 --- a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx +++ b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx @@ -22,6 +22,8 @@ import { Card, ListGroup } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; +import { isEmpty } from 'lodash'; + import { Icon } from '@/components'; import { questionLink } from '@/services'; import { pathFactory } from '@/router/pathFactory'; @@ -43,7 +45,7 @@ const Index: FC = ({ id }) => { page_size: 5, }); - if (!data || !data.list) { + if (!data || isEmpty(data?.list)) { return null; } From 86020654901342bdc1497306d7baf2639092a273 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 16 Oct 2024 17:03:29 +0800 Subject: [PATCH 254/336] refactor(provider): add importer provider --- cmd/wire_gen.go | 2 +- internal/service/provider.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 29e0a441..978ab23b 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -79,13 +79,13 @@ import ( "github.com/apache/incubator-answer/internal/service/collection_common" comment2 "github.com/apache/incubator-answer/internal/service/comment" "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/importer" config2 "github.com/apache/incubator-answer/internal/service/config" "github.com/apache/incubator-answer/internal/service/content" "github.com/apache/incubator-answer/internal/service/dashboard" "github.com/apache/incubator-answer/internal/service/event_queue" export2 "github.com/apache/incubator-answer/internal/service/export" "github.com/apache/incubator-answer/internal/service/follow" + "github.com/apache/incubator-answer/internal/service/importer" meta2 "github.com/apache/incubator-answer/internal/service/meta" "github.com/apache/incubator-answer/internal/service/meta_common" "github.com/apache/incubator-answer/internal/service/notice_queue" diff --git a/internal/service/provider.go b/internal/service/provider.go index 12e0db79..9d523b49 100644 --- a/internal/service/provider.go +++ b/internal/service/provider.go @@ -37,6 +37,7 @@ import ( "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/apache/incubator-answer/internal/service/export" "github.com/apache/incubator-answer/internal/service/follow" + "github.com/apache/incubator-answer/internal/service/importer" "github.com/apache/incubator-answer/internal/service/meta" "github.com/apache/incubator-answer/internal/service/meta_common" "github.com/apache/incubator-answer/internal/service/notice_queue" @@ -124,4 +125,5 @@ var ProviderSetService = wire.NewSet( badge.NewBadgeEventService, badge.NewBadgeAwardService, badge.NewBadgeGroupService, + importer.NewImporterService, ) From a8e008de0702f76733c79ae784357469b4bb496c Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Tue, 15 Oct 2024 19:20:04 +0800 Subject: [PATCH 255/336] feat: Support related and hot questions template --- cmd/wire_gen.go | 2 +- internal/controller/template_controller.go | 68 ++++++++++++++++------ ui/template/hot-question.html | 42 +++++++++++++ ui/template/question-detail.html | 10 +++- ui/template/question.html | 4 +- ui/template/related-question.html | 42 +++++++++++++ 6 files changed, 146 insertions(+), 22 deletions(-) create mode 100644 ui/template/hot-question.html create mode 100644 ui/template/related-question.html diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 978ab23b..d8e6c744 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -277,7 +277,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, avatarMiddleware := middleware.NewAvatarMiddleware(serviceConf, uploaderService) shortIDMiddleware := middleware.NewShortIDMiddleware(siteInfoCommonService) templateRenderController := templaterender.NewTemplateRenderController(questionService, userService, tagService, answerService, commentService, siteInfoCommonService, questionRepo) - templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService, eventQueueService, userService) + templateController := controller.NewTemplateController(templateRenderController, siteInfoCommonService, eventQueueService, userService, questionService) templateRouter := router.NewTemplateRouter(templateController, templateRenderController, siteInfoController, authUserMiddleware) connectorController := controller.NewConnectorController(siteInfoCommonService, emailService, userExternalLoginService) userCenterLoginService := user_external_login2.NewUserCenterLoginService(userRepo, userCommon, userExternalLoginRepo, userActiveActivityRepo, siteInfoCommonService) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 56a38f00..5a63e6de 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -22,6 +22,7 @@ package controller import ( "encoding/json" "fmt" + "github.com/apache/incubator-answer/internal/base/middleware" "github.com/apache/incubator-answer/internal/service/content" "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/apache/incubator-answer/plugin" @@ -58,6 +59,7 @@ type TemplateController struct { siteInfoService siteinfo_common.SiteInfoCommonService eventQueueService event_queue.EventQueueService userService *content.UserService + questionService *content.QuestionService } // NewTemplateController new controller @@ -66,6 +68,7 @@ func NewTemplateController( siteInfoService siteinfo_common.SiteInfoCommonService, eventQueueService event_queue.EventQueueService, userService *content.UserService, + questionService *content.QuestionService, ) *TemplateController { script, css := GetStyle() return &TemplateController{ @@ -75,6 +78,7 @@ func NewTemplateController( siteInfoService: siteInfoService, eventQueueService: eventQueueService, userService: userService, + questionService: questionService, } } func GetStyle() (script []string, css string) { @@ -146,6 +150,14 @@ func (tc *TemplateController) Index(ctx *gin.Context) { return } + hotQuestionReq := &schema.QuestionPageReq{ + Page: 1, + PageSize: 6, + OrderCond: "hot", + InDays: 7, + } + hotQuestion, _, _ := tc.templateRenderController.Index(ctx, hotQuestionReq) + siteInfo := tc.SiteInfo(ctx) siteInfo.Canonical = siteInfo.General.SiteUrl @@ -156,10 +168,11 @@ func (tc *TemplateController) Index(ctx *gin.Context) { } siteInfo.Title = "" tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{ - "data": data, - "useTitle": UrlUseTitle, - "page": templaterender.Paginator(page, req.PageSize, count), - "path": "questions", + "data": data, + "useTitle": UrlUseTitle, + "page": templaterender.Paginator(page, req.PageSize, count), + "path": "questions", + "hotQuestion": hotQuestion, }) } @@ -177,6 +190,15 @@ func (tc *TemplateController) QuestionList(ctx *gin.Context) { tc.Page404(ctx) return } + + hotQuestionReq := &schema.QuestionPageReq{ + Page: 1, + PageSize: 6, + OrderCond: "hot", + InDays: 7, + } + hotQuestion, _, _ := tc.templateRenderController.Index(ctx, hotQuestionReq) + siteInfo := tc.SiteInfo(ctx) siteInfo.Canonical = fmt.Sprintf("%s/questions", siteInfo.General.SiteUrl) if page > 1 { @@ -190,13 +212,14 @@ func (tc *TemplateController) QuestionList(ctx *gin.Context) { } siteInfo.Title = fmt.Sprintf("%s - %s", translator.Tr(handler.GetLang(ctx), constant.QuestionsTitleTrKey), siteInfo.General.Name) tc.html(ctx, http.StatusOK, "question.html", siteInfo, gin.H{ - "data": data, - "useTitle": UrlUseTitle, - "page": templaterender.Paginator(page, req.PageSize, count), + "data": data, + "useTitle": UrlUseTitle, + "page": templaterender.Paginator(page, req.PageSize, count), + "hotQuestion": hotQuestion, }) } -func (tc *TemplateController) QuestionInfoeRdirect(ctx *gin.Context, siteInfo *schema.TemplateSiteInfoResp, correctTitle bool) (jump bool, url string) { +func (tc *TemplateController) QuestionInfoRedirect(ctx *gin.Context, siteInfo *schema.TemplateSiteInfoResp, correctTitle bool) (jump bool, url string) { questionID := ctx.Param("id") title := ctx.Param("title") answerID := uid.DeShortID(title) @@ -316,7 +339,7 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { } siteInfo := tc.SiteInfo(ctx) - jump, jumpurl := tc.QuestionInfoeRdirect(ctx, siteInfo, correctTitle) + jump, jumpurl := tc.QuestionInfoRedirect(ctx, siteInfo, correctTitle) if jump { ctx.Redirect(http.StatusFound, jumpurl) return @@ -337,7 +360,6 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { } // comments - objectIDs := []string{uid.DeShortID(id)} for _, answer := range answers { answerID := uid.DeShortID(answer.ID) @@ -348,6 +370,17 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { tc.Page404(ctx) return } + + UrlUseTitle := false + if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitle || + siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDAndTitleByShortID { + UrlUseTitle = true + } + + //related question + userID := middleware.GetLoginUserIDFromContext(ctx) + relatedQuestion, _, _ := tc.questionService.SimilarQuestion(ctx, id, userID) + siteInfo.Canonical = fmt.Sprintf("%s/questions/%s/%s", siteInfo.General.SiteUrl, id, encodeTitle) if siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionID || siteInfo.SiteSeo.Permalink == constant.PermalinkQuestionIDByShortID { siteInfo.Canonical = fmt.Sprintf("%s/questions/%s", siteInfo.General.SiteUrl, id) @@ -389,7 +422,6 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { item.Author.URL = fmt.Sprintf("%s/users/%s", siteInfo.General.SiteUrl, answer.UserInfo.Username) answerList = append(answerList, item) } - } jsonLD.MainEntity.SuggestedAnswer = answerList jsonLDStr, err := json.Marshal(jsonLD) @@ -405,12 +437,14 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { siteInfo.Keywords = strings.Replace(strings.Trim(fmt.Sprint(tags), "[]"), " ", ",", -1) siteInfo.Title = fmt.Sprintf("%s - %s", detail.Title, siteInfo.General.Name) tc.html(ctx, http.StatusOK, "question-detail.html", siteInfo, gin.H{ - "id": id, - "answerid": answerid, - "detail": detail, - "answers": answers, - "comments": comments, - "noindex": detail.Show == entity.QuestionHide, + "id": id, + "answerid": answerid, + "detail": detail, + "answers": answers, + "comments": comments, + "noindex": detail.Show == entity.QuestionHide, + "useTitle": UrlUseTitle, + "relatedQuestion": relatedQuestion, }) } diff --git a/ui/template/hot-question.html b/ui/template/hot-question.html new file mode 100644 index 00000000..23981926 --- /dev/null +++ b/ui/template/hot-question.html @@ -0,0 +1,42 @@ + +{{define "hot-question"}} +
+
{{translator $.language "ui.question.hot_questions"}}
+ +
+{{end}} diff --git a/ui/template/question-detail.html b/ui/template/question-detail.html index 2134a04f..d0e6933d 100644 --- a/ui/template/question-detail.html +++ b/ui/template/question-detail.html @@ -24,7 +24,11 @@

+ {{if $.useTitle }} + {{.detail.Title}} + {{else}} {{.detail.Title}} + {{end}}

@@ -116,7 +120,7 @@
{{.detail.AnswerCount}} Answers
{{range .answers}} -
+
{{formatLinkNofollow .HTML}}
@@ -192,8 +196,8 @@
{{end}}
-
- +
+ {{template "related-question" .}}
diff --git a/ui/template/question.html b/ui/template/question.html index 40c645ed..058645e5 100644 --- a/ui/template/question.html +++ b/ui/template/question.html @@ -94,7 +94,9 @@
-
+
+ {{template "hot-question" .}} +
{{template "footer" .}} diff --git a/ui/template/related-question.html b/ui/template/related-question.html new file mode 100644 index 00000000..c93ccc8d --- /dev/null +++ b/ui/template/related-question.html @@ -0,0 +1,42 @@ + +{{define "related-question"}} +
+
{{translator $.language "ui.related_question.title"}}
+ +
+{{end}} From 916dba3f063b95ab8297c63630750b2d08988046 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Fri, 18 Oct 2024 10:12:59 +0800 Subject: [PATCH 256/336] feat(pager): Show 404 when page is out of range (#1135) close #1133 --- internal/base/pager/pagination.go | 12 ++++++++++++ internal/controller/question_controller.go | 4 ++++ internal/controller/tag_controller.go | 5 +++++ internal/controller/template_controller.go | 10 +++++++--- internal/service/tag/tag_service.go | 1 - ui/src/services/client/question.ts | 5 ++--- ui/src/services/common.ts | 10 +++++----- 7 files changed, 35 insertions(+), 12 deletions(-) diff --git a/internal/base/pager/pagination.go b/internal/base/pager/pagination.go index 5411e685..36849fed 100644 --- a/internal/base/pager/pagination.go +++ b/internal/base/pager/pagination.go @@ -62,3 +62,15 @@ func ValPageAndPageSize(page, pageSize int) (int, int) { } return page, pageSize } + +// ValPageOutOfRange validate page out of range +func ValPageOutOfRange(total int64, page, pageSize int) bool { + if total <= 0 { + return false + } + if pageSize <= 0 { + return true + } + totalPages := (total + int64(pageSize) - 1) / int64(pageSize) + return page < 1 || page > int(totalPages) +} diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 8f349855..310a8201 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -337,6 +337,10 @@ func (qc *QuestionController) QuestionPage(ctx *gin.Context) { handler.HandleResponse(ctx, err, nil) return } + if pager.ValPageOutOfRange(total, req.Page, req.PageSize) { + handler.HandleResponse(ctx, errors.NotFound(reason.RequestFormatError), nil) + return + } handler.HandleResponse(ctx, nil, pager.NewPageModel(total, questions)) } diff --git a/internal/controller/tag_controller.go b/internal/controller/tag_controller.go index 5f5cf5fb..1e98b480 100644 --- a/internal/controller/tag_controller.go +++ b/internal/controller/tag_controller.go @@ -22,6 +22,7 @@ package controller import ( "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/middleware" + "github.com/apache/incubator-answer/internal/base/pager" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/permission" @@ -269,6 +270,10 @@ func (tc *TagController) GetTagWithPage(ctx *gin.Context) { req.UserID = middleware.GetLoginUserIDFromContext(ctx) resp, err := tc.tagService.GetTagWithPage(ctx, req) + if pager.ValPageOutOfRange(resp.Count, req.Page, req.PageSize) { + handler.HandleResponse(ctx, errors.NotFound(reason.RequestFormatError), nil) + return + } handler.HandleResponse(ctx, err, resp) } diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 5a63e6de..c3a2ff0a 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -23,6 +23,7 @@ import ( "encoding/json" "fmt" "github.com/apache/incubator-answer/internal/base/middleware" + "github.com/apache/incubator-answer/internal/base/pager" "github.com/apache/incubator-answer/internal/service/content" "github.com/apache/incubator-answer/internal/service/event_queue" "github.com/apache/incubator-answer/plugin" @@ -145,7 +146,7 @@ func (tc *TemplateController) Index(ctx *gin.Context) { var page = req.Page data, count, err := tc.templateRenderController.Index(ctx, req) - if err != nil { + if err != nil || (len(data) == 0 && pager.ValPageOutOfRange(count, page, req.PageSize)) { tc.Page404(ctx) return } @@ -186,7 +187,7 @@ func (tc *TemplateController) QuestionList(ctx *gin.Context) { } var page = req.Page data, count, err := tc.templateRenderController.Index(ctx, req) - if err != nil { + if err != nil || (len(data) == 0 && pager.ValPageOutOfRange(count, page, req.PageSize)) { tc.Page404(ctx) return } @@ -454,8 +455,11 @@ func (tc *TemplateController) TagList(ctx *gin.Context) { if handler.BindAndCheck(ctx, req) { return } + if req.PageSize == 0 { + req.PageSize = constant.DefaultPageSize + } data, err := tc.templateRenderController.TagList(ctx, req) - if err != nil { + if err != nil || pager.ValPageOutOfRange(data.Count, req.Page, req.PageSize) { tc.Page404(ctx) return } diff --git a/internal/service/tag/tag_service.go b/internal/service/tag/tag_service.go index 01864163..e5fcf597 100644 --- a/internal/service/tag/tag_service.go +++ b/internal/service/tag/tag_service.go @@ -432,7 +432,6 @@ func (ts *TagService) GetTagWithPage(ctx context.Context, req *schema.GetTagWith } item.GetExcerpt() resp = append(resp, item) - } return pager.NewPageModel(total, resp), nil } diff --git a/ui/src/services/client/question.ts b/ui/src/services/client/question.ts index b62fbf1a..169ccf3d 100644 --- a/ui/src/services/client/question.ts +++ b/ui/src/services/client/question.ts @@ -25,9 +25,8 @@ import type * as Type from '@/common/interface'; export const useQuestionList = (params: Type.QueryQuestionsReq) => { const apiUrl = `/answer/api/v1/question/page?${qs.stringify(params)}`; - const { data, error } = useSWR( - [apiUrl], - request.instance.get, + const { data, error } = useSWR(apiUrl, (url) => + request.get(url, { allow404: true }), ); return { data, diff --git a/ui/src/services/common.ts b/ui/src/services/common.ts index ad0d99e0..cfc1d9cd 100644 --- a/ui/src/services/common.ts +++ b/ui/src/services/common.ts @@ -35,11 +35,11 @@ export const queryQuestionByTitle = (title: string) => { }; export const useQueryTags = (params) => { - const { data, error, mutate } = useSWR( - `/answer/api/v1/tags/page?${qs.stringify(params, { - skipNulls: true, - })}`, - request.instance.get, + const apiUrl = `/answer/api/v1/tags/page?${qs.stringify(params, { + skipNulls: true, + })}`; + const { data, error, mutate } = useSWR(apiUrl, (url) => + request.get(url, { allow404: true }), ); return { data, From 43c09e8b8c2cb2f7cb2c0c98b2606b596bce8ee8 Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 18 Oct 2024 12:33:06 +0800 Subject: [PATCH 257/336] fix: badge modal zindex --- ui/src/components/Modal/BadgeModal.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index 9c77e9d4..01983bac 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -71,6 +71,9 @@ const BadgeModal: FC = ({ badge, visible }) => { const LENGTH = 200; const bgNode = document.documentElement || document.body; const parentNode = document.getElementById('badgeModal')?.parentNode; + const badgeModalNode = document.getElementById('badgeModal'); + + badgeModalNode?.setAttribute('style', 'z-index: 1'); if (parentNode) { bg1 = new AnimateGift({ From e893a656586eaaa772e66ecbb6f20143136bcc07 Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 18 Oct 2024 12:33:46 +0800 Subject: [PATCH 258/336] fix: badge modal zindex --- ui/src/components/Modal/BadgeModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index 01983bac..18524852 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -70,8 +70,8 @@ const BadgeModal: FC = ({ badge, visible }) => { const DURATION = 8000; const LENGTH = 200; const bgNode = document.documentElement || document.body; - const parentNode = document.getElementById('badgeModal')?.parentNode; const badgeModalNode = document.getElementById('badgeModal'); + const parentNode = badgeModalNode?.parentNode; badgeModalNode?.setAttribute('style', 'z-index: 1'); From 24b53d53550e5a645638c8dd9fed4d58a8bb412a Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 18 Oct 2024 14:24:47 +0800 Subject: [PATCH 259/336] fix: personal badges list style --- .../Personal/components/Overview/index.tsx | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 3c1f590e..81ed7b32 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -49,35 +49,32 @@ const Index: FC = ({ visible, introduction, data, username }) => { dangerouslySetInnerHTML={{ __html: introduction }} /> ) : ( -
{t('about_me_empty')}
+
{t('about_me_empty')}
)} - 0 || data?.question?.length > 0 ? 'mb-4' : '' - }> - -
{t('top_answers')}
- {data?.answer?.length > 0 ? ( - - ) : ( -
{t('content_empty')}
+ + + {data?.answer?.length > 0 && ( + <> +
{t('top_answers')}
+ + )} -
{t('top_questions')}
- {data?.question?.length > 0 ? ( - - ) : ( -
{t('content_empty')}
+ {data?.question?.length > 0 && ( + <> +
{t('top_questions')}
+ + )}
-
-
{t('recent_badges')}
- {Number(recentBadges?.count) > 0 ? ( -
+ {Number(recentBadges?.count) > 0 && ( +
+
{t('recent_badges')}
+ {recentBadges?.list?.map((item) => { return ( @@ -89,11 +86,9 @@ const Index: FC = ({ visible, introduction, data, username }) => { ); })} -
- ) : ( -
{t('content_empty')}
- )} -
+ +
+ )}
); }; From 81fbea171b16cff2da5d84e1fc0dcb49e93be818 Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 18 Oct 2024 14:59:04 +0800 Subject: [PATCH 260/336] fix: linked page list add order params --- .../components/LinkedQuestions/index.tsx | 4 +-- ui/src/pages/Questions/Linked/index.tsx | 32 +++++++++---------- ui/src/pages/Tags/Detail/index.tsx | 2 +- ui/src/services/common.ts | 3 +- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx index c5d92cbe..0706cc4b 100644 --- a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx +++ b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx @@ -25,7 +25,7 @@ import { useTranslation } from 'react-i18next'; import { isEmpty } from 'lodash'; import { Icon } from '@/components'; -import { questionLink } from '@/services'; +import { useQuestionLink } from '@/services'; import { pathFactory } from '@/router/pathFactory'; interface Props { @@ -39,7 +39,7 @@ const Index: FC = ({ id }) => { keyPrefix: 'related_question', }); - const { data } = questionLink({ + const { data } = useQuestionLink({ question_id: id, page: 1, page_size: 5, diff --git a/ui/src/pages/Questions/Linked/index.tsx b/ui/src/pages/Questions/Linked/index.tsx index 981e8c4e..9a08af52 100644 --- a/ui/src/pages/Questions/Linked/index.tsx +++ b/ui/src/pages/Questions/Linked/index.tsx @@ -17,13 +17,13 @@ * under the License. */ -import { FC, useState } from 'react'; +import { FC, useEffect, useState } from 'react'; import { Row, Col } from 'react-bootstrap'; import { useParams, useSearchParams, Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { usePageTags } from '@/hooks'; -import { questionLink, questionDetail } from '@/services'; +import { useQuestionLink, questionDetail } from '@/services'; import * as Type from '@/common/interface'; import { QuestionList, @@ -50,21 +50,25 @@ const LinkedQuestions: FC = () => { QUESTION_ORDER_KEYS[0]) as Type.QuestionOrderBy; const pageSize = 10; const { siteInfo } = siteInfoStore(); - const { data: listData, isLoading: listLoading } = questionLink({ + const { data: listData, isLoading: listLoading } = useQuestionLink({ question_id: qid || '', page: curPage, page_size: pageSize, + order: curOrder, }); const { login: loginSetting } = loginSettingStore(); const [questionTitle, setQuestionTitle] = useState(''); - questionDetail(qid || '') - .then((res) => { - setQuestionTitle(res.title); - }) - .catch((err) => { - console.error('get question detail failed:', err); - setQuestionTitle(`#${qid}`); - }); + + useEffect(() => { + questionDetail(qid || '') + .then((res) => { + setQuestionTitle(res.title); + }) + .catch((err) => { + console.error('get question detail failed:', err); + setQuestionTitle(`#${qid}`); + }); + }, []); usePageTags({ title: t('title'), }); @@ -81,11 +85,7 @@ const LinkedQuestions: FC = () => { source="linked" data={listData} order={curOrder} - orderList={ - loggedUser.username - ? QUESTION_ORDER_KEYS - : QUESTION_ORDER_KEYS.filter((key) => key !== 'recommend') - } + orderList={QUESTION_ORDER_KEYS.slice(0, 5)} isLoading={listLoading} /> diff --git a/ui/src/pages/Tags/Detail/index.tsx b/ui/src/pages/Tags/Detail/index.tsx index ac2fa937..33f65414 100644 --- a/ui/src/pages/Tags/Detail/index.tsx +++ b/ui/src/pages/Tags/Detail/index.tsx @@ -176,7 +176,7 @@ const Index: FC = () => { source="tag" data={listData} order={curOrder} - orderList={QUESTION_ORDER_KEYS.slice(0, 4)} + orderList={QUESTION_ORDER_KEYS.slice(0, 5)} isLoading={listLoading} /> diff --git a/ui/src/services/common.ts b/ui/src/services/common.ts index ad0d99e0..724f8eca 100644 --- a/ui/src/services/common.ts +++ b/ui/src/services/common.ts @@ -199,10 +199,11 @@ export const questionDetail = (id: string) => { ); }; -export const questionLink = (params: { +export const useQuestionLink = (params: { question_id: string; page: number; page_size: number; + order?: string; }) => { const apiUrl = `/answer/api/v1/question/link?${qs.stringify(params)}`; const { data, error } = useSWR( From 13c17f1d3ab76bfcee8f58b0464b8ca17151a0b3 Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 18 Oct 2024 15:08:15 +0800 Subject: [PATCH 261/336] fix: Only the active issue list shows update time --- ui/src/components/QuestionList/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/src/components/QuestionList/index.tsx b/ui/src/components/QuestionList/index.tsx index 066711bb..82baea6a 100644 --- a/ui/src/components/QuestionList/index.tsx +++ b/ui/src/components/QuestionList/index.tsx @@ -118,9 +118,15 @@ const QuestionList: FC = ({ /> •
Date: Fri, 18 Oct 2024 15:25:22 +0800 Subject: [PATCH 262/336] fix: linked question component not use empty content --- ui/src/components/Modal/BadgeModal.tsx | 1 - .../components/LinkedQuestions/index.tsx | 66 ++++++++----------- 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/ui/src/components/Modal/BadgeModal.tsx b/ui/src/components/Modal/BadgeModal.tsx index 18524852..5cb6c360 100644 --- a/ui/src/components/Modal/BadgeModal.tsx +++ b/ui/src/components/Modal/BadgeModal.tsx @@ -98,7 +98,6 @@ const BadgeModal: FC = ({ badge, visible }) => { }; const destroyAnimation = () => { - console.log('destroyAnimation'); clearTimeout(timeout); bg1?.destroy(); bg2?.destroy(); diff --git a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx index 0706cc4b..208953b6 100644 --- a/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx +++ b/ui/src/pages/Questions/Detail/components/LinkedQuestions/index.tsx @@ -58,45 +58,35 @@ const Index: FC = ({ id }) => { - {data.list.length > 0 ? ( - data.list.map((item) => ( - -
{item.title}
- {item.answer_count > 0 && ( -
( + +
{item.title}
+ {item.answer_count > 0 && ( +
0 + ? 'link-success' + : 'link-secondary' + }`}> + 0 - ? 'link-success' - : 'link-secondary' - }`}> - 0 - ? 'check-circle-fill' - : 'chat-square-text-fill' - } - className="me-1" - /> - - {item.answer_count} {t2('answers')} - -
- )} -
- )) - ) : ( -
- {t('no_linked_question')} -
- )} + ? 'check-circle-fill' + : 'chat-square-text-fill' + } + className="me-1" + /> + + {item.answer_count} {t2('answers')} + +
+ )} +
+ ))}
); From a3a7a3666910433e7cb82eb915dc99ed88082e0e Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 18 Oct 2024 15:47:52 +0800 Subject: [PATCH 263/336] fix: personal page empty state --- .../Personal/components/Overview/index.tsx | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 81ed7b32..049f07f0 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -49,46 +49,47 @@ const Index: FC = ({ visible, introduction, data, username }) => { dangerouslySetInnerHTML={{ __html: introduction }} /> ) : ( -
{t('about_me_empty')}
+
{t('about_me_empty')}
)} - {data?.answer?.length > 0 && ( - <> -
{t('top_answers')}
- - +
{t('top_answers')}
+ {data?.answer?.length > 0 ? ( + + ) : ( +
{t('content_empty')}
)} - {data?.question?.length > 0 && ( - <> -
{t('top_questions')}
- - +
{t('top_questions')}
+ {data?.question?.length > 0 ? ( + + ) : ( +
{t('content_empty')}
)}
- {Number(recentBadges?.count) > 0 && ( -
-
{t('recent_badges')}
- - {recentBadges?.list?.map((item) => { - return ( - - - - ); - })} - -
- )} +
+
{t('recent_badges')}
+ {Number(recentBadges?.count) > 0 ? ( + + {recentBadges?.list?.map((item) => { + return ( + + + + ); + })} + ) : ( +
{t('content_empty')}
+ )} +
); }; From 1997af872ffb2fe74f2234a857ceb1daec142ceb Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 18 Oct 2024 15:49:29 +0800 Subject: [PATCH 264/336] fix: eslint --- .../Personal/components/Overview/index.tsx | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/ui/src/pages/Users/Personal/components/Overview/index.tsx b/ui/src/pages/Users/Personal/components/Overview/index.tsx index 049f07f0..60d502e9 100644 --- a/ui/src/pages/Users/Personal/components/Overview/index.tsx +++ b/ui/src/pages/Users/Personal/components/Overview/index.tsx @@ -74,19 +74,20 @@ const Index: FC = ({ visible, introduction, data, username }) => {
{t('recent_badges')}
{Number(recentBadges?.count) > 0 ? ( - - {recentBadges?.list?.map((item) => { - return ( - - - - ); - })} - ) : ( + + {recentBadges?.list?.map((item) => { + return ( + + + + ); + })} + + ) : (
{t('content_empty')}
)}
From 23cc755aa8ba7d536c8c5db36022264efc5b2201 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Fri, 18 Oct 2024 15:55:31 +0800 Subject: [PATCH 265/336] feat(question): add question linking feature for closing question --- cmd/wire_gen.go | 2 +- internal/service/content/question_service.go | 4 + internal/service/question_common/question.go | 76 ++++++++++++ plugin/importer.go | 124 +++++++++---------- 4 files changed, 143 insertions(+), 63 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index d8e6c744..801c5a77 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -177,7 +177,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, answerCommon := answercommon.NewAnswerCommon(answerRepo) metaRepo := meta.NewMetaRepo(dataData) metaCommonService := metacommon.NewMetaCommonService(metaRepo) - questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaCommonService, configService, activityQueueService, revisionRepo, dataData) + questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaCommonService, configService, activityQueueService, revisionRepo, siteInfoCommonService, dataData) eventQueueService := event_queue.NewEventQueueService() userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon, eventQueueService) captchaRepo := captcha.NewCaptchaRepo(dataData) diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index 7cfd39a0..51f0da9b 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -174,6 +174,9 @@ func (qs *QuestionService) CloseQuestion(ctx context.Context, req *schema.CloseQ if err != nil { return err } + if cf.Key == constant.ReasonADuplicate { + qs.questioncommon.AddQuestionLinkForCloseReason(ctx, questionInfo, req.CloseMsg) + } qs.activityQueueService.Send(ctx, &schema.ActivityMsg{ UserID: req.UserID, @@ -199,6 +202,7 @@ func (qs *QuestionService) ReopenQuestion(ctx context.Context, req *schema.Reope if err != nil { return err } + qs.questioncommon.RemoveQuestionLinkForReopen(ctx, questionInfo) qs.activityQueueService.Send(ctx, &schema.ActivityMsg{ UserID: req.UserID, ObjectID: questionInfo.ID, diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index 63c8f5a2..13df3389 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -23,6 +23,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/apache/incubator-answer/internal/service/siteinfo_common" "math" "strings" "time" @@ -98,6 +99,7 @@ type QuestionCommon struct { configService *config.ConfigService activityQueueService activity_queue.ActivityQueueService revisionRepo revision.RevisionRepo + siteInfoService siteinfo_common.SiteInfoCommonService data *data.Data } @@ -113,6 +115,7 @@ func NewQuestionCommon(questionRepo QuestionRepo, configService *config.ConfigService, activityQueueService activity_queue.ActivityQueueService, revisionRepo revision.RevisionRepo, + siteInfoService siteinfo_common.SiteInfoCommonService, data *data.Data, ) *QuestionCommon { return &QuestionCommon{ @@ -128,6 +131,7 @@ func NewQuestionCommon(questionRepo QuestionRepo, configService: configService, activityQueueService: activityQueueService, revisionRepo: revisionRepo, + siteInfoService: siteInfoService, data: data, } } @@ -795,3 +799,75 @@ func (qs *QuestionCommon) UpdateQuestionLink(ctx context.Context, questionID, an return parsedText, nil } + +// AddQuestionLinkForCloseReason When the reason about close question is a question link, add the link to the question +func (qs *QuestionCommon) AddQuestionLinkForCloseReason(ctx context.Context, + questionInfo *entity.Question, closeMsg string) { + questionID := qs.tryToGetQuestionIDFromMsg(ctx, closeMsg) + if len(questionID) == 0 { + return + } + + linkedQuestion, exist, err := qs.questionRepo.GetQuestion(ctx, questionID) + if err != nil { + log.Errorf("get question error %s", err) + return + } + if !exist { + return + } + err = qs.questionRepo.LinkQuestion(ctx, &entity.QuestionLink{ + FromQuestionID: questionInfo.ID, + ToQuestionID: linkedQuestion.ID, + Status: entity.QuestionLinkStatusAvailable, + }) + if err != nil { + log.Errorf("link question error %s", err) + } +} + +func (qs *QuestionCommon) RemoveQuestionLinkForReopen(ctx context.Context, questionInfo *entity.Question) { + questionInfo.ID = uid.DeShortID(questionInfo.ID) + metaInfo, err := qs.metaCommonService.GetMetaByObjectIdAndKey(ctx, questionInfo.ID, entity.QuestionCloseReasonKey) + if err != nil { + return + } + + closeMsgMeta := &schema.CloseQuestionMeta{} + _ = json.Unmarshal([]byte(metaInfo.Value), closeMsgMeta) + + linkedQuestionID := qs.tryToGetQuestionIDFromMsg(ctx, closeMsgMeta.CloseMsg) + if len(linkedQuestionID) == 0 { + return + } + err = qs.questionRepo.RemoveQuestionLink(ctx, &entity.QuestionLink{ + FromQuestionID: questionInfo.ID, + ToQuestionID: linkedQuestionID, + }) + if err != nil { + log.Errorf("remove question link error %s", err) + } +} + +func (qs *QuestionCommon) tryToGetQuestionIDFromMsg(ctx context.Context, closeMsg string) (questionID string) { + siteGeneral, err := qs.siteInfoService.GetSiteGeneral(ctx) + if err != nil { + log.Errorf("get site general error %s", err) + return + } + if !strings.HasPrefix(closeMsg, siteGeneral.SiteUrl) { + return + } + // get question id from url + // the url may like: https://xxx.com/questions/D1401/xxx + // the D1401 is question id + questionID = strings.TrimPrefix(closeMsg, siteGeneral.SiteUrl) + questionID = strings.TrimPrefix(questionID, "/questions/") + t := strings.Split(questionID, "/") + if len(t) < 1 { + return "" + } + questionID = t[0] + questionID = uid.DeShortID(questionID) + return questionID +} diff --git a/plugin/importer.go b/plugin/importer.go index 3893d54a..bfd7d36a 100644 --- a/plugin/importer.go +++ b/plugin/importer.go @@ -1,62 +1,62 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package plugin - -import ( - "context" -) - -type QuestionImporterInfo struct { - Title string `json:"title"` - Content string `json:"content"` - Tags []string `json:"tags"` - UserEmail string `json:"user_email"` -} - -type Importer interface { - Base - RegisterImporterFunc(ctx context.Context, importer ImporterFunc) -} - -type ImporterFunc interface { - AddQuestion(ctx context.Context, questionInfo QuestionImporterInfo) (err error) -} - -var ( - // CallImporter is a function that calls all registered parsers - CallImporter, - registerImporter = MakePlugin[Importer](false) -) - -func ImporterEnabled() (enabled bool) { - _ = CallImporter(func(fn Importer) error { - enabled = true - return nil - }) - return -} -func GetImporter() (ip Importer, ok bool) { - _ = CallImporter(func(fn Importer) error { - ip = fn - ok = true - return nil - }) - return -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package plugin + +import ( + "context" +) + +type QuestionImporterInfo struct { + Title string `json:"title"` + Content string `json:"content"` + Tags []string `json:"tags"` + UserEmail string `json:"user_email"` +} + +type Importer interface { + Base + RegisterImporterFunc(ctx context.Context, importer ImporterFunc) +} + +type ImporterFunc interface { + AddQuestion(ctx context.Context, questionInfo QuestionImporterInfo) (err error) +} + +var ( + // CallImporter is a function that calls all registered parsers + CallImporter, + registerImporter = MakePlugin[Importer](false) +) + +func ImporterEnabled() (enabled bool) { + _ = CallImporter(func(fn Importer) error { + enabled = true + return nil + }) + return +} +func GetImporter() (ip Importer, ok bool) { + _ = CallImporter(func(fn Importer) error { + ip = fn + ok = true + return nil + }) + return +} From f93fd5181b7b475004f4cb34b74513cb6c7adb49 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Fri, 18 Oct 2024 15:55:45 +0800 Subject: [PATCH 266/336] fix: display error message and HTML for invalid order --- internal/controller/template_controller.go | 2 -- internal/schema/question_schema.go | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index c3a2ff0a..4692e855 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -139,7 +139,6 @@ func (tc *TemplateController) Index(ctx *gin.Context) { OrderCond: "newest", } if handler.BindAndCheck(ctx, req) { - tc.Page404(ctx) return } @@ -182,7 +181,6 @@ func (tc *TemplateController) QuestionList(ctx *gin.Context) { OrderCond: "newest", } if handler.BindAndCheck(ctx, req) { - tc.Page404(ctx) return } var page = req.Page diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index 7c605765..de19a8a5 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -346,6 +346,7 @@ const ( QuestionOrderCondHot = "hot" QuestionOrderCondScore = "score" QuestionOrderCondUnanswered = "unanswered" + QuestionOrderCondRecommend = "recommend" // HotInDays limit max days of the hottest question HotInDays = 90 From bc8c6993b754cea1470423bafb88c7a8480589ee Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Fri, 18 Oct 2024 19:01:23 +0800 Subject: [PATCH 267/336] feat(question): add closed question linking --- internal/repo/question/question_repo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 30370281..16b6085f 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -729,7 +729,7 @@ func (qr *questionRepo) UpdateQuestionLinkStatus(ctx context.Context, status int func (qr *questionRepo) GetQuestionLink(ctx context.Context, page, pageSize int, questionID string, orderCond string, inDays int) (questionList []*entity.Question, total int64, err error) { questionList = make([]*entity.Question, 0) questionID = uid.DeShortID(questionID) - questionStatus := []int{entity.QuestionStatusAvailable, entity.QuestionStatusPending} + questionStatus := []int{entity.QuestionStatusAvailable, entity.QuestionStatusClosed, entity.QuestionStatusPending} if questionID == "0" { return nil, 0, errors.InternalServer(reason.DatabaseError).WithError( fmt.Errorf("questionID is empty"), From 7e4aa98ce2213773f38e484fd8f770d65db7c6a5 Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 21 Oct 2024 10:18:49 +0800 Subject: [PATCH 268/336] fix: navbar header dropdown cannot auto close --- .../Header/components/NavItems/index.tsx | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/ui/src/components/Header/components/NavItems/index.tsx b/ui/src/components/Header/components/NavItems/index.tsx index bd80729d..badd1b79 100644 --- a/ui/src/components/Header/components/NavItems/index.tsx +++ b/ui/src/components/Header/components/NavItems/index.tsx @@ -26,6 +26,7 @@ import type * as Type from '@/common/interface'; import { Avatar, Icon } from '@/components'; import { floppyNavigation } from '@/utils'; import { userCenterStore } from '@/stores'; +import { REACT_BASE_PATH } from '@/router/alias'; interface Props { redDot: Type.NotificationStatus | undefined; @@ -95,31 +96,27 @@ const Index: FC = ({ redDot, userInfo, logOut }) => { - 'dropdown-item'} + {t('header.nav.profile')} - - 'dropdown-item'} + + {t('header.nav.bookmark')} - - 'dropdown-item'} + + {t('header.nav.setting')} - + - 'dropdown-item'} + logOut(e)}> {t('header.nav.logout')} - + {/* Dropdown for user center agent info */} From 5f28f1068fdcf8eebb5170cde09a223711096887 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 21 Oct 2024 10:57:36 +0800 Subject: [PATCH 269/336] refactor(router): comment out UI index file check for dynamic routing --- internal/router/ui.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/router/ui.go b/internal/router/ui.go index b959bcd3..b0b8a6d9 100644 --- a/internal/router/ui.go +++ b/internal/router/ui.go @@ -153,10 +153,15 @@ func (a *UIRouter) Register(r *gin.Engine, baseURLPath string) { return } - if filePath == UIIndexFilePath { - c.String(http.StatusNotFound, string(file)) - return - } + // This part is to solve the problem of returning 404 when the access path does not exist. + // However, there is no way to check whether the current route exists in the frontend. + // We can only hand over the route to the frontend for processing. + // And the plugin, frontend routes can now be dynamically registered, + // so there's no good way to get all frontend routes + //if filePath == UIIndexFilePath { + // c.String(http.StatusNotFound, string(file)) + // return + //} c.String(http.StatusOK, string(file)) }) From 5fd09d878368edc3b2b020b62e48c417d6948fce Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 21 Oct 2024 10:57:36 +0800 Subject: [PATCH 270/336] refactor(router): comment out UI index file check for dynamic routing --- internal/router/ui.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/router/ui.go b/internal/router/ui.go index b959bcd3..b0b8a6d9 100644 --- a/internal/router/ui.go +++ b/internal/router/ui.go @@ -153,10 +153,15 @@ func (a *UIRouter) Register(r *gin.Engine, baseURLPath string) { return } - if filePath == UIIndexFilePath { - c.String(http.StatusNotFound, string(file)) - return - } + // This part is to solve the problem of returning 404 when the access path does not exist. + // However, there is no way to check whether the current route exists in the frontend. + // We can only hand over the route to the frontend for processing. + // And the plugin, frontend routes can now be dynamically registered, + // so there's no good way to get all frontend routes + //if filePath == UIIndexFilePath { + // c.String(http.StatusNotFound, string(file)) + // return + //} c.String(http.StatusOK, string(file)) }) From c0a1f4e5cd816d739f1eb98ec9ca0294008165b3 Mon Sep 17 00:00:00 2001 From: Ourai Lin Date: Sat, 19 Oct 2024 20:25:10 +0800 Subject: [PATCH 271/336] fix(ui): route plugins register failed --- ui/src/App.tsx | 29 ++++++++++++++++++--- ui/src/router/index.tsx | 14 ++++++---- ui/src/utils/pluginKit/index.ts | 46 ++++++++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/ui/src/App.tsx b/ui/src/App.tsx index affac7a9..1b7d1b82 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -17,14 +17,37 @@ * under the License. */ -import { RouterProvider, createBrowserRouter } from 'react-router-dom'; +import { + type RouteObject, + RouterProvider, + createBrowserRouter, +} from 'react-router-dom'; +import { useState, useEffect } from 'react'; import './i18n/init'; -import '@/utils/pluginKit'; -import routes from '@/router'; +import { subscribe, unsubscribe } from '@/utils/pluginKit'; +import resolveRoutes from '@/router'; function App() { + const [routes, setRoutes] = useState([]); + + useEffect(() => { + const callback = () => { + setRoutes(resolveRoutes()); + }; + + subscribe('registered', callback); + + return () => { + unsubscribe('registered', callback); + }; + }, []); + + if (routes.length === 0) { + return
initializing
; + } + const router = createBrowserRouter(routes, { basename: process.env.REACT_APP_BASE_URL, }); diff --git a/ui/src/router/index.tsx b/ui/src/router/index.tsx index 432cb581..8c111e0f 100644 --- a/ui/src/router/index.tsx +++ b/ui/src/router/index.tsx @@ -27,8 +27,6 @@ import baseRoutes, { RouteNode } from './routes'; import RouteGuard from './RouteGuard'; import RouteErrorBoundary from './RouteErrorBoundary'; -const routes: RouteNode[] = []; - const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => { routeNodes.forEach((rn) => { if (rn.page === 'pages/Layout') { @@ -76,8 +74,14 @@ const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => { } }); }; -const mergedRoutes = mergeRoutePlugins(baseRoutes); -routeWrapper(mergedRoutes, routes); +function resolveRoutes(): RouteObject[] { + const routes: RouteNode[] = []; + const mergedRoutes = mergeRoutePlugins(baseRoutes); -export default routes as RouteObject[]; + routeWrapper(mergedRoutes, routes); + + return routes as RouteObject[]; +} + +export default resolveRoutes; diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 66d5c376..43b0d691 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -42,15 +42,46 @@ import { Plugin, PluginInfo, PluginType } from './interface'; * @field description: Plugin description, optionally configurable. Usually read from the `i18n` file */ +type EventName = string; +type EventHandler = () => void; + class Plugins { plugins: Plugin[] = []; registeredPlugins: Type.ActivatedPlugin[] = []; + events: Record = {}; + constructor() { this.init(); } + on(name: EventName, handler: EventHandler) { + if (!this.events[name]) { + this.events[name] = []; + } + + this.events[name].push(handler); + } + + off(name: EventName, handler?: EventHandler) { + const handlers = this.events[name]; + + if (!handlers || handlers.length === 0) { + return; + } + + if (handler) { + this.events[name] = handlers.filter((func) => func !== handler); + } else { + delete this.events[name]; + } + } + + trigger(name: EventName) { + (this.events[name] || []).forEach((handler) => handler()); + } + init() { this.registerBuiltin(); @@ -101,12 +132,10 @@ class Plugins { return func; }) .filter((p) => p); - return new Promise((resolve) => { - plugins.forEach(async (p) => { - const plugin = await p(); - this.register(plugin); - }); - resolve(true); + return Promise.all(plugins.map((p) => p())).then((resolvedPlugins) => { + resolvedPlugins.forEach((plugin) => this.register(plugin)); + this.trigger('registered'); + return true; }); } @@ -150,6 +179,9 @@ class Plugins { const plugins = new Plugins(); +const subscribe = plugins.on.bind(plugins); +const unsubscribe = plugins.off.bind(plugins); + const getRoutePlugins = () => { return plugins .getPlugins() @@ -287,5 +319,7 @@ export { useCaptchaPlugin, useRenderPlugin, PluginType, + subscribe, + unsubscribe, }; export default plugins; From 49033820568b81fdb1d860fa631417f451b0ff4c Mon Sep 17 00:00:00 2001 From: Ourai Lin Date: Sun, 20 Oct 2024 11:40:47 +0800 Subject: [PATCH 272/336] refactor(ui): extract event logic of plugin kit out --- ui/src/utils/pluginKit/emitter.ts | 34 ++++++++++++++++++++++++++++ ui/src/utils/pluginKit/index.ts | 37 ++++--------------------------- 2 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 ui/src/utils/pluginKit/emitter.ts diff --git a/ui/src/utils/pluginKit/emitter.ts b/ui/src/utils/pluginKit/emitter.ts new file mode 100644 index 00000000..eee427b6 --- /dev/null +++ b/ui/src/utils/pluginKit/emitter.ts @@ -0,0 +1,34 @@ +type EventName = string; +type EventHandler = () => void; + +class SimpleEventEmitter { + events: Record = {}; + + on(name: EventName, handler: EventHandler) { + if (!this.events[name]) { + this.events[name] = []; + } + + this.events[name].push(handler); + } + + off(name: EventName, handler?: EventHandler) { + const handlers = this.events[name]; + + if (!handlers || handlers.length === 0) { + return; + } + + if (handler) { + this.events[name] = handlers.filter((func) => func !== handler); + } else { + delete this.events[name]; + } + } + + emit(name: EventName) { + (this.events[name] || []).forEach((handler) => handler()); + } +} + +export default SimpleEventEmitter; diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 43b0d691..39d1edb5 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -29,6 +29,7 @@ import request from '@/utils/request'; import { initI18nResource } from './utils'; import { Plugin, PluginInfo, PluginType } from './interface'; +import SimpleEventEmitter from './emitter'; /** * This information is to be defined for all components. @@ -42,46 +43,16 @@ import { Plugin, PluginInfo, PluginType } from './interface'; * @field description: Plugin description, optionally configurable. Usually read from the `i18n` file */ -type EventName = string; -type EventHandler = () => void; - -class Plugins { +class Plugins extends SimpleEventEmitter { plugins: Plugin[] = []; registeredPlugins: Type.ActivatedPlugin[] = []; - events: Record = {}; - constructor() { + super(); this.init(); } - on(name: EventName, handler: EventHandler) { - if (!this.events[name]) { - this.events[name] = []; - } - - this.events[name].push(handler); - } - - off(name: EventName, handler?: EventHandler) { - const handlers = this.events[name]; - - if (!handlers || handlers.length === 0) { - return; - } - - if (handler) { - this.events[name] = handlers.filter((func) => func !== handler); - } else { - delete this.events[name]; - } - } - - trigger(name: EventName) { - (this.events[name] || []).forEach((handler) => handler()); - } - init() { this.registerBuiltin(); @@ -134,7 +105,7 @@ class Plugins { .filter((p) => p); return Promise.all(plugins.map((p) => p())).then((resolvedPlugins) => { resolvedPlugins.forEach((plugin) => this.register(plugin)); - this.trigger('registered'); + this.emit('registered'); return true; }); } From 6e51cc756df7313732ad65400a0a533e7f4582e5 Mon Sep 17 00:00:00 2001 From: Ourai Lin Date: Sun, 20 Oct 2024 12:13:23 +0800 Subject: [PATCH 273/336] refactor(ui): optimize initial loading --- ui/src/App.tsx | 11 +++++++++-- .../InitialLoadingPlaceholder/index.tsx | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 ui/src/components/InitialLoadingPlaceholder/index.tsx diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 1b7d1b82..f799042a 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -28,8 +28,9 @@ import './i18n/init'; import { subscribe, unsubscribe } from '@/utils/pluginKit'; import resolveRoutes from '@/router'; +import InitialLoadingPlaceholder from '@/components/InitialLoadingPlaceholder'; -function App() { +function useResolvedRoutes() { const [routes, setRoutes] = useState([]); useEffect(() => { @@ -44,8 +45,14 @@ function App() { }; }, []); + return routes; +} + +function App() { + const routes = useResolvedRoutes(); + if (routes.length === 0) { - return
initializing
; + return ; } const router = createBrowserRouter(routes, { diff --git a/ui/src/components/InitialLoadingPlaceholder/index.tsx b/ui/src/components/InitialLoadingPlaceholder/index.tsx new file mode 100644 index 00000000..28ba1cfd --- /dev/null +++ b/ui/src/components/InitialLoadingPlaceholder/index.tsx @@ -0,0 +1,18 @@ +import { Spinner } from 'react-bootstrap'; + +function InitialLoadingPlaceholder() { + return ( +
+ + Initializing +
+ ); +} + +export default InitialLoadingPlaceholder; From 8753716ceb789d59effc5c3613d0215775c225ec Mon Sep 17 00:00:00 2001 From: robin Date: Mon, 21 Oct 2024 16:19:32 +0800 Subject: [PATCH 274/336] refactor(ui): optimize initial loading and extract event logic of plugin kit out --- ui/src/App.tsx | 33 +++--------------------- ui/src/router/index.tsx | 22 ++++++++++------ ui/src/utils/pluginKit/emitter.ts | 34 ------------------------- ui/src/utils/pluginKit/index.ts | 42 +++++++++---------------------- 4 files changed, 31 insertions(+), 100 deletions(-) delete mode 100644 ui/src/utils/pluginKit/emitter.ts diff --git a/ui/src/App.tsx b/ui/src/App.tsx index f799042a..8c425f29 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -17,44 +17,19 @@ * under the License. */ -import { - type RouteObject, - RouterProvider, - createBrowserRouter, -} from 'react-router-dom'; -import { useState, useEffect } from 'react'; +import { RouterProvider, createBrowserRouter } from 'react-router-dom'; import './i18n/init'; -import { subscribe, unsubscribe } from '@/utils/pluginKit'; -import resolveRoutes from '@/router'; +import '@/utils/pluginKit'; +import { useMergeRoutes } from '@/router'; import InitialLoadingPlaceholder from '@/components/InitialLoadingPlaceholder'; -function useResolvedRoutes() { - const [routes, setRoutes] = useState([]); - - useEffect(() => { - const callback = () => { - setRoutes(resolveRoutes()); - }; - - subscribe('registered', callback); - - return () => { - unsubscribe('registered', callback); - }; - }, []); - - return routes; -} - function App() { - const routes = useResolvedRoutes(); - + const routes = useMergeRoutes(); if (routes.length === 0) { return ; } - const router = createBrowserRouter(routes, { basename: process.env.REACT_APP_BASE_URL, }); diff --git a/ui/src/router/index.tsx b/ui/src/router/index.tsx index 8c111e0f..ea2fdf3c 100644 --- a/ui/src/router/index.tsx +++ b/ui/src/router/index.tsx @@ -17,7 +17,7 @@ * under the License. */ -import { Suspense, lazy } from 'react'; +import { Suspense, lazy, useEffect, useState } from 'react'; import { RouteObject } from 'react-router-dom'; import Layout from '@/pages/Layout'; @@ -75,13 +75,21 @@ const routeWrapper = (routeNodes: RouteNode[], root: RouteNode[]) => { }); }; -function resolveRoutes(): RouteObject[] { - const routes: RouteNode[] = []; - const mergedRoutes = mergeRoutePlugins(baseRoutes); +function useMergeRoutes() { + const [routesState, setRoutes] = useState([]); - routeWrapper(mergedRoutes, routes); + const init = async () => { + const routes = []; + const mergedRoutes = await mergeRoutePlugins(baseRoutes).catch(() => []); + routeWrapper(mergedRoutes, routes); + setRoutes(routes); + }; - return routes as RouteObject[]; + useEffect(() => { + init(); + }, []); + + return routesState; } -export default resolveRoutes; +export { useMergeRoutes }; diff --git a/ui/src/utils/pluginKit/emitter.ts b/ui/src/utils/pluginKit/emitter.ts deleted file mode 100644 index eee427b6..00000000 --- a/ui/src/utils/pluginKit/emitter.ts +++ /dev/null @@ -1,34 +0,0 @@ -type EventName = string; -type EventHandler = () => void; - -class SimpleEventEmitter { - events: Record = {}; - - on(name: EventName, handler: EventHandler) { - if (!this.events[name]) { - this.events[name] = []; - } - - this.events[name].push(handler); - } - - off(name: EventName, handler?: EventHandler) { - const handlers = this.events[name]; - - if (!handlers || handlers.length === 0) { - return; - } - - if (handler) { - this.events[name] = handlers.filter((func) => func !== handler); - } else { - delete this.events[name]; - } - } - - emit(name: EventName) { - (this.events[name] || []).forEach((handler) => handler()); - } -} - -export default SimpleEventEmitter; diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 39d1edb5..346c1456 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -29,7 +29,6 @@ import request from '@/utils/request'; import { initI18nResource } from './utils'; import { Plugin, PluginInfo, PluginType } from './interface'; -import SimpleEventEmitter from './emitter'; /** * This information is to be defined for all components. @@ -43,23 +42,23 @@ import SimpleEventEmitter from './emitter'; * @field description: Plugin description, optionally configurable. Usually read from the `i18n` file */ -class Plugins extends SimpleEventEmitter { +class Plugins { plugins: Plugin[] = []; registeredPlugins: Type.ActivatedPlugin[] = []; + initialization: Promise; + constructor() { - super(); - this.init(); + this.initialization = this.init(); } - init() { + async init() { this.registerBuiltin(); - getPluginsStatus().then((plugins) => { - this.registeredPlugins = plugins.filter((p) => p.enabled); - this.registerPlugins(); - }); + const plugins = await getPluginsStatus().catch(() => []); + this.registeredPlugins = plugins.filter((p) => p.enabled); + await this.registerPlugins(); } refresh() { @@ -105,7 +104,6 @@ class Plugins extends SimpleEventEmitter { .filter((p) => p); return Promise.all(plugins.map((p) => p())).then((resolvedPlugins) => { resolvedPlugins.forEach((plugin) => this.register(plugin)); - this.emit('registered'); return true; }); } @@ -122,18 +120,6 @@ class Plugins extends SimpleEventEmitter { this.plugins.push(plugin); } - activatePlugins(activatedPlugins: Type.ActivatedPlugin[]) { - this.plugins.forEach((plugin: any) => { - const { slug_name } = plugin.info; - const activatedPlugin: any = activatedPlugins?.find( - (p) => p.slug_name === slug_name, - ); - if (activatedPlugin) { - plugin.activated = activatedPlugin?.enabled; - } - }); - } - getPlugin(slug_name: string) { return this.plugins.find((p) => p.info.slug_name === slug_name); } @@ -150,10 +136,8 @@ class Plugins extends SimpleEventEmitter { const plugins = new Plugins(); -const subscribe = plugins.on.bind(plugins); -const unsubscribe = plugins.off.bind(plugins); - -const getRoutePlugins = () => { +const getRoutePlugins = async () => { + await plugins.initialization; return plugins .getPlugins() .filter((plugin) => plugin.info.type === PluginType.Route); @@ -183,8 +167,8 @@ const validateRoutePlugin = async (slugName) => { return Boolean(registeredPlugin?.enabled); }; -const mergeRoutePlugins = (routes) => { - const routePlugins = getRoutePlugins(); +const mergeRoutePlugins = async (routes) => { + const routePlugins = await getRoutePlugins(); if (routePlugins.length === 0) { return routes; } @@ -290,7 +274,5 @@ export { useCaptchaPlugin, useRenderPlugin, PluginType, - subscribe, - unsubscribe, }; export default plugins; From 9fa6ef6851895a52f18535aafd006d0192aafe5d Mon Sep 17 00:00:00 2001 From: Ourai Lin Date: Tue, 22 Oct 2024 11:32:52 +0800 Subject: [PATCH 275/336] chore(ui): copy style from `public/index.html` to keep consistency --- .../InitialLoadingPlaceholder/index.scss | 35 +++++++++++++++++++ .../InitialLoadingPlaceholder/index.tsx | 17 ++++----- 2 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 ui/src/components/InitialLoadingPlaceholder/index.scss diff --git a/ui/src/components/InitialLoadingPlaceholder/index.scss b/ui/src/components/InitialLoadingPlaceholder/index.scss new file mode 100644 index 00000000..2b73f163 --- /dev/null +++ b/ui/src/components/InitialLoadingPlaceholder/index.scss @@ -0,0 +1,35 @@ +// Same as spin in `public/index.html` + +@keyframes _initial-loading-spin { + to { transform: rotate(360deg) } +} + +.InitialLoadingPlaceholder { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: white; + z-index: 9999; + + &-spinnerContainer { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + + &-spinner { + box-sizing: border-box; + display: inline-block; + width: 2rem; + height: 2rem; + vertical-align: -.125em; + border: .25rem solid currentColor; + border-right-color: transparent; + color: rgba(108, 117, 125, .75); + border-radius: 50%; + animation: 0.75s linear infinite _initial-loading-spin; + } +} diff --git a/ui/src/components/InitialLoadingPlaceholder/index.tsx b/ui/src/components/InitialLoadingPlaceholder/index.tsx index 28ba1cfd..41e81d1a 100644 --- a/ui/src/components/InitialLoadingPlaceholder/index.tsx +++ b/ui/src/components/InitialLoadingPlaceholder/index.tsx @@ -1,16 +1,13 @@ -import { Spinner } from 'react-bootstrap'; +// Same as spin in `public/index.html` + +import './index.scss'; function InitialLoadingPlaceholder() { return ( -
- - Initializing +
+
+
+
); } From 895c1c41df1c9141d8b601051bb960ae95491a0e Mon Sep 17 00:00:00 2001 From: Prithvijit Dasgupta Date: Sun, 13 Oct 2024 23:46:10 -0400 Subject: [PATCH 276/336] fix: add 400 second tag search debounce --- ui/src/components/TagSelector/index.tsx | 34 ++++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/ui/src/components/TagSelector/index.tsx b/ui/src/components/TagSelector/index.tsx index b3cb4480..3ce36819 100644 --- a/ui/src/components/TagSelector/index.tsx +++ b/ui/src/components/TagSelector/index.tsx @@ -18,10 +18,11 @@ */ /* eslint-disable no-nested-ternary */ -import { FC, useState, useEffect, useRef } from 'react'; +import { FC, useState, useEffect, useRef, useCallback } from 'react'; import { Dropdown, Button, Form } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; +import debounce from 'lodash/debounce'; import { marked } from 'marked'; import classNames from 'classnames'; @@ -69,7 +70,7 @@ const TagSelector: FC = ({ const [currentIndex, setCurrentIndex] = useState(0); const [repeatIndex, setRepeatIndex] = useState(-1); const [searchValue, setSearchValue] = useState(''); - const [tags, setTags] = useState(null); + const [tags, setTags] = useState([]); const [requiredTags, setRequiredTags] = useState(null); const { t } = useTranslation('translation', { keyPrefix: 'tag_selector' }); const { data: userPermission } = useUserPermission('tag.add'); @@ -146,20 +147,23 @@ const TagSelector: FC = ({ handleMenuShow(false); }; - const fetchTags = (str) => { - if (!showRequiredTag && !str) { - setTags([]); - return; - } - queryTags(str).then((res) => { - const tagArray: Type.Tag[] = filterTags(res || []); - if (str === '') { - setRequiredTags(res); + const fetchTags = useCallback( + debounce((str) => { + if (!showRequiredTag && !str) { + setTags([]); + return; } - handleMenuShow(tagArray.length > 0); - setTags(tagArray); - }); - }; + queryTags(str).then((res) => { + const tagArray: Type.Tag[] = filterTags(res || []); + if (str === '') { + setRequiredTags(res); + } + handleMenuShow(tagArray.length > 0); + setTags(tagArray); + }); + }, 400), + [], + ); const resetSearch = () => { setCurrentIndex(0); From dd16be0a6190cf54f3ed09c640a25e680f3d8e9b Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 14:52:52 +0800 Subject: [PATCH 277/336] docs(Makefile): upgrade version to 1.4.1 --- Makefile | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8279d17a..0e398f93 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: build clean ui -VERSION=1.4.0 +VERSION=1.4.1 BIN=answer DIR_SRC=./cmd/answer DOCKER_CMD=docker diff --git a/README.md b/README.md index 7d753805..351b5f67 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ To learn more about the project, visit [answer.apache.org](https://answer.apache ### Running with docker ```bash -docker run -d -p 9080:80 -v answer-data:/data --name answer apache/answer:1.4.0 +docker run -d -p 9080:80 -v answer-data:/data --name answer apache/answer:1.4.1 ``` For more information, see [Installation](https://answer.apache.org/docs/installation). From 08c2fc78ecfad6c59a712051c8b94c33879537be Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:06:58 +0800 Subject: [PATCH 278/336] docs(ui): add Apache license header to InitialLoadingPlaceholder components --- .../InitialLoadingPlaceholder/index.scss | 19 +++++++++++++++++++ .../InitialLoadingPlaceholder/index.tsx | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/ui/src/components/InitialLoadingPlaceholder/index.scss b/ui/src/components/InitialLoadingPlaceholder/index.scss index 2b73f163..a1cad1a5 100644 --- a/ui/src/components/InitialLoadingPlaceholder/index.scss +++ b/ui/src/components/InitialLoadingPlaceholder/index.scss @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Same as spin in `public/index.html` @keyframes _initial-loading-spin { diff --git a/ui/src/components/InitialLoadingPlaceholder/index.tsx b/ui/src/components/InitialLoadingPlaceholder/index.tsx index 41e81d1a..1650aede 100644 --- a/ui/src/components/InitialLoadingPlaceholder/index.tsx +++ b/ui/src/components/InitialLoadingPlaceholder/index.tsx @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Same as spin in `public/index.html` import './index.scss'; From f581e8b7387739303bad8ef27060706dd3280585 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:06:58 +0800 Subject: [PATCH 279/336] docs(ui): add Apache license header to InitialLoadingPlaceholder components --- .../InitialLoadingPlaceholder/index.scss | 19 +++++++++++++++++++ .../InitialLoadingPlaceholder/index.tsx | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/ui/src/components/InitialLoadingPlaceholder/index.scss b/ui/src/components/InitialLoadingPlaceholder/index.scss index 2b73f163..a1cad1a5 100644 --- a/ui/src/components/InitialLoadingPlaceholder/index.scss +++ b/ui/src/components/InitialLoadingPlaceholder/index.scss @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Same as spin in `public/index.html` @keyframes _initial-loading-spin { diff --git a/ui/src/components/InitialLoadingPlaceholder/index.tsx b/ui/src/components/InitialLoadingPlaceholder/index.tsx index 41e81d1a..1650aede 100644 --- a/ui/src/components/InitialLoadingPlaceholder/index.tsx +++ b/ui/src/components/InitialLoadingPlaceholder/index.tsx @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // Same as spin in `public/index.html` import './index.scss'; From 803da7852657ea0dd80783ee6fd70e62b85d170f Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:36:53 +0800 Subject: [PATCH 280/336] # Conflicts: # i18n/da_DK.yaml # i18n/de_DE.yaml # i18n/es_ES.yaml # i18n/fa_IR.yaml # i18n/fr_FR.yaml # i18n/it_IT.yaml # i18n/ko_KR.yaml # i18n/pl_PL.yaml # i18n/pt_PT.yaml # i18n/ro_RO.yaml # i18n/ru_RU.yaml # i18n/sv_SE.yaml # i18n/uk_UA.yaml # i18n/vi_VN.yaml # i18n/zh_CN.yaml --- i18n/cs_CZ.yaml | 20 +- i18n/cy_GB.yaml | 20 +- i18n/da_DK.yaml | 20 +- i18n/de_DE.yaml | 30 +- i18n/es_ES.yaml | 20 +- i18n/fa_IR.yaml | 20 +- i18n/fr_FR.yaml | 20 +- i18n/hi_IN.yaml | 20 +- i18n/id_ID.yaml | 20 +- i18n/it_IT.yaml | 170 ++-- i18n/ja_JP.yaml | 20 +- i18n/ko_KR.yaml | 22 +- i18n/ml_IN.yaml | 2221 +++++++++++++++++++++++++++++++++++++++++++++++ i18n/pl_PL.yaml | 68 +- i18n/pt_PT.yaml | 617 +++++++------ i18n/ro_RO.yaml | 20 +- i18n/ru_RU.yaml | 20 +- i18n/sk_SK.yaml | 20 +- i18n/sv_SE.yaml | 43 +- i18n/te_IN.yaml | 20 +- i18n/tr_TR.yaml | 36 +- i18n/uk_UA.yaml | 188 ++-- i18n/vi_VN.yaml | 331 ++++--- i18n/zh_CN.yaml | 22 +- i18n/zh_TW.yaml | 20 +- 25 files changed, 3100 insertions(+), 928 deletions(-) create mode 100644 i18n/ml_IN.yaml diff --git a/i18n/cs_CZ.yaml b/i18n/cs_CZ.yaml index 0a54c51a..65438419 100644 --- a/i18n/cs_CZ.yaml +++ b/i18n/cs_CZ.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prev next: Next @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/cy_GB.yaml b/i18n/cy_GB.yaml index c3b3b55a..af605269 100644 --- a/i18n/cy_GB.yaml +++ b/i18n/cy_GB.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: angen manylion neu eglurder desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: rhywbeth arall @@ -794,7 +787,7 @@ ui: how_to_format: title: Sut i Fformatio desc: >- -
  • i wneud cysylltiadau

    <https://url.com>

    [Title]( https://url.com)
  • rhoi dychweliadau rhwng paragraffau

  • _italic_ neu **beiddgar**

  • cod mewnoliad gan 4 bwlch

  • dyfyniad drwy osod > ar ddechrau'r llinell

  • backtick yn dianc o `like _this_`

  • creu ffensys cod gyda thic wrth gefn `

    ```
    cod yma
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Cynt next: Nesaf @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/da_DK.yaml b/i18n/da_DK.yaml index d707d355..bd19779f 100644 --- a/i18n/da_DK.yaml +++ b/i18n/da_DK.yaml @@ -326,9 +326,7 @@ backend: name: other: uhøflig eller misbrug desc: - other: - - En fornuftig person ville finde dette indhold upassende eller ikke respektfuldt - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: en duplikering @@ -340,10 +338,7 @@ backend: name: other: ikke et svar desc: - other: - - Dette blev sendt som svar, men det forsøger ikke at besvare - - spørgsmål. Det bør muligvis være en redigering, en kommentar, et andet spørgsmål - - eller slettet helt. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: ikke længere nødvendigt @@ -402,9 +397,7 @@ backend: name: other: kræver detaljer eller klarhed desc: - other: - - Dette spørgsmål indeholder i øjeblikket flere spørgsmål i et. Det bør - - fokusere på kun ét problem. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: noget andet @@ -794,7 +787,7 @@ ui: how_to_format: title: Sådan formaterer du desc: >- -
  • for at lave links

    <https://url.com>

    [Titel](https://url.com)
  • indsæt linieskift mellem paragraffer

  • _kursiv_ or **fed**

  • indskyd kode med 4 mellemrum

  • citér ved at placere > på starten af linie

  • backtick escapes `som _dette_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Forrige next: Næste @@ -1341,6 +1334,10 @@ ui: related_question: title: Relaterede spørgsmål answers: svar + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Inviter personer desc: Invitér personer, som du tror, kan svare. @@ -1559,6 +1556,7 @@ ui: top_questions: Populære Spørgsmål stats: Statistik list_empty: Ingen indlæg fundet.
Måske vil du vælge en anden fane? + content_empty: No posts found. accepted: Accepteret answered: besvaret asked: spurgt diff --git a/i18n/de_DE.yaml b/i18n/de_DE.yaml index d780b438..9eee7c03 100644 --- a/i18n/de_DE.yaml +++ b/i18n/de_DE.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Ungültige URL. status_invalid: - other: Invalid status. + other: Ungültiger Status. password: space_invalid: other: Passwort darf keine Leerzeichen enthalten. @@ -326,9 +326,7 @@ backend: name: other: unhöflich oder beleidigend desc: - other: - - Eine vernünftige Person würde diesen Inhalt als unangemessen für einen respektvollen - - Umgang empfinden + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: ein Duplikat @@ -340,10 +338,7 @@ backend: name: other: keine Antwort desc: - other: - - Dies wurde als Antwort gepostet, aber es wird nicht versucht, die - - Frage zu beantworten. Es sollte vielleicht eine Bearbeitung, ein Kommentar oder eine andere Frage sein, - - oder ganz gelöscht. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: nicht mehr benötigt @@ -402,9 +397,7 @@ backend: name: other: benötigt Details oder Klarheit desc: - other: - - Diese Frage enthält derzeit mehrere Fragen in einer. Sie sollte - - auf ein einziges Problem konzentrieren. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: etwas anderes @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: hat dich eingeladen, zu antworten earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Du hast das "{{.BadgeName}}" Abzeichen verdient email_tpl: change_email: title: @@ -536,12 +529,12 @@ backend: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiograph desc: other: Filled out profile information. certified: name: - other: Certified + other: Zertifiziert desc: other: Completed our new user tutorial. editor: @@ -794,7 +787,7 @@ ui: how_to_format: title: Wie man formatiert desc: >- -
  • um Links

    <https://url.com>

    [Titel](https://url.com)
  • Zwischen den Absätzen Zeilenumbrüche einfügen

  • _italic_ oder **fett**

  • Code um 4 Leerzeichen einrücken

  • Zitat durch Setzen von > am Anfang der Zeile

  • Backtick-Escapes `wie _this_`

  • Codeumrandungen mit Backticks `

    `
    Code hier
    ``
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Zurück next: Weiter @@ -1341,6 +1334,10 @@ ui: related_question: title: Verwandte Fragen answers: antworten + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Frage jemanden desc: Lade Leute ein, von denen du glaubst, dass sie die Antwort wissen könnten. @@ -1559,6 +1556,7 @@ ui: top_questions: Top-Fragen stats: Statistiken list_empty: Keine Beiträge gefunden.
Vielleicht möchtest du einen anderen Reiter auswählen? + content_empty: No posts found. accepted: Akzeptiert answered: antwortete asked: gefragt @@ -2205,7 +2203,7 @@ ui: users_with_the_most_vote: Benutzer, die diese Woche am meisten gestimmt haben staffs: Unsere Community Teammitglieder reputation: Ansehen - votes: stimmen + votes: Stimmen prompt: leave_page: Bist du sicher, dass du die Seite verlassen willst? changes_not_save: Deine Änderungen werden möglicherweise nicht gespeichert. diff --git a/i18n/es_ES.yaml b/i18n/es_ES.yaml index ff3853d1..561b461d 100644 --- a/i18n/es_ES.yaml +++ b/i18n/es_ES.yaml @@ -326,9 +326,7 @@ backend: name: other: grosero u ofensivo desc: - other: - - Una persona razonable consideraría este contenido como inapropiado - - discurso. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: un duplicado @@ -340,10 +338,7 @@ backend: name: other: no es una respuesta desc: - other: - - Esto fue publicado como respuesta, pero no responde la - - pregunta. Podría ser una edición, un comentario, otra pregunta, - - o borrado por completo. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: ya no es necesario @@ -402,9 +397,7 @@ backend: name: other: necesita más detalles o aclaraciónes desc: - other: - - Esta pregunta actualmente incluye múltiples preguntas en una. Debería - - centrarse en un problema solamente. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: otra razón @@ -794,7 +787,7 @@ ui: how_to_format: title: Cómo formatear desc: >- -
  • Para hacer enlaces

     <https://url.com>

    [Title](https://url.com)
  • Colocar saltos de línea entre párrafos

  • _cursiva_ o **negrita**

  • Indentar el código con 4 espacios

  • Citar colocando > al inicio de la línea

  • Escape con backticks `como _esto_`

  • Crear barreras de código con backticks `

      ```
    código aquí
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Anterior next: Siguiente @@ -1341,6 +1334,10 @@ ui: related_question: title: Preguntas relacionadas answers: respuestas + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Personas Preguntadas desc: Selecciona personas que creas que sepan la respuesta. @@ -1559,6 +1556,7 @@ ui: top_questions: Preguntas Principales stats: Estadísticas list_empty: No se encontraron publicaciones.
¿Quizás le gustaría seleccionar una pestaña diferente? + content_empty: No posts found. accepted: Aceptada answered: respondida asked: preguntó diff --git a/i18n/fa_IR.yaml b/i18n/fa_IR.yaml index 274b97d5..55cc9805 100644 --- a/i18n/fa_IR.yaml +++ b/i18n/fa_IR.yaml @@ -326,9 +326,7 @@ backend: name: other: بی ادب یا توهین آمیز desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: تکراری @@ -340,10 +338,7 @@ backend: name: other: این یک پاسخ نیست desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: دیگر نیازی نیست @@ -402,9 +397,7 @@ backend: name: other: نیاز به جزئیات یا واضح کردن دارد desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: یک مورد دیگر @@ -794,7 +787,7 @@ ui: how_to_format: title: نحوه فرمت کردن desc: >- -
  • برای ایجاد پیوند

    <https://url.com>

    [Title](https://url.com)
  • بین پاراگراف ها اینتر قرار بدهید

  • _italic_ یا **پررنگ**

  • کد تورفتگی با 4 فاصله

  • نقل قول با قرار دادن >< /code> در ابتدای خط

  • بکتیک فرار می کند `مانند _this_`

  • < li>

    حصارهای کد با بکتیک ایجاد کنید `

    ```
    کد اینجا
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: قبلی next: بعدی @@ -1341,6 +1334,10 @@ ui: related_question: title: سوالات مرتبط answers: جواب ها + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: مردم پرسیدند desc: افرادی را دعوت کنید که فکر می کنید ممکن است پاسخ را بدانند. @@ -1559,6 +1556,7 @@ ui: top_questions: سوالات برتر stats: آمار list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: پذیرفته شده answered: جواب داده asked: پرسیده شده diff --git a/i18n/fr_FR.yaml b/i18n/fr_FR.yaml index c7bf5fce..52ad1375 100644 --- a/i18n/fr_FR.yaml +++ b/i18n/fr_FR.yaml @@ -326,9 +326,7 @@ backend: name: other: grossier ou abusif desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: un doublon @@ -340,10 +338,7 @@ backend: name: other: n'est pas une réponse desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: ce n’est plus nécessaire @@ -402,9 +397,7 @@ backend: name: other: a besoin de détails ou de clarté desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: quelque chose d'autre @@ -794,7 +787,7 @@ ui: how_to_format: title: Comment mettre en forme desc: >- -
  • Pour faire des liens

    <https://url.com>

    [Title](https://url.com)
  • mettre des retour entre les paragraphes

  • _italic_ or **gras**

  • indenter le code par 4 espaces

  • citation en plaçant > au début de la ligne

  • guillemets inversés `comme_ca_`

  • créer une banière de code avec les guillemets inversés `

    ```
    code ici
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Préc next: Suivant @@ -1341,6 +1334,10 @@ ui: related_question: title: Questions liées answers: réponses + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Personnes interrogées desc: Invite people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Questions les plus populaires stats: Statistiques list_empty: Aucune publication trouvée.
Peut-être souhaiteriez-vous sélectionner un autre onglet ? + content_empty: No posts found. accepted: Accepté answered: a répondu asked: a demandé diff --git a/i18n/hi_IN.yaml b/i18n/hi_IN.yaml index 78a23394..8a9da4d5 100644 --- a/i18n/hi_IN.yaml +++ b/i18n/hi_IN.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prev next: Next @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/id_ID.yaml b/i18n/id_ID.yaml index 11da0521..bf8e827d 100644 --- a/i18n/id_ID.yaml +++ b/i18n/id_ID.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: membutuhkan detail atau kejelasan desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: lainnya @@ -794,7 +787,7 @@ ui: how_to_format: title: Cara memformat desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Sebelumnya next: Selanjutnya @@ -1341,6 +1334,10 @@ ui: related_question: title: Pertanyaan Terkait answers: jawaban + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Pertanyaan terpopuler stats: Statistik list_empty: Postingan tidak ditemukan.
Mungkin Anda ingin memilih tab lain? + content_empty: No posts found. accepted: Diterima answered: dijawab asked: ditanyakan diff --git a/i18n/it_IT.yaml b/i18n/it_IT.yaml index 1c9f8a85..3cc90171 100644 --- a/i18n/it_IT.yaml +++ b/i18n/it_IT.yaml @@ -138,7 +138,7 @@ backend: pass: other: Password original_text: - other: This post + other: Questo post email_or_password_wrong_error: other: Email o password errati. error: @@ -146,7 +146,7 @@ backend: invalid_url: other: URL non valido. status_invalid: - other: Invalid status. + other: Status non valido. password: space_invalid: other: La password non può contenere spazi. @@ -154,7 +154,7 @@ backend: cannot_update_their_password: other: Non è possibile modificare la password. cannot_edit_their_profile: - other: You cannot modify your profile. + other: Non è possibile modificare il profilo. cannot_modify_self_status: other: Non è possibile modificare il tuo status. email_or_password_wrong: @@ -207,10 +207,10 @@ backend: new_password_same_as_previous_setting: other: La nuova password è identica alla precedente already_deleted: - other: This post has been deleted. + other: Questo post è stato eliminato. meta: object_not_found: - other: Meta object not found + other: Meta oggetto non trovato question: already_deleted: other: Questo post è stato eliminato. @@ -315,7 +315,7 @@ backend: other: Configurazione del sito non trovata. badge: object_not_found: - other: Badge object not found + other: Oggetto badge non trovato reason: spam: name: @@ -326,9 +326,7 @@ backend: name: other: scortese o offensivo desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: duplicato @@ -340,10 +338,7 @@ backend: name: other: Non è una risposta desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: Non più necessario @@ -402,9 +397,7 @@ backend: name: other: richiede maggiori dettagli o chiarezza desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: altro @@ -420,12 +413,12 @@ backend: deleted_title: other: "\nDomanda cancellata" questions_title: - other: Questions + other: Domande tag: tags_title: other: Tags no_description: - other: The tag has no description. + other: Il tag non ha descrizioni. notification: action: update_question: @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: sei invitato a rispondere earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Hai ottenuto il badge "{{.BadgeName}}" email_tpl: change_email: title: @@ -531,89 +524,89 @@ backend: other: Modifiche suggerite reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} e {{ .Count }} più..." badge: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiografo desc: - other: Filled out profile information. + other: Informazioni sul profilo completate. certified: name: - other: Certified + other: Certificato desc: - other: Completed our new user tutorial. + other: "\nCompletato il nostro nuovo tutorial per l'utente." editor: name: other: Editor desc: - other: First post edit. + other: Prima modifica al post. first_flag: name: - other: First Flag + other: Primo Contrassegno desc: - other: First flagged a post. + other: Primo contrassegno di un post. first_upvote: name: - other: First Upvote + other: Primo Mi Piace desc: - other: First up voted a post. + other: Primo Mi Piace a un post first_link: name: - other: First Link + other: Primo Link desc: - other: First dirst added a link to another post. + other: Aggiunto un link a un altro post per la prima volta first_reaction: name: - other: First Reaction + other: Prima Reazione desc: - other: First reacted to the post. + other: Prima reazione al post. first_share: name: - other: First Share + other: Prima Condivisione desc: - other: First shared a post. + other: Prima condivisione a un post. scholar: name: - other: Scholar + other: Studioso desc: - other: Asked a question and accepted an answer. + other: Ha posto una domanda e ha accettato una risposta commentator: name: - other: Commentator + other: Commentatore desc: - other: Leave 5 comments. + other: Lascia 5 commenti. new_user_of_the_month: name: - other: New User of the Month + other: Nuovo Utente del Mese desc: - other: Outstanding contributions in their first month. + other: Contributi straordinari nel primo mese. read_guidelines: name: - other: Read Guidelines + other: Leggi le Linee Guida desc: - other: Read the [community guidelines]. + other: Leggi le [linee guida della community]. reader: name: - other: Reader + other: Lettore desc: - other: Read every answers in a topic with more than 10 answers. + other: Leggi ogni risposta in un argomento con più di 10 risposte. welcome: name: - other: Welcome + other: Benvenuto desc: - other: Received a up vote. + other: Ricevuto un voto positivo. nice_share: name: - other: Nice Share + other: Condivisione positiva. desc: - other: Shared a post with 25 unique visitors. + other: Ha condiviso un post con 25 visitatori unici. good_share: name: - other: Good Share + other: Condivisione positiva. desc: - other: Shared a post with 300 unique visitors. + other: Condiviso un post con 300 visitatori unici. great_share: name: other: Great Share @@ -741,60 +734,60 @@ backend: other: Question score of 10 or more. good_question: name: - other: Good Question + other: Buona domanda desc: - other: Question score of 25 or more. + other: Punteggio della domanda di 25 o più great_question: name: - other: Great Question + other: Ottima domanda desc: - other: Question score of 50 or more. + other: Punteggio domande pari o superiore a 50. popular_question: name: - other: Popular Question + other: Domanda popolare desc: - other: Question with 500 views. + other: "Domanda con 500 visualizzazioni\n" notable_question: name: - other: Notable Question + other: Domanda notevole desc: - other: Question with 1,000 views. + other: Domanda con 1.000 visualizzazioni. famous_question: name: - other: Famous Question + other: Domanda celebre desc: - other: Question with 5,000 views. + other: "Domanda con 5.000 visualizzazioni.\n." popular_link: name: - other: Popular Link + other: Link Popolare desc: - other: Posted an external link with 50 clicks. + other: Pubblicato un link esterno con 50 clic. hot_link: name: - other: Hot Link + other: Link popolare desc: - other: Posted an external link with 300 clicks. + other: Pubblicato un link esterno con 300 clic. famous_link: name: - other: Famous Link + other: Link celebre desc: - other: Posted an external link with 100 clicks. + other: Pubblicato un link esterno con 100 clic. default_badge_groups: getting_started: name: - other: Getting Started + other: Primi passi community: name: other: Community posting: name: - other: Posting + other: Pubblicazione in corso # The following fields are used for interface presentation(Front-end) ui: how_to_format: title: Come formattare desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url. om)
  • mette i rendimenti tra i paragrafi

  • _italic_ o **grassetto**

  • trattino di codice per 4 spazi

  • preventivo inserendo > all'inizio della riga

  • backtick escapes `like _this_`

  • crea recinzioni di codice con backticks `

    ````
    codice qui
    `````
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prec next: Successivo @@ -843,9 +836,9 @@ ui: posts: Messaggi invites: Inviti votes: Voti - answer: Answer - question: Question - badge_award: Badge + answer: Risposta + question: Domanda + badge_award: Distintivo suspended: title: Il tuo account è stato sospeso until_time: "Il tuo account è stato sospeso fino a {{ time }}." @@ -1017,9 +1010,9 @@ ui: delete: title: Elimina questo tag tip_with_posts: >- -

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+

Non è consentita l'eliminazione di tag con post.

Rimuovi prima questo tag dai post.

tip_with_synonyms: >- -

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+

Non è consentita l'eliminazione di tag con sinonimi.

Per favore, rimuovi prima i sinonimi da questo tag.

tip: Sei sicuro di voler cancellare? close: Chiudi edit_tag: @@ -1041,13 +1034,13 @@ ui: hours: ore days: giorni reaction: - heart: heart - smile: smile - frown: frown - btn_label: add or remove reactions - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} - unreact_emoji: unreact with {{ emoji }} + heart: cuore + smile: sorriso + frown: disapprovare + btn_label: aggiungere o rimuovere le reazioni + undo_emoji: annulla reazione {{ emoji }} + react_emoji: reagire con {{ emoji }} + unreact_emoji: non reagire con {{ emoji }} comment: btn_add_comment: Aggiungi un commento reply_to: Rispondi a @@ -1186,7 +1179,7 @@ ui: msg: empty: Il nome non può essere vuoto. range: Name must be between 2 to 30 characters in length. - character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + character: 'È necessario utilizzare il set di caratteri "a-z", "0-9", " - . _"' email: label: E-mail msg: @@ -1341,6 +1334,10 @@ ui: related_question: title: Domande correlate answers: risposte + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Persone Interpellate desc: Seleziona le persone che pensi potrebbero conoscere la risposta. @@ -1502,7 +1499,7 @@ ui: success: Il tuo nuovo account è confermato; sarai reindirizzato alla home page. link: Continua alla Homepage oops: Oops! - invalid: The link you used no longer works. + invalid: Il link che hai usato non è più attivo. confirm_new_email: La tua email è stata aggiornata. confirm_new_email_invalid: >- Siamo spiacenti, questo link di conferma non è più valido. Forse la tua email è già stata modificata? @@ -1524,8 +1521,8 @@ ui: answers: Risposte newest: Più recenti active: Attivo - hot: Hot - recommend: Recommend + hot: Caldo + recommend: Raccomandato score: Punteggio unanswered: Senza risposta modified: Modificato @@ -1559,6 +1556,7 @@ ui: top_questions: Domande principali stats: Statistiche list_empty: Nessun post trovato.
Forse desideri selezionare una scheda diversa? + content_empty: No posts found. accepted: Accettato answered: risposto asked: chiesto diff --git a/i18n/ja_JP.yaml b/i18n/ja_JP.yaml index 887ba790..433831f4 100644 --- a/i18n/ja_JP.yaml +++ b/i18n/ja_JP.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: 前へ next: 次へ @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: 質問済み diff --git a/i18n/ko_KR.yaml b/i18n/ko_KR.yaml index fba3d7d9..53b413f3 100644 --- a/i18n/ko_KR.yaml +++ b/i18n/ko_KR.yaml @@ -326,9 +326,7 @@ backend: name: other: 폭언 또는 무례한 언행입니다. desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: 중복 @@ -340,10 +338,7 @@ backend: name: other: 답변이 아닙니다 desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: 더 이상 필요하지 않습니다. @@ -402,9 +397,7 @@ backend: name: other: 세부사항 또는 명확성이 필요합니다. desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: 다른 이유 @@ -794,7 +787,7 @@ ui: how_to_format: title: 포맷 방법 desc: >- -
  • 링크 만들기

    <https://url.com>

    [Title](https://url.com)
  • 단락 사이에 줄 바꿈 넣기

  • _이탤릭체_ 또는 **볼드체**

  • 코드는 4칸 들여쓰기

  • 인용은 >로 시작하기

  • 백틱으로 이스케이프 `이렇게_사용`

  • 백틱으로 코드 펜스 만들기 `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: 이전 next: 다음 @@ -1185,7 +1178,7 @@ ui: label: 이름 msg: empty: 이름을 입력하세요. - range: 이름은 최대 30자까지 입력 가능합니다. + range: Name must be between 2 to 30 characters in length. character: '문자 집합 "a-z", "0-9", " - . _"를 사용해야 합니다' email: label: 이메일 @@ -1341,6 +1334,10 @@ ui: related_question: title: 관련 질문 answers: 답변 + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: 질문자 초대 desc: 답변을 알고 있을 것으로 생각되는 사람을 선택하세요. @@ -1559,6 +1556,7 @@ ui: top_questions: 최고 질문 stats: 통계 list_empty: 게시물을 찾을 수 없습니다.
다른 탭을 선택하실 수 있습니다. + content_empty: No posts found. accepted: 채택됨 answered: 답변됨 asked: 질문됨 diff --git a/i18n/ml_IN.yaml b/i18n/ml_IN.yaml new file mode 100644 index 00000000..c2d2af8f --- /dev/null +++ b/i18n/ml_IN.yaml @@ -0,0 +1,2221 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# The following fields are used for back-end +backend: + base: + success: + other: Success. + unknown: + other: Unknown error. + request_format_error: + other: Request format is not valid. + unauthorized_error: + other: Unauthorized. + database_error: + other: Data server error. + forbidden_error: + other: Forbidden. + duplicate_request_error: + other: Duplicate submission. + action: + report: + other: Flag + edit: + other: Edit + delete: + other: Delete + close: + other: Close + reopen: + other: Reopen + forbidden_error: + other: Forbidden. + pin: + other: Pin + hide: + other: Unlist + unpin: + other: Unpin + show: + other: List + invite_someone_to_answer: + other: Edit + undelete: + other: Undelete + role: + name: + user: + other: User + admin: + other: Admin + moderator: + other: Moderator + description: + user: + other: Default with no special access. + admin: + other: Have the full power to access the site. + moderator: + other: Has access to all posts except admin settings. + privilege: + level_1: + description: + other: Level 1 (less reputation required for private team, group) + level_2: + description: + other: Level 2 (low reputation required for startup community) + level_3: + description: + other: Level 3 (high reputation required for mature community) + level_custom: + description: + other: Custom Level + rank_question_add_label: + other: Ask question + rank_answer_add_label: + other: Write answer + rank_comment_add_label: + other: Write comment + rank_report_add_label: + other: Flag + rank_comment_vote_up_label: + other: Upvote comment + rank_link_url_limit_label: + other: Post more than 2 links at a time + rank_question_vote_up_label: + other: Upvote question + rank_answer_vote_up_label: + other: Upvote answer + rank_question_vote_down_label: + other: Downvote question + rank_answer_vote_down_label: + other: Downvote answer + rank_invite_someone_to_answer_label: + other: Invite someone to answer + rank_tag_add_label: + other: Create new tag + rank_tag_edit_label: + other: Edit tag description (need to review) + rank_question_edit_label: + other: Edit other's question (need to review) + rank_answer_edit_label: + other: Edit other's answer (need to review) + rank_question_edit_without_review_label: + other: Edit other's question without review + rank_answer_edit_without_review_label: + other: Edit other's answer without review + rank_question_audit_label: + other: Review question edits + rank_answer_audit_label: + other: Review answer edits + rank_tag_audit_label: + other: Review tag edits + rank_tag_edit_without_review_label: + other: Edit tag description without review + rank_tag_synonym_label: + other: Manage tag synonyms + email: + other: Email + e_mail: + other: Email + password: + other: Password + pass: + other: Password + original_text: + other: This post + email_or_password_wrong_error: + other: Email and password do not match. + error: + common: + invalid_url: + other: Invalid URL. + status_invalid: + other: Invalid status. + password: + space_invalid: + other: Password cannot contain spaces. + admin: + cannot_update_their_password: + other: You cannot modify your password. + cannot_edit_their_profile: + other: You cannot modify your profile. + cannot_modify_self_status: + other: You cannot modify your status. + email_or_password_wrong: + other: Email and password do not match. + answer: + not_found: + other: Answer do not found. + cannot_deleted: + other: No permission to delete. + cannot_update: + other: No permission to update. + question_closed_cannot_add: + other: Questions are closed and cannot be added. + comment: + edit_without_permission: + other: Comment are not allowed to edit. + not_found: + other: Comment not found. + cannot_edit_after_deadline: + other: The comment time has been too long to modify. + email: + duplicate: + other: Email already exists. + need_to_be_verified: + other: Email should be verified. + verify_url_expired: + other: Email verified URL has expired, please resend the email. + illegal_email_domain_error: + other: Email is not allowed from that email domain. Please use another one. + lang: + not_found: + other: Language file not found. + object: + captcha_verification_failed: + other: Captcha wrong. + disallow_follow: + other: You are not allowed to follow. + disallow_vote: + other: You are not allowed to vote. + disallow_vote_your_self: + other: You can't vote for your own post. + not_found: + other: Object not found. + verification_failed: + other: Verification failed. + email_or_password_incorrect: + other: Email and password do not match. + old_password_verification_failed: + other: The old password verification failed + new_password_same_as_previous_setting: + other: The new password is the same as the previous one. + already_deleted: + other: This post has been deleted. + meta: + object_not_found: + other: Meta object not found + question: + already_deleted: + other: This post has been deleted. + under_review: + other: Your post is awaiting review. It will be visible after it has been approved. + not_found: + other: Question not found. + cannot_deleted: + other: No permission to delete. + cannot_close: + other: No permission to close. + cannot_update: + other: No permission to update. + rank: + fail_to_meet_the_condition: + other: Reputation rank fail to meet the condition. + vote_fail_to_meet_the_condition: + other: Thanks for the feedback. You need at least {{.Rank}} reputation to cast a vote. + no_enough_rank_to_operate: + other: You need at least {{.Rank}} reputation to do this. + report: + handle_failed: + other: Report handle failed. + not_found: + other: Report not found. + tag: + already_exist: + other: Tag already exists. + not_found: + other: Tag not found. + recommend_tag_not_found: + other: Recommend tag is not exist. + recommend_tag_enter: + other: Please enter at least one required tag. + not_contain_synonym_tags: + other: Should not contain synonym tags. + cannot_update: + other: No permission to update. + is_used_cannot_delete: + other: You cannot delete a tag that is in use. + cannot_set_synonym_as_itself: + other: You cannot set the synonym of the current tag as itself. + smtp: + config_from_name_cannot_be_email: + other: The from name cannot be a email address. + theme: + not_found: + other: Theme not found. + revision: + review_underway: + other: Can't edit currently, there is a version in the review queue. + no_permission: + other: No permission to revise. + user: + external_login_missing_user_id: + other: The third-party platform does not provide a unique UserID, so you cannot login, please contact the website administrator. + external_login_unbinding_forbidden: + other: Please set a login password for your account before you remove this login. + email_or_password_wrong: + other: + other: Email and password do not match. + not_found: + other: User not found. + suspended: + other: User has been suspended. + username_invalid: + other: Username is invalid. + username_duplicate: + other: Username is already in use. + set_avatar: + other: Avatar set failed. + cannot_update_your_role: + other: You cannot modify your role. + not_allowed_registration: + other: Currently the site is not open for registration. + not_allowed_login_via_password: + other: Currently the site is not allowed to login via password. + access_denied: + other: Access denied + page_access_denied: + other: You do not have access to this page. + add_bulk_users_format_error: + other: "Error {{.Field}} format near '{{.Content}}' at line {{.Line}}. {{.ExtraMessage}}" + add_bulk_users_amount_error: + other: "The number of users you add at once should be in the range of 1-{{.MaxAmount}}." + config: + read_config_failed: + other: Read config failed + database: + connection_failed: + other: Database connection failed + create_table_failed: + other: Create table failed + install: + create_config_failed: + other: Can't create the config.yaml file. + upload: + unsupported_file_format: + other: Unsupported file format. + site_info: + config_not_found: + other: Site config not found. + badge: + object_not_found: + other: Badge object not found + reason: + spam: + name: + other: spam + desc: + other: This post is an advertisement, or vandalism. It is not useful or relevant to the current topic. + rude_or_abusive: + name: + other: rude or abusive + desc: + other: "A reasonable person would find this content inappropriate for respectful discourse." + a_duplicate: + name: + other: a duplicate + desc: + other: This question has been asked before and already has an answer. + placeholder: + other: Enter the existing question link + not_a_answer: + name: + other: not an answer + desc: + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." + no_longer_needed: + name: + other: no longer needed + desc: + other: This comment is outdated, conversational or not relevant to this post. + something: + name: + other: something else + desc: + other: This post requires staff attention for another reason not listed above. + placeholder: + other: Let us know specifically what you are concerned about + community_specific: + name: + other: a community-specific reason + desc: + other: This question doesn't meet a community guideline. + not_clarity: + name: + other: needs details or clarity + desc: + other: This question currently includes multiple questions in one. It should focus on one problem only. + looks_ok: + name: + other: looks OK + desc: + other: This post is good as-is and not low quality. + needs_edit: + name: + other: needs edit, and I did it + desc: + other: Improve and correct problems with this post yourself. + needs_close: + name: + other: needs close + desc: + other: A closed question can't answer, but still can edit, vote and comment. + needs_delete: + name: + other: needs delete + desc: + other: This post will be deleted. + question: + close: + duplicate: + name: + other: spam + desc: + other: This question has been asked before and already has an answer. + guideline: + name: + other: a community-specific reason + desc: + other: This question doesn't meet a community guideline. + multiple: + name: + other: needs details or clarity + desc: + other: This question currently includes multiple questions in one. It should focus on one problem only. + other: + name: + other: something else + desc: + other: This post requires another reason not listed above. + operation_type: + asked: + other: asked + answered: + other: answered + modified: + other: modified + deleted_title: + other: Deleted question + questions_title: + other: Questions + tag: + tags_title: + other: Tags + no_description: + other: The tag has no description. + notification: + action: + update_question: + other: updated question + answer_the_question: + other: answered question + update_answer: + other: updated answer + accept_answer: + other: accepted answer + comment_question: + other: commented question + comment_answer: + other: commented answer + reply_to_you: + other: replied to you + mention_you: + other: mentioned you + your_question_is_closed: + other: Your question has been closed + your_question_was_deleted: + other: Your question has been deleted + your_answer_was_deleted: + other: Your answer has been deleted + your_comment_was_deleted: + other: Your comment has been deleted + up_voted_question: + other: upvoted question + down_voted_question: + other: downvoted question + up_voted_answer: + other: upvoted answer + down_voted_answer: + other: downvoted answer + up_voted_comment: + other: upvoted comment + invited_you_to_answer: + other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge + email_tpl: + change_email: + title: + other: "[{{.SiteName}}] Confirm your new email address" + body: + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
\n{{.ChangeEmailUrl}}

\n\nIf you did not request this change, please ignore this email.\n" + new_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} answered your question" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + invited_you_to_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
I think you may know the answer.

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + new_comment: + title: + other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + new_question: + title: + other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" + body: + other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\nUnsubscribe" + pass_reset: + title: + other: "[{{.SiteName }}] Password reset" + body: + other: "Somebody asked to reset your password on {{.SiteName}}.

\n\nIf it was not you, you can safely ignore this email.

\n\nClick the following link to choose a new password:
\n{{.PassResetUrl}}\n" + register: + title: + other: "[{{.SiteName}}] Confirm your new account" + body: + other: "Welcome to {{.SiteName}}!

\n\nClick the following link to confirm and activate your new account:
\n{{.RegisterUrl}}

\n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + test: + title: + other: "[{{.SiteName}}] Test Email" + body: + other: "This is a test email." + action_activity_type: + upvote: + other: upvote + upvoted: + other: upvoted + downvote: + other: downvote + downvoted: + other: downvoted + accept: + other: accept + accepted: + other: accepted + edit: + other: edit + review: + queued_post: + other: Queued post + flagged_post: + other: Flagged post + suggested_post_edit: + other: Suggested edits + reaction: + tooltip: + other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting +# The following fields are used for interface presentation(Front-end) +ui: + how_to_format: + title: How to Format + desc: >- +
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+ pagination: + prev: Prev + next: Next + page_title: + question: Question + questions: Questions + tag: Tag + tags: Tags + tag_wiki: tag wiki + create_tag: Create Tag + edit_tag: Edit Tag + ask_a_question: Add Question + edit_question: Edit Question + edit_answer: Edit Answer + search: Search + posts_containing: Posts containing + settings: Settings + notifications: Notifications + login: Log In + sign_up: Sign Up + account_recovery: Account Recovery + account_activation: Account Activation + confirm_email: Confirm Email + account_suspended: Account Suspended + admin: Admin + change_email: Modify Email + install: Answer Installation + upgrade: Answer Upgrade + maintenance: Website Maintenance + users: Users + oauth_callback: Processing + http_404: HTTP Error 404 + http_50X: HTTP Error 500 + http_403: HTTP Error 403 + logout: Log Out + notifications: + title: Notifications + inbox: Inbox + achievement: Achievements + new_alerts: New alerts + all_read: Mark all as read + show_more: Show more + someone: Someone + inbox_type: + all: All + posts: Posts + invites: Invites + votes: Votes + answer: Answer + question: Question + badge_award: Badge + suspended: + title: Your Account has been Suspended + until_time: "Your account was suspended until {{ time }}." + forever: This user was suspended forever. + end: You don't meet a community guideline. + contact_us: Contact us + editor: + blockquote: + text: Blockquote + bold: + text: Strong + chart: + text: Chart + flow_chart: Flow chart + sequence_diagram: Sequence diagram + class_diagram: Class diagram + state_diagram: State diagram + entity_relationship_diagram: Entity relationship diagram + user_defined_diagram: User defined diagram + gantt_chart: Gantt chart + pie_chart: Pie chart + code: + text: Code Sample + add_code: Add code sample + form: + fields: + code: + label: Code + msg: + empty: Code cannot be empty. + language: + label: Language + placeholder: Automatic detection + btn_cancel: Cancel + btn_confirm: Add + formula: + text: Formula + options: + inline: Inline formula + block: Block formula + heading: + text: Heading + options: + h1: Heading 1 + h2: Heading 2 + h3: Heading 3 + h4: Heading 4 + h5: Heading 5 + h6: Heading 6 + help: + text: Help + hr: + text: Horizontal rule + image: + text: Image + add_image: Add image + tab_image: Upload image + form_image: + fields: + file: + label: Image file + btn: Select image + msg: + empty: File cannot be empty. + only_image: Only image files are allowed. + max_size: File size cannot exceed 4 MB. + desc: + label: Description + tab_url: Image URL + form_url: + fields: + url: + label: Image URL + msg: + empty: Image URL cannot be empty. + name: + label: Description + btn_cancel: Cancel + btn_confirm: Add + uploading: Uploading + indent: + text: Indent + outdent: + text: Outdent + italic: + text: Emphasis + link: + text: Hyperlink + add_link: Add hyperlink + form: + fields: + url: + label: URL + msg: + empty: URL cannot be empty. + name: + label: Description + btn_cancel: Cancel + btn_confirm: Add + ordered_list: + text: Numbered list + unordered_list: + text: Bulleted list + table: + text: Table + heading: Heading + cell: Cell + close_modal: + title: I am closing this post as... + btn_cancel: Cancel + btn_submit: Submit + remark: + empty: Cannot be empty. + msg: + empty: Please select a reason. + report_modal: + flag_title: I am flagging to report this post as... + close_title: I am closing this post as... + review_question_title: Review question + review_answer_title: Review answer + review_comment_title: Review comment + btn_cancel: Cancel + btn_submit: Submit + remark: + empty: Cannot be empty. + msg: + empty: Please select a reason. + not_a_url: URL format is incorrect. + url_not_match: URL origin does not match the current website. + tag_modal: + title: Create new tag + form: + fields: + display_name: + label: Display name + msg: + empty: Display name cannot be empty. + range: Display name up to 35 characters. + slug_name: + label: URL slug + desc: URL slug up to 35 characters. + msg: + empty: URL slug cannot be empty. + range: URL slug up to 35 characters. + character: URL slug contains unallowed character set. + desc: + label: Description + revision: + label: Revision + edit_summary: + label: Edit summary + placeholder: >- + Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + btn_cancel: Cancel + btn_submit: Submit + btn_post: Post new tag + tag_info: + created_at: Created + edited_at: Edited + history: History + synonyms: + title: Synonyms + text: The following tags will be remapped to + empty: No synonyms found. + btn_add: Add a synonym + btn_edit: Edit + btn_save: Save + synonyms_text: The following tags will be remapped to + delete: + title: Delete this tag + tip_with_posts: >- +

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+ tip_with_synonyms: >- +

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+ tip: Are you sure you wish to delete? + close: Close + edit_tag: + title: Edit Tag + default_reason: Edit tag + default_first_reason: Add tag + btn_save_edits: Save edits + btn_cancel: Cancel + dates: + long_date: MMM D + long_date_with_year: "MMM D, YYYY" + long_date_with_time: "MMM D, YYYY [at] HH:mm" + now: now + x_seconds_ago: "{{count}}s ago" + x_minutes_ago: "{{count}}m ago" + x_hours_ago: "{{count}}h ago" + hour: hour + day: day + hours: hours + days: days + reaction: + heart: heart + smile: smile + frown: frown + btn_label: add or remove reactions + undo_emoji: undo {{ emoji }} reaction + react_emoji: react with {{ emoji }} + unreact_emoji: unreact with {{ emoji }} + comment: + btn_add_comment: Add comment + reply_to: Reply to + btn_reply: Reply + btn_edit: Edit + btn_delete: Delete + btn_flag: Flag + btn_save_edits: Save edits + btn_cancel: Cancel + show_more: "{{count}} more comments" + tip_question: >- + Use comments to ask for more information or suggest improvements. Avoid answering questions in comments. + tip_answer: >- + Use comments to reply to other users or notify them of changes. If you are adding new information, edit your post instead of commenting. + tip_vote: It adds something useful to the post + edit_answer: + title: Edit Answer + default_reason: Edit answer + default_first_reason: Add answer + form: + fields: + revision: + label: Revision + answer: + label: Answer + feedback: + characters: content must be at least 6 characters in length. + edit_summary: + label: Edit summary + placeholder: >- + Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + btn_save_edits: Save edits + btn_cancel: Cancel + tags: + title: Tags + sort_buttons: + popular: Popular + name: Name + newest: Newest + button_follow: Follow + button_following: Following + tag_label: questions + search_placeholder: Filter by tag name + no_desc: The tag has no description. + more: More + ask: + title: Add Question + edit_title: Edit Question + default_reason: Edit question + default_first_reason: Add question + similar_questions: Similar questions + form: + fields: + revision: + label: Revision + title: + label: Title + placeholder: Be specific and imagine you're asking a question to another person + msg: + empty: Title cannot be empty. + range: Title up to 150 characters + body: + label: Body + msg: + empty: Body cannot be empty. + tags: + label: Tags + msg: + empty: Tags cannot be empty. + answer: + label: Answer + msg: + empty: Answer cannot be empty. + edit_summary: + label: Edit summary + placeholder: >- + Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + btn_post_question: Post your question + btn_save_edits: Save edits + answer_question: Answer your own question + post_question&answer: Post your question and answer + tag_selector: + add_btn: Add tag + create_btn: Create new tag + search_tag: Search tag + hint: "Describe what your question is about, at least one tag is required." + no_result: No tags matched + tag_required_text: Required tag (at least one) + header: + nav: + question: Questions + tag: Tags + user: Users + badges: Badges + profile: Profile + setting: Settings + logout: Log out + admin: Admin + review: Review + bookmark: Bookmarks + moderation: Moderation + search: + placeholder: Search + footer: + build_on: >- + Powered by <1> Apache Answer - the open-source software that powers Q&A communities.
Made with love © {{cc}}. + upload_img: + name: Change + loading: loading... + pic_auth_code: + title: Captcha + placeholder: Type the text above + msg: + empty: Captcha cannot be empty. + inactive: + first: >- + You're almost done! We sent an activation mail to {{mail}}. Please follow the instructions in the mail to activate your account. + info: "If it doesn't arrive, check your spam folder." + another: >- + We sent another activation email to you at {{mail}}. It might take a few minutes for it to arrive; be sure to check your spam folder. + btn_name: Resend activation email + change_btn_name: Change email + msg: + empty: Cannot be empty. + resend_email: + url_label: Are you sure you want to resend the activation email? + url_text: You can also give the activation link above to the user. + login: + login_to_continue: Log in to continue + info_sign: Don't have an account? <1>Sign up + info_login: Already have an account? <1>Log in + agreements: By registering, you agree to the <1>privacy policy and <3>terms of service. + forgot_pass: Forgot password? + name: + label: Name + msg: + empty: Name cannot be empty. + range: Name must be between 2 to 30 characters in length. + character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + email: + label: Email + msg: + empty: Email cannot be empty. + password: + label: Password + msg: + empty: Password cannot be empty. + different: The passwords entered on both sides are inconsistent + account_forgot: + page_title: Forgot Your Password + btn_name: Send me recovery email + send_success: >- + If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + email: + label: Email + msg: + empty: Email cannot be empty. + change_email: + btn_cancel: Cancel + btn_update: Update email address + send_success: >- + If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + email: + label: New email + msg: + empty: Email cannot be empty. + oauth: + connect: Connect with {{ auth_name }} + remove: Remove {{ auth_name }} + oauth_bind_email: + subtitle: Add a recovery email to your account. + btn_update: Update email address + email: + label: Email + msg: + empty: Email cannot be empty. + modal_title: Email already existes. + modal_content: This email address already registered. Are you sure you want to connect to the existing account? + modal_cancel: Change email + modal_confirm: Connect to the existing account + password_reset: + page_title: Password Reset + btn_name: Reset my password + reset_success: >- + You successfully changed your password; you will be redirected to the log in page. + link_invalid: >- + Sorry, this password reset link is no longer valid. Perhaps your password is already reset? + to_login: Continue to log in page + password: + label: Password + msg: + empty: Password cannot be empty. + length: The length needs to be between 8 and 32 + different: The passwords entered on both sides are inconsistent + password_confirm: + label: Confirm new password + settings: + page_title: Settings + goto_modify: Go to modify + nav: + profile: Profile + notification: Notifications + account: Account + interface: Interface + profile: + heading: Profile + btn_name: Save + display_name: + label: Display name + msg: Display name cannot be empty. + msg_range: Display name up to 30 characters. + username: + label: Username + caption: People can mention you as "@username". + msg: Username cannot be empty. + msg_range: Username up to 30 characters. + character: 'Must use the character set "a-z", "0-9", " - . _"' + avatar: + label: Profile image + gravatar: Gravatar + gravatar_text: You can change image on + custom: Custom + custom_text: You can upload your image. + default: System + msg: Please upload an avatar + bio: + label: About me + website: + label: Website + placeholder: "https://example.com" + msg: Website incorrect format + location: + label: Location + placeholder: "City, Country" + notification: + heading: Email Notifications + turn_on: Turn on + inbox: + label: Inbox notifications + description: Answers to your questions, comments, invites, and more. + all_new_question: + label: All new questions + description: Get notified of all new questions. Up to 50 questions per week. + all_new_question_for_following_tags: + label: All new questions for following tags + description: Get notified of new questions for following tags. + account: + heading: Account + change_email_btn: Change email + change_pass_btn: Change password + change_email_info: >- + We've sent an email to that address. Please follow the confirmation instructions. + email: + label: Email + new_email: + label: New email + msg: New email cannot be empty. + pass: + label: Current password + msg: Password cannot be empty. + password_title: Password + current_pass: + label: Current password + msg: + empty: Current password cannot be empty. + length: The length needs to be between 8 and 32. + different: The two entered passwords do not match. + new_pass: + label: New password + pass_confirm: + label: Confirm new password + interface: + heading: Interface + lang: + label: Interface language + text: User interface language. It will change when you refresh the page. + my_logins: + title: My logins + label: Log in or sign up on this site using these accounts. + modal_title: Remove login + modal_content: Are you sure you want to remove this login from your account? + modal_confirm_btn: Remove + remove_success: Removed successfully + toast: + update: update success + update_password: Password changed successfully. + flag_success: Thanks for flagging. + forbidden_operate_self: Forbidden to operate on yourself + review: Your revision will show after review. + sent_success: Sent successfully + related_question: + title: Related Questions + answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. + invite_to_answer: + title: Invite People + desc: Invite people you think can answer. + invite: Invite to answer + add: Add people + search: Search people + question_detail: + action: Action + Asked: Asked + asked: asked + update: Modified + edit: edited + commented: commented + Views: Viewed + Follow: Follow + Following: Following + follow_tip: Follow this question to receive notifications + answered: answered + closed_in: Closed in + show_exist: Show existing question. + useful: Useful + question_useful: It is useful and clear + question_un_useful: It is unclear or not useful + question_bookmark: Bookmark this question + answer_useful: It is useful + answer_un_useful: It is not useful + answers: + title: Answers + score: Score + newest: Newest + oldest: Oldest + btn_accept: Accept + btn_accepted: Accepted + write_answer: + title: Your Answer + edit_answer: Edit my existing answer + btn_name: Post your answer + add_another_answer: Add another answer + confirm_title: Continue to answer + continue: Continue + confirm_info: >- +

Are you sure you want to add another answer?

You could use the edit link to refine and improve your existing answer, instead.

+ empty: Answer cannot be empty. + characters: content must be at least 6 characters in length. + tips: + header_1: Thanks for your answer + li1_1: Please be sure to answer the question. Provide details and share your research. + li1_2: Back up any statements you make with references or personal experience. + header_2: But avoid ... + li2_1: Asking for help, seeking clarification, or responding to other answers. + reopen: + confirm_btn: Reopen + title: Reopen this post + content: Are you sure you want to reopen? + list: + confirm_btn: List + title: List this post + content: Are you sure you want to list? + unlist: + confirm_btn: Unlist + title: Unlist this post + content: Are you sure you want to unlist? + pin: + title: Pin this post + content: Are you sure you wish to pinned globally? This post will appear at the top of all post lists. + confirm_btn: Pin + delete: + title: Delete this post + question: >- + We do not recommend deleting questions with answers because doing so deprives future readers of this knowledge.

Repeated deletion of answered questions can result in your account being blocked from asking. Are you sure you wish to delete? + answer_accepted: >- +

We do not recommend deleting accepted answer because doing so deprives future readers of this knowledge.

Repeated deletion of accepted answers can result in your account being blocked from answering. Are you sure you wish to delete? + other: Are you sure you wish to delete? + tip_answer_deleted: This answer has been deleted + undelete_title: Undelete this post + undelete_desc: Are you sure you wish to undelete? + btns: + confirm: Confirm + cancel: Cancel + edit: Edit + save: Save + delete: Delete + undelete: Undelete + list: List + unlist: Unlist + unlisted: Unlisted + login: Log in + signup: Sign up + logout: Log out + verify: Verify + add_question: Add question + approve: Approve + reject: Reject + skip: Skip + discard_draft: Discard draft + pinned: Pinned + all: All + question: Question + answer: Answer + comment: Comment + refresh: Refresh + resend: Resend + deactivate: Deactivate + active: Active + suspend: Suspend + unsuspend: Unsuspend + close: Close + reopen: Reopen + ok: OK + light: Light + dark: Dark + system_setting: System setting + default: Default + reset: Reset + tag: Tag + post_lowercase: post + filter: Filter + ignore: Ignore + submit: Submit + normal: Normal + closed: Closed + deleted: Deleted + pending: Pending + more: More + search: + title: Search Results + keywords: Keywords + options: Options + follow: Follow + following: Following + counts: "{{count}} Results" + more: More + sort_btns: + relevance: Relevance + newest: Newest + active: Active + score: Score + more: More + tips: + title: Advanced Search Tips + tag: "<1>[tag] search with a tag" + user: "<1>user:username search by author" + answer: "<1>answers:0 unanswered questions" + score: "<1>score:3 posts with a 3+ score" + question: "<1>is:question search questions" + is_answer: "<1>is:answer search answers" + empty: We couldn't find anything.
Try different or less specific keywords. + share: + name: Share + copy: Copy link + via: Share post via... + copied: Copied + facebook: Share to Facebook + twitter: Share to Twitter + cannot_vote_for_self: You can't vote for your own post. + modal_confirm: + title: Error... + account_result: + success: Your new account is confirmed; you will be redirected to the home page. + link: Continue to homepage + oops: Oops! + invalid: The link you used no longer works. + confirm_new_email: Your email has been updated. + confirm_new_email_invalid: >- + Sorry, this confirmation link is no longer valid. Perhaps your email was already changed? + unsubscribe: + page_title: Unsubscribe + success_title: Unsubscribe Successful + success_desc: You have been successfully removed from this subscriber list and won't receive any further emails from us. + link: Change settings + question: + following_tags: Following Tags + edit: Edit + save: Save + follow_tag_tip: Follow tags to curate your list of questions. + hot_questions: Hot Questions + all_questions: All Questions + x_questions: "{{ count }} Questions" + x_answers: "{{ count }} answers" + questions: Questions + answers: Answers + newest: Newest + active: Active + hot: Hot + recommend: Recommend + score: Score + unanswered: Unanswered + modified: modified + answered: answered + asked: asked + closed: closed + follow_a_tag: Follow a tag + more: More + personal: + overview: Overview + answers: Answers + answer: answer + questions: Questions + question: question + bookmarks: Bookmarks + reputation: Reputation + comments: Comments + votes: Votes + badges: Badges + newest: Newest + score: Score + edit_profile: Edit profile + visited_x_days: "Visited {{ count }} days" + viewed: Viewed + joined: Joined + comma: "," + last_login: Seen + about_me: About Me + about_me_empty: "// Hello, World !" + top_answers: Top Answers + top_questions: Top Questions + stats: Stats + list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. + accepted: Accepted + answered: answered + asked: asked + downvoted: downvoted + mod_short: MOD + mod_long: Moderators + x_reputation: reputation + x_votes: votes received + x_answers: answers + x_questions: questions + recent_badges: Recent Badges + install: + title: Installation + next: Next + done: Done + config_yaml_error: Can't create the config.yaml file. + lang: + label: Please choose a language + db_type: + label: Database engine + db_username: + label: Username + placeholder: root + msg: Username cannot be empty. + db_password: + label: Password + placeholder: root + msg: Password cannot be empty. + db_host: + label: Database host + placeholder: "db:3306" + msg: Database host cannot be empty. + db_name: + label: Database name + placeholder: answer + msg: Database name cannot be empty. + db_file: + label: Database file + placeholder: /data/answer.db + msg: Database file cannot be empty. + config_yaml: + title: Create config.yaml + label: The config.yaml file created. + desc: >- + You can create the <1>config.yaml file manually in the <1>/var/wwww/xxx/ directory and paste the following text into it. + info: After you've done that, click "Next" button. + site_information: Site Information + admin_account: Admin Account + site_name: + label: Site name + msg: Site name cannot be empty. + msg_max_length: Site name must be at maximum 30 characters in length. + site_url: + label: Site URL + text: The address of your site. + msg: + empty: Site URL cannot be empty. + incorrect: Site URL incorrect format. + max_length: Site URL must be at maximum 512 characters in length. + contact_email: + label: Contact email + text: Email address of key contact responsible for this site. + msg: + empty: Contact email cannot be empty. + incorrect: Contact email incorrect format. + login_required: + label: Private + switch: Login required + text: Only logged in users can access this community. + admin_name: + label: Name + msg: Name cannot be empty. + character: 'Must use the character set "a-z", "0-9", " - . _"' + msg_max_length: Name must be at maximum 30 characters in length. + admin_password: + label: Password + text: >- + You will need this password to log in. Please store it in a secure location. + msg: Password cannot be empty. + msg_min_length: Password must be at least 8 characters in length. + msg_max_length: Password must be at maximum 32 characters in length. + admin_email: + label: Email + text: You will need this email to log in. + msg: + empty: Email cannot be empty. + incorrect: Email incorrect format. + ready_title: Your site is ready + ready_desc: >- + If you ever feel like changing more settings, visit <1>admin section; find it in the site menu. + good_luck: "Have fun, and good luck!" + warn_title: Warning + warn_desc: >- + The file <1>config.yaml already exists. If you need to reset any of the configuration items in this file, please delete it first. + install_now: You may try <1>installing now. + installed: Already installed + installed_desc: >- + You appear to have already installed. To reinstall please clear your old database tables first. + db_failed: Database connection failed + db_failed_desc: >- + This either means that the database information in your <1>config.yaml file is incorrect or that contact with the database server could not be established. This could mean your host's database server is down. + counts: + views: views + votes: votes + answers: answers + accepted: Accepted + page_error: + http_error: HTTP Error {{ code }} + desc_403: You don't have permission to access this page. + desc_404: Unfortunately, this page doesn't exist. + desc_50X: The server encountered an error and could not complete your request. + back_home: Back to homepage + page_maintenance: + desc: "We are under maintenance, we'll be back soon." + nav_menus: + dashboard: Dashboard + contents: Contents + questions: Questions + answers: Answers + users: Users + badges: Badges + flags: Flags + settings: Settings + general: General + interface: Interface + smtp: SMTP + branding: Branding + legal: Legal + write: Write + tos: Terms of Service + privacy: Privacy + seo: SEO + customize: Customize + themes: Themes + css_html: CSS/HTML + login: Login + privileges: Privileges + plugins: Plugins + installed_plugins: Installed Plugins + website_welcome: Welcome to {{site_name}} + user_center: + login: Login + qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. + login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned + admin: + admin_header: + title: Admin + dashboard: + title: Dashboard + welcome: Welcome to Admin! + site_statistics: Site statistics + questions: "Questions:" + answers: "Answers:" + comments: "Comments:" + votes: "Votes:" + users: "Users:" + flags: "Flags:" + reviews: "Reviews:" + site_health: Site health + version: "Version:" + https: "HTTPS:" + upload_folder: "Upload folder:" + run_mode: "Running mode:" + private: Private + public: Public + smtp: "SMTP:" + timezone: "Timezone:" + system_info: System info + go_version: "Go version:" + database: "Database:" + database_size: "Database size:" + storage_used: "Storage used:" + uptime: "Uptime:" + links: Links + plugins: Plugins + github: GitHub + blog: Blog + contact: Contact + forum: Forum + documents: Documents + feedback: Feedback + support: Support + review: Review + config: Config + update_to: Update to + latest: Latest + check_failed: Check failed + "yes": "Yes" + "no": "No" + not_allowed: Not allowed + allowed: Allowed + enabled: Enabled + disabled: Disabled + writable: Writable + not_writable: Not writable + flags: + title: Flags + pending: Pending + completed: Completed + flagged: Flagged + flagged_type: Flagged {{ type }} + created: Created + action: Action + review: Review + user_role_modal: + title: Change user role to... + btn_cancel: Cancel + btn_submit: Submit + new_password_modal: + title: Set new password + form: + fields: + password: + label: Password + text: The user will be logged out and need to login again. + msg: Password must be at 8-32 characters in length. + btn_cancel: Cancel + btn_submit: Submit + edit_profile_modal: + title: Edit profile + form: + fields: + display_name: + label: Display name + msg_range: Display name up to 30 characters. + username: + label: Username + msg_range: Username up to 30 characters. + email: + label: Email + msg_invalid: Invalid Email Address. + edit_success: Edited successfully + btn_cancel: Cancel + btn_submit: Submit + user_modal: + title: Add new user + form: + fields: + users: + label: Bulk add user + placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" + text: Separate “name, email, password” with commas. One user per line. + msg: "Please enter the user's email, one per line." + display_name: + label: Display name + msg: Display name must be 2-30 characters in length. + email: + label: Email + msg: Email is not valid. + password: + label: Password + msg: Password must be at 8-32 characters in length. + btn_cancel: Cancel + btn_submit: Submit + users: + title: Users + name: Name + email: Email + reputation: Reputation + created_at: Created Time + delete_at: Deleted Time + suspend_at: Suspended Time + status: Status + role: Role + action: Action + change: Change + all: All + staff: Staff + more: More + inactive: Inactive + suspended: Suspended + deleted: Deleted + normal: Normal + Moderator: Moderator + Admin: Admin + User: User + filter: + placeholder: "Filter by name, user:id" + set_new_password: Set new password + edit_profile: Edit profile + change_status: Change status + change_role: Change role + show_logs: Show logs + add_user: Add user + deactivate_user: + title: Deactivate user + content: An inactive user must re-validate their email. + delete_user: + title: Delete this user + content: Are you sure you want to delete this user? This is permanent! + remove: Remove their content + label: Remove all questions, answers, comments, etc. + text: Don’t check this if you wish to only delete the user’s account. + suspend_user: + title: Suspend this user + content: A suspended user can't log in. + questions: + page_title: Questions + unlisted: Unlisted + post: Post + votes: Votes + answers: Answers + created: Created + status: Status + action: Action + change: Change + pending: Pending + filter: + placeholder: "Filter by title, question:id" + answers: + page_title: Answers + post: Post + votes: Votes + created: Created + status: Status + action: Action + change: Change + filter: + placeholder: "Filter by title, answer:id" + general: + page_title: General + name: + label: Site name + msg: Site name cannot be empty. + text: "The name of this site, as used in the title tag." + site_url: + label: Site URL + msg: Site url cannot be empty. + validate: Please enter a valid URL. + text: The address of your site. + short_desc: + label: Short site description + msg: Short site description cannot be empty. + text: "Short description, as used in the title tag on homepage." + desc: + label: Site description + msg: Site description cannot be empty. + text: "Describe this site in one sentence, as used in the meta description tag." + contact_email: + label: Contact email + msg: Contact email cannot be empty. + validate: Contact email is not valid. + text: Email address of key contact responsible for this site. + check_update: + label: Software updates + text: Automatically check for updates + interface: + page_title: Interface + language: + label: Interface language + msg: Interface language cannot be empty. + text: User interface language. It will change when you refresh the page. + time_zone: + label: Timezone + msg: Timezone cannot be empty. + text: Choose a city in the same timezone as you. + smtp: + page_title: SMTP + from_email: + label: From email + msg: From email cannot be empty. + text: The email address which emails are sent from. + from_name: + label: From name + msg: From name cannot be empty. + text: The name which emails are sent from. + smtp_host: + label: SMTP host + msg: SMTP host cannot be empty. + text: Your mail server. + encryption: + label: Encryption + msg: Encryption cannot be empty. + text: For most servers SSL is the recommended option. + ssl: SSL + tls: TLS + none: None + smtp_port: + label: SMTP port + msg: SMTP port must be number 1 ~ 65535. + text: The port to your mail server. + smtp_username: + label: SMTP username + msg: SMTP username cannot be empty. + smtp_password: + label: SMTP password + msg: SMTP password cannot be empty. + test_email_recipient: + label: Test email recipients + text: Provide email address that will receive test sends. + msg: Test email recipients is invalid + smtp_authentication: + label: Enable authentication + title: SMTP authentication + msg: SMTP authentication cannot be empty. + "yes": "Yes" + "no": "No" + branding: + page_title: Branding + logo: + label: Logo + msg: Logo cannot be empty. + text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown. + mobile_logo: + label: Mobile logo + text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the "logo" setting will be used. + square_icon: + label: Square icon + msg: Square icon cannot be empty. + text: Image used as the base for metadata icons. Should ideally be larger than 512x512. + favicon: + label: Favicon + text: A favicon for your site. To work correctly over a CDN it must be a png. Will be resized to 32x32. If left blank, "square icon" will be used. + legal: + page_title: Legal + terms_of_service: + label: Terms of service + text: "You can add terms of service content here. If you already have a document hosted elsewhere, provide the full URL here." + privacy_policy: + label: Privacy policy + text: "You can add privacy policy content here. If you already have a document hosted elsewhere, provide the full URL here." + write: + page_title: Write + restrict_answer: + title: Answer write + label: Each user can only write one answer for the same question + text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + recommend_tags: + label: Recommend tags + text: "Recommend tags will show in the dropdown list by default." + msg: + contain_reserved: "recommended tags cannot contain reserved tags" + required_tag: + title: Set required tags + label: Set “Recommend tags” as required tags + text: "Every new question must have at least one recommend tag." + reserved_tags: + label: Reserved tags + text: "Reserved tags can only be used by moderator." + seo: + page_title: SEO + permalink: + label: Permalink + text: Custom URL structures can improve the usability, and forward-compatibility of your links. + robots: + label: robots.txt + text: This will permanently override any related site settings. + themes: + page_title: Themes + themes: + label: Themes + text: Select an existing theme. + color_scheme: + label: Color scheme + navbar_style: + label: Navbar style + primary_color: + label: Primary color + text: Modify the colors used by your themes + css_and_html: + page_title: CSS and HTML + custom_css: + label: Custom CSS + text: > + + head: + label: Head + text: > + + header: + label: Header + text: > + + footer: + label: Footer + text: This will insert before </body>. + sidebar: + label: Sidebar + text: This will insert in sidebar. + login: + page_title: Login + membership: + title: Membership + label: Allow new registrations + text: Turn off to prevent anyone from creating a new account. + email_registration: + title: Email registration + label: Allow email registration + text: Turn off to prevent anyone creating new account through email. + allowed_email_domains: + title: Allowed email domains + text: Email domains that users must register accounts with. One domain per line. Ignored when empty. + private: + title: Private + label: Login required + text: Only logged in users can access this community. + password_login: + title: Password login + label: Allow email and password login + text: "WARNING: If turn off, you may be unable to log in if you have not previously configured other login method." + installed_plugins: + title: Installed Plugins + plugin_link: Plugins extend and expand the functionality. You may find plugins in the <1>Plugin Repository. + filter: + all: All + active: Active + inactive: Inactive + outdated: Outdated + plugins: + label: Plugins + text: Select an existing plugin. + name: Name + version: Version + status: Status + action: Action + deactivate: Deactivate + activate: Activate + settings: Settings + settings_users: + title: Users + avatar: + label: Default avatar + text: For users without a custom avatar of their own. + gravatar_base_url: + label: Gravatar base URL + text: URL of the Gravatar provider's API base. Ignored when empty. + profile_editable: + title: Profile editable + allow_update_display_name: + label: Allow users to change their display name + allow_update_username: + label: Allow users to change their username + allow_update_avatar: + label: Allow users to change their profile image + allow_update_bio: + label: Allow users to change their about me + allow_update_website: + label: Allow users to change their website + allow_update_location: + label: Allow users to change their location + privilege: + title: Privileges + level: + label: Reputation required level + text: Choose the reputation required for the privileges + msg: + should_be_number: the input should be number + number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + activate: Activate + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges + form: + optional: (optional) + empty: cannot be empty + invalid: is invalid + btn_submit: Save + not_found_props: "Required property {{ key }} not found." + select: Select + page_review: + review: Review + proposed: proposed + question_edit: Question edit + answer_edit: Answer edit + tag_edit: Tag edit + edit_summary: Edit summary + edit_question: Edit question + edit_answer: Edit answer + edit_tag: Edit tag + empty: No review tasks left. + approve_revision_tip: Do you approve this revision? + approve_flag_tip: Do you approve this flag? + approve_post_tip: Do you approve this post? + approve_user_tip: Do you approve this user? + suggest_edits: Suggested edits + flag_post: Flag post + flag_user: Flag user + queued_post: Queued post + queued_user: Queued user + filter_label: Type + reputation: reputation + flag_post_type: Flagged this post as {{ type }}. + flag_user_type: Flagged this user as {{ type }}. + edit_post: Edit post + list_post: List post + unlist_post: Unlist post + timeline: + undeleted: undeleted + deleted: deleted + downvote: downvote + upvote: upvote + accept: accept + cancelled: cancelled + commented: commented + rollback: rollback + edited: edited + answered: answered + asked: asked + closed: closed + reopened: reopened + created: created + pin: pinned + unpin: unpinned + show: listed + hide: unlisted + title: "History for" + tag_title: "Timeline for" + show_votes: "Show votes" + n_or_a: N/A + title_for_question: "Timeline for" + title_for_answer: "Timeline for answer to {{ title }} by {{ author }}" + title_for_tag: "Timeline for tag" + datetime: Datetime + type: Type + by: By + comment: Comment + no_data: "We couldn't find anything." + users: + title: Users + users_with_the_most_reputation: Users with the highest reputation scores this week + users_with_the_most_vote: Users who voted the most this week + staffs: Our community staff + reputation: reputation + votes: votes + prompt: + leave_page: Are you sure you want to leave the page? + changes_not_save: Your changes may not be saved. + draft: + discard_confirm: Are you sure you want to discard your draft? + messages: + post_deleted: This post has been deleted. + post_pin: This post has been pinned. + post_unpin: This post has been unpinned. + post_hide_list: This post has been hidden from list. + post_show_list: This post has been shown to list. + post_reopen: This post has been reopened. + post_list: This post has been listed. + post_unlist: This post has been unlisted. + post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. diff --git a/i18n/pl_PL.yaml b/i18n/pl_PL.yaml index 7e885b92..9c0adc78 100644 --- a/i18n/pl_PL.yaml +++ b/i18n/pl_PL.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Nieprawidłowy URL. status_invalid: - other: Invalid status. + other: Nieprawidłowy status. password: space_invalid: other: Hasło nie może zawierać spacji. @@ -326,9 +326,7 @@ backend: name: other: niegrzeczny lub obraźliwy desc: - other: - - Rozsądna osoba uznałaby tę treść za nieodpowiednią do dyskusji opartej na szacunku - - dyskomfort. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: duplikat @@ -340,10 +338,7 @@ backend: name: other: nie jest odpowiedzią desc: - other: - - To zostało opublikowane jako odpowiedź, ale nie próbuje odpowiedzieć na - - pytanie. Powinna być prawdopodobnie edytowana, opatrzona komentarzem, kolejnym pytaniem, - - lub całkowicie usunięta. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: nie jest już potrzebne @@ -402,9 +397,7 @@ backend: name: other: wymaga szczegółów lub wyjaśnienia desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: coś innego @@ -420,12 +413,12 @@ backend: deleted_title: other: Usunięte pytanie questions_title: - other: Questions + other: Pytania tag: tags_title: - other: Tags + other: Tagi no_description: - other: The tag has no description. + other: Tag nie posiada opisu. notification: action: update_question: @@ -536,57 +529,57 @@ backend: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiografista desc: other: Filled out profile information. certified: name: - other: Certified + other: Certyfikowany desc: - other: Completed our new user tutorial. + other: Ukończono nasz nowy samouczek. editor: name: - other: Editor + other: Edytor desc: other: First post edit. first_flag: name: - other: First Flag + other: Pierwsza flaga desc: other: First flagged a post. first_upvote: name: - other: First Upvote + other: Pierwszy pozytywny głos desc: other: First up voted a post. first_link: name: - other: First Link + other: Pierwszy odnośnik desc: other: First dirst added a link to another post. first_reaction: name: - other: First Reaction + other: Pierwsza Reakcja desc: other: First reacted to the post. first_share: name: - other: First Share + other: Pierwsze udostępnianie desc: other: First shared a post. scholar: name: other: Scholar desc: - other: Asked a question and accepted an answer. + other: Zadane pytania i zaakceptowane odpowiedź. commentator: name: other: Commentator desc: - other: Leave 5 comments. + other: Pozostaw 5 komentarzy. new_user_of_the_month: name: - other: New User of the Month + other: Nowy użytkownik miesiąca desc: other: Outstanding contributions in their first month. read_guidelines: @@ -794,7 +787,7 @@ ui: how_to_format: title: Jak formatować desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url. com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Poprzedni next: Następny @@ -1341,6 +1334,10 @@ ui: related_question: title: Powiązane pytania answers: odpowiedzi + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Ludzie pytali desc: Wybierz osoby, które mogą znać odpowiedź. @@ -1524,8 +1521,8 @@ ui: answers: Odpowiedzi newest: Najnowsze active: Aktywne - hot: Hot - recommend: Recommend + hot: Gorące + recommend: Polecane score: Ocena unanswered: Bez odpowiedzi modified: zmodyfikowane @@ -1544,7 +1541,7 @@ ui: reputation: Reputacja comments: Komentarze votes: Głosy - badges: Badges + badges: Odznaczenia newest: Najnowsze score: Ocena edit_profile: Edytuj Profil @@ -1559,6 +1556,7 @@ ui: top_questions: Najlepsze pytania stats: Statystyki list_empty: Nie znaleziono wpisów.
Być może chcesz wybrać inną kartę? + content_empty: No posts found. accepted: Zaakceptowane answered: Udzielone odpowiedzi asked: zapytano @@ -1705,7 +1703,7 @@ ui: login_failed_email_tip: Logowanie nie powiodło się, przed ponowną próbą zezwól na dostęp tej aplikacji do informacji o Twojej skrzynce pocztowej. badges: modal: - title: Congratulations + title: Gratulacje content: You've earned a new badge. close: Close confirm: View badges @@ -1795,10 +1793,10 @@ ui: fields: display_name: label: Display name - msg_range: Display name up to 30 characters. + msg_range: Wyświetlana nazwa użytkownika maksymalnie 30 znaków. username: label: Nazwa - msg_range: Username up to 30 characters. + msg_range: Nazwa użytkownika maksymalnie 30 znaków. email: label: Email msg_invalid: Błędny adresy email. @@ -2128,10 +2126,10 @@ ui: deactivate: Deactivate filter: placeholder: Filter by name, badge:id - group: Group + group: Grupa inactive: Inactive name: Name - show_logs: Show logs + show_logs: Wyświetl dzienniki status: Status title: Badges form: diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index d95385e1..5c21779e 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -110,11 +110,11 @@ backend: rank_tag_add_label: other: Criar marcador rank_tag_edit_label: - other: Editar descrição de um marcador (precisa revisar) + other: Editar descrição de um marcador (revisão necessária) rank_question_edit_label: - other: Editar pergunta do outro (precisa revisar) + other: Editar pergunta do outro (revisão necessária) rank_answer_edit_label: - other: Editar a resposta do outro (precisa revisar) + other: Editar a resposta do outro (revisão necessária) rank_question_edit_without_review_label: other: Editar a pergunta do outro sem revisar rank_answer_edit_without_review_label: @@ -138,7 +138,7 @@ backend: pass: other: Senha original_text: - other: This post + other: Esta publicação email_or_password_wrong_error: other: O e-mail e a palavra-passe não coincidem. error: @@ -146,7 +146,7 @@ backend: invalid_url: other: URL inválida. status_invalid: - other: Invalid status. + other: Estado inválido. password: space_invalid: other: A senha não pode conter espaços. @@ -207,15 +207,15 @@ backend: new_password_same_as_previous_setting: other: A nova senha é a mesma que a anterior. already_deleted: - other: This post has been deleted. + other: Esta publicação foi removida. meta: object_not_found: - other: Meta object not found + other: Objeto meta não encontrado question: already_deleted: other: Essa publicação foi deletado. under_review: - other: Your post is awaiting review. It will be visible after it has been approved. + other: Sua postagem está aguardando revisão. Ela ficará visível depois que for aprovada. not_found: other: Pergunta não encontrada. cannot_deleted: @@ -287,7 +287,7 @@ backend: not_allowed_registration: other: Atualmente o site não está aberto para cadastro not_allowed_login_via_password: - other: Currently the site is not allowed to login via password. + other: Atualmente o site não tem permissão para acessar utilizando senha. access_denied: other: Acesso negado page_access_denied: @@ -315,7 +315,7 @@ backend: other: Configuração do site não encontrada. badge: object_not_found: - other: Badge object not found + other: Objeto emblema não encontrado reason: spam: name: @@ -326,9 +326,7 @@ backend: name: other: rude ou abusivo desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: uma duplicação @@ -340,10 +338,7 @@ backend: name: other: não é uma resposta desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: não é mais necessário @@ -402,9 +397,7 @@ backend: name: other: precisa de detalhes ou clareza desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: algo mais @@ -420,12 +413,12 @@ backend: deleted_title: other: Questão excluída questions_title: - other: Questions + other: Questões tag: tags_title: - other: Tags + other: Marcadores no_description: - other: The tag has no description. + other: O marcador não possui descrição. notification: action: update_question: @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: lhe convidou para responder earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Ganhou o emblema "{{.BadgeName}}" emblema email_tpl: change_email: title: @@ -501,7 +494,7 @@ backend: title: other: "[{{.SiteName}}] Confirme seu novo endereço de e-mail" body: - other: "Bem-vindo a {{.SiteName}}!

\n\nClique no seguinte link para confirmar e ativar sua nova conta:
\n{{.RegisterUrl}}

\n\nSe o link acima não é clicável, tente copiar e colá-lo na barra de endereços do seu navegador da web.\n" + other: "Bem-vindo ao {{.SiteName}}!

\n\nClique no seguinte link para confirmar e ativar sua nova conta:
\n{{.RegisterUrl}}

\n\nSe o link acima não é clicável, tente copiar e colá-lo na barra de endereços do seu navegador da web.\n" test: title: other: "[{{.SiteName}}] E-mail de teste" @@ -521,280 +514,280 @@ backend: accepted: other: aceito edit: - other: edit + other: editar review: queued_post: - other: Queued post + other: Publicação na fila flagged_post: - other: Flagged post + other: Postagem sinalizada suggested_post_edit: - other: Suggested edits + other: Edições sugeridas reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} e mais {{ .Count }}..." badge: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiógrafo desc: - other: Filled out profile information. + other: Preenchido com perfil . certified: name: - other: Certified + other: Certificado desc: - other: Completed our new user tutorial. + other: Completou o nosso tutorial de novo usuário. editor: name: other: Editor desc: - other: First post edit. + other: Primeira edição em publicação. first_flag: name: - other: First Flag + other: Primeira Sinalização desc: - other: First flagged a post. + other: Primeiro sinalização numa publicação. first_upvote: name: - other: First Upvote + other: Primeiro voto desc: - other: First up voted a post. + other: Primeiro post votado. first_link: name: - other: First Link + other: Primeiro link desc: - other: First dirst added a link to another post. + other: Primeiro a adicionar um link a outra postagem. first_reaction: name: - other: First Reaction + other: Primeira Reação desc: - other: First reacted to the post. + other: Primeira reação a um post. first_share: name: - other: First Share + other: Primeiro Compartilhamento desc: - other: First shared a post. + other: Primeiro a compartilhar um post. scholar: name: - other: Scholar + other: Académico desc: - other: Asked a question and accepted an answer. + other: Fez uma pergunta e aceitou uma resposta. commentator: name: - other: Commentator + other: Comentador desc: - other: Leave 5 comments. + other: Fez 5 comentários. new_user_of_the_month: name: - other: New User of the Month + other: Novo usuário do mês desc: - other: Outstanding contributions in their first month. + other: Contribuições pendentes no seu primeiro mês. read_guidelines: name: - other: Read Guidelines + other: Ler diretrizes desc: - other: Read the [community guidelines]. + other: Leia as [diretrizes da comunidade]. reader: name: - other: Reader + other: Leitor desc: - other: Read every answers in a topic with more than 10 answers. + other: Leia todas as respostas num tópico com mais de 10 respostas. welcome: name: - other: Welcome + other: Bem-vindo desc: - other: Received a up vote. + other: Recebeu um voto positivo. nice_share: name: - other: Nice Share + other: Bom compartilhador desc: - other: Shared a post with 25 unique visitors. + other: Compartilhou um post com 25 visitantes únicos. good_share: name: - other: Good Share + other: Bom compartilhador desc: - other: Shared a post with 300 unique visitors. + other: Compartilhou um post com 300 visitantes únicos. great_share: name: - other: Great Share + other: Grande Compartilhador desc: - other: Shared a post with 1000 unique visitors. + other: Compartilhou um post com 1000 visitantes únicos. out_of_love: name: - other: Out of Love + other: Por amor desc: - other: Used 50 up votes in a day. + other: Cinquenta votos positivos em um dia. higher_love: name: - other: Higher Love + other: Amor Superior desc: - other: Used 50 up votes in a day 5 times. + other: Usou 50 votos positivos em um dia — 5 vezes. crazy_in_love: name: - other: Crazy in Love + other: Amor Louco desc: - other: Used 50 up votes in a day 20 times. + other: Usou 50 votos positivos em um dia — 20 vezes. promoter: name: - other: Promoter + other: Promotor desc: - other: Invited a user. + other: Convidou um usuário. campaigner: name: - other: Campaigner + other: Ativista desc: - other: Invited 3 basic users. + other: Foram convidados 3 usuários básicos. champion: name: - other: Champion + other: Campeão desc: - other: Invited 5 members. + other: Cinco membros convidados. thank_you: name: - other: Thank You + other: Obrigado desc: - other: Has 20 up voted posts and gave 10 up votes. + other: Recebeu 20 votos positivos e deu 10 votos. gives_back: name: - other: Gives Back + other: Dar de volta desc: - other: Has 100 up voted posts and gave 100 up votes. + other: Recebeu100 votos positivos e deu 100 votos a favor. empathetic: name: - other: Empathetic + other: Empático desc: - other: Has 500 up voted posts and gave 1000 up votes. + other: Recebeu 500 votos e deu 1000 votos. enthusiast: name: - other: Enthusiast + other: Entusiasta desc: - other: Visited 10 consecutive days. + other: . aficionado: name: other: Aficionado desc: - other: Visited 100 consecutive days. + other: Visitou 100 dias consecutivos. devotee: name: - other: Devotee + other: Devoto desc: - other: Visited 365 consecutive days. + other: Visitou 365 dias consecutivos. anniversary: name: - other: Anniversary + other: Aniversário desc: - other: Active member for a year, posted at least once. + other: Membro ativo por um ano, postando pelo menos uma vez. appreciated: name: - other: Appreciated + other: Apreciado desc: - other: Received 1 up vote on 20 posts. + other: Recebeu 1 voto positivo em 20 posts. respected: name: - other: Respected + other: Respeitado desc: - other: Received 2 up votes on 100 posts. + other: Novos 2 votos em 100 posts. admired: name: - other: Admired + other: Admirado desc: - other: Received 5 up votes on 300 posts. + other: Recebeu 5 votos positivos em 300 posts. solved: name: - other: Solved + other: Resolvido desc: - other: Have an answer be accepted. + other: Ter uma resposta aceita. guidance_counsellor: name: - other: Guidance Counsellor + other: Orientador Educacional desc: - other: Have 10 answers be accepted. + other: Tenham 10 respostas aceitas. know_it_all: name: - other: Know-it-All + other: Sabichão desc: - other: Have 50 answers be accepted. + other: Tenha 50 respostas aceitas. solution_institution: name: - other: Solution Institution + other: Instituição de Soluções desc: - other: Have 150 answers be accepted. + other: Tenham 150 respostas aceitas. nice_answer: name: - other: Nice Answer + other: Resposta legal desc: - other: Answer score of 10 or more. + other: Resposta com pontuação maior que 10. good_answer: name: - other: Good Answer + other: Boa resposta desc: - other: Answer score of 25 or more. + other: Resposta com pontuação maior que 25. great_answer: name: - other: Great Answer + other: Ótima Resposta desc: - other: Answer score of 50 or more. + other: Resposta com pontuação maior que 50. nice_question: name: - other: Nice Question + other: Questão legal desc: - other: Question score of 10 or more. + other: Pergunta com pontuação maior que 10. good_question: name: - other: Good Question + other: Boa questão desc: - other: Question score of 25 or more. + other: Questão com pontuação maior que 25. great_question: name: - other: Great Question + other: Otima questão desc: - other: Question score of 50 or more. + other: Questão com pontuação maior que 50. popular_question: name: - other: Popular Question + other: Pergunta Popular desc: - other: Question with 500 views. + other: Pergunta com 500 visualizações. notable_question: name: - other: Notable Question + other: Pergunta Notável desc: - other: Question with 1,000 views. + other: Pergunta com 1000 visualizações. famous_question: name: - other: Famous Question + other: Pergunta Famosa desc: - other: Question with 5,000 views. + other: Pergunta com 5000 visualizações. popular_link: name: - other: Popular Link + other: Link Popular desc: - other: Posted an external link with 50 clicks. + other: Postou um link externo com 50 cliques. hot_link: name: - other: Hot Link + other: Link Quente desc: - other: Posted an external link with 300 clicks. + other: Postou um link externo com 300 cliques. famous_link: name: - other: Famous Link + other: Link Famoso desc: - other: Posted an external link with 100 clicks. + other: Postou um link externo com 100 cliques. default_badge_groups: getting_started: name: - other: Getting Started + other: Começando community: name: - other: Community + other: Comunidade posting: name: - other: Posting + other: Postando # The following fields are used for interface presentation(Front-end) ui: how_to_format: title: Como formatar desc: >- -
  • para mais links

    <https://url.com>

    [Título](https://url.com)
  • colocar retornos entre parágrafos

  • _italic_ ou **bold**

  • identar código por 4 espaços

  • cotação colocando > no início da linha

  • aspas invertidas `tipo_isso`

  • criar cercas de código com aspas invertidas `

    ```
    código aqui
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Anterior next: Próximo @@ -829,7 +822,7 @@ ui: http_404: HTTP Erro 404 http_50X: HTTP Erro 500 http_403: HTTP Erro 403 - logout: Log Out + logout: Encerrar Sessão notifications: title: Notificações inbox: Caixa de entrada @@ -843,9 +836,9 @@ ui: posts: Postagens invites: Convites votes: Votos - answer: Answer - question: Question - badge_award: Badge + answer: Resposta + question: Questão + badge_award: Emblema suspended: title: A sua conta foi suspensa until_time: "Sua conta está suspensa até {{ time }}." @@ -973,8 +966,8 @@ ui: empty: Não pode ser vazio. msg: empty: Por favor selecione um motivo. - not_a_url: URL format is incorrect. - url_not_match: URL origin does not match the current website. + not_a_url: Formato da URL incorreto. + url_not_match: A origem da URL não corresponde ao site atual. tag_modal: title: Criar novo marcador form: @@ -994,11 +987,11 @@ ui: desc: label: Descrição (opcional) revision: - label: Revision + label: Revisão edit_summary: - label: Edit summary + label: Editar descrição placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + Explique resumidamente as suas alterações (ortografia corrigida, gramática corrigida, formatação aprimorada) btn_cancel: Cancelar btn_submit: Enviar btn_post: Postar novo marcador @@ -1017,15 +1010,15 @@ ui: delete: title: Remover este marcador tip_with_posts: >- -

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+

Nós não permitimos remover marcadores com postagens.

Por favor, remova este marcador a partir da postagem.

tip_with_synonyms: >- -

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+

Nós não permitimos remover marcadores com postagens.

Por favor, remova este marcador a partir da postagem.

tip: Você tem certeza que deseja remover? close: Fechar edit_tag: title: Editar marcador default_reason: Editar marcador - default_first_reason: Add tag + default_first_reason: Adicionar marcador btn_save_edits: Salvar edições btn_cancel: Cancelar dates: @@ -1038,16 +1031,16 @@ ui: x_hours_ago: "{{count}}h atrás" hour: hora day: dia - hours: hours - days: days + hours: horas + days: dias reaction: - heart: heart - smile: smile - frown: frown - btn_label: add or remove reactions - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} - unreact_emoji: unreact with {{ emoji }} + heart: coração + smile: sorrir + frown: cara feia + btn_label: adicionar ou remover reações + undo_emoji: desfazer reação {{ emoji }} + react_emoji: reagir com {{ emoji }} + unreact_emoji: remover reação {{ emoji }} comment: btn_add_comment: Adicionar comentário reply_to: Responder a @@ -1057,7 +1050,7 @@ ui: btn_flag: Marcador btn_save_edits: Salvar edições btn_cancel: Cancelar - show_more: "{{count}} more comments" + show_more: "Mais {{count}} comentários" tip_question: >- Use os comentários para pedir mais informações ou sugerir melhorias. Evite responder perguntas nos comentários. tip_answer: >- @@ -1066,7 +1059,7 @@ ui: edit_answer: title: Editar Resposta default_reason: Editar Resposta - default_first_reason: Add answer + default_first_reason: Adicionar resposta form: fields: revision: @@ -1097,7 +1090,7 @@ ui: title: Adicionar Pergunta edit_title: Editar Pergunta default_reason: Editar pergunta - default_first_reason: Add question + default_first_reason: Adicionar questão similar_questions: Similar perguntas form: fields: @@ -1141,7 +1134,7 @@ ui: question: Perguntas tag: Marcadores user: Usuários - badges: Badges + badges: Emblemas profile: Perfil setting: Configurações logout: Sair @@ -1153,7 +1146,7 @@ ui: placeholder: Procurar footer: build_on: >- - Powered by <1> Apache Answer - the open-source software that powers Q&A communities.
Made with love © {{cc}}. + . upload_img: name: Mudar loading: carregando... @@ -1186,7 +1179,7 @@ ui: msg: empty: Nome não pode ser vazio. range: Name must be between 2 to 30 characters in length. - character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + character: 'Deve usar o conjunto de caracteres "a-z", "0-9", " - . _"' email: label: E-mail msg: @@ -1283,10 +1276,10 @@ ui: label: Localização (opcional) placeholder: "Cidade, País" notification: - heading: Email Notifications - turn_on: Turn on + heading: Notificações por e-mail + turn_on: Ativar inbox: - label: Inbox notifications + label: Notificações na caixa de entrada description: Responda suas próprias perguntas, comentários, convites e muito mais. all_new_question: label: Todas as perguntas novas @@ -1301,10 +1294,10 @@ ui: change_email_info: >- Enviamos um e-mail para esse endereço. Siga as instruções de confirmação. email: - label: Email + label: Correio eletrónico new_email: - label: New email - msg: New email cannot be empty. + label: Novo correio eletrónico + msg: Novo correio eletrónico não pode ser vazio. pass: label: Senha atual msg: Senha não pode ser vazio. @@ -1341,6 +1334,10 @@ ui: related_question: title: Perguntas relacionadas answers: respostas + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Pessoas Perguntaram desc: Select people who you think might know the answer. @@ -1353,7 +1350,7 @@ ui: asked: perguntado update: Modificado edit: modificado - commented: commented + commented: comentado Views: Visualizado Follow: Seguir Following: Seguindo @@ -1371,12 +1368,12 @@ ui: title: Respostas score: Pontuação newest: Mais recente - oldest: Oldest + oldest: Mais Antigos btn_accept: Aceito btn_accepted: Aceito write_answer: title: A sua Resposta - edit_answer: Edit my existing answer + edit_answer: Editar a minha resposta existente btn_name: Publicação a sua resposta add_another_answer: Adicionar outra resposta confirm_title: Continuar a responder @@ -1396,13 +1393,13 @@ ui: title: Reabrir esta postagem content: Você tem certeza que deseja reabrir? list: - confirm_btn: List - title: List this post - content: Are you sure you want to list? + confirm_btn: Lista + title: Liste esta postagem + content: Você tem certeza que deseja listar? unlist: - confirm_btn: Unlist - title: Unlist this post - content: Are you sure you want to unlist? + confirm_btn: Remover da lista + title: Remover da lista de postagens + content: Tem certeza de que deseja remover da lista? pin: title: Fixe esta postagem content: Tem certeza de que deseja fixar globalmente? Esta postagem aparecerá no topo de todas as listas de postagens. @@ -1415,18 +1412,18 @@ ui:

Nós não recomendamos excluir perguntas com respostas porque isso priva os futuros leitores desse conhecimento.

A exclusão repetida de respostas aceitas pode resultar no bloqueio de respostas de sua conta.. Você tem certeza que deseja deletar? other: Você tem certeza que deseja deletar? tip_answer_deleted: Esta resposta foi deletada - undelete_title: Undelete this post - undelete_desc: Are you sure you wish to undelete? + undelete_title: Recuperar esta publicação + undelete_desc: Você tem certeza que deseja recuperar? btns: confirm: Confirmar cancel: Cancelar edit: Editar save: Salvar delete: Excluir - undelete: Undelete - list: List - unlist: Unlist - unlisted: Unlisted + undelete: Recuperar + list: Lista + unlist: Não listar + unlisted: Não listado login: Entrar signup: Cadastrar-se logout: Sair @@ -1443,28 +1440,28 @@ ui: comment: Comentário refresh: Atualizar resend: Reenviar - deactivate: Deactivate - active: Active - suspend: Suspend - unsuspend: Unsuspend - close: Close - reopen: Reopen + deactivate: Desativar + active: Ativar + suspend: Suspender + unsuspend: Suspensão cancelada + close: Fechar + reopen: Reabrir ok: OK - light: Light - dark: Dark - system_setting: System setting - default: Default + light: Claro + dark: Escuro + system_setting: Definições de sistema + default: Padrão reset: Reset - tag: Tag - post_lowercase: post - filter: Filter - ignore: Ignore - submit: Submit + tag: Marcador + post_lowercase: publicação + filter: Filtro + ignore: Ignorar + submit: Submeter normal: Normal - closed: Closed - deleted: Deleted - pending: Pending - more: More + closed: Fechado + deleted: Removido + pending: Pendente + more: Mais search: title: Procurar Resultados keywords: Palavras-chave @@ -1481,7 +1478,7 @@ ui: more: Mais tips: title: Dicas de Pesquisa Avançada - tag: "<1>[tag] search with a tag" + tag: "<1>[tag] pesquisar com um marcador" user: "<1>user:username buscar por autor" answer: "<1>answers:0 perguntas não respondidas" score: "<1>score:3 postagens com mais de 3+ placares" @@ -1502,7 +1499,7 @@ ui: success: A sua nova conta está confirmada; você será redirecionado para a página inicial. link: Continuar para a página inicial. oops: Oops! - invalid: The link you used no longer works. + invalid: O link utilizado não funciona mais. confirm_new_email: O seu e-mail foi atualizado. confirm_new_email_invalid: >- Desculpe, este link de confirmação não é mais válido. Talvez o seu e-mail já tenha sido alterado. @@ -1524,8 +1521,8 @@ ui: answers: Respostas newest: Mais recente active: Ativo - hot: Hot - recommend: Recommend + hot: Popular + recommend: Recomendado score: Pontuação unanswered: Não Respondido modified: modificado @@ -1544,7 +1541,7 @@ ui: reputation: Reputação comments: Comentários votes: Votos - badges: Badges + badges: Emblemas newest: Mais recente score: Pontuação edit_profile: Editar Perfil @@ -1559,6 +1556,7 @@ ui: top_questions: Melhores Perguntas stats: Estatísticas list_empty: Postagens não encontradas.
Talvez você queira selecionar uma guia diferente? + content_empty: No posts found. accepted: Aceito answered: respondido asked: perguntado @@ -1569,9 +1567,9 @@ ui: x_votes: votos recebidos x_answers: respostas x_questions: perguntas - recent_badges: Recent Badges + recent_badges: Emblemas recentes install: - title: Installation + title: Instalação next: Proximo done: Completo config_yaml_error: Não é possível criar o arquivo config.yaml. @@ -1610,14 +1608,14 @@ ui: site_name: label: Site Nome msg: Site Nome não pode ser vazio. - msg_max_length: Site name must be at maximum 30 characters in length. + msg_max_length: O nome do site deve ter no máximo 30 caracteres. site_url: label: URL do Site text: O endereço do seu site. msg: empty: Site URL não pode ser vazio. incorrect: URL do site está incorreto. - max_length: Site URL must be at maximum 512 characters in length. + max_length: A URL do site deve ter no máximo 512 caracteres. contact_email: label: E-mail par contato text: O endereço de e-mail do contato principal deste site. @@ -1632,21 +1630,21 @@ ui: label: Nome msg: Nome não pode ser vazio. character: 'Deve usar o conjunto de caracteres "a-z", "0-9", " - . _"' - msg_max_length: Name must be at maximum 30 characters in length. + msg_max_length: O nome deve ter no máximo 30 caracteres. admin_password: label: Senha text: >- You will need this password to log in. Por favor store it in a secure location. msg: Senha não pode ser vazio. - msg_min_length: Password must be at least 8 characters in length. - msg_max_length: Password must be at maximum 32 characters in length. + msg_min_length: A senha deve ser ter pelo menos 8 caracteres. + msg_max_length: A senha deve ter no máximo 32 caracteres. admin_email: label: E-mail text: Você precisará deste e-mail para efetuar o login. msg: empty: Email não pode ser vazio. incorrect: O formato do e-mail está incorreto. - ready_title: Your site is ready + ready_title: Seu site está pronto ready_desc: >- Se você quiser alterar mais configurações, visite <1>seção de administrador; encontre-o no menu do site. good_luck: "Divirta-se, e boa sorte!" @@ -1679,7 +1677,7 @@ ui: questions: Perguntas answers: Respostas users: Usuários - badges: Badges + badges: Emblemas flags: Marcadores settings: Configurações general: Geral @@ -1705,50 +1703,50 @@ ui: login_failed_email_tip: Falha ao entrar, por favor, permita que este aplicativo acesse a informação do seu e-mail antes de tentar novamente. badges: modal: - title: Congratulations - content: You've earned a new badge. - close: Close - confirm: View badges - title: Badges - awarded: Awarded - earned_×: Earned ×{{ number }} - ×_awarded: "{{ number }} awarded" - can_earn_multiple: You can earn this multiple times. - earned: Earned + title: Parabéns + content: Você ganhou um novo emblema. + close: Fechar + confirm: Ver emblemas + title: Emblemas + awarded: Premiado + earned_×: Ganhou ×{{ number }} + ×_awarded: "{{ number }} premiado" + can_earn_multiple: Você pode ganhar isto várias vezes. + earned: Ganhou admin: admin_header: title: Administrador dashboard: title: Painel - welcome: Welcome to Admin! - site_statistics: Site statistics + welcome: Bem-vindo ao Admin! + site_statistics: Estatísticas do site questions: "Perguntas:" answers: "Respostas:" comments: "Comentários:" votes: "Votos:" - users: "Users:" + users: "Usuários:" flags: "Marcadores:" - reviews: "Reviews:" - site_health: Site health + reviews: "Revisão:" + site_health: Saúde do site version: "Versão:" https: "HTTPS:" - upload_folder: "Upload folder:" - run_mode: "Running mode:" - private: Private - public: Public + upload_folder: "Upload da pasta:" + run_mode: "Mode de execução:" + private: Privado + public: Público smtp: "SMTP:" timezone: "Fuso horário:" - system_info: System info - go_version: "Go version:" - database: "Database:" - database_size: "Database size:" + system_info: Informação do sistema + go_version: "Versão do Go:" + database: "Banco de dados:" + database_size: "Tamanho do banco de dados:" storage_used: "Armazenamento usado:" uptime: "Tempo de atividade:" links: Links plugins: Plugins github: GitHub blog: Blog - contact: Contact + contact: Contato forum: Forum documents: Documentos feedback: Opinião @@ -1764,8 +1762,8 @@ ui: allowed: Permitido enabled: Ativo disabled: Disponível - writable: Writable - not_writable: Not writable + writable: Possível escrever + not_writable: Não é possível escrever flags: title: Marcadores pending: Pendente @@ -1790,21 +1788,21 @@ ui: btn_cancel: Cancelar btn_submit: Enviar edit_profile_modal: - title: Edit profile + title: Editar profile form: fields: display_name: - label: Display name - msg_range: Display name up to 30 characters. + label: Nome no display + msg_range: Nome no display pode conter até 30 caracteres. username: - label: Username - msg_range: Username up to 30 characters. + label: Nome do usuário + msg_range: Nome do usuário pode conter até 30 caracteres. email: - label: Email - msg_invalid: Invalid Email Address. - edit_success: Edited successfully - btn_cancel: Cancel - btn_submit: Submit + label: Correio eletrônico + msg_invalid: Correio eletrônico invalido. + edit_success: Editado com sucesso + btn_cancel: Cancelar + btn_submit: Submeter user_modal: title: Adicionar novo usuário form: @@ -1850,26 +1848,26 @@ ui: filter: placeholder: "Filtrar por nome, user:id" set_new_password: Configurar nova senha - edit_profile: Edit profile + edit_profile: Editar profile change_status: Mudar status change_role: Mudar função show_logs: Mostrar registros add_user: Adicionar usuário deactivate_user: - title: Deactivate user - content: An inactive user must re-validate their email. + title: Desativar usuários + content: Um usuário inativo deve revalidar seu e-mail. delete_user: - title: Delete this user - content: Are you sure you want to delete this user? This is permanent! - remove: Remove their content - label: Remove all questions, answers, comments, etc. - text: Don’t check this if you wish to only delete the user’s account. + title: Remover este usuário + content: Tem certeza de que deseja excluir este usuário? Isso é permanente! + remove: Remover o conteúdo dele + label: Remover todas as perguntas, respostas, comentários etc. + text: Não marque isso se deseja excluir apenas a conta do usuário. suspend_user: - title: Suspend this user - content: A suspended user can't log in. + title: Suspender este usuário + content: Um usuário suspenso não pode fazer login. questions: page_title: Perguntas - unlisted: Unlisted + unlisted: Não-listado post: Publicação votes: Votos answers: Respostas @@ -1877,7 +1875,7 @@ ui: status: Estado action: Ação change: Mudar - pending: Pending + pending: Pendente filter: placeholder: "Filtrar por título, question:id" answers: @@ -1915,8 +1913,8 @@ ui: validate: E-mail par contato não é válido. text: Endereço de e-mail do principal contato responsável por este site. check_update: - label: Software updates - text: Automatically check for updates + label: Atualizações de software + text: Verificar se há atualizações automaticamente interface: page_title: Interface language: @@ -1995,28 +1993,28 @@ ui: write: page_title: Escrever restrict_answer: - title: Answer write + title: Escrever resposta label: Each user can only write one answer for each question - text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + text: "Desative para permitir que os usuários escrevam várias respostas para a mesma pergunta, o que pode fazer com que as respostas fiquem menos focadas." recommend_tags: label: Recommend Marcadores - text: "Recommend tags will show in the dropdown list by default." + text: "Os marcadores recomendados serão exibidos na lista dropdown por padrão." msg: - contain_reserved: "recommended tags cannot contain reserved tags" + contain_reserved: "tags recomendadas não podem conter tags reservadas" required_tag: - title: Set required tags - label: Set “Recommend tags” as required tags + title: Definir tags necessárias + label: Definir "Tags recomendadas" como tags necessárias text: "Every new question must have ao menos one recommend tag." reserved_tags: label: Reserved Marcadores - text: "Reserved tags can only be used by moderator." + text: "Tags reservadas só podem ser usadas pelo moderador." seo: page_title: SEO permalink: label: Link permanente text: Custom URL structures can improve the usability, and forward-compatibility of a sua links. robots: - label: robots.txt + label: robos.txt text: Isto irá substituir permanentemente quaisquer configurações do site relacionadas. themes: page_title: Temas @@ -2024,11 +2022,11 @@ ui: label: Temas text: Selecionar um tema existente. color_scheme: - label: Color scheme + label: Esquema de cores navbar_style: - label: Navbar style + label: Estilo da barra de navegação primary_color: - label: Primary color + label: Cor primária text: Modifica as cores usadas por seus temas css_and_html: page_title: CSS e HTML @@ -2046,7 +2044,7 @@ ui: footer: label: Rodapé - text: This will insert before </body>. + text: Isto será inserido antes de </body>. sidebar: label: Barra lateral text: Isto irá inserir na barra lateral. @@ -2068,12 +2066,12 @@ ui: label: Login requirido text: Somente usuários conectados podem acessar esta comunidade. password_login: - title: Password login - label: Allow email and password login - text: "WARNING: If turn off, you may be unable to log in if you have not previously configured other login method." + title: Login com senha + label: Permitir login por e-mail e senha + text: "AVISO: Se desativar, você pode ser incapaz de efetuar login se você não tiver configurado anteriormente outro método de login." installed_plugins: title: Extensões instaladas - plugin_link: Plugins extend and expand the functionality. You may find plugins in the <1>Plugin Repository. + plugin_link: Plugins ampliam e expandem a funcionalidade. Você pode encontrar plugins no <1>Repositório de Plugins. filter: all: Todos active: Ativo @@ -2117,23 +2115,24 @@ ui: label: Nível de reputação necessário text: Escolha a reputação necessária para os privilégios msg: - should_be_number: the input should be number - number_larger_1: number should be equal or larger than 1 + should_be_number: o valor de entrada deve ser número + number_larger_1: número deve ser igual ou maior que 1 badges: - action: Action - active: Active + action: Ação + active: Ativo + activate: Ativado activate: Activate - all: All - awards: Awards - deactivate: Deactivate + all: Todos + awards: Prêmios + deactivate: Desativar filter: - placeholder: Filter by name, badge:id - group: Group - inactive: Inactive - name: Name - show_logs: Show logs + placeholder: Filtrar por nome, badge:id + group: Grupo + inactive: Inativo + name: Nome + show_logs: Mostrar registros status: Status - title: Badges + title: Emblemas form: optional: (opcional) empty: não pode ser vazio @@ -2152,22 +2151,22 @@ ui: edit_answer: Editar resposta edit_tag: Editar marcador empty: Nenhuma tarefa de revisão restante. - approve_revision_tip: Do you approve this revision? - approve_flag_tip: Do you approve this flag? - approve_post_tip: Do you approve this post? - approve_user_tip: Do you approve this user? - suggest_edits: Suggested edits - flag_post: Flag post - flag_user: Flag user - queued_post: Queued post - queued_user: Queued user - filter_label: Type - reputation: reputation - flag_post_type: Flagged this post as {{ type }}. - flag_user_type: Flagged this user as {{ type }}. - edit_post: Edit post - list_post: List post - unlist_post: Unlist post + approve_revision_tip: Você aprova esta revisão? + approve_flag_tip: Você aprova esta sinalização? + approve_post_tip: Você aprova esta publicação? + approve_user_tip: Você aprova este usuário? + suggest_edits: Edições sugeridas + flag_post: Post sinalizado + flag_user: Sinalizar usuário + queued_post: Publicação na fila + queued_user: Usuário na fila + filter_label: Tipo + reputation: reputação + flag_post_type: Sinalizou esta publicação como {{ type }}. + flag_user_type: Sinalizou este usuário como {{ type }}. + edit_post: Editar publicação + list_post: Listar postagem + unlist_post: Remover postagem da lista timeline: undeleted: não removido deleted: removido @@ -2218,6 +2217,6 @@ ui: post_hide_list: Esta postagem foi ocultada da lista. post_show_list: Esta postagem foi exibida à lista. post_reopen: Esta publicação foi re-aberta. - post_list: This post has been listed. - post_unlist: This post has been unlisted. - post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_list: Esta postagem foi listada. + post_unlist: Esta publicação foi removida da lista. + post_pending: A sua postagem está aguardando revisão. Ela ficará visível depois que for aprovada. diff --git a/i18n/ro_RO.yaml b/i18n/ro_RO.yaml index c73eb566..9b7ed200 100644 --- a/i18n/ro_RO.yaml +++ b/i18n/ro_RO.yaml @@ -326,9 +326,7 @@ backend: name: other: nepoliticos sau abuziv desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: un duplicat @@ -340,10 +338,7 @@ backend: name: other: nu este un răspuns desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: nu mai este necesar @@ -402,9 +397,7 @@ backend: name: other: necesită detalii sau claritate desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: altceva @@ -794,7 +787,7 @@ ui: how_to_format: title: Cum se formatează desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Înapoi next: Înainte @@ -1341,6 +1334,10 @@ ui: related_question: title: Întrebări conexe answers: răspunsuri + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Persoane întrebate desc: Invită persoane care crezi că știu răspunsul. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Intrebari stats: Statistici list_empty: Nici o postare găsită.
Poate doriţi să selectaţi o filă diferită? + content_empty: No posts found. accepted: Acceptat answered: răspunse asked: întrebat diff --git a/i18n/ru_RU.yaml b/i18n/ru_RU.yaml index 9adf491a..1e370b5c 100644 --- a/i18n/ru_RU.yaml +++ b/i18n/ru_RU.yaml @@ -326,9 +326,7 @@ backend: name: other: Грубость или оскорбления desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: дубликат @@ -340,10 +338,7 @@ backend: name: other: это не ответ desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: Не актуально @@ -402,9 +397,7 @@ backend: name: other: нуждается в деталях или ясности desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: прочее @@ -794,7 +787,7 @@ ui: how_to_format: title: 'Форматирование:' desc: >- -
  • создание ссылок:

    <https://url.com>

    [Title](https://url.com)
  • пробел между абзацами

  • _italic_ или **bold**

  • отступ для кода - 4 пробела

  • тег > для цитаты в начале строки

  • обратные кавычки для строки кода `like _this_`

  • тройные обратные кавычки для блоков кода `

    ```
    тут код
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Назад next: Следующий @@ -1341,6 +1334,10 @@ ui: related_question: title: Похожие вопросы answers: ответы + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Позвать на помощь desc: Выберите людей, которые, по вашему мнению, могут знать ответ. @@ -1559,6 +1556,7 @@ ui: top_questions: Топ вопросов stats: Статистика list_empty: Сообщений не найдено.
Возможно, вы хотели бы выбрать другую вкладку? + content_empty: No posts found. accepted: Принято answered: отвеченные asked: спросил diff --git a/i18n/sk_SK.yaml b/i18n/sk_SK.yaml index eac4f204..28e77be0 100644 --- a/i18n/sk_SK.yaml +++ b/i18n/sk_SK.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: potrebuje podrobnosti alebo jasnosť desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: niečo iné @@ -794,7 +787,7 @@ ui: how_to_format: title: Ako formátovať desc: >- -
  • na vytváranie odkazov

    <https://url.com>

    [Title](https://url.com)
  • vracať medzi odsekmi

  • _italic_ alebo **tučné**

  • odsadenie kódu o 4 medzery

  • citát umiestnením > na začiatku riadku

  • backtick uniká `ako _this_`

  • vytvorte kódové ploty s `

    ```
    kódom tu
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Predch next: Ďalšie @@ -1341,6 +1334,10 @@ ui: related_question: title: Súvisiace otázky answers: odpovede + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Najlepšie otázky stats: Štatistiky list_empty: Nenašli sa žiadne príspevky.
Možno by ste chceli vybrať inú kartu? + content_empty: No posts found. accepted: Prijaté answered: zodpovedané asked: opýtané diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index 36b59fe6..b6c5e90e 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Ogiltig URL. status_invalid: - other: Invalid status. + other: Ogiltig status. password: space_invalid: other: Password cannot contain spaces. @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prev next: Nästa @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Bjud in personer som du tror kan svara. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked @@ -1705,9 +1703,9 @@ ui: login_failed_email_tip: Login failed, please allow this app to access your email information before try again. badges: modal: - title: Congratulations + title: Grattis content: You've earned a new badge. - close: Close + close: Stäng confirm: View badges title: Badges awarded: Awarded @@ -1794,7 +1792,7 @@ ui: form: fields: display_name: - label: Display name + label: Visningsnamn msg_range: Display name up to 30 characters. username: label: Username @@ -2121,17 +2119,18 @@ ui: number_larger_1: number should be equal or larger than 1 badges: action: Action - active: Active + active: Aktiv + activate: Aktivera activate: Activate - all: All + all: Alla awards: Awards - deactivate: Deactivate + deactivate: Inaktivera filter: placeholder: Filter by name, badge:id - group: Group - inactive: Inactive - name: Name - show_logs: Show logs + group: Grupp + inactive: Inaktiv + name: Namn + show_logs: Visa loggar status: Status title: Badges form: diff --git a/i18n/te_IN.yaml b/i18n/te_IN.yaml index 638a1870..2b9ea470 100644 --- a/i18n/te_IN.yaml +++ b/i18n/te_IN.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: మునుపటి next: Next @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/tr_TR.yaml b/i18n/tr_TR.yaml index 656da997..5bfb1bbd 100644 --- a/i18n/tr_TR.yaml +++ b/i18n/tr_TR.yaml @@ -183,7 +183,7 @@ backend: verify_url_expired: other: Email verified URL has expired, please resend the email. illegal_email_domain_error: - other: Email is not allowed from that email domain. Please use another one. + other: Bu alan adındaki e-posta adreslerine izin verilmiyor. Lütfen başka bir e-posta deneyin. lang: not_found: other: Dil dosyası bulunamadı. @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -400,23 +395,21 @@ backend: other: This question doesn't meet a community guideline. multiple: name: - other: needs details or clarity + other: açıklanmaya veya detaya ihtiyacı var desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: - other: something else + other: başka bir şey desc: other: This post requires another reason not listed above. operation_type: asked: - other: asked + other: soruldu answered: - other: answered + other: cevaplandı modified: - other: modified + other: düzenlendi deleted_title: other: Deleted question questions_title: @@ -641,7 +634,7 @@ backend: other: Invited a user. campaigner: name: - other: Campaigner + other: Kampanyacı desc: other: Invited 3 basic users. champion: @@ -651,7 +644,7 @@ backend: other: Invited 5 members. thank_you: name: - other: Thank You + other: desc: other: Has 20 up voted posts and gave 10 up votes. gives_back: @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Önceki next: Sonraki @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/uk_UA.yaml b/i18n/uk_UA.yaml index 58a538e2..a8f29b30 100644 --- a/i18n/uk_UA.yaml +++ b/i18n/uk_UA.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Невірна URL. status_invalid: - other: Invalid status. + other: Неприпустимий статус. password: space_invalid: other: Пароль не може містити пробіли. @@ -315,7 +315,7 @@ backend: other: Конфігурацію сайту не знайдено. badge: object_not_found: - other: Badge object not found + other: Об'єкт значка не знайдено reason: spam: name: @@ -326,9 +326,7 @@ backend: name: other: грубо чи образливо desc: - other: - - Розсудлива людина вважатиме цей контент неприйнятним з точки зору шанобливого ставлення - - дискурс. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: дублікат @@ -340,10 +338,7 @@ backend: name: other: не відповідь desc: - other: - - Це повідомлення було розміщено як відповідь, але воно не є спробою відповісти на - - запитання. Можливо, його слід відредагувати, додати коментар, поставити інше запитання - - або взагалі видалити. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: більше не потрібно @@ -402,9 +397,7 @@ backend: name: other: потребує деталей або ясності desc: - other: - - Наразі це запитання містить кілька запитань в одному. Воно має - - зосереджуватися лише на одній проблемі. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: інше @@ -420,10 +413,10 @@ backend: deleted_title: other: Видалене питання questions_title: - other: Questions + other: Питання tag: tags_title: - other: Tags + other: Теґи no_description: other: The tag has no description. notification: @@ -515,7 +508,7 @@ backend: downvote: other: голос "проти" downvoted: - other: downvoted + other: проголосував проти accept: other: прийняти accepted: @@ -541,14 +534,14 @@ backend: other: Filled out profile information. certified: name: - other: Certified + other: Підтверджений desc: other: Completed our new user tutorial. editor: name: - other: Editor + other: Редактор desc: - other: First post edit. + other: Перше редагування посту. first_flag: name: other: First Flag @@ -561,12 +554,12 @@ backend: other: First up voted a post. first_link: name: - other: First Link + other: Перше посилання desc: other: First dirst added a link to another post. first_reaction: name: - other: First Reaction + other: Перша реакція desc: other: First reacted to the post. first_share: @@ -576,34 +569,34 @@ backend: other: First shared a post. scholar: name: - other: Scholar + other: Вчений desc: other: Asked a question and accepted an answer. commentator: name: - other: Commentator + other: Коментатор desc: - other: Leave 5 comments. + other: Залиште 5 коментарів. new_user_of_the_month: name: - other: New User of the Month + other: Новий користувач місяця desc: other: Outstanding contributions in their first month. read_guidelines: name: other: Read Guidelines desc: - other: Read the [community guidelines]. + other: Прочитайте [рекомендації для спільноти]. reader: name: - other: Reader + other: Читач desc: other: Read every answers in a topic with more than 10 answers. welcome: name: - other: Welcome + other: Ласкаво просимо desc: - other: Received a up vote. + other: Отримав голос. nice_share: name: other: Nice Share @@ -636,9 +629,9 @@ backend: other: Used 50 up votes in a day 20 times. promoter: name: - other: Promoter + other: Промоутер desc: - other: Invited a user. + other: Запросив користувача. campaigner: name: other: Campaigner @@ -646,12 +639,12 @@ backend: other: Invited 3 basic users. champion: name: - other: Champion + other: Чемпіон desc: - other: Invited 5 members. + other: Запросив 5 учасників. thank_you: name: - other: Thank You + other: Дякую desc: other: Has 20 up voted posts and gave 10 up votes. gives_back: @@ -691,7 +684,7 @@ backend: other: Received 1 up vote on 20 posts. respected: name: - other: Respected + other: Шанований desc: other: Received 2 up votes on 100 posts. admired: @@ -701,7 +694,7 @@ backend: other: Received 5 up votes on 300 posts. solved: name: - other: Solved + other: Вирішено desc: other: Have an answer be accepted. guidance_counsellor: @@ -785,7 +778,7 @@ backend: other: Getting Started community: name: - other: Community + other: Спільнота posting: name: other: Posting @@ -794,7 +787,7 @@ ui: how_to_format: title: Як відформатувати desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Назад next: Далі @@ -843,7 +836,7 @@ ui: posts: Публікації invites: Запрошення votes: Голоси - answer: Answer + answer: Відповідь question: Question badge_award: Badge suspended: @@ -1037,12 +1030,12 @@ ui: x_minutes_ago: "{{count}}m ago" x_hours_ago: "{{count}}h ago" hour: hour - day: day + day: день hours: hours - days: days + days: дні reaction: heart: heart - smile: smile + smile: посмішка frown: frown btn_label: add or remove reactions undo_emoji: undo {{ emoji }} reaction @@ -1341,6 +1334,10 @@ ui: related_question: title: Пов'язані запитання answers: відповіді + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Люди запитували desc: Виберіть людей, які, на вашу думку, можуть знати відповідь. @@ -1361,7 +1358,7 @@ ui: answered: answered closed_in: Closed in show_exist: Показати наявне запитання. - useful: Useful + useful: Корисне question_useful: It is useful and clear question_un_useful: It is unclear or not useful question_bookmark: Bookmark this question @@ -1372,10 +1369,10 @@ ui: score: Score newest: Newest oldest: Oldest - btn_accept: Accept + btn_accept: Прийняти btn_accepted: Accepted write_answer: - title: Your Answer + title: Ваша відповідь edit_answer: Edit my existing answer btn_name: Post your answer add_another_answer: Add another answer @@ -1383,7 +1380,7 @@ ui: continue: Continue confirm_info: >-

Are you sure you want to add another answer?

You could use the edit link to refine and improve your existing answer, instead.

- empty: Answer cannot be empty. + empty: Відповідь не може бути порожньою. characters: вміст має бути не менше 6 символів. tips: header_1: Дякуємо за відповідь @@ -1424,8 +1421,8 @@ ui: save: Зберегти delete: Видалити undelete: Скасувати видалення - list: List - unlist: Unlist + list: Список + unlist: Вилучити зі списку unlisted: Unlisted login: Увійти signup: Зареєструватися @@ -1449,7 +1446,7 @@ ui: unsuspend: Unsuspend close: Закрити reopen: Відкрити знову - ok: OK + ok: ОК light: Світла dark: Темна system_setting: Налаштування системи @@ -1462,7 +1459,7 @@ ui: submit: Submit normal: Normal closed: Closed - deleted: Deleted + deleted: Видалені pending: Pending more: More search: @@ -1497,11 +1494,11 @@ ui: twitter: Share to Twitter cannot_vote_for_self: You can't vote for your own post. modal_confirm: - title: Error... + title: Помилка... account_result: success: Your new account is confirmed; you will be redirected to the home page. - link: Continue to homepage - oops: Oops! + link: Перейти на головну сторінку + oops: Йой! invalid: The link you used no longer works. confirm_new_email: Your email has been updated. confirm_new_email_invalid: >- @@ -1514,7 +1511,7 @@ ui: question: following_tags: Підписки на теги edit: Edit - save: Save + save: Зберегти follow_tag_tip: Підпишіться на теги, щоб упорядкувати свій список запитань. hot_questions: Hot Questions all_questions: Всі питання @@ -1559,6 +1556,7 @@ ui: top_questions: Найкращі запитання stats: Статистика list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked @@ -1576,17 +1574,17 @@ ui: done: Done config_yaml_error: Can't create the config.yaml file. lang: - label: Please choose a language + label: Будь ласка, виберіть мову db_type: label: Database engine db_username: - label: Username + label: Ім'я користувача placeholder: root msg: Username cannot be empty. db_password: - label: Password + label: Пароль placeholder: root - msg: Password cannot be empty. + msg: Поле паролю не може бути порожнім. db_host: label: Database host placeholder: "db:3306" @@ -1664,7 +1662,7 @@ ui: views: views votes: votes answers: answers - accepted: Accepted + accepted: Схвалено page_error: http_error: HTTP Error {{ code }} desc_403: You don't have permission to access this page. @@ -1681,17 +1679,17 @@ ui: users: Users badges: Badges flags: Відмітки - settings: Settings + settings: Налаштування general: General interface: Interface smtp: SMTP branding: Branding legal: Legal - write: Write + write: Написати tos: Terms of Service privacy: Privacy seo: SEO - customize: Customize + customize: Персоналізувати themes: Themes css_html: CSS/HTML login: Login @@ -1707,17 +1705,17 @@ ui: modal: title: Congratulations content: You've earned a new badge. - close: Close + close: Закрити confirm: View badges title: Badges awarded: Awarded earned_×: Earned ×{{ number }} ×_awarded: "{{ number }} awarded" can_earn_multiple: You can earn this multiple times. - earned: Earned + earned: Зароблено admin: admin_header: - title: Admin + title: Адмін dashboard: title: Dashboard welcome: Welcome to Admin! @@ -1744,11 +1742,11 @@ ui: database_size: "Розмір бази даних:" storage_used: "Використаний обсяг пам’яті:" uptime: "Uptime:" - links: Links + links: Посилання plugins: Плаґіни github: GitHub blog: Блоґ - contact: Contact + contact: Контакт forum: Forum documents: Документи feedback: Відгук @@ -1777,20 +1775,20 @@ ui: review: Огляд user_role_modal: title: Change user role to... - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати new_password_modal: - title: Set new password + title: Встановити новий пароль form: fields: password: - label: Password + label: Пароль text: The user will be logged out and need to login again. msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати edit_profile_modal: - title: Edit profile + title: Редагувати профіль form: fields: display_name: @@ -1800,13 +1798,13 @@ ui: label: Username msg_range: Username up to 30 characters. email: - label: Email + label: Електронна пошта msg_invalid: Invalid Email Address. edit_success: Edited successfully - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати user_modal: - title: Add new user + title: Додати нового користувача form: fields: users: @@ -1818,17 +1816,17 @@ ui: label: Ім'я для відображення msg: Ім'я для відображення повинно мати довжину від 2 до 30 символів. email: - label: Email + label: Електронна пошта msg: Email is not valid. password: - label: Password + label: Пароль msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати users: - title: Users - name: Name - email: Email + title: Користувачі + name: Ім’я + email: Електронна пошта reputation: Reputation created_at: Created Time delete_at: Deleted Time @@ -1870,7 +1868,7 @@ ui: questions: page_title: Запитання unlisted: Unlisted - post: Post + post: Опублікувати votes: Votes answers: Answers created: Створені @@ -1993,7 +1991,7 @@ ui: label: Політика конфіденційности text: "Ви можете додати вміст політики конфіденційності тут. Якщо у вас уже є документ, розміщений деінде, надайте тут повну URL-адресу." write: - page_title: Write + page_title: Написати restrict_answer: title: Answer write label: Кожен користувач може написати лише одну відповідь на кожне запитання @@ -2028,7 +2026,7 @@ ui: navbar_style: label: Navbar style primary_color: - label: Primary color + label: Основний колір text: Modify the colors used by your themes css_and_html: page_title: CSS and HTML @@ -2051,7 +2049,7 @@ ui: label: Sidebar text: This will insert in sidebar. login: - page_title: Login + page_title: Увійти membership: title: Membership label: Дозволити нові реєстрації @@ -2082,15 +2080,15 @@ ui: plugins: label: Plugins text: Select an existing plugin. - name: Name + name: Ім’я version: Version status: Status action: Action deactivate: Deactivate activate: Activate - settings: Settings + settings: Налаштування settings_users: - title: Users + title: Користувачі avatar: label: Default avatar text: For users without a custom avatar of their own. @@ -2130,17 +2128,17 @@ ui: placeholder: Filter by name, badge:id group: Group inactive: Inactive - name: Name + name: Ім’я show_logs: Show logs status: Status title: Badges form: optional: (optional) - empty: cannot be empty + empty: не може бути порожнім invalid: is invalid - btn_submit: Save + btn_submit: Зберегти not_found_props: "Required property {{ key }} not found." - select: Select + select: Вибрати page_review: review: Review proposed: proposed diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 59f56978..044817fa 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: URL không tồn tại. status_invalid: - other: Invalid status. + other: Trạng thái không hợp lệ password: space_invalid: other: Mật khẩu không thể tồn tại khoảng trắng. @@ -315,35 +315,30 @@ backend: other: Không tìm thấy cấu hình trang. badge: object_not_found: - other: Badge object not found + other: Đối tượng không tìm thấy reason: spam: name: - other: Lạm dụng + other: thư rác desc: - other: Bài đăng này là quảng cáo hoặc phá hoại. Nó không hữu ích hoặc liên quan đến chủ đề hiện tại. + other: Bài đăng này quảng cáo hoặc phá hoại. Nó không hữu ích hoặc liên quan đến chủ đề hiện tại. rude_or_abusive: name: other: thô lỗ hoặc lạm dụng desc: - other: - - Một người lý trí sẽ thấy nội dung này không phù hợp để thảo luận tôn trọng - - Đàm thoại + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: một bản sao desc: - other: Câu hỏi này đã được hỏi trước đó và đã có câu trả lời. + other: Câu hỏi này đã được hỏi trước đó, đã có câu trả lời. placeholder: other: Nhập liên kết câu hỏi hiện tại not_a_answer: name: - other: không phải là câu trả lời + other: không phải câu trả lời desc: - other: - - Nội dung này được đăng dưới dạng câu trả lời, nhưng nó không hề trả lời cho câu hỏi... - - câu hỏi. Nó có thể là một chỉnh sửa, một bình luận, một câu hỏi khác, - - hoặc bị xóa hoàn toàn. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: không còn cần thiết @@ -402,9 +397,7 @@ backend: name: other: cần chi tiết hoặc rõ ràng desc: - other: - - Câu hỏi này hiện bao gồm nhiều câu hỏi trong một. Nó nên tập trung vào một vấn đề duy nhất - - chỉ tập trung vào một vấn đề. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: điều gì đó khác @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: đã mời bạn trả lời earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Bạn đã nhận được huy hiệu "{{.BadgeName}}" email_tpl: change_email: title: @@ -536,265 +529,265 @@ backend: default_badges: autobiographer: name: - other: Autobiographer + other: Tác giả tự truyện desc: - other: Filled out profile information. + other: Đã điền thông tin hồ sơ. certified: name: - other: Certified + other: Đã xác minh desc: - other: Completed our new user tutorial. + other: Hoàn thành hướng dẫn cho người dùng mới của chúng tôi. editor: name: - other: Editor + other: Trình chỉnh sửa desc: - other: First post edit. + other: Chỉnh sửa bài đăng đầu tiên. first_flag: name: - other: First Flag + other: Cờ đầu tiên desc: - other: First flagged a post. + other: Lần đầu tiên báo cáo một bài viết. first_upvote: name: - other: First Upvote + other: Lượt thích đầu tiên desc: - other: First up voted a post. + other: Lần đầu tiên báo cáo một bài viết. first_link: name: - other: First Link + other: Liên kết đầu tiên desc: - other: First dirst added a link to another post. + other: Đầu tiên, Dirst đã thêm một liên kết đến một bài viết khác. first_reaction: name: - other: First Reaction + other: Phản ứng đầu tiên desc: - other: First reacted to the post. + other: Phản ứng với bài viết đầu tiên. first_share: name: - other: First Share + other: Chia sẻ đầu tiên desc: - other: First shared a post. + other: Lần đầu chia sẻ một bài viết. scholar: name: - other: Scholar + other: Học giả desc: - other: Asked a question and accepted an answer. + other: Đặt một câu hỏi và chấp nhận một câu trả lời. commentator: name: - other: Commentator + other: Bình luận viên desc: - other: Leave 5 comments. + other: Để lại 5 bình luận. new_user_of_the_month: name: - other: New User of the Month + other: Người dùng mới của tháng desc: - other: Outstanding contributions in their first month. + other: Đóng góp nổi bật trong tháng đầu tiên của họ. read_guidelines: name: - other: Read Guidelines + other: Đọc hướng dẫn desc: - other: Read the [community guidelines]. + other: Đọc [nguyên tắc cộng đồng]. reader: name: - other: Reader + other: Người đọc desc: - other: Read every answers in a topic with more than 10 answers. + other: Đọc mọi câu trả lời trong một chủ đề có hơn 10 câu trả lời. welcome: name: - other: Welcome + other: Xin chào desc: - other: Received a up vote. + other: Đã nhận được phiếu tán thành. nice_share: name: - other: Nice Share + other: Chia sẻ hay desc: - other: Shared a post with 25 unique visitors. + other: Đã chia sẻ một bài đăng với 25 khách truy cập. good_share: name: - other: Good Share + other: Chia sẻ tốt desc: - other: Shared a post with 300 unique visitors. + other: Đã chia sẻ một bài đăng với 300 khách truy cập. great_share: name: - other: Great Share + other: Chia sẻ tuyệt vời desc: - other: Shared a post with 1000 unique visitors. + other: Đã chia sẻ một bài đăng với 1000 khách truy cập. out_of_love: name: - other: Out of Love + other: Hết yêu thích desc: - other: Used 50 up votes in a day. + other: Đã sử dụng 50 phiếu bầu trong một ngày. higher_love: name: - other: Higher Love + other: Thích cao hơn desc: - other: Used 50 up votes in a day 5 times. + other: Đã sử dụng 50 phiếu bầu trong một ngày. crazy_in_love: name: - other: Crazy in Love + other: Thích điên cuồng desc: - other: Used 50 up votes in a day 20 times. + other: Đã sử dụng 50 phiếu bầu trong một ngày 20 lần. promoter: name: - other: Promoter + other: Người quảng bá desc: - other: Invited a user. + other: Đã mời một người dùng. campaigner: name: - other: Campaigner + other: Chiến dịch desc: - other: Invited 3 basic users. + other: Đã mời 3 người dùng cơ bản. champion: name: - other: Champion + other: Vô địch desc: - other: Invited 5 members. + other: Mời 5 thành viên. thank_you: name: - other: Thank You + other: Cảm ơn bạn desc: - other: Has 20 up voted posts and gave 10 up votes. + other: Có 20 bài đăng được bình chọn đưa ra 10 phiếu bầu. gives_back: name: - other: Gives Back + other: Trả lại desc: - other: Has 100 up voted posts and gave 100 up votes. + other: Có 100 bài đăng được bình chọn và đưa ra 100 phiếu bầu. empathetic: name: - other: Empathetic + other: Đồng cảm desc: - other: Has 500 up voted posts and gave 1000 up votes. + other: Có 500 bài đăng được bình chọn đưa ra 1000 phiếu bầu. enthusiast: name: - other: Enthusiast + other: Người nhiệt thành desc: - other: Visited 10 consecutive days. + other: Đã truy cập 10 ngày liên tiếp. aficionado: name: - other: Aficionado + other: Người hâm mộ desc: - other: Visited 100 consecutive days. + other: Đã truy cập 100 ngày liên tiếp. devotee: name: - other: Devotee + other: Tín đồ desc: - other: Visited 365 consecutive days. + other: Đã truy cập 365 ngày liên tiếp. anniversary: name: - other: Anniversary + other: Kỉ niệm desc: - other: Active member for a year, posted at least once. + other: Thành viên tích cực trong một năm, đăng ít nhất một lần. appreciated: name: - other: Appreciated + other: Đánh giá cao desc: - other: Received 1 up vote on 20 posts. + other: Nhận được 1 lượt bình chọn cho 20 bài viết. respected: name: - other: Respected + other: Tôn trọng desc: - other: Received 2 up votes on 100 posts. + other: Nhận được 2 lượt bình chọn cho 100 bài viết. admired: name: - other: Admired + other: Ngưỡng mộ desc: - other: Received 5 up votes on 300 posts. + other: Nhận được 5 lượt bình chọn trên 300 bài đăng. solved: name: - other: Solved + other: Đã giải quyết desc: - other: Have an answer be accepted. + other: Có một câu trả lời được chấp nhận. guidance_counsellor: name: - other: Guidance Counsellor + other: Cố vấn hướng dẫn desc: - other: Have 10 answers be accepted. + other: Có 10 câu trả lời được chấp nhận. know_it_all: name: - other: Know-it-All + other: Biết tất cả desc: - other: Have 50 answers be accepted. + other: Có 50 câu trả lời được chấp nhận. solution_institution: name: - other: Solution Institution + other: Viện giải pháp desc: - other: Have 150 answers be accepted. + other: Có 150 câu trả lời được chấp nhận. nice_answer: name: - other: Nice Answer + other: Câu trả lời tốt desc: - other: Answer score of 10 or more. + other: Điểm trả lời từ 10 trở lên. good_answer: name: - other: Good Answer + other: Câu trả lời của bạn desc: - other: Answer score of 25 or more. + other: Điểm trả lời từ 25 trở lên. great_answer: name: - other: Great Answer + other: Câu trả lời tuyệt vời desc: - other: Answer score of 50 or more. + other: Điểm trả lời từ 50 trở lên. nice_question: name: - other: Nice Question + other: Câu trả lời tốt desc: - other: Question score of 10 or more. + other: Điểm trả lời từ 10 trở lên. good_question: name: - other: Good Question + other: Câu trả lời tốt desc: - other: Question score of 25 or more. + other: Điểm trả lời từ 25 trở lên. great_question: name: - other: Great Question + other: Câu trả lời tốt desc: - other: Question score of 50 or more. + other: Điểm trả lời từ 50 trở lên. popular_question: name: - other: Popular Question + other: Câu hỏi phổ biến desc: - other: Question with 500 views. + other: Câu hỏi với 500 lượt xem. notable_question: name: - other: Notable Question + other: Câu hỏi đáng chú ý desc: - other: Question with 1,000 views. + other: Câu hỏi với 1.000 lượt xem. famous_question: name: - other: Famous Question + other: Câu hỏi nổi tiếng desc: - other: Question with 5,000 views. + other: Câu hỏi với 5.000 lượt xem. popular_link: name: - other: Popular Link + other: Liên kết phổ biến desc: - other: Posted an external link with 50 clicks. + other: Đã đăng một liên kết bên ngoài với 50 lần nhấp chuột. hot_link: name: - other: Hot Link + other: Liên kết nổi bật desc: - other: Posted an external link with 300 clicks. + other: Đã đăng một liên kết bên ngoài với 300 lần nhấp chuột. famous_link: name: - other: Famous Link + other: Liên kết nổi tiếng desc: - other: Posted an external link with 100 clicks. + other: Đã đăng một liên kết bên ngoài với 100 lần nhấp chuột. default_badge_groups: getting_started: name: - other: Getting Started + other: Bắt đầu community: name: - other: Community + other: Cộng đồng posting: name: - other: Posting + other: Viết bài thảo luận # The following fields are used for interface presentation(Front-end) ui: how_to_format: title: Cách định dạng desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Trước next: Tiếp @@ -843,9 +836,9 @@ ui: posts: Bài đăng invites: Lời mời votes: Bình chọn - answer: Answer - question: Question - badge_award: Badge + answer: Câu trả lời + question: Câu hỏi + badge_award: Huy hiệu suspended: title: Tài khoản của bạn đã bị đình chỉ until_time: "Tài khoản của bạn đã bị đình chỉ cho đến {{ time }}." @@ -868,8 +861,8 @@ ui: gantt_chart: Biểu đồ Gantt pie_chart: Biểu đồ tròn code: - text: Mẫu mã - add_code: Thêm mẫu mã + text: Mẫu code + add_code: Thêm code mẫu form: fields: code: @@ -938,7 +931,7 @@ ui: form: fields: url: - label: URL + label: Đường link url msg: empty: URL không thể trống. name: @@ -1043,9 +1036,9 @@ ui: reaction: heart: trái tim smile: nụ cười - frown: khắc nghiệt - btn_label: thêm hoặc loại bỏ lại - undo_emoji: trở lại {{ emoji }} lặp lại + frown: nhăn mặt + btn_label: thêm hoặc loại bỏ phản ứng + undo_emoji: bỏ dấu {{ emoji }} phản ứng react_emoji: biểu cảm với {{ emoji }} unreact_emoji: hủy biểu cảm {{ emoji }} comment: @@ -1141,7 +1134,7 @@ ui: question: Câu hỏi tag: Thẻ user: Người dùng - badges: Badges + badges: Danh hiệu profile: Hồ sơ setting: Cài đặt logout: Đăng xuất @@ -1167,11 +1160,11 @@ ui: Bạn gần như đã hoàn tất! Chúng tôi đã gửi một email kích hoạt đến {{mail}}. Vui lòng làm theo hướng dẫn trong email để kích hoạt tài khoản của bạn. info: "Nếu không nhận được, hãy kiểm tra thư mục spam của bạn." another: >- - Chúng tôi đã gửi một email kích hoạt khác cho bạn tại {{mail}}. Có thể mất vài phút để nó đến; hãy chắc chắn kiểm tra thư mục spam của bạn. + Chúng tôi đã gửi một email kích hoạt khác cho bạn tại {{mail}}. Có thể mất vài phút để nó đến; hãy chắc chắn kiểm tra thư mục thư rác của bạn. btn_name: Gửi lại email kích hoạt change_btn_name: Thay đổi email msg: - empty: Không thể trống. + empty: Không thể để trống mục này. resend_email: url_label: Bạn có chắc chắn muốn gửi lại email kích hoạt không? url_text: Bạn cũng có thể cung cấp liên kết kích hoạt ở trên cho người dùng. @@ -1301,7 +1294,7 @@ ui: change_email_info: >- Chúng tôi đã gửi một email đến địa chỉ đó. Vui lòng làm theo hướng dẫn xác nhận. email: - label: Email mới + label: Email new_email: label: Email mới msg: Email mới không được để trống. @@ -1341,6 +1334,10 @@ ui: related_question: title: Các câu hỏi liên quan answers: câu trả lời + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Mời mọi người desc: Mời những người bạn nghĩ có thể trả lời. @@ -1525,7 +1522,7 @@ ui: newest: Mới nhất active: Hoạt động hot: Được nhiều quan tâm - recommend: Recommend + recommend: Đề xuất score: Điểm unanswered: Chưa được trả lời modified: đã chỉnh sửa @@ -1544,7 +1541,7 @@ ui: reputation: Danh tiếng comments: Bình luận votes: Bình chọn - badges: Badges + badges: Danh hiệu newest: Mới nhất score: Điểm edit_profile: Chỉnh sửa hồ sơ @@ -1558,7 +1555,8 @@ ui: top_answers: Câu trả lời hàng đầu top_questions: Câu hỏi hàng đầu stats: Thống kê - list_empty: Không tìm thấy bài đăng.
Có thể bạn muốn chọn một tab khác? + list_empty: Không tìm thấy bài đăng.
Có thể bạn muốn chọn một thẻ khác? + content_empty: No posts found. accepted: Đã chấp nhận answered: đã trả lời asked: đã hỏi @@ -1569,7 +1567,7 @@ ui: x_votes: phiếu bầu nhận được x_answers: câu trả lời x_questions: câu hỏi - recent_badges: Recent Badges + recent_badges: Huy hiệu gần đây install: title: Cài đặt next: Tiếp theo @@ -1646,7 +1644,7 @@ ui: msg: empty: Email không thể trống. incorrect: Định dạng email không chính xác. - ready_title: Answer của bạn đã sẵn sàng + ready_title: Trang web của bạn đã sẵn sàng ready_desc: >- Nếu bạn cảm thấy muốn thay đổi thêm cài đặt nào đó, hãy truy cập <1>mục quản trị; tìm nó trong menu trang. good_luck: "Chúc bạn vui vẻ và may mắn!" @@ -1679,7 +1677,7 @@ ui: questions: Câu hỏi answers: Câu trả lời users: Người dùng - badges: Badges + badges: Huy hiệu flags: Cờ settings: Cài đặt general: Chung @@ -1696,7 +1694,7 @@ ui: css_html: CSS/HTML login: Đăng nhập privileges: Đặc quyền - plugins: Plugin + plugins: Plugins installed_plugins: Plugin đã cài đặt website_welcome: Chào mừng bạn đến với {{site_name}} user_center: @@ -1705,16 +1703,16 @@ ui: login_failed_email_tip: Đăng nhập thất bại, vui lòng cho phép ứng dụng này truy cập thông tin email của bạn trước khi thử lại. badges: modal: - title: Congratulations - content: You've earned a new badge. - close: Close - confirm: View badges - title: Badges - awarded: Awarded - earned_×: Earned ×{{ number }} - ×_awarded: "{{ number }} awarded" - can_earn_multiple: You can earn this multiple times. - earned: Earned + title: Chúc mừng + content: Bạn đã nhận được huy hiệu mới. + close: Đóng + confirm: Xem huy hiệu + title: Huy hiệu + awarded: Giải Thưởng + earned_×: Nhận được ×{{ number }} + ×_awarded: "{{ number }} được trao tặng" + can_earn_multiple: Bạn có thể kiếm được nhiều lần. + earned: Đã nhận admin: admin_header: title: Quản trị @@ -1774,7 +1772,7 @@ ui: flagged_type: Đã đánh dấu {{ type }} created: Đã tạo action: Hành động - review: Xem xét + review: Đánh giá user_role_modal: title: Thay đổi vai trò người dùng thành... btn_cancel: Hủy @@ -2013,7 +2011,7 @@ ui: seo: page_title: SEO permalink: - label: Permalink + label: Liên kết cố định text: Cấu trúc URL tùy chỉnh có thể cải thiện khả năng sử dụng và khả năng tương thích về sau của liên kết của bạn. robots: label: robots.txt @@ -2073,7 +2071,7 @@ ui: text: "CẢNH BÁO: Nếu tắt, bạn có thể không thể đăng nhập nếu bạn chưa cấu hình phương thức đăng nhập khác trước đó." installed_plugins: title: Plugin đã cài đặt - plugin_link: Plugin mở rộng và mở rộng chức năng của Answer. Bạn có thể tìm thấy plugin trong <1>Kho Plugin Answer. + plugin_link: Plugin mở rộng và mở rộng chức năng của trang web. Bạn có thể tìm thấy plugin trong <1>Kho Plugin Answer. filter: all: Tất cả active: Đang hoạt động @@ -2117,23 +2115,24 @@ ui: label: Mức độ danh tiếng yêu cầu text: Chọn mức danh tiếng yêu cầu cho các đặc quyền msg: - should_be_number: dữ liệu đầu vào phải là số + should_be_number: dữ liệu đầu vào phải là kiểu số number_larger_1: số phải bằng hoặc lớn hơn 1 badges: - action: Action - active: Active + action: Hành động + active: Hoạt động + activate: Kích hoạt activate: Activate - all: All - awards: Awards - deactivate: Deactivate + all: Tất cả + awards: Giải Thưởng + deactivate: Ngừng kích hoạt filter: - placeholder: Filter by name, badge:id - group: Group - inactive: Inactive - name: Name - show_logs: Show logs - status: Status - title: Badges + placeholder: Lọc theo tên, user:id + group: Nhóm + inactive: Không hoạt động + name: Tên + show_logs: Hiển thị nhật ký + status: Trạng thái + title: Danh hiệu form: optional: (tùy chọn) empty: không thể trống @@ -2190,7 +2189,7 @@ ui: title: "Lịch sử cho" tag_title: "Dòng thời gian cho" show_votes: "Hiển thị phiếu bầu" - n_or_a: Không có + n_or_a: N/A title_for_question: "Dòng thời gian cho" title_for_answer: "Dòng thời gian cho câu trả lời của {{ title }} bởi {{ author }}" title_for_tag: "Dòng thời gian cho thẻ" diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index f6777d89..3a0d56e8 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -326,9 +326,7 @@ backend: name: other: 粗鲁或辱骂的 desc: - other: - - 一个有理智的人都会认为这种内容不适合进行尊重性的讨论。 - - 论坛 + other: "一个有理智的人都会认为这种内容不适合进行尊重性的讨论。" a_duplicate: name: other: 重复内容 @@ -340,10 +338,7 @@ backend: name: other: 不是答案 desc: - other: - - 这张贴作为答案,但它不会试图回答 - - 这可能是一个编辑、一个评论、另一个问题。 - - 或全部删除。 + other: "该帖是作为答案发布的,但它并没有试图回答这个问题。总之,它可能应该是个编辑、评论、另一个问题或者需要被删除。" no_longer_needed: name: other: 不再需要 @@ -402,9 +397,7 @@ backend: name: other: 需要细节或澄清 desc: - other: - - 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - - 只关注一个问题。 + other: 该问题目前涵盖多个问题。它应该只集中在一个问题上。 other: name: other: 其他原因 @@ -688,7 +681,7 @@ backend: name: other: 欣赏 desc: - other: 20个员额获得1次补票。 + other: 在 20 个帖子中获得 1个投票 respected: name: other: 尊敬 @@ -1185,7 +1178,7 @@ ui: label: 名字 msg: empty: 名字不能为空 - range: 名字应该在 2 到 30 个字符之间 + range: 名称长度必须在 2 至 30 个字符之间。 character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' email: label: 邮箱 @@ -1342,8 +1335,9 @@ ui: title: 相关问题 answers: 个回答 linked_question: - title: 关联问题 - no_linked_question: 没有关联的问题。 + title: 关联的问题 + description: 问题关联到 + no_linked_question: 这个问题没有相关联的问题。 invite_to_answer: title: 受邀人 desc: 邀请你认为可能知道答案的人。 diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index 32938f4d..bec0a0b3 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: 需要細節或明晰 desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: 其他原因 @@ -794,7 +787,7 @@ ui: how_to_format: title: 如何設定文本格式 desc: >- -
  • 加入連結:

    <https://url.com>

    [Title](https://url.com)
  • 段落之間使用回车

  • _斜體_ 或者 **粗體**

  • 使用 4 個空格縮排代碼

  • 在行首加入>表示引用

  • 反引號進行轉義 `像 _這樣_`

  • 使用反引號創建代碼柵欄`

    ```
    這是程式碼
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: 上一頁 next: 下一頁 @@ -1341,6 +1334,10 @@ ui: related_question: title: 相關問題 answers: 個回答 + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Invite people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: 熱門問題 stats: 狀態 list_empty: 沒有找到相關的內容。
試試看其他標籤? + content_empty: No posts found. accepted: 已採納 answered: 回答於 asked: 提問於 From 76fe2187fcb58827f580a7dc67201b8864f22c64 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:36:53 +0800 Subject: [PATCH 281/336] # Conflicts: # i18n/da_DK.yaml # i18n/de_DE.yaml # i18n/es_ES.yaml # i18n/fa_IR.yaml # i18n/fr_FR.yaml # i18n/it_IT.yaml # i18n/ko_KR.yaml # i18n/pl_PL.yaml # i18n/pt_PT.yaml # i18n/ro_RO.yaml # i18n/ru_RU.yaml # i18n/sv_SE.yaml # i18n/uk_UA.yaml # i18n/vi_VN.yaml # i18n/zh_CN.yaml --- i18n/cs_CZ.yaml | 20 +- i18n/cy_GB.yaml | 20 +- i18n/da_DK.yaml | 20 +- i18n/de_DE.yaml | 30 +- i18n/es_ES.yaml | 20 +- i18n/fa_IR.yaml | 20 +- i18n/fr_FR.yaml | 20 +- i18n/hi_IN.yaml | 20 +- i18n/id_ID.yaml | 20 +- i18n/it_IT.yaml | 170 ++-- i18n/ja_JP.yaml | 20 +- i18n/ko_KR.yaml | 22 +- i18n/ml_IN.yaml | 2221 +++++++++++++++++++++++++++++++++++++++++++++++ i18n/pl_PL.yaml | 68 +- i18n/pt_PT.yaml | 617 +++++++------ i18n/ro_RO.yaml | 20 +- i18n/ru_RU.yaml | 20 +- i18n/sk_SK.yaml | 20 +- i18n/sv_SE.yaml | 43 +- i18n/te_IN.yaml | 20 +- i18n/tr_TR.yaml | 36 +- i18n/uk_UA.yaml | 188 ++-- i18n/vi_VN.yaml | 331 ++++--- i18n/zh_CN.yaml | 22 +- i18n/zh_TW.yaml | 20 +- 25 files changed, 3100 insertions(+), 928 deletions(-) create mode 100644 i18n/ml_IN.yaml diff --git a/i18n/cs_CZ.yaml b/i18n/cs_CZ.yaml index 0a54c51a..65438419 100644 --- a/i18n/cs_CZ.yaml +++ b/i18n/cs_CZ.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prev next: Next @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/cy_GB.yaml b/i18n/cy_GB.yaml index c3b3b55a..af605269 100644 --- a/i18n/cy_GB.yaml +++ b/i18n/cy_GB.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: angen manylion neu eglurder desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: rhywbeth arall @@ -794,7 +787,7 @@ ui: how_to_format: title: Sut i Fformatio desc: >- -
  • i wneud cysylltiadau

    <https://url.com>

    [Title]( https://url.com)
  • rhoi dychweliadau rhwng paragraffau

  • _italic_ neu **beiddgar**

  • cod mewnoliad gan 4 bwlch

  • dyfyniad drwy osod > ar ddechrau'r llinell

  • backtick yn dianc o `like _this_`

  • creu ffensys cod gyda thic wrth gefn `

    ```
    cod yma
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Cynt next: Nesaf @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/da_DK.yaml b/i18n/da_DK.yaml index d707d355..bd19779f 100644 --- a/i18n/da_DK.yaml +++ b/i18n/da_DK.yaml @@ -326,9 +326,7 @@ backend: name: other: uhøflig eller misbrug desc: - other: - - En fornuftig person ville finde dette indhold upassende eller ikke respektfuldt - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: en duplikering @@ -340,10 +338,7 @@ backend: name: other: ikke et svar desc: - other: - - Dette blev sendt som svar, men det forsøger ikke at besvare - - spørgsmål. Det bør muligvis være en redigering, en kommentar, et andet spørgsmål - - eller slettet helt. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: ikke længere nødvendigt @@ -402,9 +397,7 @@ backend: name: other: kræver detaljer eller klarhed desc: - other: - - Dette spørgsmål indeholder i øjeblikket flere spørgsmål i et. Det bør - - fokusere på kun ét problem. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: noget andet @@ -794,7 +787,7 @@ ui: how_to_format: title: Sådan formaterer du desc: >- -
  • for at lave links

    <https://url.com>

    [Titel](https://url.com)
  • indsæt linieskift mellem paragraffer

  • _kursiv_ or **fed**

  • indskyd kode med 4 mellemrum

  • citér ved at placere > på starten af linie

  • backtick escapes `som _dette_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Forrige next: Næste @@ -1341,6 +1334,10 @@ ui: related_question: title: Relaterede spørgsmål answers: svar + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Inviter personer desc: Invitér personer, som du tror, kan svare. @@ -1559,6 +1556,7 @@ ui: top_questions: Populære Spørgsmål stats: Statistik list_empty: Ingen indlæg fundet.
Måske vil du vælge en anden fane? + content_empty: No posts found. accepted: Accepteret answered: besvaret asked: spurgt diff --git a/i18n/de_DE.yaml b/i18n/de_DE.yaml index d780b438..9eee7c03 100644 --- a/i18n/de_DE.yaml +++ b/i18n/de_DE.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Ungültige URL. status_invalid: - other: Invalid status. + other: Ungültiger Status. password: space_invalid: other: Passwort darf keine Leerzeichen enthalten. @@ -326,9 +326,7 @@ backend: name: other: unhöflich oder beleidigend desc: - other: - - Eine vernünftige Person würde diesen Inhalt als unangemessen für einen respektvollen - - Umgang empfinden + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: ein Duplikat @@ -340,10 +338,7 @@ backend: name: other: keine Antwort desc: - other: - - Dies wurde als Antwort gepostet, aber es wird nicht versucht, die - - Frage zu beantworten. Es sollte vielleicht eine Bearbeitung, ein Kommentar oder eine andere Frage sein, - - oder ganz gelöscht. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: nicht mehr benötigt @@ -402,9 +397,7 @@ backend: name: other: benötigt Details oder Klarheit desc: - other: - - Diese Frage enthält derzeit mehrere Fragen in einer. Sie sollte - - auf ein einziges Problem konzentrieren. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: etwas anderes @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: hat dich eingeladen, zu antworten earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Du hast das "{{.BadgeName}}" Abzeichen verdient email_tpl: change_email: title: @@ -536,12 +529,12 @@ backend: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiograph desc: other: Filled out profile information. certified: name: - other: Certified + other: Zertifiziert desc: other: Completed our new user tutorial. editor: @@ -794,7 +787,7 @@ ui: how_to_format: title: Wie man formatiert desc: >- -
  • um Links

    <https://url.com>

    [Titel](https://url.com)
  • Zwischen den Absätzen Zeilenumbrüche einfügen

  • _italic_ oder **fett**

  • Code um 4 Leerzeichen einrücken

  • Zitat durch Setzen von > am Anfang der Zeile

  • Backtick-Escapes `wie _this_`

  • Codeumrandungen mit Backticks `

    `
    Code hier
    ``
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Zurück next: Weiter @@ -1341,6 +1334,10 @@ ui: related_question: title: Verwandte Fragen answers: antworten + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Frage jemanden desc: Lade Leute ein, von denen du glaubst, dass sie die Antwort wissen könnten. @@ -1559,6 +1556,7 @@ ui: top_questions: Top-Fragen stats: Statistiken list_empty: Keine Beiträge gefunden.
Vielleicht möchtest du einen anderen Reiter auswählen? + content_empty: No posts found. accepted: Akzeptiert answered: antwortete asked: gefragt @@ -2205,7 +2203,7 @@ ui: users_with_the_most_vote: Benutzer, die diese Woche am meisten gestimmt haben staffs: Unsere Community Teammitglieder reputation: Ansehen - votes: stimmen + votes: Stimmen prompt: leave_page: Bist du sicher, dass du die Seite verlassen willst? changes_not_save: Deine Änderungen werden möglicherweise nicht gespeichert. diff --git a/i18n/es_ES.yaml b/i18n/es_ES.yaml index ff3853d1..561b461d 100644 --- a/i18n/es_ES.yaml +++ b/i18n/es_ES.yaml @@ -326,9 +326,7 @@ backend: name: other: grosero u ofensivo desc: - other: - - Una persona razonable consideraría este contenido como inapropiado - - discurso. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: un duplicado @@ -340,10 +338,7 @@ backend: name: other: no es una respuesta desc: - other: - - Esto fue publicado como respuesta, pero no responde la - - pregunta. Podría ser una edición, un comentario, otra pregunta, - - o borrado por completo. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: ya no es necesario @@ -402,9 +397,7 @@ backend: name: other: necesita más detalles o aclaraciónes desc: - other: - - Esta pregunta actualmente incluye múltiples preguntas en una. Debería - - centrarse en un problema solamente. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: otra razón @@ -794,7 +787,7 @@ ui: how_to_format: title: Cómo formatear desc: >- -
  • Para hacer enlaces

     <https://url.com>

    [Title](https://url.com)
  • Colocar saltos de línea entre párrafos

  • _cursiva_ o **negrita**

  • Indentar el código con 4 espacios

  • Citar colocando > al inicio de la línea

  • Escape con backticks `como _esto_`

  • Crear barreras de código con backticks `

      ```
    código aquí
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Anterior next: Siguiente @@ -1341,6 +1334,10 @@ ui: related_question: title: Preguntas relacionadas answers: respuestas + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Personas Preguntadas desc: Selecciona personas que creas que sepan la respuesta. @@ -1559,6 +1556,7 @@ ui: top_questions: Preguntas Principales stats: Estadísticas list_empty: No se encontraron publicaciones.
¿Quizás le gustaría seleccionar una pestaña diferente? + content_empty: No posts found. accepted: Aceptada answered: respondida asked: preguntó diff --git a/i18n/fa_IR.yaml b/i18n/fa_IR.yaml index 274b97d5..55cc9805 100644 --- a/i18n/fa_IR.yaml +++ b/i18n/fa_IR.yaml @@ -326,9 +326,7 @@ backend: name: other: بی ادب یا توهین آمیز desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: تکراری @@ -340,10 +338,7 @@ backend: name: other: این یک پاسخ نیست desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: دیگر نیازی نیست @@ -402,9 +397,7 @@ backend: name: other: نیاز به جزئیات یا واضح کردن دارد desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: یک مورد دیگر @@ -794,7 +787,7 @@ ui: how_to_format: title: نحوه فرمت کردن desc: >- -
  • برای ایجاد پیوند

    <https://url.com>

    [Title](https://url.com)
  • بین پاراگراف ها اینتر قرار بدهید

  • _italic_ یا **پررنگ**

  • کد تورفتگی با 4 فاصله

  • نقل قول با قرار دادن >< /code> در ابتدای خط

  • بکتیک فرار می کند `مانند _this_`

  • < li>

    حصارهای کد با بکتیک ایجاد کنید `

    ```
    کد اینجا
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: قبلی next: بعدی @@ -1341,6 +1334,10 @@ ui: related_question: title: سوالات مرتبط answers: جواب ها + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: مردم پرسیدند desc: افرادی را دعوت کنید که فکر می کنید ممکن است پاسخ را بدانند. @@ -1559,6 +1556,7 @@ ui: top_questions: سوالات برتر stats: آمار list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: پذیرفته شده answered: جواب داده asked: پرسیده شده diff --git a/i18n/fr_FR.yaml b/i18n/fr_FR.yaml index c7bf5fce..52ad1375 100644 --- a/i18n/fr_FR.yaml +++ b/i18n/fr_FR.yaml @@ -326,9 +326,7 @@ backend: name: other: grossier ou abusif desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: un doublon @@ -340,10 +338,7 @@ backend: name: other: n'est pas une réponse desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: ce n’est plus nécessaire @@ -402,9 +397,7 @@ backend: name: other: a besoin de détails ou de clarté desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: quelque chose d'autre @@ -794,7 +787,7 @@ ui: how_to_format: title: Comment mettre en forme desc: >- -
  • Pour faire des liens

    <https://url.com>

    [Title](https://url.com)
  • mettre des retour entre les paragraphes

  • _italic_ or **gras**

  • indenter le code par 4 espaces

  • citation en plaçant > au début de la ligne

  • guillemets inversés `comme_ca_`

  • créer une banière de code avec les guillemets inversés `

    ```
    code ici
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Préc next: Suivant @@ -1341,6 +1334,10 @@ ui: related_question: title: Questions liées answers: réponses + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Personnes interrogées desc: Invite people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Questions les plus populaires stats: Statistiques list_empty: Aucune publication trouvée.
Peut-être souhaiteriez-vous sélectionner un autre onglet ? + content_empty: No posts found. accepted: Accepté answered: a répondu asked: a demandé diff --git a/i18n/hi_IN.yaml b/i18n/hi_IN.yaml index 78a23394..8a9da4d5 100644 --- a/i18n/hi_IN.yaml +++ b/i18n/hi_IN.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prev next: Next @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/id_ID.yaml b/i18n/id_ID.yaml index 11da0521..bf8e827d 100644 --- a/i18n/id_ID.yaml +++ b/i18n/id_ID.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: membutuhkan detail atau kejelasan desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: lainnya @@ -794,7 +787,7 @@ ui: how_to_format: title: Cara memformat desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Sebelumnya next: Selanjutnya @@ -1341,6 +1334,10 @@ ui: related_question: title: Pertanyaan Terkait answers: jawaban + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Pertanyaan terpopuler stats: Statistik list_empty: Postingan tidak ditemukan.
Mungkin Anda ingin memilih tab lain? + content_empty: No posts found. accepted: Diterima answered: dijawab asked: ditanyakan diff --git a/i18n/it_IT.yaml b/i18n/it_IT.yaml index 1c9f8a85..3cc90171 100644 --- a/i18n/it_IT.yaml +++ b/i18n/it_IT.yaml @@ -138,7 +138,7 @@ backend: pass: other: Password original_text: - other: This post + other: Questo post email_or_password_wrong_error: other: Email o password errati. error: @@ -146,7 +146,7 @@ backend: invalid_url: other: URL non valido. status_invalid: - other: Invalid status. + other: Status non valido. password: space_invalid: other: La password non può contenere spazi. @@ -154,7 +154,7 @@ backend: cannot_update_their_password: other: Non è possibile modificare la password. cannot_edit_their_profile: - other: You cannot modify your profile. + other: Non è possibile modificare il profilo. cannot_modify_self_status: other: Non è possibile modificare il tuo status. email_or_password_wrong: @@ -207,10 +207,10 @@ backend: new_password_same_as_previous_setting: other: La nuova password è identica alla precedente already_deleted: - other: This post has been deleted. + other: Questo post è stato eliminato. meta: object_not_found: - other: Meta object not found + other: Meta oggetto non trovato question: already_deleted: other: Questo post è stato eliminato. @@ -315,7 +315,7 @@ backend: other: Configurazione del sito non trovata. badge: object_not_found: - other: Badge object not found + other: Oggetto badge non trovato reason: spam: name: @@ -326,9 +326,7 @@ backend: name: other: scortese o offensivo desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: duplicato @@ -340,10 +338,7 @@ backend: name: other: Non è una risposta desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: Non più necessario @@ -402,9 +397,7 @@ backend: name: other: richiede maggiori dettagli o chiarezza desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: altro @@ -420,12 +413,12 @@ backend: deleted_title: other: "\nDomanda cancellata" questions_title: - other: Questions + other: Domande tag: tags_title: other: Tags no_description: - other: The tag has no description. + other: Il tag non ha descrizioni. notification: action: update_question: @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: sei invitato a rispondere earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Hai ottenuto il badge "{{.BadgeName}}" email_tpl: change_email: title: @@ -531,89 +524,89 @@ backend: other: Modifiche suggerite reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} e {{ .Count }} più..." badge: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiografo desc: - other: Filled out profile information. + other: Informazioni sul profilo completate. certified: name: - other: Certified + other: Certificato desc: - other: Completed our new user tutorial. + other: "\nCompletato il nostro nuovo tutorial per l'utente." editor: name: other: Editor desc: - other: First post edit. + other: Prima modifica al post. first_flag: name: - other: First Flag + other: Primo Contrassegno desc: - other: First flagged a post. + other: Primo contrassegno di un post. first_upvote: name: - other: First Upvote + other: Primo Mi Piace desc: - other: First up voted a post. + other: Primo Mi Piace a un post first_link: name: - other: First Link + other: Primo Link desc: - other: First dirst added a link to another post. + other: Aggiunto un link a un altro post per la prima volta first_reaction: name: - other: First Reaction + other: Prima Reazione desc: - other: First reacted to the post. + other: Prima reazione al post. first_share: name: - other: First Share + other: Prima Condivisione desc: - other: First shared a post. + other: Prima condivisione a un post. scholar: name: - other: Scholar + other: Studioso desc: - other: Asked a question and accepted an answer. + other: Ha posto una domanda e ha accettato una risposta commentator: name: - other: Commentator + other: Commentatore desc: - other: Leave 5 comments. + other: Lascia 5 commenti. new_user_of_the_month: name: - other: New User of the Month + other: Nuovo Utente del Mese desc: - other: Outstanding contributions in their first month. + other: Contributi straordinari nel primo mese. read_guidelines: name: - other: Read Guidelines + other: Leggi le Linee Guida desc: - other: Read the [community guidelines]. + other: Leggi le [linee guida della community]. reader: name: - other: Reader + other: Lettore desc: - other: Read every answers in a topic with more than 10 answers. + other: Leggi ogni risposta in un argomento con più di 10 risposte. welcome: name: - other: Welcome + other: Benvenuto desc: - other: Received a up vote. + other: Ricevuto un voto positivo. nice_share: name: - other: Nice Share + other: Condivisione positiva. desc: - other: Shared a post with 25 unique visitors. + other: Ha condiviso un post con 25 visitatori unici. good_share: name: - other: Good Share + other: Condivisione positiva. desc: - other: Shared a post with 300 unique visitors. + other: Condiviso un post con 300 visitatori unici. great_share: name: other: Great Share @@ -741,60 +734,60 @@ backend: other: Question score of 10 or more. good_question: name: - other: Good Question + other: Buona domanda desc: - other: Question score of 25 or more. + other: Punteggio della domanda di 25 o più great_question: name: - other: Great Question + other: Ottima domanda desc: - other: Question score of 50 or more. + other: Punteggio domande pari o superiore a 50. popular_question: name: - other: Popular Question + other: Domanda popolare desc: - other: Question with 500 views. + other: "Domanda con 500 visualizzazioni\n" notable_question: name: - other: Notable Question + other: Domanda notevole desc: - other: Question with 1,000 views. + other: Domanda con 1.000 visualizzazioni. famous_question: name: - other: Famous Question + other: Domanda celebre desc: - other: Question with 5,000 views. + other: "Domanda con 5.000 visualizzazioni.\n." popular_link: name: - other: Popular Link + other: Link Popolare desc: - other: Posted an external link with 50 clicks. + other: Pubblicato un link esterno con 50 clic. hot_link: name: - other: Hot Link + other: Link popolare desc: - other: Posted an external link with 300 clicks. + other: Pubblicato un link esterno con 300 clic. famous_link: name: - other: Famous Link + other: Link celebre desc: - other: Posted an external link with 100 clicks. + other: Pubblicato un link esterno con 100 clic. default_badge_groups: getting_started: name: - other: Getting Started + other: Primi passi community: name: other: Community posting: name: - other: Posting + other: Pubblicazione in corso # The following fields are used for interface presentation(Front-end) ui: how_to_format: title: Come formattare desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url. om)
  • mette i rendimenti tra i paragrafi

  • _italic_ o **grassetto**

  • trattino di codice per 4 spazi

  • preventivo inserendo > all'inizio della riga

  • backtick escapes `like _this_`

  • crea recinzioni di codice con backticks `

    ````
    codice qui
    `````
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prec next: Successivo @@ -843,9 +836,9 @@ ui: posts: Messaggi invites: Inviti votes: Voti - answer: Answer - question: Question - badge_award: Badge + answer: Risposta + question: Domanda + badge_award: Distintivo suspended: title: Il tuo account è stato sospeso until_time: "Il tuo account è stato sospeso fino a {{ time }}." @@ -1017,9 +1010,9 @@ ui: delete: title: Elimina questo tag tip_with_posts: >- -

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+

Non è consentita l'eliminazione di tag con post.

Rimuovi prima questo tag dai post.

tip_with_synonyms: >- -

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+

Non è consentita l'eliminazione di tag con sinonimi.

Per favore, rimuovi prima i sinonimi da questo tag.

tip: Sei sicuro di voler cancellare? close: Chiudi edit_tag: @@ -1041,13 +1034,13 @@ ui: hours: ore days: giorni reaction: - heart: heart - smile: smile - frown: frown - btn_label: add or remove reactions - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} - unreact_emoji: unreact with {{ emoji }} + heart: cuore + smile: sorriso + frown: disapprovare + btn_label: aggiungere o rimuovere le reazioni + undo_emoji: annulla reazione {{ emoji }} + react_emoji: reagire con {{ emoji }} + unreact_emoji: non reagire con {{ emoji }} comment: btn_add_comment: Aggiungi un commento reply_to: Rispondi a @@ -1186,7 +1179,7 @@ ui: msg: empty: Il nome non può essere vuoto. range: Name must be between 2 to 30 characters in length. - character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + character: 'È necessario utilizzare il set di caratteri "a-z", "0-9", " - . _"' email: label: E-mail msg: @@ -1341,6 +1334,10 @@ ui: related_question: title: Domande correlate answers: risposte + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Persone Interpellate desc: Seleziona le persone che pensi potrebbero conoscere la risposta. @@ -1502,7 +1499,7 @@ ui: success: Il tuo nuovo account è confermato; sarai reindirizzato alla home page. link: Continua alla Homepage oops: Oops! - invalid: The link you used no longer works. + invalid: Il link che hai usato non è più attivo. confirm_new_email: La tua email è stata aggiornata. confirm_new_email_invalid: >- Siamo spiacenti, questo link di conferma non è più valido. Forse la tua email è già stata modificata? @@ -1524,8 +1521,8 @@ ui: answers: Risposte newest: Più recenti active: Attivo - hot: Hot - recommend: Recommend + hot: Caldo + recommend: Raccomandato score: Punteggio unanswered: Senza risposta modified: Modificato @@ -1559,6 +1556,7 @@ ui: top_questions: Domande principali stats: Statistiche list_empty: Nessun post trovato.
Forse desideri selezionare una scheda diversa? + content_empty: No posts found. accepted: Accettato answered: risposto asked: chiesto diff --git a/i18n/ja_JP.yaml b/i18n/ja_JP.yaml index 887ba790..433831f4 100644 --- a/i18n/ja_JP.yaml +++ b/i18n/ja_JP.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: 前へ next: 次へ @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: 質問済み diff --git a/i18n/ko_KR.yaml b/i18n/ko_KR.yaml index fba3d7d9..53b413f3 100644 --- a/i18n/ko_KR.yaml +++ b/i18n/ko_KR.yaml @@ -326,9 +326,7 @@ backend: name: other: 폭언 또는 무례한 언행입니다. desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: 중복 @@ -340,10 +338,7 @@ backend: name: other: 답변이 아닙니다 desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: 더 이상 필요하지 않습니다. @@ -402,9 +397,7 @@ backend: name: other: 세부사항 또는 명확성이 필요합니다. desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: 다른 이유 @@ -794,7 +787,7 @@ ui: how_to_format: title: 포맷 방법 desc: >- -
  • 링크 만들기

    <https://url.com>

    [Title](https://url.com)
  • 단락 사이에 줄 바꿈 넣기

  • _이탤릭체_ 또는 **볼드체**

  • 코드는 4칸 들여쓰기

  • 인용은 >로 시작하기

  • 백틱으로 이스케이프 `이렇게_사용`

  • 백틱으로 코드 펜스 만들기 `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: 이전 next: 다음 @@ -1185,7 +1178,7 @@ ui: label: 이름 msg: empty: 이름을 입력하세요. - range: 이름은 최대 30자까지 입력 가능합니다. + range: Name must be between 2 to 30 characters in length. character: '문자 집합 "a-z", "0-9", " - . _"를 사용해야 합니다' email: label: 이메일 @@ -1341,6 +1334,10 @@ ui: related_question: title: 관련 질문 answers: 답변 + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: 질문자 초대 desc: 답변을 알고 있을 것으로 생각되는 사람을 선택하세요. @@ -1559,6 +1556,7 @@ ui: top_questions: 최고 질문 stats: 통계 list_empty: 게시물을 찾을 수 없습니다.
다른 탭을 선택하실 수 있습니다. + content_empty: No posts found. accepted: 채택됨 answered: 답변됨 asked: 질문됨 diff --git a/i18n/ml_IN.yaml b/i18n/ml_IN.yaml new file mode 100644 index 00000000..c2d2af8f --- /dev/null +++ b/i18n/ml_IN.yaml @@ -0,0 +1,2221 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# The following fields are used for back-end +backend: + base: + success: + other: Success. + unknown: + other: Unknown error. + request_format_error: + other: Request format is not valid. + unauthorized_error: + other: Unauthorized. + database_error: + other: Data server error. + forbidden_error: + other: Forbidden. + duplicate_request_error: + other: Duplicate submission. + action: + report: + other: Flag + edit: + other: Edit + delete: + other: Delete + close: + other: Close + reopen: + other: Reopen + forbidden_error: + other: Forbidden. + pin: + other: Pin + hide: + other: Unlist + unpin: + other: Unpin + show: + other: List + invite_someone_to_answer: + other: Edit + undelete: + other: Undelete + role: + name: + user: + other: User + admin: + other: Admin + moderator: + other: Moderator + description: + user: + other: Default with no special access. + admin: + other: Have the full power to access the site. + moderator: + other: Has access to all posts except admin settings. + privilege: + level_1: + description: + other: Level 1 (less reputation required for private team, group) + level_2: + description: + other: Level 2 (low reputation required for startup community) + level_3: + description: + other: Level 3 (high reputation required for mature community) + level_custom: + description: + other: Custom Level + rank_question_add_label: + other: Ask question + rank_answer_add_label: + other: Write answer + rank_comment_add_label: + other: Write comment + rank_report_add_label: + other: Flag + rank_comment_vote_up_label: + other: Upvote comment + rank_link_url_limit_label: + other: Post more than 2 links at a time + rank_question_vote_up_label: + other: Upvote question + rank_answer_vote_up_label: + other: Upvote answer + rank_question_vote_down_label: + other: Downvote question + rank_answer_vote_down_label: + other: Downvote answer + rank_invite_someone_to_answer_label: + other: Invite someone to answer + rank_tag_add_label: + other: Create new tag + rank_tag_edit_label: + other: Edit tag description (need to review) + rank_question_edit_label: + other: Edit other's question (need to review) + rank_answer_edit_label: + other: Edit other's answer (need to review) + rank_question_edit_without_review_label: + other: Edit other's question without review + rank_answer_edit_without_review_label: + other: Edit other's answer without review + rank_question_audit_label: + other: Review question edits + rank_answer_audit_label: + other: Review answer edits + rank_tag_audit_label: + other: Review tag edits + rank_tag_edit_without_review_label: + other: Edit tag description without review + rank_tag_synonym_label: + other: Manage tag synonyms + email: + other: Email + e_mail: + other: Email + password: + other: Password + pass: + other: Password + original_text: + other: This post + email_or_password_wrong_error: + other: Email and password do not match. + error: + common: + invalid_url: + other: Invalid URL. + status_invalid: + other: Invalid status. + password: + space_invalid: + other: Password cannot contain spaces. + admin: + cannot_update_their_password: + other: You cannot modify your password. + cannot_edit_their_profile: + other: You cannot modify your profile. + cannot_modify_self_status: + other: You cannot modify your status. + email_or_password_wrong: + other: Email and password do not match. + answer: + not_found: + other: Answer do not found. + cannot_deleted: + other: No permission to delete. + cannot_update: + other: No permission to update. + question_closed_cannot_add: + other: Questions are closed and cannot be added. + comment: + edit_without_permission: + other: Comment are not allowed to edit. + not_found: + other: Comment not found. + cannot_edit_after_deadline: + other: The comment time has been too long to modify. + email: + duplicate: + other: Email already exists. + need_to_be_verified: + other: Email should be verified. + verify_url_expired: + other: Email verified URL has expired, please resend the email. + illegal_email_domain_error: + other: Email is not allowed from that email domain. Please use another one. + lang: + not_found: + other: Language file not found. + object: + captcha_verification_failed: + other: Captcha wrong. + disallow_follow: + other: You are not allowed to follow. + disallow_vote: + other: You are not allowed to vote. + disallow_vote_your_self: + other: You can't vote for your own post. + not_found: + other: Object not found. + verification_failed: + other: Verification failed. + email_or_password_incorrect: + other: Email and password do not match. + old_password_verification_failed: + other: The old password verification failed + new_password_same_as_previous_setting: + other: The new password is the same as the previous one. + already_deleted: + other: This post has been deleted. + meta: + object_not_found: + other: Meta object not found + question: + already_deleted: + other: This post has been deleted. + under_review: + other: Your post is awaiting review. It will be visible after it has been approved. + not_found: + other: Question not found. + cannot_deleted: + other: No permission to delete. + cannot_close: + other: No permission to close. + cannot_update: + other: No permission to update. + rank: + fail_to_meet_the_condition: + other: Reputation rank fail to meet the condition. + vote_fail_to_meet_the_condition: + other: Thanks for the feedback. You need at least {{.Rank}} reputation to cast a vote. + no_enough_rank_to_operate: + other: You need at least {{.Rank}} reputation to do this. + report: + handle_failed: + other: Report handle failed. + not_found: + other: Report not found. + tag: + already_exist: + other: Tag already exists. + not_found: + other: Tag not found. + recommend_tag_not_found: + other: Recommend tag is not exist. + recommend_tag_enter: + other: Please enter at least one required tag. + not_contain_synonym_tags: + other: Should not contain synonym tags. + cannot_update: + other: No permission to update. + is_used_cannot_delete: + other: You cannot delete a tag that is in use. + cannot_set_synonym_as_itself: + other: You cannot set the synonym of the current tag as itself. + smtp: + config_from_name_cannot_be_email: + other: The from name cannot be a email address. + theme: + not_found: + other: Theme not found. + revision: + review_underway: + other: Can't edit currently, there is a version in the review queue. + no_permission: + other: No permission to revise. + user: + external_login_missing_user_id: + other: The third-party platform does not provide a unique UserID, so you cannot login, please contact the website administrator. + external_login_unbinding_forbidden: + other: Please set a login password for your account before you remove this login. + email_or_password_wrong: + other: + other: Email and password do not match. + not_found: + other: User not found. + suspended: + other: User has been suspended. + username_invalid: + other: Username is invalid. + username_duplicate: + other: Username is already in use. + set_avatar: + other: Avatar set failed. + cannot_update_your_role: + other: You cannot modify your role. + not_allowed_registration: + other: Currently the site is not open for registration. + not_allowed_login_via_password: + other: Currently the site is not allowed to login via password. + access_denied: + other: Access denied + page_access_denied: + other: You do not have access to this page. + add_bulk_users_format_error: + other: "Error {{.Field}} format near '{{.Content}}' at line {{.Line}}. {{.ExtraMessage}}" + add_bulk_users_amount_error: + other: "The number of users you add at once should be in the range of 1-{{.MaxAmount}}." + config: + read_config_failed: + other: Read config failed + database: + connection_failed: + other: Database connection failed + create_table_failed: + other: Create table failed + install: + create_config_failed: + other: Can't create the config.yaml file. + upload: + unsupported_file_format: + other: Unsupported file format. + site_info: + config_not_found: + other: Site config not found. + badge: + object_not_found: + other: Badge object not found + reason: + spam: + name: + other: spam + desc: + other: This post is an advertisement, or vandalism. It is not useful or relevant to the current topic. + rude_or_abusive: + name: + other: rude or abusive + desc: + other: "A reasonable person would find this content inappropriate for respectful discourse." + a_duplicate: + name: + other: a duplicate + desc: + other: This question has been asked before and already has an answer. + placeholder: + other: Enter the existing question link + not_a_answer: + name: + other: not an answer + desc: + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." + no_longer_needed: + name: + other: no longer needed + desc: + other: This comment is outdated, conversational or not relevant to this post. + something: + name: + other: something else + desc: + other: This post requires staff attention for another reason not listed above. + placeholder: + other: Let us know specifically what you are concerned about + community_specific: + name: + other: a community-specific reason + desc: + other: This question doesn't meet a community guideline. + not_clarity: + name: + other: needs details or clarity + desc: + other: This question currently includes multiple questions in one. It should focus on one problem only. + looks_ok: + name: + other: looks OK + desc: + other: This post is good as-is and not low quality. + needs_edit: + name: + other: needs edit, and I did it + desc: + other: Improve and correct problems with this post yourself. + needs_close: + name: + other: needs close + desc: + other: A closed question can't answer, but still can edit, vote and comment. + needs_delete: + name: + other: needs delete + desc: + other: This post will be deleted. + question: + close: + duplicate: + name: + other: spam + desc: + other: This question has been asked before and already has an answer. + guideline: + name: + other: a community-specific reason + desc: + other: This question doesn't meet a community guideline. + multiple: + name: + other: needs details or clarity + desc: + other: This question currently includes multiple questions in one. It should focus on one problem only. + other: + name: + other: something else + desc: + other: This post requires another reason not listed above. + operation_type: + asked: + other: asked + answered: + other: answered + modified: + other: modified + deleted_title: + other: Deleted question + questions_title: + other: Questions + tag: + tags_title: + other: Tags + no_description: + other: The tag has no description. + notification: + action: + update_question: + other: updated question + answer_the_question: + other: answered question + update_answer: + other: updated answer + accept_answer: + other: accepted answer + comment_question: + other: commented question + comment_answer: + other: commented answer + reply_to_you: + other: replied to you + mention_you: + other: mentioned you + your_question_is_closed: + other: Your question has been closed + your_question_was_deleted: + other: Your question has been deleted + your_answer_was_deleted: + other: Your answer has been deleted + your_comment_was_deleted: + other: Your comment has been deleted + up_voted_question: + other: upvoted question + down_voted_question: + other: downvoted question + up_voted_answer: + other: upvoted answer + down_voted_answer: + other: downvoted answer + up_voted_comment: + other: upvoted comment + invited_you_to_answer: + other: invited you to answer + earned_badge: + other: You've earned the "{{.BadgeName}}" badge + email_tpl: + change_email: + title: + other: "[{{.SiteName}}] Confirm your new email address" + body: + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
\n{{.ChangeEmailUrl}}

\n\nIf you did not request this change, please ignore this email.\n" + new_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} answered your question" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + invited_you_to_answer: + title: + other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
I think you may know the answer.

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + new_comment: + title: + other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" + body: + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + new_question: + title: + other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" + body: + other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\nUnsubscribe" + pass_reset: + title: + other: "[{{.SiteName }}] Password reset" + body: + other: "Somebody asked to reset your password on {{.SiteName}}.

\n\nIf it was not you, you can safely ignore this email.

\n\nClick the following link to choose a new password:
\n{{.PassResetUrl}}\n" + register: + title: + other: "[{{.SiteName}}] Confirm your new account" + body: + other: "Welcome to {{.SiteName}}!

\n\nClick the following link to confirm and activate your new account:
\n{{.RegisterUrl}}

\n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + test: + title: + other: "[{{.SiteName}}] Test Email" + body: + other: "This is a test email." + action_activity_type: + upvote: + other: upvote + upvoted: + other: upvoted + downvote: + other: downvote + downvoted: + other: downvoted + accept: + other: accept + accepted: + other: accepted + edit: + other: edit + review: + queued_post: + other: Queued post + flagged_post: + other: Flagged post + suggested_post_edit: + other: Suggested edits + reaction: + tooltip: + other: "{{ .Names }} and {{ .Count }} more..." + badge: + default_badges: + autobiographer: + name: + other: Autobiographer + desc: + other: Filled out profile information. + certified: + name: + other: Certified + desc: + other: Completed our new user tutorial. + editor: + name: + other: Editor + desc: + other: First post edit. + first_flag: + name: + other: First Flag + desc: + other: First flagged a post. + first_upvote: + name: + other: First Upvote + desc: + other: First up voted a post. + first_link: + name: + other: First Link + desc: + other: First dirst added a link to another post. + first_reaction: + name: + other: First Reaction + desc: + other: First reacted to the post. + first_share: + name: + other: First Share + desc: + other: First shared a post. + scholar: + name: + other: Scholar + desc: + other: Asked a question and accepted an answer. + commentator: + name: + other: Commentator + desc: + other: Leave 5 comments. + new_user_of_the_month: + name: + other: New User of the Month + desc: + other: Outstanding contributions in their first month. + read_guidelines: + name: + other: Read Guidelines + desc: + other: Read the [community guidelines]. + reader: + name: + other: Reader + desc: + other: Read every answers in a topic with more than 10 answers. + welcome: + name: + other: Welcome + desc: + other: Received a up vote. + nice_share: + name: + other: Nice Share + desc: + other: Shared a post with 25 unique visitors. + good_share: + name: + other: Good Share + desc: + other: Shared a post with 300 unique visitors. + great_share: + name: + other: Great Share + desc: + other: Shared a post with 1000 unique visitors. + out_of_love: + name: + other: Out of Love + desc: + other: Used 50 up votes in a day. + higher_love: + name: + other: Higher Love + desc: + other: Used 50 up votes in a day 5 times. + crazy_in_love: + name: + other: Crazy in Love + desc: + other: Used 50 up votes in a day 20 times. + promoter: + name: + other: Promoter + desc: + other: Invited a user. + campaigner: + name: + other: Campaigner + desc: + other: Invited 3 basic users. + champion: + name: + other: Champion + desc: + other: Invited 5 members. + thank_you: + name: + other: Thank You + desc: + other: Has 20 up voted posts and gave 10 up votes. + gives_back: + name: + other: Gives Back + desc: + other: Has 100 up voted posts and gave 100 up votes. + empathetic: + name: + other: Empathetic + desc: + other: Has 500 up voted posts and gave 1000 up votes. + enthusiast: + name: + other: Enthusiast + desc: + other: Visited 10 consecutive days. + aficionado: + name: + other: Aficionado + desc: + other: Visited 100 consecutive days. + devotee: + name: + other: Devotee + desc: + other: Visited 365 consecutive days. + anniversary: + name: + other: Anniversary + desc: + other: Active member for a year, posted at least once. + appreciated: + name: + other: Appreciated + desc: + other: Received 1 up vote on 20 posts. + respected: + name: + other: Respected + desc: + other: Received 2 up votes on 100 posts. + admired: + name: + other: Admired + desc: + other: Received 5 up votes on 300 posts. + solved: + name: + other: Solved + desc: + other: Have an answer be accepted. + guidance_counsellor: + name: + other: Guidance Counsellor + desc: + other: Have 10 answers be accepted. + know_it_all: + name: + other: Know-it-All + desc: + other: Have 50 answers be accepted. + solution_institution: + name: + other: Solution Institution + desc: + other: Have 150 answers be accepted. + nice_answer: + name: + other: Nice Answer + desc: + other: Answer score of 10 or more. + good_answer: + name: + other: Good Answer + desc: + other: Answer score of 25 or more. + great_answer: + name: + other: Great Answer + desc: + other: Answer score of 50 or more. + nice_question: + name: + other: Nice Question + desc: + other: Question score of 10 or more. + good_question: + name: + other: Good Question + desc: + other: Question score of 25 or more. + great_question: + name: + other: Great Question + desc: + other: Question score of 50 or more. + popular_question: + name: + other: Popular Question + desc: + other: Question with 500 views. + notable_question: + name: + other: Notable Question + desc: + other: Question with 1,000 views. + famous_question: + name: + other: Famous Question + desc: + other: Question with 5,000 views. + popular_link: + name: + other: Popular Link + desc: + other: Posted an external link with 50 clicks. + hot_link: + name: + other: Hot Link + desc: + other: Posted an external link with 300 clicks. + famous_link: + name: + other: Famous Link + desc: + other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting +# The following fields are used for interface presentation(Front-end) +ui: + how_to_format: + title: How to Format + desc: >- +
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+ pagination: + prev: Prev + next: Next + page_title: + question: Question + questions: Questions + tag: Tag + tags: Tags + tag_wiki: tag wiki + create_tag: Create Tag + edit_tag: Edit Tag + ask_a_question: Add Question + edit_question: Edit Question + edit_answer: Edit Answer + search: Search + posts_containing: Posts containing + settings: Settings + notifications: Notifications + login: Log In + sign_up: Sign Up + account_recovery: Account Recovery + account_activation: Account Activation + confirm_email: Confirm Email + account_suspended: Account Suspended + admin: Admin + change_email: Modify Email + install: Answer Installation + upgrade: Answer Upgrade + maintenance: Website Maintenance + users: Users + oauth_callback: Processing + http_404: HTTP Error 404 + http_50X: HTTP Error 500 + http_403: HTTP Error 403 + logout: Log Out + notifications: + title: Notifications + inbox: Inbox + achievement: Achievements + new_alerts: New alerts + all_read: Mark all as read + show_more: Show more + someone: Someone + inbox_type: + all: All + posts: Posts + invites: Invites + votes: Votes + answer: Answer + question: Question + badge_award: Badge + suspended: + title: Your Account has been Suspended + until_time: "Your account was suspended until {{ time }}." + forever: This user was suspended forever. + end: You don't meet a community guideline. + contact_us: Contact us + editor: + blockquote: + text: Blockquote + bold: + text: Strong + chart: + text: Chart + flow_chart: Flow chart + sequence_diagram: Sequence diagram + class_diagram: Class diagram + state_diagram: State diagram + entity_relationship_diagram: Entity relationship diagram + user_defined_diagram: User defined diagram + gantt_chart: Gantt chart + pie_chart: Pie chart + code: + text: Code Sample + add_code: Add code sample + form: + fields: + code: + label: Code + msg: + empty: Code cannot be empty. + language: + label: Language + placeholder: Automatic detection + btn_cancel: Cancel + btn_confirm: Add + formula: + text: Formula + options: + inline: Inline formula + block: Block formula + heading: + text: Heading + options: + h1: Heading 1 + h2: Heading 2 + h3: Heading 3 + h4: Heading 4 + h5: Heading 5 + h6: Heading 6 + help: + text: Help + hr: + text: Horizontal rule + image: + text: Image + add_image: Add image + tab_image: Upload image + form_image: + fields: + file: + label: Image file + btn: Select image + msg: + empty: File cannot be empty. + only_image: Only image files are allowed. + max_size: File size cannot exceed 4 MB. + desc: + label: Description + tab_url: Image URL + form_url: + fields: + url: + label: Image URL + msg: + empty: Image URL cannot be empty. + name: + label: Description + btn_cancel: Cancel + btn_confirm: Add + uploading: Uploading + indent: + text: Indent + outdent: + text: Outdent + italic: + text: Emphasis + link: + text: Hyperlink + add_link: Add hyperlink + form: + fields: + url: + label: URL + msg: + empty: URL cannot be empty. + name: + label: Description + btn_cancel: Cancel + btn_confirm: Add + ordered_list: + text: Numbered list + unordered_list: + text: Bulleted list + table: + text: Table + heading: Heading + cell: Cell + close_modal: + title: I am closing this post as... + btn_cancel: Cancel + btn_submit: Submit + remark: + empty: Cannot be empty. + msg: + empty: Please select a reason. + report_modal: + flag_title: I am flagging to report this post as... + close_title: I am closing this post as... + review_question_title: Review question + review_answer_title: Review answer + review_comment_title: Review comment + btn_cancel: Cancel + btn_submit: Submit + remark: + empty: Cannot be empty. + msg: + empty: Please select a reason. + not_a_url: URL format is incorrect. + url_not_match: URL origin does not match the current website. + tag_modal: + title: Create new tag + form: + fields: + display_name: + label: Display name + msg: + empty: Display name cannot be empty. + range: Display name up to 35 characters. + slug_name: + label: URL slug + desc: URL slug up to 35 characters. + msg: + empty: URL slug cannot be empty. + range: URL slug up to 35 characters. + character: URL slug contains unallowed character set. + desc: + label: Description + revision: + label: Revision + edit_summary: + label: Edit summary + placeholder: >- + Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + btn_cancel: Cancel + btn_submit: Submit + btn_post: Post new tag + tag_info: + created_at: Created + edited_at: Edited + history: History + synonyms: + title: Synonyms + text: The following tags will be remapped to + empty: No synonyms found. + btn_add: Add a synonym + btn_edit: Edit + btn_save: Save + synonyms_text: The following tags will be remapped to + delete: + title: Delete this tag + tip_with_posts: >- +

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+ tip_with_synonyms: >- +

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+ tip: Are you sure you wish to delete? + close: Close + edit_tag: + title: Edit Tag + default_reason: Edit tag + default_first_reason: Add tag + btn_save_edits: Save edits + btn_cancel: Cancel + dates: + long_date: MMM D + long_date_with_year: "MMM D, YYYY" + long_date_with_time: "MMM D, YYYY [at] HH:mm" + now: now + x_seconds_ago: "{{count}}s ago" + x_minutes_ago: "{{count}}m ago" + x_hours_ago: "{{count}}h ago" + hour: hour + day: day + hours: hours + days: days + reaction: + heart: heart + smile: smile + frown: frown + btn_label: add or remove reactions + undo_emoji: undo {{ emoji }} reaction + react_emoji: react with {{ emoji }} + unreact_emoji: unreact with {{ emoji }} + comment: + btn_add_comment: Add comment + reply_to: Reply to + btn_reply: Reply + btn_edit: Edit + btn_delete: Delete + btn_flag: Flag + btn_save_edits: Save edits + btn_cancel: Cancel + show_more: "{{count}} more comments" + tip_question: >- + Use comments to ask for more information or suggest improvements. Avoid answering questions in comments. + tip_answer: >- + Use comments to reply to other users or notify them of changes. If you are adding new information, edit your post instead of commenting. + tip_vote: It adds something useful to the post + edit_answer: + title: Edit Answer + default_reason: Edit answer + default_first_reason: Add answer + form: + fields: + revision: + label: Revision + answer: + label: Answer + feedback: + characters: content must be at least 6 characters in length. + edit_summary: + label: Edit summary + placeholder: >- + Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + btn_save_edits: Save edits + btn_cancel: Cancel + tags: + title: Tags + sort_buttons: + popular: Popular + name: Name + newest: Newest + button_follow: Follow + button_following: Following + tag_label: questions + search_placeholder: Filter by tag name + no_desc: The tag has no description. + more: More + ask: + title: Add Question + edit_title: Edit Question + default_reason: Edit question + default_first_reason: Add question + similar_questions: Similar questions + form: + fields: + revision: + label: Revision + title: + label: Title + placeholder: Be specific and imagine you're asking a question to another person + msg: + empty: Title cannot be empty. + range: Title up to 150 characters + body: + label: Body + msg: + empty: Body cannot be empty. + tags: + label: Tags + msg: + empty: Tags cannot be empty. + answer: + label: Answer + msg: + empty: Answer cannot be empty. + edit_summary: + label: Edit summary + placeholder: >- + Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + btn_post_question: Post your question + btn_save_edits: Save edits + answer_question: Answer your own question + post_question&answer: Post your question and answer + tag_selector: + add_btn: Add tag + create_btn: Create new tag + search_tag: Search tag + hint: "Describe what your question is about, at least one tag is required." + no_result: No tags matched + tag_required_text: Required tag (at least one) + header: + nav: + question: Questions + tag: Tags + user: Users + badges: Badges + profile: Profile + setting: Settings + logout: Log out + admin: Admin + review: Review + bookmark: Bookmarks + moderation: Moderation + search: + placeholder: Search + footer: + build_on: >- + Powered by <1> Apache Answer - the open-source software that powers Q&A communities.
Made with love © {{cc}}. + upload_img: + name: Change + loading: loading... + pic_auth_code: + title: Captcha + placeholder: Type the text above + msg: + empty: Captcha cannot be empty. + inactive: + first: >- + You're almost done! We sent an activation mail to {{mail}}. Please follow the instructions in the mail to activate your account. + info: "If it doesn't arrive, check your spam folder." + another: >- + We sent another activation email to you at {{mail}}. It might take a few minutes for it to arrive; be sure to check your spam folder. + btn_name: Resend activation email + change_btn_name: Change email + msg: + empty: Cannot be empty. + resend_email: + url_label: Are you sure you want to resend the activation email? + url_text: You can also give the activation link above to the user. + login: + login_to_continue: Log in to continue + info_sign: Don't have an account? <1>Sign up + info_login: Already have an account? <1>Log in + agreements: By registering, you agree to the <1>privacy policy and <3>terms of service. + forgot_pass: Forgot password? + name: + label: Name + msg: + empty: Name cannot be empty. + range: Name must be between 2 to 30 characters in length. + character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + email: + label: Email + msg: + empty: Email cannot be empty. + password: + label: Password + msg: + empty: Password cannot be empty. + different: The passwords entered on both sides are inconsistent + account_forgot: + page_title: Forgot Your Password + btn_name: Send me recovery email + send_success: >- + If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + email: + label: Email + msg: + empty: Email cannot be empty. + change_email: + btn_cancel: Cancel + btn_update: Update email address + send_success: >- + If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + email: + label: New email + msg: + empty: Email cannot be empty. + oauth: + connect: Connect with {{ auth_name }} + remove: Remove {{ auth_name }} + oauth_bind_email: + subtitle: Add a recovery email to your account. + btn_update: Update email address + email: + label: Email + msg: + empty: Email cannot be empty. + modal_title: Email already existes. + modal_content: This email address already registered. Are you sure you want to connect to the existing account? + modal_cancel: Change email + modal_confirm: Connect to the existing account + password_reset: + page_title: Password Reset + btn_name: Reset my password + reset_success: >- + You successfully changed your password; you will be redirected to the log in page. + link_invalid: >- + Sorry, this password reset link is no longer valid. Perhaps your password is already reset? + to_login: Continue to log in page + password: + label: Password + msg: + empty: Password cannot be empty. + length: The length needs to be between 8 and 32 + different: The passwords entered on both sides are inconsistent + password_confirm: + label: Confirm new password + settings: + page_title: Settings + goto_modify: Go to modify + nav: + profile: Profile + notification: Notifications + account: Account + interface: Interface + profile: + heading: Profile + btn_name: Save + display_name: + label: Display name + msg: Display name cannot be empty. + msg_range: Display name up to 30 characters. + username: + label: Username + caption: People can mention you as "@username". + msg: Username cannot be empty. + msg_range: Username up to 30 characters. + character: 'Must use the character set "a-z", "0-9", " - . _"' + avatar: + label: Profile image + gravatar: Gravatar + gravatar_text: You can change image on + custom: Custom + custom_text: You can upload your image. + default: System + msg: Please upload an avatar + bio: + label: About me + website: + label: Website + placeholder: "https://example.com" + msg: Website incorrect format + location: + label: Location + placeholder: "City, Country" + notification: + heading: Email Notifications + turn_on: Turn on + inbox: + label: Inbox notifications + description: Answers to your questions, comments, invites, and more. + all_new_question: + label: All new questions + description: Get notified of all new questions. Up to 50 questions per week. + all_new_question_for_following_tags: + label: All new questions for following tags + description: Get notified of new questions for following tags. + account: + heading: Account + change_email_btn: Change email + change_pass_btn: Change password + change_email_info: >- + We've sent an email to that address. Please follow the confirmation instructions. + email: + label: Email + new_email: + label: New email + msg: New email cannot be empty. + pass: + label: Current password + msg: Password cannot be empty. + password_title: Password + current_pass: + label: Current password + msg: + empty: Current password cannot be empty. + length: The length needs to be between 8 and 32. + different: The two entered passwords do not match. + new_pass: + label: New password + pass_confirm: + label: Confirm new password + interface: + heading: Interface + lang: + label: Interface language + text: User interface language. It will change when you refresh the page. + my_logins: + title: My logins + label: Log in or sign up on this site using these accounts. + modal_title: Remove login + modal_content: Are you sure you want to remove this login from your account? + modal_confirm_btn: Remove + remove_success: Removed successfully + toast: + update: update success + update_password: Password changed successfully. + flag_success: Thanks for flagging. + forbidden_operate_self: Forbidden to operate on yourself + review: Your revision will show after review. + sent_success: Sent successfully + related_question: + title: Related Questions + answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. + invite_to_answer: + title: Invite People + desc: Invite people you think can answer. + invite: Invite to answer + add: Add people + search: Search people + question_detail: + action: Action + Asked: Asked + asked: asked + update: Modified + edit: edited + commented: commented + Views: Viewed + Follow: Follow + Following: Following + follow_tip: Follow this question to receive notifications + answered: answered + closed_in: Closed in + show_exist: Show existing question. + useful: Useful + question_useful: It is useful and clear + question_un_useful: It is unclear or not useful + question_bookmark: Bookmark this question + answer_useful: It is useful + answer_un_useful: It is not useful + answers: + title: Answers + score: Score + newest: Newest + oldest: Oldest + btn_accept: Accept + btn_accepted: Accepted + write_answer: + title: Your Answer + edit_answer: Edit my existing answer + btn_name: Post your answer + add_another_answer: Add another answer + confirm_title: Continue to answer + continue: Continue + confirm_info: >- +

Are you sure you want to add another answer?

You could use the edit link to refine and improve your existing answer, instead.

+ empty: Answer cannot be empty. + characters: content must be at least 6 characters in length. + tips: + header_1: Thanks for your answer + li1_1: Please be sure to answer the question. Provide details and share your research. + li1_2: Back up any statements you make with references or personal experience. + header_2: But avoid ... + li2_1: Asking for help, seeking clarification, or responding to other answers. + reopen: + confirm_btn: Reopen + title: Reopen this post + content: Are you sure you want to reopen? + list: + confirm_btn: List + title: List this post + content: Are you sure you want to list? + unlist: + confirm_btn: Unlist + title: Unlist this post + content: Are you sure you want to unlist? + pin: + title: Pin this post + content: Are you sure you wish to pinned globally? This post will appear at the top of all post lists. + confirm_btn: Pin + delete: + title: Delete this post + question: >- + We do not recommend deleting questions with answers because doing so deprives future readers of this knowledge.

Repeated deletion of answered questions can result in your account being blocked from asking. Are you sure you wish to delete? + answer_accepted: >- +

We do not recommend deleting accepted answer because doing so deprives future readers of this knowledge.

Repeated deletion of accepted answers can result in your account being blocked from answering. Are you sure you wish to delete? + other: Are you sure you wish to delete? + tip_answer_deleted: This answer has been deleted + undelete_title: Undelete this post + undelete_desc: Are you sure you wish to undelete? + btns: + confirm: Confirm + cancel: Cancel + edit: Edit + save: Save + delete: Delete + undelete: Undelete + list: List + unlist: Unlist + unlisted: Unlisted + login: Log in + signup: Sign up + logout: Log out + verify: Verify + add_question: Add question + approve: Approve + reject: Reject + skip: Skip + discard_draft: Discard draft + pinned: Pinned + all: All + question: Question + answer: Answer + comment: Comment + refresh: Refresh + resend: Resend + deactivate: Deactivate + active: Active + suspend: Suspend + unsuspend: Unsuspend + close: Close + reopen: Reopen + ok: OK + light: Light + dark: Dark + system_setting: System setting + default: Default + reset: Reset + tag: Tag + post_lowercase: post + filter: Filter + ignore: Ignore + submit: Submit + normal: Normal + closed: Closed + deleted: Deleted + pending: Pending + more: More + search: + title: Search Results + keywords: Keywords + options: Options + follow: Follow + following: Following + counts: "{{count}} Results" + more: More + sort_btns: + relevance: Relevance + newest: Newest + active: Active + score: Score + more: More + tips: + title: Advanced Search Tips + tag: "<1>[tag] search with a tag" + user: "<1>user:username search by author" + answer: "<1>answers:0 unanswered questions" + score: "<1>score:3 posts with a 3+ score" + question: "<1>is:question search questions" + is_answer: "<1>is:answer search answers" + empty: We couldn't find anything.
Try different or less specific keywords. + share: + name: Share + copy: Copy link + via: Share post via... + copied: Copied + facebook: Share to Facebook + twitter: Share to Twitter + cannot_vote_for_self: You can't vote for your own post. + modal_confirm: + title: Error... + account_result: + success: Your new account is confirmed; you will be redirected to the home page. + link: Continue to homepage + oops: Oops! + invalid: The link you used no longer works. + confirm_new_email: Your email has been updated. + confirm_new_email_invalid: >- + Sorry, this confirmation link is no longer valid. Perhaps your email was already changed? + unsubscribe: + page_title: Unsubscribe + success_title: Unsubscribe Successful + success_desc: You have been successfully removed from this subscriber list and won't receive any further emails from us. + link: Change settings + question: + following_tags: Following Tags + edit: Edit + save: Save + follow_tag_tip: Follow tags to curate your list of questions. + hot_questions: Hot Questions + all_questions: All Questions + x_questions: "{{ count }} Questions" + x_answers: "{{ count }} answers" + questions: Questions + answers: Answers + newest: Newest + active: Active + hot: Hot + recommend: Recommend + score: Score + unanswered: Unanswered + modified: modified + answered: answered + asked: asked + closed: closed + follow_a_tag: Follow a tag + more: More + personal: + overview: Overview + answers: Answers + answer: answer + questions: Questions + question: question + bookmarks: Bookmarks + reputation: Reputation + comments: Comments + votes: Votes + badges: Badges + newest: Newest + score: Score + edit_profile: Edit profile + visited_x_days: "Visited {{ count }} days" + viewed: Viewed + joined: Joined + comma: "," + last_login: Seen + about_me: About Me + about_me_empty: "// Hello, World !" + top_answers: Top Answers + top_questions: Top Questions + stats: Stats + list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. + accepted: Accepted + answered: answered + asked: asked + downvoted: downvoted + mod_short: MOD + mod_long: Moderators + x_reputation: reputation + x_votes: votes received + x_answers: answers + x_questions: questions + recent_badges: Recent Badges + install: + title: Installation + next: Next + done: Done + config_yaml_error: Can't create the config.yaml file. + lang: + label: Please choose a language + db_type: + label: Database engine + db_username: + label: Username + placeholder: root + msg: Username cannot be empty. + db_password: + label: Password + placeholder: root + msg: Password cannot be empty. + db_host: + label: Database host + placeholder: "db:3306" + msg: Database host cannot be empty. + db_name: + label: Database name + placeholder: answer + msg: Database name cannot be empty. + db_file: + label: Database file + placeholder: /data/answer.db + msg: Database file cannot be empty. + config_yaml: + title: Create config.yaml + label: The config.yaml file created. + desc: >- + You can create the <1>config.yaml file manually in the <1>/var/wwww/xxx/ directory and paste the following text into it. + info: After you've done that, click "Next" button. + site_information: Site Information + admin_account: Admin Account + site_name: + label: Site name + msg: Site name cannot be empty. + msg_max_length: Site name must be at maximum 30 characters in length. + site_url: + label: Site URL + text: The address of your site. + msg: + empty: Site URL cannot be empty. + incorrect: Site URL incorrect format. + max_length: Site URL must be at maximum 512 characters in length. + contact_email: + label: Contact email + text: Email address of key contact responsible for this site. + msg: + empty: Contact email cannot be empty. + incorrect: Contact email incorrect format. + login_required: + label: Private + switch: Login required + text: Only logged in users can access this community. + admin_name: + label: Name + msg: Name cannot be empty. + character: 'Must use the character set "a-z", "0-9", " - . _"' + msg_max_length: Name must be at maximum 30 characters in length. + admin_password: + label: Password + text: >- + You will need this password to log in. Please store it in a secure location. + msg: Password cannot be empty. + msg_min_length: Password must be at least 8 characters in length. + msg_max_length: Password must be at maximum 32 characters in length. + admin_email: + label: Email + text: You will need this email to log in. + msg: + empty: Email cannot be empty. + incorrect: Email incorrect format. + ready_title: Your site is ready + ready_desc: >- + If you ever feel like changing more settings, visit <1>admin section; find it in the site menu. + good_luck: "Have fun, and good luck!" + warn_title: Warning + warn_desc: >- + The file <1>config.yaml already exists. If you need to reset any of the configuration items in this file, please delete it first. + install_now: You may try <1>installing now. + installed: Already installed + installed_desc: >- + You appear to have already installed. To reinstall please clear your old database tables first. + db_failed: Database connection failed + db_failed_desc: >- + This either means that the database information in your <1>config.yaml file is incorrect or that contact with the database server could not be established. This could mean your host's database server is down. + counts: + views: views + votes: votes + answers: answers + accepted: Accepted + page_error: + http_error: HTTP Error {{ code }} + desc_403: You don't have permission to access this page. + desc_404: Unfortunately, this page doesn't exist. + desc_50X: The server encountered an error and could not complete your request. + back_home: Back to homepage + page_maintenance: + desc: "We are under maintenance, we'll be back soon." + nav_menus: + dashboard: Dashboard + contents: Contents + questions: Questions + answers: Answers + users: Users + badges: Badges + flags: Flags + settings: Settings + general: General + interface: Interface + smtp: SMTP + branding: Branding + legal: Legal + write: Write + tos: Terms of Service + privacy: Privacy + seo: SEO + customize: Customize + themes: Themes + css_html: CSS/HTML + login: Login + privileges: Privileges + plugins: Plugins + installed_plugins: Installed Plugins + website_welcome: Welcome to {{site_name}} + user_center: + login: Login + qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. + login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + badges: + modal: + title: Congratulations + content: You've earned a new badge. + close: Close + confirm: View badges + title: Badges + awarded: Awarded + earned_×: Earned ×{{ number }} + ×_awarded: "{{ number }} awarded" + can_earn_multiple: You can earn this multiple times. + earned: Earned + admin: + admin_header: + title: Admin + dashboard: + title: Dashboard + welcome: Welcome to Admin! + site_statistics: Site statistics + questions: "Questions:" + answers: "Answers:" + comments: "Comments:" + votes: "Votes:" + users: "Users:" + flags: "Flags:" + reviews: "Reviews:" + site_health: Site health + version: "Version:" + https: "HTTPS:" + upload_folder: "Upload folder:" + run_mode: "Running mode:" + private: Private + public: Public + smtp: "SMTP:" + timezone: "Timezone:" + system_info: System info + go_version: "Go version:" + database: "Database:" + database_size: "Database size:" + storage_used: "Storage used:" + uptime: "Uptime:" + links: Links + plugins: Plugins + github: GitHub + blog: Blog + contact: Contact + forum: Forum + documents: Documents + feedback: Feedback + support: Support + review: Review + config: Config + update_to: Update to + latest: Latest + check_failed: Check failed + "yes": "Yes" + "no": "No" + not_allowed: Not allowed + allowed: Allowed + enabled: Enabled + disabled: Disabled + writable: Writable + not_writable: Not writable + flags: + title: Flags + pending: Pending + completed: Completed + flagged: Flagged + flagged_type: Flagged {{ type }} + created: Created + action: Action + review: Review + user_role_modal: + title: Change user role to... + btn_cancel: Cancel + btn_submit: Submit + new_password_modal: + title: Set new password + form: + fields: + password: + label: Password + text: The user will be logged out and need to login again. + msg: Password must be at 8-32 characters in length. + btn_cancel: Cancel + btn_submit: Submit + edit_profile_modal: + title: Edit profile + form: + fields: + display_name: + label: Display name + msg_range: Display name up to 30 characters. + username: + label: Username + msg_range: Username up to 30 characters. + email: + label: Email + msg_invalid: Invalid Email Address. + edit_success: Edited successfully + btn_cancel: Cancel + btn_submit: Submit + user_modal: + title: Add new user + form: + fields: + users: + label: Bulk add user + placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" + text: Separate “name, email, password” with commas. One user per line. + msg: "Please enter the user's email, one per line." + display_name: + label: Display name + msg: Display name must be 2-30 characters in length. + email: + label: Email + msg: Email is not valid. + password: + label: Password + msg: Password must be at 8-32 characters in length. + btn_cancel: Cancel + btn_submit: Submit + users: + title: Users + name: Name + email: Email + reputation: Reputation + created_at: Created Time + delete_at: Deleted Time + suspend_at: Suspended Time + status: Status + role: Role + action: Action + change: Change + all: All + staff: Staff + more: More + inactive: Inactive + suspended: Suspended + deleted: Deleted + normal: Normal + Moderator: Moderator + Admin: Admin + User: User + filter: + placeholder: "Filter by name, user:id" + set_new_password: Set new password + edit_profile: Edit profile + change_status: Change status + change_role: Change role + show_logs: Show logs + add_user: Add user + deactivate_user: + title: Deactivate user + content: An inactive user must re-validate their email. + delete_user: + title: Delete this user + content: Are you sure you want to delete this user? This is permanent! + remove: Remove their content + label: Remove all questions, answers, comments, etc. + text: Don’t check this if you wish to only delete the user’s account. + suspend_user: + title: Suspend this user + content: A suspended user can't log in. + questions: + page_title: Questions + unlisted: Unlisted + post: Post + votes: Votes + answers: Answers + created: Created + status: Status + action: Action + change: Change + pending: Pending + filter: + placeholder: "Filter by title, question:id" + answers: + page_title: Answers + post: Post + votes: Votes + created: Created + status: Status + action: Action + change: Change + filter: + placeholder: "Filter by title, answer:id" + general: + page_title: General + name: + label: Site name + msg: Site name cannot be empty. + text: "The name of this site, as used in the title tag." + site_url: + label: Site URL + msg: Site url cannot be empty. + validate: Please enter a valid URL. + text: The address of your site. + short_desc: + label: Short site description + msg: Short site description cannot be empty. + text: "Short description, as used in the title tag on homepage." + desc: + label: Site description + msg: Site description cannot be empty. + text: "Describe this site in one sentence, as used in the meta description tag." + contact_email: + label: Contact email + msg: Contact email cannot be empty. + validate: Contact email is not valid. + text: Email address of key contact responsible for this site. + check_update: + label: Software updates + text: Automatically check for updates + interface: + page_title: Interface + language: + label: Interface language + msg: Interface language cannot be empty. + text: User interface language. It will change when you refresh the page. + time_zone: + label: Timezone + msg: Timezone cannot be empty. + text: Choose a city in the same timezone as you. + smtp: + page_title: SMTP + from_email: + label: From email + msg: From email cannot be empty. + text: The email address which emails are sent from. + from_name: + label: From name + msg: From name cannot be empty. + text: The name which emails are sent from. + smtp_host: + label: SMTP host + msg: SMTP host cannot be empty. + text: Your mail server. + encryption: + label: Encryption + msg: Encryption cannot be empty. + text: For most servers SSL is the recommended option. + ssl: SSL + tls: TLS + none: None + smtp_port: + label: SMTP port + msg: SMTP port must be number 1 ~ 65535. + text: The port to your mail server. + smtp_username: + label: SMTP username + msg: SMTP username cannot be empty. + smtp_password: + label: SMTP password + msg: SMTP password cannot be empty. + test_email_recipient: + label: Test email recipients + text: Provide email address that will receive test sends. + msg: Test email recipients is invalid + smtp_authentication: + label: Enable authentication + title: SMTP authentication + msg: SMTP authentication cannot be empty. + "yes": "Yes" + "no": "No" + branding: + page_title: Branding + logo: + label: Logo + msg: Logo cannot be empty. + text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown. + mobile_logo: + label: Mobile logo + text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the "logo" setting will be used. + square_icon: + label: Square icon + msg: Square icon cannot be empty. + text: Image used as the base for metadata icons. Should ideally be larger than 512x512. + favicon: + label: Favicon + text: A favicon for your site. To work correctly over a CDN it must be a png. Will be resized to 32x32. If left blank, "square icon" will be used. + legal: + page_title: Legal + terms_of_service: + label: Terms of service + text: "You can add terms of service content here. If you already have a document hosted elsewhere, provide the full URL here." + privacy_policy: + label: Privacy policy + text: "You can add privacy policy content here. If you already have a document hosted elsewhere, provide the full URL here." + write: + page_title: Write + restrict_answer: + title: Answer write + label: Each user can only write one answer for the same question + text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + recommend_tags: + label: Recommend tags + text: "Recommend tags will show in the dropdown list by default." + msg: + contain_reserved: "recommended tags cannot contain reserved tags" + required_tag: + title: Set required tags + label: Set “Recommend tags” as required tags + text: "Every new question must have at least one recommend tag." + reserved_tags: + label: Reserved tags + text: "Reserved tags can only be used by moderator." + seo: + page_title: SEO + permalink: + label: Permalink + text: Custom URL structures can improve the usability, and forward-compatibility of your links. + robots: + label: robots.txt + text: This will permanently override any related site settings. + themes: + page_title: Themes + themes: + label: Themes + text: Select an existing theme. + color_scheme: + label: Color scheme + navbar_style: + label: Navbar style + primary_color: + label: Primary color + text: Modify the colors used by your themes + css_and_html: + page_title: CSS and HTML + custom_css: + label: Custom CSS + text: > + + head: + label: Head + text: > + + header: + label: Header + text: > + + footer: + label: Footer + text: This will insert before </body>. + sidebar: + label: Sidebar + text: This will insert in sidebar. + login: + page_title: Login + membership: + title: Membership + label: Allow new registrations + text: Turn off to prevent anyone from creating a new account. + email_registration: + title: Email registration + label: Allow email registration + text: Turn off to prevent anyone creating new account through email. + allowed_email_domains: + title: Allowed email domains + text: Email domains that users must register accounts with. One domain per line. Ignored when empty. + private: + title: Private + label: Login required + text: Only logged in users can access this community. + password_login: + title: Password login + label: Allow email and password login + text: "WARNING: If turn off, you may be unable to log in if you have not previously configured other login method." + installed_plugins: + title: Installed Plugins + plugin_link: Plugins extend and expand the functionality. You may find plugins in the <1>Plugin Repository. + filter: + all: All + active: Active + inactive: Inactive + outdated: Outdated + plugins: + label: Plugins + text: Select an existing plugin. + name: Name + version: Version + status: Status + action: Action + deactivate: Deactivate + activate: Activate + settings: Settings + settings_users: + title: Users + avatar: + label: Default avatar + text: For users without a custom avatar of their own. + gravatar_base_url: + label: Gravatar base URL + text: URL of the Gravatar provider's API base. Ignored when empty. + profile_editable: + title: Profile editable + allow_update_display_name: + label: Allow users to change their display name + allow_update_username: + label: Allow users to change their username + allow_update_avatar: + label: Allow users to change their profile image + allow_update_bio: + label: Allow users to change their about me + allow_update_website: + label: Allow users to change their website + allow_update_location: + label: Allow users to change their location + privilege: + title: Privileges + level: + label: Reputation required level + text: Choose the reputation required for the privileges + msg: + should_be_number: the input should be number + number_larger_1: number should be equal or larger than 1 + badges: + action: Action + active: Active + activate: Activate + all: All + awards: Awards + deactivate: Deactivate + filter: + placeholder: Filter by name, badge:id + group: Group + inactive: Inactive + name: Name + show_logs: Show logs + status: Status + title: Badges + form: + optional: (optional) + empty: cannot be empty + invalid: is invalid + btn_submit: Save + not_found_props: "Required property {{ key }} not found." + select: Select + page_review: + review: Review + proposed: proposed + question_edit: Question edit + answer_edit: Answer edit + tag_edit: Tag edit + edit_summary: Edit summary + edit_question: Edit question + edit_answer: Edit answer + edit_tag: Edit tag + empty: No review tasks left. + approve_revision_tip: Do you approve this revision? + approve_flag_tip: Do you approve this flag? + approve_post_tip: Do you approve this post? + approve_user_tip: Do you approve this user? + suggest_edits: Suggested edits + flag_post: Flag post + flag_user: Flag user + queued_post: Queued post + queued_user: Queued user + filter_label: Type + reputation: reputation + flag_post_type: Flagged this post as {{ type }}. + flag_user_type: Flagged this user as {{ type }}. + edit_post: Edit post + list_post: List post + unlist_post: Unlist post + timeline: + undeleted: undeleted + deleted: deleted + downvote: downvote + upvote: upvote + accept: accept + cancelled: cancelled + commented: commented + rollback: rollback + edited: edited + answered: answered + asked: asked + closed: closed + reopened: reopened + created: created + pin: pinned + unpin: unpinned + show: listed + hide: unlisted + title: "History for" + tag_title: "Timeline for" + show_votes: "Show votes" + n_or_a: N/A + title_for_question: "Timeline for" + title_for_answer: "Timeline for answer to {{ title }} by {{ author }}" + title_for_tag: "Timeline for tag" + datetime: Datetime + type: Type + by: By + comment: Comment + no_data: "We couldn't find anything." + users: + title: Users + users_with_the_most_reputation: Users with the highest reputation scores this week + users_with_the_most_vote: Users who voted the most this week + staffs: Our community staff + reputation: reputation + votes: votes + prompt: + leave_page: Are you sure you want to leave the page? + changes_not_save: Your changes may not be saved. + draft: + discard_confirm: Are you sure you want to discard your draft? + messages: + post_deleted: This post has been deleted. + post_pin: This post has been pinned. + post_unpin: This post has been unpinned. + post_hide_list: This post has been hidden from list. + post_show_list: This post has been shown to list. + post_reopen: This post has been reopened. + post_list: This post has been listed. + post_unlist: This post has been unlisted. + post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. diff --git a/i18n/pl_PL.yaml b/i18n/pl_PL.yaml index 7e885b92..9c0adc78 100644 --- a/i18n/pl_PL.yaml +++ b/i18n/pl_PL.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Nieprawidłowy URL. status_invalid: - other: Invalid status. + other: Nieprawidłowy status. password: space_invalid: other: Hasło nie może zawierać spacji. @@ -326,9 +326,7 @@ backend: name: other: niegrzeczny lub obraźliwy desc: - other: - - Rozsądna osoba uznałaby tę treść za nieodpowiednią do dyskusji opartej na szacunku - - dyskomfort. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: duplikat @@ -340,10 +338,7 @@ backend: name: other: nie jest odpowiedzią desc: - other: - - To zostało opublikowane jako odpowiedź, ale nie próbuje odpowiedzieć na - - pytanie. Powinna być prawdopodobnie edytowana, opatrzona komentarzem, kolejnym pytaniem, - - lub całkowicie usunięta. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: nie jest już potrzebne @@ -402,9 +397,7 @@ backend: name: other: wymaga szczegółów lub wyjaśnienia desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: coś innego @@ -420,12 +413,12 @@ backend: deleted_title: other: Usunięte pytanie questions_title: - other: Questions + other: Pytania tag: tags_title: - other: Tags + other: Tagi no_description: - other: The tag has no description. + other: Tag nie posiada opisu. notification: action: update_question: @@ -536,57 +529,57 @@ backend: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiografista desc: other: Filled out profile information. certified: name: - other: Certified + other: Certyfikowany desc: - other: Completed our new user tutorial. + other: Ukończono nasz nowy samouczek. editor: name: - other: Editor + other: Edytor desc: other: First post edit. first_flag: name: - other: First Flag + other: Pierwsza flaga desc: other: First flagged a post. first_upvote: name: - other: First Upvote + other: Pierwszy pozytywny głos desc: other: First up voted a post. first_link: name: - other: First Link + other: Pierwszy odnośnik desc: other: First dirst added a link to another post. first_reaction: name: - other: First Reaction + other: Pierwsza Reakcja desc: other: First reacted to the post. first_share: name: - other: First Share + other: Pierwsze udostępnianie desc: other: First shared a post. scholar: name: other: Scholar desc: - other: Asked a question and accepted an answer. + other: Zadane pytania i zaakceptowane odpowiedź. commentator: name: other: Commentator desc: - other: Leave 5 comments. + other: Pozostaw 5 komentarzy. new_user_of_the_month: name: - other: New User of the Month + other: Nowy użytkownik miesiąca desc: other: Outstanding contributions in their first month. read_guidelines: @@ -794,7 +787,7 @@ ui: how_to_format: title: Jak formatować desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url. com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Poprzedni next: Następny @@ -1341,6 +1334,10 @@ ui: related_question: title: Powiązane pytania answers: odpowiedzi + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Ludzie pytali desc: Wybierz osoby, które mogą znać odpowiedź. @@ -1524,8 +1521,8 @@ ui: answers: Odpowiedzi newest: Najnowsze active: Aktywne - hot: Hot - recommend: Recommend + hot: Gorące + recommend: Polecane score: Ocena unanswered: Bez odpowiedzi modified: zmodyfikowane @@ -1544,7 +1541,7 @@ ui: reputation: Reputacja comments: Komentarze votes: Głosy - badges: Badges + badges: Odznaczenia newest: Najnowsze score: Ocena edit_profile: Edytuj Profil @@ -1559,6 +1556,7 @@ ui: top_questions: Najlepsze pytania stats: Statystyki list_empty: Nie znaleziono wpisów.
Być może chcesz wybrać inną kartę? + content_empty: No posts found. accepted: Zaakceptowane answered: Udzielone odpowiedzi asked: zapytano @@ -1705,7 +1703,7 @@ ui: login_failed_email_tip: Logowanie nie powiodło się, przed ponowną próbą zezwól na dostęp tej aplikacji do informacji o Twojej skrzynce pocztowej. badges: modal: - title: Congratulations + title: Gratulacje content: You've earned a new badge. close: Close confirm: View badges @@ -1795,10 +1793,10 @@ ui: fields: display_name: label: Display name - msg_range: Display name up to 30 characters. + msg_range: Wyświetlana nazwa użytkownika maksymalnie 30 znaków. username: label: Nazwa - msg_range: Username up to 30 characters. + msg_range: Nazwa użytkownika maksymalnie 30 znaków. email: label: Email msg_invalid: Błędny adresy email. @@ -2128,10 +2126,10 @@ ui: deactivate: Deactivate filter: placeholder: Filter by name, badge:id - group: Group + group: Grupa inactive: Inactive name: Name - show_logs: Show logs + show_logs: Wyświetl dzienniki status: Status title: Badges form: diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index d95385e1..5c21779e 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -110,11 +110,11 @@ backend: rank_tag_add_label: other: Criar marcador rank_tag_edit_label: - other: Editar descrição de um marcador (precisa revisar) + other: Editar descrição de um marcador (revisão necessária) rank_question_edit_label: - other: Editar pergunta do outro (precisa revisar) + other: Editar pergunta do outro (revisão necessária) rank_answer_edit_label: - other: Editar a resposta do outro (precisa revisar) + other: Editar a resposta do outro (revisão necessária) rank_question_edit_without_review_label: other: Editar a pergunta do outro sem revisar rank_answer_edit_without_review_label: @@ -138,7 +138,7 @@ backend: pass: other: Senha original_text: - other: This post + other: Esta publicação email_or_password_wrong_error: other: O e-mail e a palavra-passe não coincidem. error: @@ -146,7 +146,7 @@ backend: invalid_url: other: URL inválida. status_invalid: - other: Invalid status. + other: Estado inválido. password: space_invalid: other: A senha não pode conter espaços. @@ -207,15 +207,15 @@ backend: new_password_same_as_previous_setting: other: A nova senha é a mesma que a anterior. already_deleted: - other: This post has been deleted. + other: Esta publicação foi removida. meta: object_not_found: - other: Meta object not found + other: Objeto meta não encontrado question: already_deleted: other: Essa publicação foi deletado. under_review: - other: Your post is awaiting review. It will be visible after it has been approved. + other: Sua postagem está aguardando revisão. Ela ficará visível depois que for aprovada. not_found: other: Pergunta não encontrada. cannot_deleted: @@ -287,7 +287,7 @@ backend: not_allowed_registration: other: Atualmente o site não está aberto para cadastro not_allowed_login_via_password: - other: Currently the site is not allowed to login via password. + other: Atualmente o site não tem permissão para acessar utilizando senha. access_denied: other: Acesso negado page_access_denied: @@ -315,7 +315,7 @@ backend: other: Configuração do site não encontrada. badge: object_not_found: - other: Badge object not found + other: Objeto emblema não encontrado reason: spam: name: @@ -326,9 +326,7 @@ backend: name: other: rude ou abusivo desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: uma duplicação @@ -340,10 +338,7 @@ backend: name: other: não é uma resposta desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: não é mais necessário @@ -402,9 +397,7 @@ backend: name: other: precisa de detalhes ou clareza desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: algo mais @@ -420,12 +413,12 @@ backend: deleted_title: other: Questão excluída questions_title: - other: Questions + other: Questões tag: tags_title: - other: Tags + other: Marcadores no_description: - other: The tag has no description. + other: O marcador não possui descrição. notification: action: update_question: @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: lhe convidou para responder earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Ganhou o emblema "{{.BadgeName}}" emblema email_tpl: change_email: title: @@ -501,7 +494,7 @@ backend: title: other: "[{{.SiteName}}] Confirme seu novo endereço de e-mail" body: - other: "Bem-vindo a {{.SiteName}}!

\n\nClique no seguinte link para confirmar e ativar sua nova conta:
\n{{.RegisterUrl}}

\n\nSe o link acima não é clicável, tente copiar e colá-lo na barra de endereços do seu navegador da web.\n" + other: "Bem-vindo ao {{.SiteName}}!

\n\nClique no seguinte link para confirmar e ativar sua nova conta:
\n{{.RegisterUrl}}

\n\nSe o link acima não é clicável, tente copiar e colá-lo na barra de endereços do seu navegador da web.\n" test: title: other: "[{{.SiteName}}] E-mail de teste" @@ -521,280 +514,280 @@ backend: accepted: other: aceito edit: - other: edit + other: editar review: queued_post: - other: Queued post + other: Publicação na fila flagged_post: - other: Flagged post + other: Postagem sinalizada suggested_post_edit: - other: Suggested edits + other: Edições sugeridas reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} e mais {{ .Count }}..." badge: default_badges: autobiographer: name: - other: Autobiographer + other: Autobiógrafo desc: - other: Filled out profile information. + other: Preenchido com perfil . certified: name: - other: Certified + other: Certificado desc: - other: Completed our new user tutorial. + other: Completou o nosso tutorial de novo usuário. editor: name: other: Editor desc: - other: First post edit. + other: Primeira edição em publicação. first_flag: name: - other: First Flag + other: Primeira Sinalização desc: - other: First flagged a post. + other: Primeiro sinalização numa publicação. first_upvote: name: - other: First Upvote + other: Primeiro voto desc: - other: First up voted a post. + other: Primeiro post votado. first_link: name: - other: First Link + other: Primeiro link desc: - other: First dirst added a link to another post. + other: Primeiro a adicionar um link a outra postagem. first_reaction: name: - other: First Reaction + other: Primeira Reação desc: - other: First reacted to the post. + other: Primeira reação a um post. first_share: name: - other: First Share + other: Primeiro Compartilhamento desc: - other: First shared a post. + other: Primeiro a compartilhar um post. scholar: name: - other: Scholar + other: Académico desc: - other: Asked a question and accepted an answer. + other: Fez uma pergunta e aceitou uma resposta. commentator: name: - other: Commentator + other: Comentador desc: - other: Leave 5 comments. + other: Fez 5 comentários. new_user_of_the_month: name: - other: New User of the Month + other: Novo usuário do mês desc: - other: Outstanding contributions in their first month. + other: Contribuições pendentes no seu primeiro mês. read_guidelines: name: - other: Read Guidelines + other: Ler diretrizes desc: - other: Read the [community guidelines]. + other: Leia as [diretrizes da comunidade]. reader: name: - other: Reader + other: Leitor desc: - other: Read every answers in a topic with more than 10 answers. + other: Leia todas as respostas num tópico com mais de 10 respostas. welcome: name: - other: Welcome + other: Bem-vindo desc: - other: Received a up vote. + other: Recebeu um voto positivo. nice_share: name: - other: Nice Share + other: Bom compartilhador desc: - other: Shared a post with 25 unique visitors. + other: Compartilhou um post com 25 visitantes únicos. good_share: name: - other: Good Share + other: Bom compartilhador desc: - other: Shared a post with 300 unique visitors. + other: Compartilhou um post com 300 visitantes únicos. great_share: name: - other: Great Share + other: Grande Compartilhador desc: - other: Shared a post with 1000 unique visitors. + other: Compartilhou um post com 1000 visitantes únicos. out_of_love: name: - other: Out of Love + other: Por amor desc: - other: Used 50 up votes in a day. + other: Cinquenta votos positivos em um dia. higher_love: name: - other: Higher Love + other: Amor Superior desc: - other: Used 50 up votes in a day 5 times. + other: Usou 50 votos positivos em um dia — 5 vezes. crazy_in_love: name: - other: Crazy in Love + other: Amor Louco desc: - other: Used 50 up votes in a day 20 times. + other: Usou 50 votos positivos em um dia — 20 vezes. promoter: name: - other: Promoter + other: Promotor desc: - other: Invited a user. + other: Convidou um usuário. campaigner: name: - other: Campaigner + other: Ativista desc: - other: Invited 3 basic users. + other: Foram convidados 3 usuários básicos. champion: name: - other: Champion + other: Campeão desc: - other: Invited 5 members. + other: Cinco membros convidados. thank_you: name: - other: Thank You + other: Obrigado desc: - other: Has 20 up voted posts and gave 10 up votes. + other: Recebeu 20 votos positivos e deu 10 votos. gives_back: name: - other: Gives Back + other: Dar de volta desc: - other: Has 100 up voted posts and gave 100 up votes. + other: Recebeu100 votos positivos e deu 100 votos a favor. empathetic: name: - other: Empathetic + other: Empático desc: - other: Has 500 up voted posts and gave 1000 up votes. + other: Recebeu 500 votos e deu 1000 votos. enthusiast: name: - other: Enthusiast + other: Entusiasta desc: - other: Visited 10 consecutive days. + other: . aficionado: name: other: Aficionado desc: - other: Visited 100 consecutive days. + other: Visitou 100 dias consecutivos. devotee: name: - other: Devotee + other: Devoto desc: - other: Visited 365 consecutive days. + other: Visitou 365 dias consecutivos. anniversary: name: - other: Anniversary + other: Aniversário desc: - other: Active member for a year, posted at least once. + other: Membro ativo por um ano, postando pelo menos uma vez. appreciated: name: - other: Appreciated + other: Apreciado desc: - other: Received 1 up vote on 20 posts. + other: Recebeu 1 voto positivo em 20 posts. respected: name: - other: Respected + other: Respeitado desc: - other: Received 2 up votes on 100 posts. + other: Novos 2 votos em 100 posts. admired: name: - other: Admired + other: Admirado desc: - other: Received 5 up votes on 300 posts. + other: Recebeu 5 votos positivos em 300 posts. solved: name: - other: Solved + other: Resolvido desc: - other: Have an answer be accepted. + other: Ter uma resposta aceita. guidance_counsellor: name: - other: Guidance Counsellor + other: Orientador Educacional desc: - other: Have 10 answers be accepted. + other: Tenham 10 respostas aceitas. know_it_all: name: - other: Know-it-All + other: Sabichão desc: - other: Have 50 answers be accepted. + other: Tenha 50 respostas aceitas. solution_institution: name: - other: Solution Institution + other: Instituição de Soluções desc: - other: Have 150 answers be accepted. + other: Tenham 150 respostas aceitas. nice_answer: name: - other: Nice Answer + other: Resposta legal desc: - other: Answer score of 10 or more. + other: Resposta com pontuação maior que 10. good_answer: name: - other: Good Answer + other: Boa resposta desc: - other: Answer score of 25 or more. + other: Resposta com pontuação maior que 25. great_answer: name: - other: Great Answer + other: Ótima Resposta desc: - other: Answer score of 50 or more. + other: Resposta com pontuação maior que 50. nice_question: name: - other: Nice Question + other: Questão legal desc: - other: Question score of 10 or more. + other: Pergunta com pontuação maior que 10. good_question: name: - other: Good Question + other: Boa questão desc: - other: Question score of 25 or more. + other: Questão com pontuação maior que 25. great_question: name: - other: Great Question + other: Otima questão desc: - other: Question score of 50 or more. + other: Questão com pontuação maior que 50. popular_question: name: - other: Popular Question + other: Pergunta Popular desc: - other: Question with 500 views. + other: Pergunta com 500 visualizações. notable_question: name: - other: Notable Question + other: Pergunta Notável desc: - other: Question with 1,000 views. + other: Pergunta com 1000 visualizações. famous_question: name: - other: Famous Question + other: Pergunta Famosa desc: - other: Question with 5,000 views. + other: Pergunta com 5000 visualizações. popular_link: name: - other: Popular Link + other: Link Popular desc: - other: Posted an external link with 50 clicks. + other: Postou um link externo com 50 cliques. hot_link: name: - other: Hot Link + other: Link Quente desc: - other: Posted an external link with 300 clicks. + other: Postou um link externo com 300 cliques. famous_link: name: - other: Famous Link + other: Link Famoso desc: - other: Posted an external link with 100 clicks. + other: Postou um link externo com 100 cliques. default_badge_groups: getting_started: name: - other: Getting Started + other: Começando community: name: - other: Community + other: Comunidade posting: name: - other: Posting + other: Postando # The following fields are used for interface presentation(Front-end) ui: how_to_format: title: Como formatar desc: >- -
  • para mais links

    <https://url.com>

    [Título](https://url.com)
  • colocar retornos entre parágrafos

  • _italic_ ou **bold**

  • identar código por 4 espaços

  • cotação colocando > no início da linha

  • aspas invertidas `tipo_isso`

  • criar cercas de código com aspas invertidas `

    ```
    código aqui
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Anterior next: Próximo @@ -829,7 +822,7 @@ ui: http_404: HTTP Erro 404 http_50X: HTTP Erro 500 http_403: HTTP Erro 403 - logout: Log Out + logout: Encerrar Sessão notifications: title: Notificações inbox: Caixa de entrada @@ -843,9 +836,9 @@ ui: posts: Postagens invites: Convites votes: Votos - answer: Answer - question: Question - badge_award: Badge + answer: Resposta + question: Questão + badge_award: Emblema suspended: title: A sua conta foi suspensa until_time: "Sua conta está suspensa até {{ time }}." @@ -973,8 +966,8 @@ ui: empty: Não pode ser vazio. msg: empty: Por favor selecione um motivo. - not_a_url: URL format is incorrect. - url_not_match: URL origin does not match the current website. + not_a_url: Formato da URL incorreto. + url_not_match: A origem da URL não corresponde ao site atual. tag_modal: title: Criar novo marcador form: @@ -994,11 +987,11 @@ ui: desc: label: Descrição (opcional) revision: - label: Revision + label: Revisão edit_summary: - label: Edit summary + label: Editar descrição placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + Explique resumidamente as suas alterações (ortografia corrigida, gramática corrigida, formatação aprimorada) btn_cancel: Cancelar btn_submit: Enviar btn_post: Postar novo marcador @@ -1017,15 +1010,15 @@ ui: delete: title: Remover este marcador tip_with_posts: >- -

We do not allow deleting tag with posts.

Please remove this tag from the posts first.

+

Nós não permitimos remover marcadores com postagens.

Por favor, remova este marcador a partir da postagem.

tip_with_synonyms: >- -

We do not allow deleting tag with synonyms.

Please remove the synonyms from this tag first.

+

Nós não permitimos remover marcadores com postagens.

Por favor, remova este marcador a partir da postagem.

tip: Você tem certeza que deseja remover? close: Fechar edit_tag: title: Editar marcador default_reason: Editar marcador - default_first_reason: Add tag + default_first_reason: Adicionar marcador btn_save_edits: Salvar edições btn_cancel: Cancelar dates: @@ -1038,16 +1031,16 @@ ui: x_hours_ago: "{{count}}h atrás" hour: hora day: dia - hours: hours - days: days + hours: horas + days: dias reaction: - heart: heart - smile: smile - frown: frown - btn_label: add or remove reactions - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} - unreact_emoji: unreact with {{ emoji }} + heart: coração + smile: sorrir + frown: cara feia + btn_label: adicionar ou remover reações + undo_emoji: desfazer reação {{ emoji }} + react_emoji: reagir com {{ emoji }} + unreact_emoji: remover reação {{ emoji }} comment: btn_add_comment: Adicionar comentário reply_to: Responder a @@ -1057,7 +1050,7 @@ ui: btn_flag: Marcador btn_save_edits: Salvar edições btn_cancel: Cancelar - show_more: "{{count}} more comments" + show_more: "Mais {{count}} comentários" tip_question: >- Use os comentários para pedir mais informações ou sugerir melhorias. Evite responder perguntas nos comentários. tip_answer: >- @@ -1066,7 +1059,7 @@ ui: edit_answer: title: Editar Resposta default_reason: Editar Resposta - default_first_reason: Add answer + default_first_reason: Adicionar resposta form: fields: revision: @@ -1097,7 +1090,7 @@ ui: title: Adicionar Pergunta edit_title: Editar Pergunta default_reason: Editar pergunta - default_first_reason: Add question + default_first_reason: Adicionar questão similar_questions: Similar perguntas form: fields: @@ -1141,7 +1134,7 @@ ui: question: Perguntas tag: Marcadores user: Usuários - badges: Badges + badges: Emblemas profile: Perfil setting: Configurações logout: Sair @@ -1153,7 +1146,7 @@ ui: placeholder: Procurar footer: build_on: >- - Powered by <1> Apache Answer - the open-source software that powers Q&A communities.
Made with love © {{cc}}. + . upload_img: name: Mudar loading: carregando... @@ -1186,7 +1179,7 @@ ui: msg: empty: Nome não pode ser vazio. range: Name must be between 2 to 30 characters in length. - character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + character: 'Deve usar o conjunto de caracteres "a-z", "0-9", " - . _"' email: label: E-mail msg: @@ -1283,10 +1276,10 @@ ui: label: Localização (opcional) placeholder: "Cidade, País" notification: - heading: Email Notifications - turn_on: Turn on + heading: Notificações por e-mail + turn_on: Ativar inbox: - label: Inbox notifications + label: Notificações na caixa de entrada description: Responda suas próprias perguntas, comentários, convites e muito mais. all_new_question: label: Todas as perguntas novas @@ -1301,10 +1294,10 @@ ui: change_email_info: >- Enviamos um e-mail para esse endereço. Siga as instruções de confirmação. email: - label: Email + label: Correio eletrónico new_email: - label: New email - msg: New email cannot be empty. + label: Novo correio eletrónico + msg: Novo correio eletrónico não pode ser vazio. pass: label: Senha atual msg: Senha não pode ser vazio. @@ -1341,6 +1334,10 @@ ui: related_question: title: Perguntas relacionadas answers: respostas + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Pessoas Perguntaram desc: Select people who you think might know the answer. @@ -1353,7 +1350,7 @@ ui: asked: perguntado update: Modificado edit: modificado - commented: commented + commented: comentado Views: Visualizado Follow: Seguir Following: Seguindo @@ -1371,12 +1368,12 @@ ui: title: Respostas score: Pontuação newest: Mais recente - oldest: Oldest + oldest: Mais Antigos btn_accept: Aceito btn_accepted: Aceito write_answer: title: A sua Resposta - edit_answer: Edit my existing answer + edit_answer: Editar a minha resposta existente btn_name: Publicação a sua resposta add_another_answer: Adicionar outra resposta confirm_title: Continuar a responder @@ -1396,13 +1393,13 @@ ui: title: Reabrir esta postagem content: Você tem certeza que deseja reabrir? list: - confirm_btn: List - title: List this post - content: Are you sure you want to list? + confirm_btn: Lista + title: Liste esta postagem + content: Você tem certeza que deseja listar? unlist: - confirm_btn: Unlist - title: Unlist this post - content: Are you sure you want to unlist? + confirm_btn: Remover da lista + title: Remover da lista de postagens + content: Tem certeza de que deseja remover da lista? pin: title: Fixe esta postagem content: Tem certeza de que deseja fixar globalmente? Esta postagem aparecerá no topo de todas as listas de postagens. @@ -1415,18 +1412,18 @@ ui:

Nós não recomendamos excluir perguntas com respostas porque isso priva os futuros leitores desse conhecimento.

A exclusão repetida de respostas aceitas pode resultar no bloqueio de respostas de sua conta.. Você tem certeza que deseja deletar? other: Você tem certeza que deseja deletar? tip_answer_deleted: Esta resposta foi deletada - undelete_title: Undelete this post - undelete_desc: Are you sure you wish to undelete? + undelete_title: Recuperar esta publicação + undelete_desc: Você tem certeza que deseja recuperar? btns: confirm: Confirmar cancel: Cancelar edit: Editar save: Salvar delete: Excluir - undelete: Undelete - list: List - unlist: Unlist - unlisted: Unlisted + undelete: Recuperar + list: Lista + unlist: Não listar + unlisted: Não listado login: Entrar signup: Cadastrar-se logout: Sair @@ -1443,28 +1440,28 @@ ui: comment: Comentário refresh: Atualizar resend: Reenviar - deactivate: Deactivate - active: Active - suspend: Suspend - unsuspend: Unsuspend - close: Close - reopen: Reopen + deactivate: Desativar + active: Ativar + suspend: Suspender + unsuspend: Suspensão cancelada + close: Fechar + reopen: Reabrir ok: OK - light: Light - dark: Dark - system_setting: System setting - default: Default + light: Claro + dark: Escuro + system_setting: Definições de sistema + default: Padrão reset: Reset - tag: Tag - post_lowercase: post - filter: Filter - ignore: Ignore - submit: Submit + tag: Marcador + post_lowercase: publicação + filter: Filtro + ignore: Ignorar + submit: Submeter normal: Normal - closed: Closed - deleted: Deleted - pending: Pending - more: More + closed: Fechado + deleted: Removido + pending: Pendente + more: Mais search: title: Procurar Resultados keywords: Palavras-chave @@ -1481,7 +1478,7 @@ ui: more: Mais tips: title: Dicas de Pesquisa Avançada - tag: "<1>[tag] search with a tag" + tag: "<1>[tag] pesquisar com um marcador" user: "<1>user:username buscar por autor" answer: "<1>answers:0 perguntas não respondidas" score: "<1>score:3 postagens com mais de 3+ placares" @@ -1502,7 +1499,7 @@ ui: success: A sua nova conta está confirmada; você será redirecionado para a página inicial. link: Continuar para a página inicial. oops: Oops! - invalid: The link you used no longer works. + invalid: O link utilizado não funciona mais. confirm_new_email: O seu e-mail foi atualizado. confirm_new_email_invalid: >- Desculpe, este link de confirmação não é mais válido. Talvez o seu e-mail já tenha sido alterado. @@ -1524,8 +1521,8 @@ ui: answers: Respostas newest: Mais recente active: Ativo - hot: Hot - recommend: Recommend + hot: Popular + recommend: Recomendado score: Pontuação unanswered: Não Respondido modified: modificado @@ -1544,7 +1541,7 @@ ui: reputation: Reputação comments: Comentários votes: Votos - badges: Badges + badges: Emblemas newest: Mais recente score: Pontuação edit_profile: Editar Perfil @@ -1559,6 +1556,7 @@ ui: top_questions: Melhores Perguntas stats: Estatísticas list_empty: Postagens não encontradas.
Talvez você queira selecionar uma guia diferente? + content_empty: No posts found. accepted: Aceito answered: respondido asked: perguntado @@ -1569,9 +1567,9 @@ ui: x_votes: votos recebidos x_answers: respostas x_questions: perguntas - recent_badges: Recent Badges + recent_badges: Emblemas recentes install: - title: Installation + title: Instalação next: Proximo done: Completo config_yaml_error: Não é possível criar o arquivo config.yaml. @@ -1610,14 +1608,14 @@ ui: site_name: label: Site Nome msg: Site Nome não pode ser vazio. - msg_max_length: Site name must be at maximum 30 characters in length. + msg_max_length: O nome do site deve ter no máximo 30 caracteres. site_url: label: URL do Site text: O endereço do seu site. msg: empty: Site URL não pode ser vazio. incorrect: URL do site está incorreto. - max_length: Site URL must be at maximum 512 characters in length. + max_length: A URL do site deve ter no máximo 512 caracteres. contact_email: label: E-mail par contato text: O endereço de e-mail do contato principal deste site. @@ -1632,21 +1630,21 @@ ui: label: Nome msg: Nome não pode ser vazio. character: 'Deve usar o conjunto de caracteres "a-z", "0-9", " - . _"' - msg_max_length: Name must be at maximum 30 characters in length. + msg_max_length: O nome deve ter no máximo 30 caracteres. admin_password: label: Senha text: >- You will need this password to log in. Por favor store it in a secure location. msg: Senha não pode ser vazio. - msg_min_length: Password must be at least 8 characters in length. - msg_max_length: Password must be at maximum 32 characters in length. + msg_min_length: A senha deve ser ter pelo menos 8 caracteres. + msg_max_length: A senha deve ter no máximo 32 caracteres. admin_email: label: E-mail text: Você precisará deste e-mail para efetuar o login. msg: empty: Email não pode ser vazio. incorrect: O formato do e-mail está incorreto. - ready_title: Your site is ready + ready_title: Seu site está pronto ready_desc: >- Se você quiser alterar mais configurações, visite <1>seção de administrador; encontre-o no menu do site. good_luck: "Divirta-se, e boa sorte!" @@ -1679,7 +1677,7 @@ ui: questions: Perguntas answers: Respostas users: Usuários - badges: Badges + badges: Emblemas flags: Marcadores settings: Configurações general: Geral @@ -1705,50 +1703,50 @@ ui: login_failed_email_tip: Falha ao entrar, por favor, permita que este aplicativo acesse a informação do seu e-mail antes de tentar novamente. badges: modal: - title: Congratulations - content: You've earned a new badge. - close: Close - confirm: View badges - title: Badges - awarded: Awarded - earned_×: Earned ×{{ number }} - ×_awarded: "{{ number }} awarded" - can_earn_multiple: You can earn this multiple times. - earned: Earned + title: Parabéns + content: Você ganhou um novo emblema. + close: Fechar + confirm: Ver emblemas + title: Emblemas + awarded: Premiado + earned_×: Ganhou ×{{ number }} + ×_awarded: "{{ number }} premiado" + can_earn_multiple: Você pode ganhar isto várias vezes. + earned: Ganhou admin: admin_header: title: Administrador dashboard: title: Painel - welcome: Welcome to Admin! - site_statistics: Site statistics + welcome: Bem-vindo ao Admin! + site_statistics: Estatísticas do site questions: "Perguntas:" answers: "Respostas:" comments: "Comentários:" votes: "Votos:" - users: "Users:" + users: "Usuários:" flags: "Marcadores:" - reviews: "Reviews:" - site_health: Site health + reviews: "Revisão:" + site_health: Saúde do site version: "Versão:" https: "HTTPS:" - upload_folder: "Upload folder:" - run_mode: "Running mode:" - private: Private - public: Public + upload_folder: "Upload da pasta:" + run_mode: "Mode de execução:" + private: Privado + public: Público smtp: "SMTP:" timezone: "Fuso horário:" - system_info: System info - go_version: "Go version:" - database: "Database:" - database_size: "Database size:" + system_info: Informação do sistema + go_version: "Versão do Go:" + database: "Banco de dados:" + database_size: "Tamanho do banco de dados:" storage_used: "Armazenamento usado:" uptime: "Tempo de atividade:" links: Links plugins: Plugins github: GitHub blog: Blog - contact: Contact + contact: Contato forum: Forum documents: Documentos feedback: Opinião @@ -1764,8 +1762,8 @@ ui: allowed: Permitido enabled: Ativo disabled: Disponível - writable: Writable - not_writable: Not writable + writable: Possível escrever + not_writable: Não é possível escrever flags: title: Marcadores pending: Pendente @@ -1790,21 +1788,21 @@ ui: btn_cancel: Cancelar btn_submit: Enviar edit_profile_modal: - title: Edit profile + title: Editar profile form: fields: display_name: - label: Display name - msg_range: Display name up to 30 characters. + label: Nome no display + msg_range: Nome no display pode conter até 30 caracteres. username: - label: Username - msg_range: Username up to 30 characters. + label: Nome do usuário + msg_range: Nome do usuário pode conter até 30 caracteres. email: - label: Email - msg_invalid: Invalid Email Address. - edit_success: Edited successfully - btn_cancel: Cancel - btn_submit: Submit + label: Correio eletrônico + msg_invalid: Correio eletrônico invalido. + edit_success: Editado com sucesso + btn_cancel: Cancelar + btn_submit: Submeter user_modal: title: Adicionar novo usuário form: @@ -1850,26 +1848,26 @@ ui: filter: placeholder: "Filtrar por nome, user:id" set_new_password: Configurar nova senha - edit_profile: Edit profile + edit_profile: Editar profile change_status: Mudar status change_role: Mudar função show_logs: Mostrar registros add_user: Adicionar usuário deactivate_user: - title: Deactivate user - content: An inactive user must re-validate their email. + title: Desativar usuários + content: Um usuário inativo deve revalidar seu e-mail. delete_user: - title: Delete this user - content: Are you sure you want to delete this user? This is permanent! - remove: Remove their content - label: Remove all questions, answers, comments, etc. - text: Don’t check this if you wish to only delete the user’s account. + title: Remover este usuário + content: Tem certeza de que deseja excluir este usuário? Isso é permanente! + remove: Remover o conteúdo dele + label: Remover todas as perguntas, respostas, comentários etc. + text: Não marque isso se deseja excluir apenas a conta do usuário. suspend_user: - title: Suspend this user - content: A suspended user can't log in. + title: Suspender este usuário + content: Um usuário suspenso não pode fazer login. questions: page_title: Perguntas - unlisted: Unlisted + unlisted: Não-listado post: Publicação votes: Votos answers: Respostas @@ -1877,7 +1875,7 @@ ui: status: Estado action: Ação change: Mudar - pending: Pending + pending: Pendente filter: placeholder: "Filtrar por título, question:id" answers: @@ -1915,8 +1913,8 @@ ui: validate: E-mail par contato não é válido. text: Endereço de e-mail do principal contato responsável por este site. check_update: - label: Software updates - text: Automatically check for updates + label: Atualizações de software + text: Verificar se há atualizações automaticamente interface: page_title: Interface language: @@ -1995,28 +1993,28 @@ ui: write: page_title: Escrever restrict_answer: - title: Answer write + title: Escrever resposta label: Each user can only write one answer for each question - text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + text: "Desative para permitir que os usuários escrevam várias respostas para a mesma pergunta, o que pode fazer com que as respostas fiquem menos focadas." recommend_tags: label: Recommend Marcadores - text: "Recommend tags will show in the dropdown list by default." + text: "Os marcadores recomendados serão exibidos na lista dropdown por padrão." msg: - contain_reserved: "recommended tags cannot contain reserved tags" + contain_reserved: "tags recomendadas não podem conter tags reservadas" required_tag: - title: Set required tags - label: Set “Recommend tags” as required tags + title: Definir tags necessárias + label: Definir "Tags recomendadas" como tags necessárias text: "Every new question must have ao menos one recommend tag." reserved_tags: label: Reserved Marcadores - text: "Reserved tags can only be used by moderator." + text: "Tags reservadas só podem ser usadas pelo moderador." seo: page_title: SEO permalink: label: Link permanente text: Custom URL structures can improve the usability, and forward-compatibility of a sua links. robots: - label: robots.txt + label: robos.txt text: Isto irá substituir permanentemente quaisquer configurações do site relacionadas. themes: page_title: Temas @@ -2024,11 +2022,11 @@ ui: label: Temas text: Selecionar um tema existente. color_scheme: - label: Color scheme + label: Esquema de cores navbar_style: - label: Navbar style + label: Estilo da barra de navegação primary_color: - label: Primary color + label: Cor primária text: Modifica as cores usadas por seus temas css_and_html: page_title: CSS e HTML @@ -2046,7 +2044,7 @@ ui: footer: label: Rodapé - text: This will insert before </body>. + text: Isto será inserido antes de </body>. sidebar: label: Barra lateral text: Isto irá inserir na barra lateral. @@ -2068,12 +2066,12 @@ ui: label: Login requirido text: Somente usuários conectados podem acessar esta comunidade. password_login: - title: Password login - label: Allow email and password login - text: "WARNING: If turn off, you may be unable to log in if you have not previously configured other login method." + title: Login com senha + label: Permitir login por e-mail e senha + text: "AVISO: Se desativar, você pode ser incapaz de efetuar login se você não tiver configurado anteriormente outro método de login." installed_plugins: title: Extensões instaladas - plugin_link: Plugins extend and expand the functionality. You may find plugins in the <1>Plugin Repository. + plugin_link: Plugins ampliam e expandem a funcionalidade. Você pode encontrar plugins no <1>Repositório de Plugins. filter: all: Todos active: Ativo @@ -2117,23 +2115,24 @@ ui: label: Nível de reputação necessário text: Escolha a reputação necessária para os privilégios msg: - should_be_number: the input should be number - number_larger_1: number should be equal or larger than 1 + should_be_number: o valor de entrada deve ser número + number_larger_1: número deve ser igual ou maior que 1 badges: - action: Action - active: Active + action: Ação + active: Ativo + activate: Ativado activate: Activate - all: All - awards: Awards - deactivate: Deactivate + all: Todos + awards: Prêmios + deactivate: Desativar filter: - placeholder: Filter by name, badge:id - group: Group - inactive: Inactive - name: Name - show_logs: Show logs + placeholder: Filtrar por nome, badge:id + group: Grupo + inactive: Inativo + name: Nome + show_logs: Mostrar registros status: Status - title: Badges + title: Emblemas form: optional: (opcional) empty: não pode ser vazio @@ -2152,22 +2151,22 @@ ui: edit_answer: Editar resposta edit_tag: Editar marcador empty: Nenhuma tarefa de revisão restante. - approve_revision_tip: Do you approve this revision? - approve_flag_tip: Do you approve this flag? - approve_post_tip: Do you approve this post? - approve_user_tip: Do you approve this user? - suggest_edits: Suggested edits - flag_post: Flag post - flag_user: Flag user - queued_post: Queued post - queued_user: Queued user - filter_label: Type - reputation: reputation - flag_post_type: Flagged this post as {{ type }}. - flag_user_type: Flagged this user as {{ type }}. - edit_post: Edit post - list_post: List post - unlist_post: Unlist post + approve_revision_tip: Você aprova esta revisão? + approve_flag_tip: Você aprova esta sinalização? + approve_post_tip: Você aprova esta publicação? + approve_user_tip: Você aprova este usuário? + suggest_edits: Edições sugeridas + flag_post: Post sinalizado + flag_user: Sinalizar usuário + queued_post: Publicação na fila + queued_user: Usuário na fila + filter_label: Tipo + reputation: reputação + flag_post_type: Sinalizou esta publicação como {{ type }}. + flag_user_type: Sinalizou este usuário como {{ type }}. + edit_post: Editar publicação + list_post: Listar postagem + unlist_post: Remover postagem da lista timeline: undeleted: não removido deleted: removido @@ -2218,6 +2217,6 @@ ui: post_hide_list: Esta postagem foi ocultada da lista. post_show_list: Esta postagem foi exibida à lista. post_reopen: Esta publicação foi re-aberta. - post_list: This post has been listed. - post_unlist: This post has been unlisted. - post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_list: Esta postagem foi listada. + post_unlist: Esta publicação foi removida da lista. + post_pending: A sua postagem está aguardando revisão. Ela ficará visível depois que for aprovada. diff --git a/i18n/ro_RO.yaml b/i18n/ro_RO.yaml index c73eb566..9b7ed200 100644 --- a/i18n/ro_RO.yaml +++ b/i18n/ro_RO.yaml @@ -326,9 +326,7 @@ backend: name: other: nepoliticos sau abuziv desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: un duplicat @@ -340,10 +338,7 @@ backend: name: other: nu este un răspuns desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: nu mai este necesar @@ -402,9 +397,7 @@ backend: name: other: necesită detalii sau claritate desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: altceva @@ -794,7 +787,7 @@ ui: how_to_format: title: Cum se formatează desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Înapoi next: Înainte @@ -1341,6 +1334,10 @@ ui: related_question: title: Întrebări conexe answers: răspunsuri + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Persoane întrebate desc: Invită persoane care crezi că știu răspunsul. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Intrebari stats: Statistici list_empty: Nici o postare găsită.
Poate doriţi să selectaţi o filă diferită? + content_empty: No posts found. accepted: Acceptat answered: răspunse asked: întrebat diff --git a/i18n/ru_RU.yaml b/i18n/ru_RU.yaml index 9adf491a..1e370b5c 100644 --- a/i18n/ru_RU.yaml +++ b/i18n/ru_RU.yaml @@ -326,9 +326,7 @@ backend: name: other: Грубость или оскорбления desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: дубликат @@ -340,10 +338,7 @@ backend: name: other: это не ответ desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: Не актуально @@ -402,9 +397,7 @@ backend: name: other: нуждается в деталях или ясности desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: прочее @@ -794,7 +787,7 @@ ui: how_to_format: title: 'Форматирование:' desc: >- -
  • создание ссылок:

    <https://url.com>

    [Title](https://url.com)
  • пробел между абзацами

  • _italic_ или **bold**

  • отступ для кода - 4 пробела

  • тег > для цитаты в начале строки

  • обратные кавычки для строки кода `like _this_`

  • тройные обратные кавычки для блоков кода `

    ```
    тут код
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Назад next: Следующий @@ -1341,6 +1334,10 @@ ui: related_question: title: Похожие вопросы answers: ответы + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Позвать на помощь desc: Выберите людей, которые, по вашему мнению, могут знать ответ. @@ -1559,6 +1556,7 @@ ui: top_questions: Топ вопросов stats: Статистика list_empty: Сообщений не найдено.
Возможно, вы хотели бы выбрать другую вкладку? + content_empty: No posts found. accepted: Принято answered: отвеченные asked: спросил diff --git a/i18n/sk_SK.yaml b/i18n/sk_SK.yaml index eac4f204..28e77be0 100644 --- a/i18n/sk_SK.yaml +++ b/i18n/sk_SK.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: potrebuje podrobnosti alebo jasnosť desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: niečo iné @@ -794,7 +787,7 @@ ui: how_to_format: title: Ako formátovať desc: >- -
  • na vytváranie odkazov

    <https://url.com>

    [Title](https://url.com)
  • vracať medzi odsekmi

  • _italic_ alebo **tučné**

  • odsadenie kódu o 4 medzery

  • citát umiestnením > na začiatku riadku

  • backtick uniká `ako _this_`

  • vytvorte kódové ploty s `

    ```
    kódom tu
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Predch next: Ďalšie @@ -1341,6 +1334,10 @@ ui: related_question: title: Súvisiace otázky answers: odpovede + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Najlepšie otázky stats: Štatistiky list_empty: Nenašli sa žiadne príspevky.
Možno by ste chceli vybrať inú kartu? + content_empty: No posts found. accepted: Prijaté answered: zodpovedané asked: opýtané diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index 36b59fe6..b6c5e90e 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Ogiltig URL. status_invalid: - other: Invalid status. + other: Ogiltig status. password: space_invalid: other: Password cannot contain spaces. @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Prev next: Nästa @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Bjud in personer som du tror kan svara. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked @@ -1705,9 +1703,9 @@ ui: login_failed_email_tip: Login failed, please allow this app to access your email information before try again. badges: modal: - title: Congratulations + title: Grattis content: You've earned a new badge. - close: Close + close: Stäng confirm: View badges title: Badges awarded: Awarded @@ -1794,7 +1792,7 @@ ui: form: fields: display_name: - label: Display name + label: Visningsnamn msg_range: Display name up to 30 characters. username: label: Username @@ -2121,17 +2119,18 @@ ui: number_larger_1: number should be equal or larger than 1 badges: action: Action - active: Active + active: Aktiv + activate: Aktivera activate: Activate - all: All + all: Alla awards: Awards - deactivate: Deactivate + deactivate: Inaktivera filter: placeholder: Filter by name, badge:id - group: Group - inactive: Inactive - name: Name - show_logs: Show logs + group: Grupp + inactive: Inaktiv + name: Namn + show_logs: Visa loggar status: Status title: Badges form: diff --git a/i18n/te_IN.yaml b/i18n/te_IN.yaml index 638a1870..2b9ea470 100644 --- a/i18n/te_IN.yaml +++ b/i18n/te_IN.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: needs details or clarity desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: something else @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: మునుపటి next: Next @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/tr_TR.yaml b/i18n/tr_TR.yaml index 656da997..5bfb1bbd 100644 --- a/i18n/tr_TR.yaml +++ b/i18n/tr_TR.yaml @@ -183,7 +183,7 @@ backend: verify_url_expired: other: Email verified URL has expired, please resend the email. illegal_email_domain_error: - other: Email is not allowed from that email domain. Please use another one. + other: Bu alan adındaki e-posta adreslerine izin verilmiyor. Lütfen başka bir e-posta deneyin. lang: not_found: other: Dil dosyası bulunamadı. @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -400,23 +395,21 @@ backend: other: This question doesn't meet a community guideline. multiple: name: - other: needs details or clarity + other: açıklanmaya veya detaya ihtiyacı var desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: - other: something else + other: başka bir şey desc: other: This post requires another reason not listed above. operation_type: asked: - other: asked + other: soruldu answered: - other: answered + other: cevaplandı modified: - other: modified + other: düzenlendi deleted_title: other: Deleted question questions_title: @@ -641,7 +634,7 @@ backend: other: Invited a user. campaigner: name: - other: Campaigner + other: Kampanyacı desc: other: Invited 3 basic users. champion: @@ -651,7 +644,7 @@ backend: other: Invited 5 members. thank_you: name: - other: Thank You + other: desc: other: Has 20 up voted posts and gave 10 up votes. gives_back: @@ -794,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Önceki next: Sonraki @@ -1341,6 +1334,10 @@ ui: related_question: title: Related Questions answers: answers + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Select people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: Top Questions stats: Stats list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked diff --git a/i18n/uk_UA.yaml b/i18n/uk_UA.yaml index 58a538e2..a8f29b30 100644 --- a/i18n/uk_UA.yaml +++ b/i18n/uk_UA.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: Невірна URL. status_invalid: - other: Invalid status. + other: Неприпустимий статус. password: space_invalid: other: Пароль не може містити пробіли. @@ -315,7 +315,7 @@ backend: other: Конфігурацію сайту не знайдено. badge: object_not_found: - other: Badge object not found + other: Об'єкт значка не знайдено reason: spam: name: @@ -326,9 +326,7 @@ backend: name: other: грубо чи образливо desc: - other: - - Розсудлива людина вважатиме цей контент неприйнятним з точки зору шанобливого ставлення - - дискурс. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: дублікат @@ -340,10 +338,7 @@ backend: name: other: не відповідь desc: - other: - - Це повідомлення було розміщено як відповідь, але воно не є спробою відповісти на - - запитання. Можливо, його слід відредагувати, додати коментар, поставити інше запитання - - або взагалі видалити. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: більше не потрібно @@ -402,9 +397,7 @@ backend: name: other: потребує деталей або ясності desc: - other: - - Наразі це запитання містить кілька запитань в одному. Воно має - - зосереджуватися лише на одній проблемі. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: інше @@ -420,10 +413,10 @@ backend: deleted_title: other: Видалене питання questions_title: - other: Questions + other: Питання tag: tags_title: - other: Tags + other: Теґи no_description: other: The tag has no description. notification: @@ -515,7 +508,7 @@ backend: downvote: other: голос "проти" downvoted: - other: downvoted + other: проголосував проти accept: other: прийняти accepted: @@ -541,14 +534,14 @@ backend: other: Filled out profile information. certified: name: - other: Certified + other: Підтверджений desc: other: Completed our new user tutorial. editor: name: - other: Editor + other: Редактор desc: - other: First post edit. + other: Перше редагування посту. first_flag: name: other: First Flag @@ -561,12 +554,12 @@ backend: other: First up voted a post. first_link: name: - other: First Link + other: Перше посилання desc: other: First dirst added a link to another post. first_reaction: name: - other: First Reaction + other: Перша реакція desc: other: First reacted to the post. first_share: @@ -576,34 +569,34 @@ backend: other: First shared a post. scholar: name: - other: Scholar + other: Вчений desc: other: Asked a question and accepted an answer. commentator: name: - other: Commentator + other: Коментатор desc: - other: Leave 5 comments. + other: Залиште 5 коментарів. new_user_of_the_month: name: - other: New User of the Month + other: Новий користувач місяця desc: other: Outstanding contributions in their first month. read_guidelines: name: other: Read Guidelines desc: - other: Read the [community guidelines]. + other: Прочитайте [рекомендації для спільноти]. reader: name: - other: Reader + other: Читач desc: other: Read every answers in a topic with more than 10 answers. welcome: name: - other: Welcome + other: Ласкаво просимо desc: - other: Received a up vote. + other: Отримав голос. nice_share: name: other: Nice Share @@ -636,9 +629,9 @@ backend: other: Used 50 up votes in a day 20 times. promoter: name: - other: Promoter + other: Промоутер desc: - other: Invited a user. + other: Запросив користувача. campaigner: name: other: Campaigner @@ -646,12 +639,12 @@ backend: other: Invited 3 basic users. champion: name: - other: Champion + other: Чемпіон desc: - other: Invited 5 members. + other: Запросив 5 учасників. thank_you: name: - other: Thank You + other: Дякую desc: other: Has 20 up voted posts and gave 10 up votes. gives_back: @@ -691,7 +684,7 @@ backend: other: Received 1 up vote on 20 posts. respected: name: - other: Respected + other: Шанований desc: other: Received 2 up votes on 100 posts. admired: @@ -701,7 +694,7 @@ backend: other: Received 5 up votes on 300 posts. solved: name: - other: Solved + other: Вирішено desc: other: Have an answer be accepted. guidance_counsellor: @@ -785,7 +778,7 @@ backend: other: Getting Started community: name: - other: Community + other: Спільнота posting: name: other: Posting @@ -794,7 +787,7 @@ ui: how_to_format: title: Як відформатувати desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Назад next: Далі @@ -843,7 +836,7 @@ ui: posts: Публікації invites: Запрошення votes: Голоси - answer: Answer + answer: Відповідь question: Question badge_award: Badge suspended: @@ -1037,12 +1030,12 @@ ui: x_minutes_ago: "{{count}}m ago" x_hours_ago: "{{count}}h ago" hour: hour - day: day + day: день hours: hours - days: days + days: дні reaction: heart: heart - smile: smile + smile: посмішка frown: frown btn_label: add or remove reactions undo_emoji: undo {{ emoji }} reaction @@ -1341,6 +1334,10 @@ ui: related_question: title: Пов'язані запитання answers: відповіді + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Люди запитували desc: Виберіть людей, які, на вашу думку, можуть знати відповідь. @@ -1361,7 +1358,7 @@ ui: answered: answered closed_in: Closed in show_exist: Показати наявне запитання. - useful: Useful + useful: Корисне question_useful: It is useful and clear question_un_useful: It is unclear or not useful question_bookmark: Bookmark this question @@ -1372,10 +1369,10 @@ ui: score: Score newest: Newest oldest: Oldest - btn_accept: Accept + btn_accept: Прийняти btn_accepted: Accepted write_answer: - title: Your Answer + title: Ваша відповідь edit_answer: Edit my existing answer btn_name: Post your answer add_another_answer: Add another answer @@ -1383,7 +1380,7 @@ ui: continue: Continue confirm_info: >-

Are you sure you want to add another answer?

You could use the edit link to refine and improve your existing answer, instead.

- empty: Answer cannot be empty. + empty: Відповідь не може бути порожньою. characters: вміст має бути не менше 6 символів. tips: header_1: Дякуємо за відповідь @@ -1424,8 +1421,8 @@ ui: save: Зберегти delete: Видалити undelete: Скасувати видалення - list: List - unlist: Unlist + list: Список + unlist: Вилучити зі списку unlisted: Unlisted login: Увійти signup: Зареєструватися @@ -1449,7 +1446,7 @@ ui: unsuspend: Unsuspend close: Закрити reopen: Відкрити знову - ok: OK + ok: ОК light: Світла dark: Темна system_setting: Налаштування системи @@ -1462,7 +1459,7 @@ ui: submit: Submit normal: Normal closed: Closed - deleted: Deleted + deleted: Видалені pending: Pending more: More search: @@ -1497,11 +1494,11 @@ ui: twitter: Share to Twitter cannot_vote_for_self: You can't vote for your own post. modal_confirm: - title: Error... + title: Помилка... account_result: success: Your new account is confirmed; you will be redirected to the home page. - link: Continue to homepage - oops: Oops! + link: Перейти на головну сторінку + oops: Йой! invalid: The link you used no longer works. confirm_new_email: Your email has been updated. confirm_new_email_invalid: >- @@ -1514,7 +1511,7 @@ ui: question: following_tags: Підписки на теги edit: Edit - save: Save + save: Зберегти follow_tag_tip: Підпишіться на теги, щоб упорядкувати свій список запитань. hot_questions: Hot Questions all_questions: Всі питання @@ -1559,6 +1556,7 @@ ui: top_questions: Найкращі запитання stats: Статистика list_empty: No posts found.
Perhaps you'd like to select a different tab? + content_empty: No posts found. accepted: Accepted answered: answered asked: asked @@ -1576,17 +1574,17 @@ ui: done: Done config_yaml_error: Can't create the config.yaml file. lang: - label: Please choose a language + label: Будь ласка, виберіть мову db_type: label: Database engine db_username: - label: Username + label: Ім'я користувача placeholder: root msg: Username cannot be empty. db_password: - label: Password + label: Пароль placeholder: root - msg: Password cannot be empty. + msg: Поле паролю не може бути порожнім. db_host: label: Database host placeholder: "db:3306" @@ -1664,7 +1662,7 @@ ui: views: views votes: votes answers: answers - accepted: Accepted + accepted: Схвалено page_error: http_error: HTTP Error {{ code }} desc_403: You don't have permission to access this page. @@ -1681,17 +1679,17 @@ ui: users: Users badges: Badges flags: Відмітки - settings: Settings + settings: Налаштування general: General interface: Interface smtp: SMTP branding: Branding legal: Legal - write: Write + write: Написати tos: Terms of Service privacy: Privacy seo: SEO - customize: Customize + customize: Персоналізувати themes: Themes css_html: CSS/HTML login: Login @@ -1707,17 +1705,17 @@ ui: modal: title: Congratulations content: You've earned a new badge. - close: Close + close: Закрити confirm: View badges title: Badges awarded: Awarded earned_×: Earned ×{{ number }} ×_awarded: "{{ number }} awarded" can_earn_multiple: You can earn this multiple times. - earned: Earned + earned: Зароблено admin: admin_header: - title: Admin + title: Адмін dashboard: title: Dashboard welcome: Welcome to Admin! @@ -1744,11 +1742,11 @@ ui: database_size: "Розмір бази даних:" storage_used: "Використаний обсяг пам’яті:" uptime: "Uptime:" - links: Links + links: Посилання plugins: Плаґіни github: GitHub blog: Блоґ - contact: Contact + contact: Контакт forum: Forum documents: Документи feedback: Відгук @@ -1777,20 +1775,20 @@ ui: review: Огляд user_role_modal: title: Change user role to... - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати new_password_modal: - title: Set new password + title: Встановити новий пароль form: fields: password: - label: Password + label: Пароль text: The user will be logged out and need to login again. msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати edit_profile_modal: - title: Edit profile + title: Редагувати профіль form: fields: display_name: @@ -1800,13 +1798,13 @@ ui: label: Username msg_range: Username up to 30 characters. email: - label: Email + label: Електронна пошта msg_invalid: Invalid Email Address. edit_success: Edited successfully - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати user_modal: - title: Add new user + title: Додати нового користувача form: fields: users: @@ -1818,17 +1816,17 @@ ui: label: Ім'я для відображення msg: Ім'я для відображення повинно мати довжину від 2 до 30 символів. email: - label: Email + label: Електронна пошта msg: Email is not valid. password: - label: Password + label: Пароль msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Скасувати + btn_submit: Надіслати users: - title: Users - name: Name - email: Email + title: Користувачі + name: Ім’я + email: Електронна пошта reputation: Reputation created_at: Created Time delete_at: Deleted Time @@ -1870,7 +1868,7 @@ ui: questions: page_title: Запитання unlisted: Unlisted - post: Post + post: Опублікувати votes: Votes answers: Answers created: Створені @@ -1993,7 +1991,7 @@ ui: label: Політика конфіденційности text: "Ви можете додати вміст політики конфіденційності тут. Якщо у вас уже є документ, розміщений деінде, надайте тут повну URL-адресу." write: - page_title: Write + page_title: Написати restrict_answer: title: Answer write label: Кожен користувач може написати лише одну відповідь на кожне запитання @@ -2028,7 +2026,7 @@ ui: navbar_style: label: Navbar style primary_color: - label: Primary color + label: Основний колір text: Modify the colors used by your themes css_and_html: page_title: CSS and HTML @@ -2051,7 +2049,7 @@ ui: label: Sidebar text: This will insert in sidebar. login: - page_title: Login + page_title: Увійти membership: title: Membership label: Дозволити нові реєстрації @@ -2082,15 +2080,15 @@ ui: plugins: label: Plugins text: Select an existing plugin. - name: Name + name: Ім’я version: Version status: Status action: Action deactivate: Deactivate activate: Activate - settings: Settings + settings: Налаштування settings_users: - title: Users + title: Користувачі avatar: label: Default avatar text: For users without a custom avatar of their own. @@ -2130,17 +2128,17 @@ ui: placeholder: Filter by name, badge:id group: Group inactive: Inactive - name: Name + name: Ім’я show_logs: Show logs status: Status title: Badges form: optional: (optional) - empty: cannot be empty + empty: не може бути порожнім invalid: is invalid - btn_submit: Save + btn_submit: Зберегти not_found_props: "Required property {{ key }} not found." - select: Select + select: Вибрати page_review: review: Review proposed: proposed diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 59f56978..044817fa 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -146,7 +146,7 @@ backend: invalid_url: other: URL không tồn tại. status_invalid: - other: Invalid status. + other: Trạng thái không hợp lệ password: space_invalid: other: Mật khẩu không thể tồn tại khoảng trắng. @@ -315,35 +315,30 @@ backend: other: Không tìm thấy cấu hình trang. badge: object_not_found: - other: Badge object not found + other: Đối tượng không tìm thấy reason: spam: name: - other: Lạm dụng + other: thư rác desc: - other: Bài đăng này là quảng cáo hoặc phá hoại. Nó không hữu ích hoặc liên quan đến chủ đề hiện tại. + other: Bài đăng này quảng cáo hoặc phá hoại. Nó không hữu ích hoặc liên quan đến chủ đề hiện tại. rude_or_abusive: name: other: thô lỗ hoặc lạm dụng desc: - other: - - Một người lý trí sẽ thấy nội dung này không phù hợp để thảo luận tôn trọng - - Đàm thoại + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: một bản sao desc: - other: Câu hỏi này đã được hỏi trước đó và đã có câu trả lời. + other: Câu hỏi này đã được hỏi trước đó, đã có câu trả lời. placeholder: other: Nhập liên kết câu hỏi hiện tại not_a_answer: name: - other: không phải là câu trả lời + other: không phải câu trả lời desc: - other: - - Nội dung này được đăng dưới dạng câu trả lời, nhưng nó không hề trả lời cho câu hỏi... - - câu hỏi. Nó có thể là một chỉnh sửa, một bình luận, một câu hỏi khác, - - hoặc bị xóa hoàn toàn. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: không còn cần thiết @@ -402,9 +397,7 @@ backend: name: other: cần chi tiết hoặc rõ ràng desc: - other: - - Câu hỏi này hiện bao gồm nhiều câu hỏi trong một. Nó nên tập trung vào một vấn đề duy nhất - - chỉ tập trung vào một vấn đề. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: điều gì đó khác @@ -465,7 +458,7 @@ backend: invited_you_to_answer: other: đã mời bạn trả lời earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Bạn đã nhận được huy hiệu "{{.BadgeName}}" email_tpl: change_email: title: @@ -536,265 +529,265 @@ backend: default_badges: autobiographer: name: - other: Autobiographer + other: Tác giả tự truyện desc: - other: Filled out profile information. + other: Đã điền thông tin hồ sơ. certified: name: - other: Certified + other: Đã xác minh desc: - other: Completed our new user tutorial. + other: Hoàn thành hướng dẫn cho người dùng mới của chúng tôi. editor: name: - other: Editor + other: Trình chỉnh sửa desc: - other: First post edit. + other: Chỉnh sửa bài đăng đầu tiên. first_flag: name: - other: First Flag + other: Cờ đầu tiên desc: - other: First flagged a post. + other: Lần đầu tiên báo cáo một bài viết. first_upvote: name: - other: First Upvote + other: Lượt thích đầu tiên desc: - other: First up voted a post. + other: Lần đầu tiên báo cáo một bài viết. first_link: name: - other: First Link + other: Liên kết đầu tiên desc: - other: First dirst added a link to another post. + other: Đầu tiên, Dirst đã thêm một liên kết đến một bài viết khác. first_reaction: name: - other: First Reaction + other: Phản ứng đầu tiên desc: - other: First reacted to the post. + other: Phản ứng với bài viết đầu tiên. first_share: name: - other: First Share + other: Chia sẻ đầu tiên desc: - other: First shared a post. + other: Lần đầu chia sẻ một bài viết. scholar: name: - other: Scholar + other: Học giả desc: - other: Asked a question and accepted an answer. + other: Đặt một câu hỏi và chấp nhận một câu trả lời. commentator: name: - other: Commentator + other: Bình luận viên desc: - other: Leave 5 comments. + other: Để lại 5 bình luận. new_user_of_the_month: name: - other: New User of the Month + other: Người dùng mới của tháng desc: - other: Outstanding contributions in their first month. + other: Đóng góp nổi bật trong tháng đầu tiên của họ. read_guidelines: name: - other: Read Guidelines + other: Đọc hướng dẫn desc: - other: Read the [community guidelines]. + other: Đọc [nguyên tắc cộng đồng]. reader: name: - other: Reader + other: Người đọc desc: - other: Read every answers in a topic with more than 10 answers. + other: Đọc mọi câu trả lời trong một chủ đề có hơn 10 câu trả lời. welcome: name: - other: Welcome + other: Xin chào desc: - other: Received a up vote. + other: Đã nhận được phiếu tán thành. nice_share: name: - other: Nice Share + other: Chia sẻ hay desc: - other: Shared a post with 25 unique visitors. + other: Đã chia sẻ một bài đăng với 25 khách truy cập. good_share: name: - other: Good Share + other: Chia sẻ tốt desc: - other: Shared a post with 300 unique visitors. + other: Đã chia sẻ một bài đăng với 300 khách truy cập. great_share: name: - other: Great Share + other: Chia sẻ tuyệt vời desc: - other: Shared a post with 1000 unique visitors. + other: Đã chia sẻ một bài đăng với 1000 khách truy cập. out_of_love: name: - other: Out of Love + other: Hết yêu thích desc: - other: Used 50 up votes in a day. + other: Đã sử dụng 50 phiếu bầu trong một ngày. higher_love: name: - other: Higher Love + other: Thích cao hơn desc: - other: Used 50 up votes in a day 5 times. + other: Đã sử dụng 50 phiếu bầu trong một ngày. crazy_in_love: name: - other: Crazy in Love + other: Thích điên cuồng desc: - other: Used 50 up votes in a day 20 times. + other: Đã sử dụng 50 phiếu bầu trong một ngày 20 lần. promoter: name: - other: Promoter + other: Người quảng bá desc: - other: Invited a user. + other: Đã mời một người dùng. campaigner: name: - other: Campaigner + other: Chiến dịch desc: - other: Invited 3 basic users. + other: Đã mời 3 người dùng cơ bản. champion: name: - other: Champion + other: Vô địch desc: - other: Invited 5 members. + other: Mời 5 thành viên. thank_you: name: - other: Thank You + other: Cảm ơn bạn desc: - other: Has 20 up voted posts and gave 10 up votes. + other: Có 20 bài đăng được bình chọn đưa ra 10 phiếu bầu. gives_back: name: - other: Gives Back + other: Trả lại desc: - other: Has 100 up voted posts and gave 100 up votes. + other: Có 100 bài đăng được bình chọn và đưa ra 100 phiếu bầu. empathetic: name: - other: Empathetic + other: Đồng cảm desc: - other: Has 500 up voted posts and gave 1000 up votes. + other: Có 500 bài đăng được bình chọn đưa ra 1000 phiếu bầu. enthusiast: name: - other: Enthusiast + other: Người nhiệt thành desc: - other: Visited 10 consecutive days. + other: Đã truy cập 10 ngày liên tiếp. aficionado: name: - other: Aficionado + other: Người hâm mộ desc: - other: Visited 100 consecutive days. + other: Đã truy cập 100 ngày liên tiếp. devotee: name: - other: Devotee + other: Tín đồ desc: - other: Visited 365 consecutive days. + other: Đã truy cập 365 ngày liên tiếp. anniversary: name: - other: Anniversary + other: Kỉ niệm desc: - other: Active member for a year, posted at least once. + other: Thành viên tích cực trong một năm, đăng ít nhất một lần. appreciated: name: - other: Appreciated + other: Đánh giá cao desc: - other: Received 1 up vote on 20 posts. + other: Nhận được 1 lượt bình chọn cho 20 bài viết. respected: name: - other: Respected + other: Tôn trọng desc: - other: Received 2 up votes on 100 posts. + other: Nhận được 2 lượt bình chọn cho 100 bài viết. admired: name: - other: Admired + other: Ngưỡng mộ desc: - other: Received 5 up votes on 300 posts. + other: Nhận được 5 lượt bình chọn trên 300 bài đăng. solved: name: - other: Solved + other: Đã giải quyết desc: - other: Have an answer be accepted. + other: Có một câu trả lời được chấp nhận. guidance_counsellor: name: - other: Guidance Counsellor + other: Cố vấn hướng dẫn desc: - other: Have 10 answers be accepted. + other: Có 10 câu trả lời được chấp nhận. know_it_all: name: - other: Know-it-All + other: Biết tất cả desc: - other: Have 50 answers be accepted. + other: Có 50 câu trả lời được chấp nhận. solution_institution: name: - other: Solution Institution + other: Viện giải pháp desc: - other: Have 150 answers be accepted. + other: Có 150 câu trả lời được chấp nhận. nice_answer: name: - other: Nice Answer + other: Câu trả lời tốt desc: - other: Answer score of 10 or more. + other: Điểm trả lời từ 10 trở lên. good_answer: name: - other: Good Answer + other: Câu trả lời của bạn desc: - other: Answer score of 25 or more. + other: Điểm trả lời từ 25 trở lên. great_answer: name: - other: Great Answer + other: Câu trả lời tuyệt vời desc: - other: Answer score of 50 or more. + other: Điểm trả lời từ 50 trở lên. nice_question: name: - other: Nice Question + other: Câu trả lời tốt desc: - other: Question score of 10 or more. + other: Điểm trả lời từ 10 trở lên. good_question: name: - other: Good Question + other: Câu trả lời tốt desc: - other: Question score of 25 or more. + other: Điểm trả lời từ 25 trở lên. great_question: name: - other: Great Question + other: Câu trả lời tốt desc: - other: Question score of 50 or more. + other: Điểm trả lời từ 50 trở lên. popular_question: name: - other: Popular Question + other: Câu hỏi phổ biến desc: - other: Question with 500 views. + other: Câu hỏi với 500 lượt xem. notable_question: name: - other: Notable Question + other: Câu hỏi đáng chú ý desc: - other: Question with 1,000 views. + other: Câu hỏi với 1.000 lượt xem. famous_question: name: - other: Famous Question + other: Câu hỏi nổi tiếng desc: - other: Question with 5,000 views. + other: Câu hỏi với 5.000 lượt xem. popular_link: name: - other: Popular Link + other: Liên kết phổ biến desc: - other: Posted an external link with 50 clicks. + other: Đã đăng một liên kết bên ngoài với 50 lần nhấp chuột. hot_link: name: - other: Hot Link + other: Liên kết nổi bật desc: - other: Posted an external link with 300 clicks. + other: Đã đăng một liên kết bên ngoài với 300 lần nhấp chuột. famous_link: name: - other: Famous Link + other: Liên kết nổi tiếng desc: - other: Posted an external link with 100 clicks. + other: Đã đăng một liên kết bên ngoài với 100 lần nhấp chuột. default_badge_groups: getting_started: name: - other: Getting Started + other: Bắt đầu community: name: - other: Community + other: Cộng đồng posting: name: - other: Posting + other: Viết bài thảo luận # The following fields are used for interface presentation(Front-end) ui: how_to_format: title: Cách định dạng desc: >- -
  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: Trước next: Tiếp @@ -843,9 +836,9 @@ ui: posts: Bài đăng invites: Lời mời votes: Bình chọn - answer: Answer - question: Question - badge_award: Badge + answer: Câu trả lời + question: Câu hỏi + badge_award: Huy hiệu suspended: title: Tài khoản của bạn đã bị đình chỉ until_time: "Tài khoản của bạn đã bị đình chỉ cho đến {{ time }}." @@ -868,8 +861,8 @@ ui: gantt_chart: Biểu đồ Gantt pie_chart: Biểu đồ tròn code: - text: Mẫu mã - add_code: Thêm mẫu mã + text: Mẫu code + add_code: Thêm code mẫu form: fields: code: @@ -938,7 +931,7 @@ ui: form: fields: url: - label: URL + label: Đường link url msg: empty: URL không thể trống. name: @@ -1043,9 +1036,9 @@ ui: reaction: heart: trái tim smile: nụ cười - frown: khắc nghiệt - btn_label: thêm hoặc loại bỏ lại - undo_emoji: trở lại {{ emoji }} lặp lại + frown: nhăn mặt + btn_label: thêm hoặc loại bỏ phản ứng + undo_emoji: bỏ dấu {{ emoji }} phản ứng react_emoji: biểu cảm với {{ emoji }} unreact_emoji: hủy biểu cảm {{ emoji }} comment: @@ -1141,7 +1134,7 @@ ui: question: Câu hỏi tag: Thẻ user: Người dùng - badges: Badges + badges: Danh hiệu profile: Hồ sơ setting: Cài đặt logout: Đăng xuất @@ -1167,11 +1160,11 @@ ui: Bạn gần như đã hoàn tất! Chúng tôi đã gửi một email kích hoạt đến {{mail}}. Vui lòng làm theo hướng dẫn trong email để kích hoạt tài khoản của bạn. info: "Nếu không nhận được, hãy kiểm tra thư mục spam của bạn." another: >- - Chúng tôi đã gửi một email kích hoạt khác cho bạn tại {{mail}}. Có thể mất vài phút để nó đến; hãy chắc chắn kiểm tra thư mục spam của bạn. + Chúng tôi đã gửi một email kích hoạt khác cho bạn tại {{mail}}. Có thể mất vài phút để nó đến; hãy chắc chắn kiểm tra thư mục thư rác của bạn. btn_name: Gửi lại email kích hoạt change_btn_name: Thay đổi email msg: - empty: Không thể trống. + empty: Không thể để trống mục này. resend_email: url_label: Bạn có chắc chắn muốn gửi lại email kích hoạt không? url_text: Bạn cũng có thể cung cấp liên kết kích hoạt ở trên cho người dùng. @@ -1301,7 +1294,7 @@ ui: change_email_info: >- Chúng tôi đã gửi một email đến địa chỉ đó. Vui lòng làm theo hướng dẫn xác nhận. email: - label: Email mới + label: Email new_email: label: Email mới msg: Email mới không được để trống. @@ -1341,6 +1334,10 @@ ui: related_question: title: Các câu hỏi liên quan answers: câu trả lời + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: Mời mọi người desc: Mời những người bạn nghĩ có thể trả lời. @@ -1525,7 +1522,7 @@ ui: newest: Mới nhất active: Hoạt động hot: Được nhiều quan tâm - recommend: Recommend + recommend: Đề xuất score: Điểm unanswered: Chưa được trả lời modified: đã chỉnh sửa @@ -1544,7 +1541,7 @@ ui: reputation: Danh tiếng comments: Bình luận votes: Bình chọn - badges: Badges + badges: Danh hiệu newest: Mới nhất score: Điểm edit_profile: Chỉnh sửa hồ sơ @@ -1558,7 +1555,8 @@ ui: top_answers: Câu trả lời hàng đầu top_questions: Câu hỏi hàng đầu stats: Thống kê - list_empty: Không tìm thấy bài đăng.
Có thể bạn muốn chọn một tab khác? + list_empty: Không tìm thấy bài đăng.
Có thể bạn muốn chọn một thẻ khác? + content_empty: No posts found. accepted: Đã chấp nhận answered: đã trả lời asked: đã hỏi @@ -1569,7 +1567,7 @@ ui: x_votes: phiếu bầu nhận được x_answers: câu trả lời x_questions: câu hỏi - recent_badges: Recent Badges + recent_badges: Huy hiệu gần đây install: title: Cài đặt next: Tiếp theo @@ -1646,7 +1644,7 @@ ui: msg: empty: Email không thể trống. incorrect: Định dạng email không chính xác. - ready_title: Answer của bạn đã sẵn sàng + ready_title: Trang web của bạn đã sẵn sàng ready_desc: >- Nếu bạn cảm thấy muốn thay đổi thêm cài đặt nào đó, hãy truy cập <1>mục quản trị; tìm nó trong menu trang. good_luck: "Chúc bạn vui vẻ và may mắn!" @@ -1679,7 +1677,7 @@ ui: questions: Câu hỏi answers: Câu trả lời users: Người dùng - badges: Badges + badges: Huy hiệu flags: Cờ settings: Cài đặt general: Chung @@ -1696,7 +1694,7 @@ ui: css_html: CSS/HTML login: Đăng nhập privileges: Đặc quyền - plugins: Plugin + plugins: Plugins installed_plugins: Plugin đã cài đặt website_welcome: Chào mừng bạn đến với {{site_name}} user_center: @@ -1705,16 +1703,16 @@ ui: login_failed_email_tip: Đăng nhập thất bại, vui lòng cho phép ứng dụng này truy cập thông tin email của bạn trước khi thử lại. badges: modal: - title: Congratulations - content: You've earned a new badge. - close: Close - confirm: View badges - title: Badges - awarded: Awarded - earned_×: Earned ×{{ number }} - ×_awarded: "{{ number }} awarded" - can_earn_multiple: You can earn this multiple times. - earned: Earned + title: Chúc mừng + content: Bạn đã nhận được huy hiệu mới. + close: Đóng + confirm: Xem huy hiệu + title: Huy hiệu + awarded: Giải Thưởng + earned_×: Nhận được ×{{ number }} + ×_awarded: "{{ number }} được trao tặng" + can_earn_multiple: Bạn có thể kiếm được nhiều lần. + earned: Đã nhận admin: admin_header: title: Quản trị @@ -1774,7 +1772,7 @@ ui: flagged_type: Đã đánh dấu {{ type }} created: Đã tạo action: Hành động - review: Xem xét + review: Đánh giá user_role_modal: title: Thay đổi vai trò người dùng thành... btn_cancel: Hủy @@ -2013,7 +2011,7 @@ ui: seo: page_title: SEO permalink: - label: Permalink + label: Liên kết cố định text: Cấu trúc URL tùy chỉnh có thể cải thiện khả năng sử dụng và khả năng tương thích về sau của liên kết của bạn. robots: label: robots.txt @@ -2073,7 +2071,7 @@ ui: text: "CẢNH BÁO: Nếu tắt, bạn có thể không thể đăng nhập nếu bạn chưa cấu hình phương thức đăng nhập khác trước đó." installed_plugins: title: Plugin đã cài đặt - plugin_link: Plugin mở rộng và mở rộng chức năng của Answer. Bạn có thể tìm thấy plugin trong <1>Kho Plugin Answer. + plugin_link: Plugin mở rộng và mở rộng chức năng của trang web. Bạn có thể tìm thấy plugin trong <1>Kho Plugin Answer. filter: all: Tất cả active: Đang hoạt động @@ -2117,23 +2115,24 @@ ui: label: Mức độ danh tiếng yêu cầu text: Chọn mức danh tiếng yêu cầu cho các đặc quyền msg: - should_be_number: dữ liệu đầu vào phải là số + should_be_number: dữ liệu đầu vào phải là kiểu số number_larger_1: số phải bằng hoặc lớn hơn 1 badges: - action: Action - active: Active + action: Hành động + active: Hoạt động + activate: Kích hoạt activate: Activate - all: All - awards: Awards - deactivate: Deactivate + all: Tất cả + awards: Giải Thưởng + deactivate: Ngừng kích hoạt filter: - placeholder: Filter by name, badge:id - group: Group - inactive: Inactive - name: Name - show_logs: Show logs - status: Status - title: Badges + placeholder: Lọc theo tên, user:id + group: Nhóm + inactive: Không hoạt động + name: Tên + show_logs: Hiển thị nhật ký + status: Trạng thái + title: Danh hiệu form: optional: (tùy chọn) empty: không thể trống @@ -2190,7 +2189,7 @@ ui: title: "Lịch sử cho" tag_title: "Dòng thời gian cho" show_votes: "Hiển thị phiếu bầu" - n_or_a: Không có + n_or_a: N/A title_for_question: "Dòng thời gian cho" title_for_answer: "Dòng thời gian cho câu trả lời của {{ title }} bởi {{ author }}" title_for_tag: "Dòng thời gian cho thẻ" diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index f6777d89..3a0d56e8 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -326,9 +326,7 @@ backend: name: other: 粗鲁或辱骂的 desc: - other: - - 一个有理智的人都会认为这种内容不适合进行尊重性的讨论。 - - 论坛 + other: "一个有理智的人都会认为这种内容不适合进行尊重性的讨论。" a_duplicate: name: other: 重复内容 @@ -340,10 +338,7 @@ backend: name: other: 不是答案 desc: - other: - - 这张贴作为答案,但它不会试图回答 - - 这可能是一个编辑、一个评论、另一个问题。 - - 或全部删除。 + other: "该帖是作为答案发布的,但它并没有试图回答这个问题。总之,它可能应该是个编辑、评论、另一个问题或者需要被删除。" no_longer_needed: name: other: 不再需要 @@ -402,9 +397,7 @@ backend: name: other: 需要细节或澄清 desc: - other: - - 该问题目前涵盖多个问题。它应该侧重在一个问题上。 - - 只关注一个问题。 + other: 该问题目前涵盖多个问题。它应该只集中在一个问题上。 other: name: other: 其他原因 @@ -688,7 +681,7 @@ backend: name: other: 欣赏 desc: - other: 20个员额获得1次补票。 + other: 在 20 个帖子中获得 1个投票 respected: name: other: 尊敬 @@ -1185,7 +1178,7 @@ ui: label: 名字 msg: empty: 名字不能为空 - range: 名字应该在 2 到 30 个字符之间 + range: 名称长度必须在 2 至 30 个字符之间。 character: '只能由 "a-z"、"A-Z"、"0-9"、" - . _" 组成' email: label: 邮箱 @@ -1342,8 +1335,9 @@ ui: title: 相关问题 answers: 个回答 linked_question: - title: 关联问题 - no_linked_question: 没有关联的问题。 + title: 关联的问题 + description: 问题关联到 + no_linked_question: 这个问题没有相关联的问题。 invite_to_answer: title: 受邀人 desc: 邀请你认为可能知道答案的人。 diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index 32938f4d..bec0a0b3 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -326,9 +326,7 @@ backend: name: other: rude or abusive desc: - other: - - A reasonable person would find this content inappropriate for respectful - - discourse. + other: "A reasonable person would find this content inappropriate for respectful discourse." a_duplicate: name: other: a duplicate @@ -340,10 +338,7 @@ backend: name: other: not an answer desc: - other: - - This was posted as an answer, but it does not attempt to answer the - - question. It should possibly be an edit, a comment, another question, - - or deleted altogether. + other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." no_longer_needed: name: other: no longer needed @@ -402,9 +397,7 @@ backend: name: other: 需要細節或明晰 desc: - other: - - This question currently includes multiple questions in one. It should - - focus on one problem only. + other: This question currently includes multiple questions in one. It should focus on one problem only. other: name: other: 其他原因 @@ -794,7 +787,7 @@ ui: how_to_format: title: 如何設定文本格式 desc: >- -
  • 加入連結:

    <https://url.com>

    [Title](https://url.com)
  • 段落之間使用回车

  • _斜體_ 或者 **粗體**

  • 使用 4 個空格縮排代碼

  • 在行首加入>表示引用

  • 反引號進行轉義 `像 _這樣_`

  • 使用反引號創建代碼柵欄`

    ```
    這是程式碼
    ```
+
  • link question or answer: #10010000000000001

  • to make links

    <https://url.com>

    [Title](https://url.com)
  • put returns between paragraphs

  • _italic_ or **bold**

  • indent code by 4 spaces

  • quote by placing > at start of line

  • backtick escapes `like _this_`

  • create code fences with backticks `

    ```
    code here
    ```
pagination: prev: 上一頁 next: 下一頁 @@ -1341,6 +1334,10 @@ ui: related_question: title: 相關問題 answers: 個回答 + linked_question: + title: Linked Questions + description: Questions linked to + no_linked_question: No questions linked from this question. invite_to_answer: title: People Asked desc: Invite people who you think might know the answer. @@ -1559,6 +1556,7 @@ ui: top_questions: 熱門問題 stats: 狀態 list_empty: 沒有找到相關的內容。
試試看其他標籤? + content_empty: No posts found. accepted: 已採納 answered: 回答於 asked: 提問於 From 1a21cd0756a740e05e798995b30af4d0b3e2bdc3 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:39:32 +0800 Subject: [PATCH 282/336] docs(i18n): update translation progress --- i18n/i18n.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/i18n/i18n.yaml b/i18n/i18n.yaml index 190ac0bf..ae7650e5 100644 --- a/i18n/i18n.yaml +++ b/i18n/i18n.yaml @@ -22,43 +22,43 @@ language_options: progress: 100 - label: "Español" value: "es_ES" - progress: 64 + progress: 83 - label: "Português(BR)" value: "pt_BR" - progress: 12 + progress: 96 - label: "Português" value: "pt_PT" - progress: 12 + progress: 96 - label: "Deutsch" value: "de_DE" - progress: 69 + progress: 83 - label: "Français" value: "fr_FR" - progress: 70 + progress: 78 - label: "日本語" value: "ja_JP" - progress: 12 + progress: 11 - label: "Italiano" value: "it_IT" - progress: 9 + progress: 89 - label: "Русский" value: "ru_RU" - progress: 20 + progress: 80 - label: "简体中文" value: "zh_CN" progress: 100 - label: "繁體中文" value: "zh_TW" - progress: 64 + progress: 47 - label: "한국어" value: "ko_KR" - progress: 0 + progress: 84 - label: "Tiếng Việt" value: "vi_VN" - progress: 0 + progress: 96 - label: "Slovak" value: "sk_SK" - progress: 62 + progress: 45 - label: "فارسی" value: "fa_IR" - progress: 85 + progress: 69 From e6cafaaa5c2330896f49f0bad3b94a47412aa5c8 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:44:07 +0800 Subject: [PATCH 283/336] docs(i18n): update translation --- i18n/pt_PT.yaml | 1 - i18n/sv_SE.yaml | 1 - i18n/vi_VN.yaml | 1 - 3 files changed, 3 deletions(-) diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index 5c21779e..670fc83f 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -2121,7 +2121,6 @@ ui: action: Ação active: Ativo activate: Ativado - activate: Activate all: Todos awards: Prêmios deactivate: Desativar diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index b6c5e90e..93dbb962 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -2121,7 +2121,6 @@ ui: action: Action active: Aktiv activate: Aktivera - activate: Activate all: Alla awards: Awards deactivate: Inaktivera diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 044817fa..495d9333 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -2121,7 +2121,6 @@ ui: action: Hành động active: Hoạt động activate: Kích hoạt - activate: Activate all: Tất cả awards: Giải Thưởng deactivate: Ngừng kích hoạt From cea87404e36b7e858ab85085198e4794149d7579 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:39:32 +0800 Subject: [PATCH 284/336] docs(i18n): update translation progress --- i18n/i18n.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/i18n/i18n.yaml b/i18n/i18n.yaml index 190ac0bf..ae7650e5 100644 --- a/i18n/i18n.yaml +++ b/i18n/i18n.yaml @@ -22,43 +22,43 @@ language_options: progress: 100 - label: "Español" value: "es_ES" - progress: 64 + progress: 83 - label: "Português(BR)" value: "pt_BR" - progress: 12 + progress: 96 - label: "Português" value: "pt_PT" - progress: 12 + progress: 96 - label: "Deutsch" value: "de_DE" - progress: 69 + progress: 83 - label: "Français" value: "fr_FR" - progress: 70 + progress: 78 - label: "日本語" value: "ja_JP" - progress: 12 + progress: 11 - label: "Italiano" value: "it_IT" - progress: 9 + progress: 89 - label: "Русский" value: "ru_RU" - progress: 20 + progress: 80 - label: "简体中文" value: "zh_CN" progress: 100 - label: "繁體中文" value: "zh_TW" - progress: 64 + progress: 47 - label: "한국어" value: "ko_KR" - progress: 0 + progress: 84 - label: "Tiếng Việt" value: "vi_VN" - progress: 0 + progress: 96 - label: "Slovak" value: "sk_SK" - progress: 62 + progress: 45 - label: "فارسی" value: "fa_IR" - progress: 85 + progress: 69 From f35561ff595a4787a509a0665a9efdc8271e3ba3 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 15:44:07 +0800 Subject: [PATCH 285/336] docs(i18n): update translation --- i18n/pt_PT.yaml | 1 - i18n/sv_SE.yaml | 1 - i18n/vi_VN.yaml | 1 - 3 files changed, 3 deletions(-) diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index 5c21779e..670fc83f 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -2121,7 +2121,6 @@ ui: action: Ação active: Ativo activate: Ativado - activate: Activate all: Todos awards: Prêmios deactivate: Desativar diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index b6c5e90e..93dbb962 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -2121,7 +2121,6 @@ ui: action: Action active: Aktiv activate: Aktivera - activate: Activate all: Alla awards: Awards deactivate: Inaktivera diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 044817fa..495d9333 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -2121,7 +2121,6 @@ ui: action: Hành động active: Hoạt động activate: Kích hoạt - activate: Activate all: Tất cả awards: Giải Thưởng deactivate: Ngừng kích hoạt From b9402e6283bd49a2f5ba955f35ef6b49b0e184f2 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 18:46:58 +0800 Subject: [PATCH 286/336] ci(gorelease): Upgrade Goreleaser version to 2 and update snapshot version template --- .github/workflows/build-binary-for-release.yml | 2 +- .goreleaser.yaml | 4 +++- script/plugin_list | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-binary-for-release.yml b/.github/workflows/build-binary-for-release.yml index 7075db8f..0356f97f 100644 --- a/.github/workflows/build-binary-for-release.yml +++ b/.github/workflows/build-binary-for-release.yml @@ -44,7 +44,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.22 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v4 with: diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 457674e9..d2869147 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +version: 2 + env: - GO11MODULE=on - GO111MODULE=on @@ -69,7 +71,7 @@ archives: checksum: name_template: 'checksums.txt' snapshot: - name_template: "{{ incpatch .Version }}" + version_template: "{{ incpatch .Version }}" changelog: sort: asc filters: diff --git a/script/plugin_list b/script/plugin_list index 67ba306f..9ebe8fd8 100644 --- a/script/plugin_list +++ b/script/plugin_list @@ -1,3 +1,6 @@ github.com/apache/incubator-answer-plugins/connector-basic@latest github.com/apache/incubator-answer-plugins/reviewer-basic@latest -github.com/apache/incubator-answer-plugins/captcha-basic@latest \ No newline at end of file +github.com/apache/incubator-answer-plugins/captcha-basic@latest +github.com/apache/incubator-answer-plugins/render-markdown-codehighlight@latest +github.com/apache/incubator-answer-plugins/embed-basic@latest +github.com/apache/incubator-answer-plugins/search-algolia@latest \ No newline at end of file From 962221be3bfb19b7f142bd487316313be6a2cae3 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 22 Oct 2024 18:46:58 +0800 Subject: [PATCH 287/336] ci(gorelease): Upgrade Goreleaser version to 2 and update snapshot version template --- .github/workflows/build-binary-for-release.yml | 2 +- .goreleaser.yaml | 4 +++- script/plugin_list | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-binary-for-release.yml b/.github/workflows/build-binary-for-release.yml index 7075db8f..0356f97f 100644 --- a/.github/workflows/build-binary-for-release.yml +++ b/.github/workflows/build-binary-for-release.yml @@ -44,7 +44,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.22 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v4 with: diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 457674e9..d2869147 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +version: 2 + env: - GO11MODULE=on - GO111MODULE=on @@ -69,7 +71,7 @@ archives: checksum: name_template: 'checksums.txt' snapshot: - name_template: "{{ incpatch .Version }}" + version_template: "{{ incpatch .Version }}" changelog: sort: asc filters: diff --git a/script/plugin_list b/script/plugin_list index 67ba306f..9ebe8fd8 100644 --- a/script/plugin_list +++ b/script/plugin_list @@ -1,3 +1,6 @@ github.com/apache/incubator-answer-plugins/connector-basic@latest github.com/apache/incubator-answer-plugins/reviewer-basic@latest -github.com/apache/incubator-answer-plugins/captcha-basic@latest \ No newline at end of file +github.com/apache/incubator-answer-plugins/captcha-basic@latest +github.com/apache/incubator-answer-plugins/render-markdown-codehighlight@latest +github.com/apache/incubator-answer-plugins/embed-basic@latest +github.com/apache/incubator-answer-plugins/search-algolia@latest \ No newline at end of file From 8affa9fabef0de8470e7cc39606bd94c143f4e73 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 23 Oct 2024 10:40:29 +0800 Subject: [PATCH 288/336] ci(plugin): make default plugin list --- script/plugin_list | 3 --- 1 file changed, 3 deletions(-) diff --git a/script/plugin_list b/script/plugin_list index 9ebe8fd8..88c23994 100644 --- a/script/plugin_list +++ b/script/plugin_list @@ -1,6 +1,3 @@ github.com/apache/incubator-answer-plugins/connector-basic@latest github.com/apache/incubator-answer-plugins/reviewer-basic@latest github.com/apache/incubator-answer-plugins/captcha-basic@latest -github.com/apache/incubator-answer-plugins/render-markdown-codehighlight@latest -github.com/apache/incubator-answer-plugins/embed-basic@latest -github.com/apache/incubator-answer-plugins/search-algolia@latest \ No newline at end of file From eeb79b3ab59fe3f4721a19a06c832bf322be32c8 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Thu, 24 Oct 2024 09:59:18 +0800 Subject: [PATCH 289/336] fix: missing js-sha256 license --- docs/release/LICENSE | 6 ++--- ...codemirror5.txt => LICENSE-codemirror.txt} | 2 +- .../licenses/LICENSE-emn178-js-sha256.txt | 22 +++++++++++++++ ...ter.txt => LICENSE-jxson-front-matter.txt} | 0 .../licenses/LICENSE-pvorb-node-md5.txt | 27 ------------------- 5 files changed, 26 insertions(+), 31 deletions(-) rename docs/release/licenses/{LICENSE-codemirror-codemirror5.txt => LICENSE-codemirror.txt} (93%) create mode 100644 docs/release/licenses/LICENSE-emn178-js-sha256.txt rename docs/release/licenses/{LICENSE-front-matter.txt => LICENSE-jxson-front-matter.txt} (100%) delete mode 100644 docs/release/licenses/LICENSE-pvorb-node-md5.txt diff --git a/docs/release/LICENSE b/docs/release/LICENSE index 65e5642d..40507a28 100644 --- a/docs/release/LICENSE +++ b/docs/release/LICENSE @@ -231,7 +231,7 @@ The following components are provided under the MIT License. See project link fo (MIT License) bootstrap (https://github.com/twbs/bootstrap) [link](./licenses/LICENSE-twbs-bootstrap.txt) (MIT License) icons (https://github.com/twbs/icons) [link](./licenses/LICENSE-twbs-icons.txt) (MIT License) classnames (https://github.com/JedWatson/classnames) [link](./LICENSE-JedWatson-classnames.txt) - (MIT License) codemirror5 (https://github.com/codemirror/codemirror5) [link](./licenses/LICENSE-codemirror-codemirror5.txt) + (MIT License) codemirror (https://github.com/codemirror/basic-setup) [link](./licenses/LICENSE-codemirror.txt) (MIT License) color (https://github.com/Qix-/color) [link](./licenses/LICENSE-Qix--color.txt) (MIT License) copy-to-clipboard (https://github.com/sudodoki/copy-to-clipboard) [link](./licenses/LICENSE-sudodoki-copy-to-clipboard.txt) (MIT License) dayjs (https://github.com/iamkun/dayjs) [link](./licenses/LICENSE-iamkun-dayjs.txt) @@ -272,7 +272,8 @@ The following components are provided under the MIT License. See project link fo (MIT License) tidwall-gjson (https://github.com/tidwall/gjson) [link](./licenses/LICENSE-tidwall-gjson.txt) (MIT License) yuin-goldmark (https://github.com/yuin/goldmark) [link](./licenses/LICENSE-yuin-goldmark.txt) (MIT License) go-gomail-gomail (https://gopkg.in/gomail.v2) [link](./licenses/LICENSE-go-gomail-gomail.txt) - (MIT License) front-matter (https://github.com/jxson/front-matter) [link](./licenses/LICENSE-front-matter.txt) + (MIT License) front-matter (https://github.com/jxson/front-matter) [link](./licenses/LICENSE-jxson-front-matter.txt) + (MIT License) js-sha256 (https://github.com/emn178/js-sha256) [link](./licenses/LICENSE-emn178-js-sha256.txt) ======================================================================== BSD licenses @@ -287,7 +288,6 @@ The following components are provided under a BSD license. See project link for (BSD 3-Clause) microcosm-cc-bluemonday (https://github.com/microcosm-cc/bluemonday) [link](./licenses/LICENSE-microcosm-cc-bluemonday.txt) (BSD 3-Clause) cznic-sqlite (https://modernc.org/sqlite) [link](./licenses/LICENSE-cznic-sqlite.txt) (BSD 3-Clause) jsdiff (https://github.com/kpdecker/jsdiff) [link](./licenses/LICENSE-kpdecker-jsdiff.txt) - (BSD 3-Clause) node-md5 (https://github.com/pvorb/node-md5) [link](./licenses/LICENSE-pvorb-node-md5.txt) (BSD 3-Clause) qs (https://github.com/ljharb/qs) [link](./licenses/LICENSE-ljharb-qs.txt) ======================================================================== diff --git a/docs/release/licenses/LICENSE-codemirror-codemirror5.txt b/docs/release/licenses/LICENSE-codemirror.txt similarity index 93% rename from docs/release/licenses/LICENSE-codemirror-codemirror5.txt rename to docs/release/licenses/LICENSE-codemirror.txt index 9018d33e..3af12e62 100644 --- a/docs/release/licenses/LICENSE-codemirror-codemirror5.txt +++ b/docs/release/licenses/LICENSE-codemirror.txt @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2017 by Marijn Haverbeke and others +Copyright (C) 2018-2021 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/release/licenses/LICENSE-emn178-js-sha256.txt b/docs/release/licenses/LICENSE-emn178-js-sha256.txt new file mode 100644 index 00000000..dd24c236 --- /dev/null +++ b/docs/release/licenses/LICENSE-emn178-js-sha256.txt @@ -0,0 +1,22 @@ +Copyright (c) 2014-2024 Chen, Yi-Cyuan + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docs/release/licenses/LICENSE-front-matter.txt b/docs/release/licenses/LICENSE-jxson-front-matter.txt similarity index 100% rename from docs/release/licenses/LICENSE-front-matter.txt rename to docs/release/licenses/LICENSE-jxson-front-matter.txt diff --git a/docs/release/licenses/LICENSE-pvorb-node-md5.txt b/docs/release/licenses/LICENSE-pvorb-node-md5.txt deleted file mode 100644 index f476d11e..00000000 --- a/docs/release/licenses/LICENSE-pvorb-node-md5.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright © 2011-2012, Paul Vorbach. -Copyright © 2009, Jeff Mott. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. -* Neither the name Crypto-JS nor the names of its contributors may be used to - endorse or promote products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 8cff85b7addf367c21a4d84df1e85da02661d445 Mon Sep 17 00:00:00 2001 From: shuai Date: Thu, 24 Oct 2024 10:00:47 +0800 Subject: [PATCH 290/336] docs: update license files --- docs/release/LICENSE | 8 ++++-- ...txt => LICENSE-codemirror-basic-setup.txt} | 2 +- .../LICENSE-codemirror-lang-markdown.txt | 21 +++++++++++++++ .../LICENSE-codemirror-language-data.txt | 21 +++++++++++++++ .../licenses/LICENSE-codemirror-state.txt | 21 +++++++++++++++ .../licenses/LICENSE-codemirror-view.txt | 21 +++++++++++++++ .../licenses/LICENSE-emn178-js-sha256.txt | 22 +++++++++++++++ .../licenses/LICENSE-pvorb-node-md5.txt | 27 ------------------- 8 files changed, 113 insertions(+), 30 deletions(-) rename docs/release/licenses/{LICENSE-codemirror-codemirror5.txt => LICENSE-codemirror-basic-setup.txt} (92%) create mode 100644 docs/release/licenses/LICENSE-codemirror-lang-markdown.txt create mode 100644 docs/release/licenses/LICENSE-codemirror-language-data.txt create mode 100644 docs/release/licenses/LICENSE-codemirror-state.txt create mode 100644 docs/release/licenses/LICENSE-codemirror-view.txt create mode 100644 docs/release/licenses/LICENSE-emn178-js-sha256.txt delete mode 100644 docs/release/licenses/LICENSE-pvorb-node-md5.txt diff --git a/docs/release/LICENSE b/docs/release/LICENSE index 65e5642d..cb4b4e16 100644 --- a/docs/release/LICENSE +++ b/docs/release/LICENSE @@ -231,7 +231,11 @@ The following components are provided under the MIT License. See project link fo (MIT License) bootstrap (https://github.com/twbs/bootstrap) [link](./licenses/LICENSE-twbs-bootstrap.txt) (MIT License) icons (https://github.com/twbs/icons) [link](./licenses/LICENSE-twbs-icons.txt) (MIT License) classnames (https://github.com/JedWatson/classnames) [link](./LICENSE-JedWatson-classnames.txt) - (MIT License) codemirror5 (https://github.com/codemirror/codemirror5) [link](./licenses/LICENSE-codemirror-codemirror5.txt) + (MIT License) codemirror (https://github.com/codemirror/basic-setup) [link](./licenses/LICENSE-codemirror-basic-setup.txt) + (MIT License) @codemirror/lang-markdown (https://github.com/codemirror/lang-markdown) [link](./licenses/LICENSE-codemirror-lang-markdown.txt) + (MIT License) @codemirror/language-data (https://github.com/codemirror/language-data) [link](./licenses/LICENSE-codemirror-language-data.txt) + (MIT License) @codemirror/state (https://github.com/codemirror/state) [link](./licenses/LICENSE-codemirror-state.txt) + (MIT License) @codemirror/view (https://github.com/codemirror/view) [link](./licenses/LICENSE-codemirror-view.txt) (MIT License) color (https://github.com/Qix-/color) [link](./licenses/LICENSE-Qix--color.txt) (MIT License) copy-to-clipboard (https://github.com/sudodoki/copy-to-clipboard) [link](./licenses/LICENSE-sudodoki-copy-to-clipboard.txt) (MIT License) dayjs (https://github.com/iamkun/dayjs) [link](./licenses/LICENSE-iamkun-dayjs.txt) @@ -273,6 +277,7 @@ The following components are provided under the MIT License. See project link fo (MIT License) yuin-goldmark (https://github.com/yuin/goldmark) [link](./licenses/LICENSE-yuin-goldmark.txt) (MIT License) go-gomail-gomail (https://gopkg.in/gomail.v2) [link](./licenses/LICENSE-go-gomail-gomail.txt) (MIT License) front-matter (https://github.com/jxson/front-matter) [link](./licenses/LICENSE-front-matter.txt) + (MIT License) js-sha256 (https://github.com/emn178/js-sha256) [link](./licenses/LICENSE-emn178-js-sha256.txt) ======================================================================== BSD licenses @@ -287,7 +292,6 @@ The following components are provided under a BSD license. See project link for (BSD 3-Clause) microcosm-cc-bluemonday (https://github.com/microcosm-cc/bluemonday) [link](./licenses/LICENSE-microcosm-cc-bluemonday.txt) (BSD 3-Clause) cznic-sqlite (https://modernc.org/sqlite) [link](./licenses/LICENSE-cznic-sqlite.txt) (BSD 3-Clause) jsdiff (https://github.com/kpdecker/jsdiff) [link](./licenses/LICENSE-kpdecker-jsdiff.txt) - (BSD 3-Clause) node-md5 (https://github.com/pvorb/node-md5) [link](./licenses/LICENSE-pvorb-node-md5.txt) (BSD 3-Clause) qs (https://github.com/ljharb/qs) [link](./licenses/LICENSE-ljharb-qs.txt) ======================================================================== diff --git a/docs/release/licenses/LICENSE-codemirror-codemirror5.txt b/docs/release/licenses/LICENSE-codemirror-basic-setup.txt similarity index 92% rename from docs/release/licenses/LICENSE-codemirror-codemirror5.txt rename to docs/release/licenses/LICENSE-codemirror-basic-setup.txt index 9018d33e..9a91f486 100644 --- a/docs/release/licenses/LICENSE-codemirror-codemirror5.txt +++ b/docs/release/licenses/LICENSE-codemirror-basic-setup.txt @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2017 by Marijn Haverbeke and others +Copyright (C) 2018-2021 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/release/licenses/LICENSE-codemirror-lang-markdown.txt b/docs/release/licenses/LICENSE-codemirror-lang-markdown.txt new file mode 100644 index 00000000..9a91f486 --- /dev/null +++ b/docs/release/licenses/LICENSE-codemirror-lang-markdown.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/docs/release/licenses/LICENSE-codemirror-language-data.txt b/docs/release/licenses/LICENSE-codemirror-language-data.txt new file mode 100644 index 00000000..9a91f486 --- /dev/null +++ b/docs/release/licenses/LICENSE-codemirror-language-data.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/docs/release/licenses/LICENSE-codemirror-state.txt b/docs/release/licenses/LICENSE-codemirror-state.txt new file mode 100644 index 00000000..9a91f486 --- /dev/null +++ b/docs/release/licenses/LICENSE-codemirror-state.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/docs/release/licenses/LICENSE-codemirror-view.txt b/docs/release/licenses/LICENSE-codemirror-view.txt new file mode 100644 index 00000000..9a91f486 --- /dev/null +++ b/docs/release/licenses/LICENSE-codemirror-view.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2018-2021 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/docs/release/licenses/LICENSE-emn178-js-sha256.txt b/docs/release/licenses/LICENSE-emn178-js-sha256.txt new file mode 100644 index 00000000..dd24c236 --- /dev/null +++ b/docs/release/licenses/LICENSE-emn178-js-sha256.txt @@ -0,0 +1,22 @@ +Copyright (c) 2014-2024 Chen, Yi-Cyuan + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docs/release/licenses/LICENSE-pvorb-node-md5.txt b/docs/release/licenses/LICENSE-pvorb-node-md5.txt deleted file mode 100644 index f476d11e..00000000 --- a/docs/release/licenses/LICENSE-pvorb-node-md5.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright © 2011-2012, Paul Vorbach. -Copyright © 2009, Jeff Mott. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. -* Neither the name Crypto-JS nor the names of its contributors may be used to - endorse or promote products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 8e3ce7d32e30993151a21240c0bf929143d59c6e Mon Sep 17 00:00:00 2001 From: shuai Date: Thu, 24 Oct 2024 10:15:41 +0800 Subject: [PATCH 291/336] docs: rename codemirror license file name --- docs/release/licenses/LICENSE-codemirror.txt | 21 -------------------- 1 file changed, 21 deletions(-) delete mode 100644 docs/release/licenses/LICENSE-codemirror.txt diff --git a/docs/release/licenses/LICENSE-codemirror.txt b/docs/release/licenses/LICENSE-codemirror.txt deleted file mode 100644 index 9a91f486..00000000 --- a/docs/release/licenses/LICENSE-codemirror.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (C) 2018-2021 by Marijn Haverbeke and others - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. From 350db91dd2d9c8a0aad8be28955b117205d44c44 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 6 Nov 2024 11:37:06 +0800 Subject: [PATCH 292/336] fix: fixed project initialization not allowing access to the plug-in interface, causing the page to continue loading #1162 --- ui/src/utils/pluginKit/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index 346c1456..a71a9539 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -56,7 +56,8 @@ class Plugins { async init() { this.registerBuiltin(); - const plugins = await getPluginsStatus().catch(() => []); + // Note: The /install stage does not allow access to the getPluginsStatus api, so an initial value needs to be given + const plugins = (await getPluginsStatus().catch(() => [])) || []; this.registeredPlugins = plugins.filter((p) => p.enabled); await this.registerPlugins(); } @@ -169,6 +170,7 @@ const validateRoutePlugin = async (slugName) => { const mergeRoutePlugins = async (routes) => { const routePlugins = await getRoutePlugins(); + console.log('routePlugins', routePlugins); if (routePlugins.length === 0) { return routes; } From c2ad8c641cf40f28d86e28729d7a60881053b6c7 Mon Sep 17 00:00:00 2001 From: shuai Date: Wed, 6 Nov 2024 11:40:31 +0800 Subject: [PATCH 293/336] fix: delete unused log --- ui/src/utils/pluginKit/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/utils/pluginKit/index.ts b/ui/src/utils/pluginKit/index.ts index a71a9539..0219da3f 100644 --- a/ui/src/utils/pluginKit/index.ts +++ b/ui/src/utils/pluginKit/index.ts @@ -170,7 +170,6 @@ const validateRoutePlugin = async (slugName) => { const mergeRoutePlugins = async (routes) => { const routePlugins = await getRoutePlugins(); - console.log('routePlugins', routePlugins); if (routePlugins.length === 0) { return routes; } From 5f468c6f054ac096cb1fc31fa5acfbdb8b730c75 Mon Sep 17 00:00:00 2001 From: Sonui Date: Sat, 26 Oct 2024 18:21:14 +0800 Subject: [PATCH 294/336] perf: optimize tag has new tag check --- internal/service/tag_common/tag_common.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index 8010b5cd..71638e18 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -290,24 +290,18 @@ func (ts *TagCommonService) ExistRecommend(ctx context.Context, tags []*schema.T func (ts *TagCommonService) HasNewTag(ctx context.Context, tags []*schema.TagItem) (bool, error) { tagNames := make([]string, 0) - tagMap := make(map[string]bool) + tagMap := make(map[string]struct{}) for _, item := range tags { item.SlugName = strings.ReplaceAll(item.SlugName, " ", "-") tagNames = append(tagNames, item.SlugName) - tagMap[item.SlugName] = false + tagMap[item.SlugName] = struct{}{} } list, err := ts.GetTagListByNames(ctx, tagNames) if err != nil { return true, err } for _, item := range list { - _, ok := tagMap[item.SlugName] - if ok { - tagMap[item.SlugName] = true - } - } - for _, has := range tagMap { - if !has { + if _, ok := tagMap[item.SlugName]; !ok { return true, nil } } From ad6387126a890b3e08235a0800f8a2a9cc7cc223 Mon Sep 17 00:00:00 2001 From: Sonui Date: Sun, 27 Oct 2024 13:30:49 +0800 Subject: [PATCH 295/336] fix: add status filter when update tag rel --- internal/repo/tag/tag_rel_repo.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/repo/tag/tag_rel_repo.go b/internal/repo/tag/tag_rel_repo.go index 70187f54..08cff9d1 100644 --- a/internal/repo/tag/tag_rel_repo.go +++ b/internal/repo/tag/tag_rel_repo.go @@ -21,6 +21,7 @@ package tag import ( "context" + "github.com/apache/incubator-answer/internal/base/data" "github.com/apache/incubator-answer/internal/base/handler" "github.com/apache/incubator-answer/internal/base/reason" @@ -85,7 +86,7 @@ func (tr *tagRelRepo) RecoverTagRelListByObjectID(ctx context.Context, objectID func (tr *tagRelRepo) HideTagRelListByObjectID(ctx context.Context, objectID string) (err error) { objectID = uid.DeShortID(objectID) - _, err = tr.data.DB.Context(ctx).Where("object_id = ?", objectID).Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusHide}) + _, err = tr.data.DB.Context(ctx).Where("object_id = ?", objectID).And("status = ?", entity.TagRelStatusAvailable).Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusHide}) if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -94,7 +95,7 @@ func (tr *tagRelRepo) HideTagRelListByObjectID(ctx context.Context, objectID str func (tr *tagRelRepo) ShowTagRelListByObjectID(ctx context.Context, objectID string) (err error) { objectID = uid.DeShortID(objectID) - _, err = tr.data.DB.Context(ctx).Where("object_id = ?", objectID).Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusAvailable}) + _, err = tr.data.DB.Context(ctx).Where("object_id = ?", objectID).And("status = ?", entity.TagRelStatusHide).Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusAvailable}) if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } From 5546bb55ea683927c2d3f51977a0da2d741d2734 Mon Sep 17 00:00:00 2001 From: Sonui Date: Sun, 27 Oct 2024 13:34:13 +0800 Subject: [PATCH 296/336] fix: wrong status when enable tag rel --- internal/repo/repo_test/tag_rel_repo_test.go | 2 +- internal/repo/tag/tag_rel_repo.go | 21 ++++++++++++++++-- internal/service/tag_common/tag_common.go | 23 ++++++++++++-------- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/internal/repo/repo_test/tag_rel_repo_test.go b/internal/repo/repo_test/tag_rel_repo_test.go index f3696590..1cc96319 100644 --- a/internal/repo/repo_test/tag_rel_repo_test.go +++ b/internal/repo/repo_test/tag_rel_repo_test.go @@ -104,7 +104,7 @@ func Test_tagListRepo_GetObjectTagRelWithoutStatus(t *testing.T) { assert.NoError(t, err) assert.True(t, exist) - err = tagRelRepo.EnableTagRelByIDs(context.TODO(), ids) + err = tagRelRepo.EnableTagRelByIDs(context.TODO(), ids, false) assert.NoError(t, err) count, err = tagRelRepo.CountTagRelByTagID(context.TODO(), "10030000000000101") diff --git a/internal/repo/tag/tag_rel_repo.go b/internal/repo/tag/tag_rel_repo.go index 08cff9d1..3188295c 100644 --- a/internal/repo/tag/tag_rel_repo.go +++ b/internal/repo/tag/tag_rel_repo.go @@ -130,8 +130,12 @@ func (tr *tagRelRepo) GetObjectTagRelWithoutStatus(ctx context.Context, objectID } // EnableTagRelByIDs update tag status to available -func (tr *tagRelRepo) EnableTagRelByIDs(ctx context.Context, ids []int64) (err error) { - _, err = tr.data.DB.Context(ctx).In("id", ids).Update(&entity.TagRel{Status: entity.TagRelStatusAvailable}) +func (tr *tagRelRepo) EnableTagRelByIDs(ctx context.Context, ids []int64, hide bool) (err error) { + status := entity.TagRelStatusAvailable + if hide { + status = entity.TagRelStatusHide + } + _, err = tr.data.DB.Context(ctx).In("id", ids).Update(&entity.TagRel{Status: status}) if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -186,3 +190,16 @@ func (tr *tagRelRepo) CountTagRelByTagID(ctx context.Context, tagID string) (cou } return } + +// GetTagRelDefaultStatusByObjectID get tag rel default status +func (tr *tagRelRepo) GetTagRelDefaultStatusByObjectID(ctx context.Context, objectID string) (status int, err error) { + question := entity.Question{} + exist, err := tr.data.DB.Context(ctx).ID(objectID).Cols("show", "status").Get(&question) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + if exist && (question.Show == entity.QuestionHide || question.Status == entity.QuestionStatusDeleted) { + return entity.TagRelStatusHide, nil + } + return entity.TagRelStatusAvailable, nil +} diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index 71638e18..ec11fe45 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -71,11 +71,12 @@ type TagRelRepo interface { ShowTagRelListByObjectID(ctx context.Context, objectID string) (err error) HideTagRelListByObjectID(ctx context.Context, objectID string) (err error) RemoveTagRelListByIDs(ctx context.Context, ids []int64) (err error) - EnableTagRelByIDs(ctx context.Context, ids []int64) (err error) + EnableTagRelByIDs(ctx context.Context, ids []int64, hide bool) (err error) GetObjectTagRelWithoutStatus(ctx context.Context, objectId, tagID string) (tagRel *entity.TagRel, exist bool, err error) GetObjectTagRelList(ctx context.Context, objectId string) (tagListList []*entity.TagRel, err error) BatchGetObjectTagRelList(ctx context.Context, objectIds []string) (tagListList []*entity.TagRel, err error) CountTagRelByTagID(ctx context.Context, tagID string) (count int64, err error) + GetTagRelDefaultStatusByObjectID(ctx context.Context, objectID string) (status int, err error) } // TagCommonService user service @@ -762,10 +763,9 @@ func (ts *TagCommonService) ShowTagRelListByObjectID(ctx context.Context, object // CreateOrUpdateTagRelList if tag relation is exists update status, if not create it func (ts *TagCommonService) CreateOrUpdateTagRelList(ctx context.Context, objectId string, tagIDs []string) (err error) { - addTagIDMapping := make(map[string]bool) - needRefreshTagIDs := make([]string, 0) + addTagIDMapping := make(map[string]struct{}) for _, t := range tagIDs { - addTagIDMapping[t] = true + addTagIDMapping[t] = struct{}{} } // get all old relation @@ -774,8 +774,10 @@ func (ts *TagCommonService) CreateOrUpdateTagRelList(ctx context.Context, object return err } var deleteTagRel []int64 + needRefreshTagIDs := make([]string, 0, len(oldTagRelList)+len(tagIDs)) + needRefreshTagIDs = append(needRefreshTagIDs, tagIDs...) for _, rel := range oldTagRelList { - if !addTagIDMapping[rel.TagID] { + if _, ok := addTagIDMapping[rel.TagID]; !ok { deleteTagRel = append(deleteTagRel, rel.ID) needRefreshTagIDs = append(needRefreshTagIDs, rel.TagID) } @@ -783,8 +785,11 @@ func (ts *TagCommonService) CreateOrUpdateTagRelList(ctx context.Context, object addTagRelList := make([]*entity.TagRel, 0) enableTagRelList := make([]int64, 0) + defaultTagRelStatus, err := ts.tagRelRepo.GetTagRelDefaultStatusByObjectID(ctx, objectId) + if err != nil { + return err + } for _, tagID := range tagIDs { - needRefreshTagIDs = append(needRefreshTagIDs, tagID) rel, exist, err := ts.tagRelRepo.GetObjectTagRelWithoutStatus(ctx, objectId, tagID) if err != nil { return err @@ -792,11 +797,11 @@ func (ts *TagCommonService) CreateOrUpdateTagRelList(ctx context.Context, object // if not exist add tag relation if !exist { addTagRelList = append(addTagRelList, &entity.TagRel{ - TagID: tagID, ObjectID: objectId, Status: entity.TagStatusAvailable, + TagID: tagID, ObjectID: objectId, Status: defaultTagRelStatus, }) } // if exist and has been removed, that should be enabled - if exist && rel.Status != entity.TagStatusAvailable { + if exist && rel.Status != entity.TagRelStatusAvailable && rel.Status != entity.TagRelStatusHide { enableTagRelList = append(enableTagRelList, rel.ID) } } @@ -812,7 +817,7 @@ func (ts *TagCommonService) CreateOrUpdateTagRelList(ctx context.Context, object } } if len(enableTagRelList) > 0 { - if err = ts.tagRelRepo.EnableTagRelByIDs(ctx, enableTagRelList); err != nil { + if err = ts.tagRelRepo.EnableTagRelByIDs(ctx, enableTagRelList, defaultTagRelStatus == entity.TagRelStatusHide); err != nil { return err } } From 68570d727119936c9e40becc4f14f7899cef9da7 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Mon, 28 Oct 2024 13:20:14 +0800 Subject: [PATCH 297/336] fix: resolve 404 error on Tags static page --- internal/controller/template_controller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 4692e855..df10931e 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -449,13 +449,13 @@ func (tc *TemplateController) QuestionInfo(ctx *gin.Context) { // TagList tags list func (tc *TemplateController) TagList(ctx *gin.Context) { - req := &schema.GetTagWithPageReq{} + req := &schema.GetTagWithPageReq{ + PageSize: constant.DefaultPageSize, + Page: 1, + } if handler.BindAndCheck(ctx, req) { return } - if req.PageSize == 0 { - req.PageSize = constant.DefaultPageSize - } data, err := tc.templateRenderController.TagList(ctx, req) if err != nil || pager.ValPageOutOfRange(data.Count, req.Page, req.PageSize) { tc.Page404(ctx) From bb73941451b08d25d98e7f82bdfd9607aefe7046 Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 29 Oct 2024 15:39:37 +0800 Subject: [PATCH 298/336] feat: update template files --- ui/template/header.html | 10 ++- ui/template/homepage.html | 104 ++++++++++++++++--------------- ui/template/question-detail.html | 40 +++++------- ui/template/question.html | 46 +++++++------- ui/template/sort-btns.html | 19 ++++++ ui/template/tag-detail.html | 87 ++++++++++++-------------- ui/template/tags.html | 88 ++++++++++++++------------ 7 files changed, 206 insertions(+), 188 deletions(-) create mode 100644 ui/template/sort-btns.html diff --git a/ui/template/header.html b/ui/template/header.html index 0243a43d..5c4977d9 100644 --- a/ui/template/header.html +++ b/ui/template/header.html @@ -189,9 +189,13 @@
-
- {{template "sidenav" . }} - {{end}} +
+
+
+ {{template "sidenav" . }} + {{end}} +
+
diff --git a/ui/template/homepage.html b/ui/template/homepage.html index ad5b0209..2f68200d 100644 --- a/ui/template/homepage.html +++ b/ui/template/homepage.html @@ -19,59 +19,61 @@ --> {{template "header" . }} -
-
-
-
- -
-
- {{.userinfo.DisplayName}} +
+
+
+
+
+
+ + {{.userinfo.Username}} + +
+ -
@{{.userinfo.Username}}
-
-
- {{.userinfo.Rank}} {{translator $.language "ui.personal.x_reputation"}} -
-
- {{.userinfo.AnswerCount}} {{translator $.language "ui.personal.x_answers"}} -
-
- {{.userinfo.QuestionCount}} {{translator $.language "ui.personal.x_questions"}} -
-
- {{if .userinfo.Website }} - - {{else}} - {{end}} -
-
-
-
-
- -
-
-
- -
-
-
{{translator $.language "ui.personal.about_me"}}
- {{if .bio }} -
{{.bio}}
- {{else}} -
{{translator $.language "ui.personal.about_me_empty"}}
- {{end}} -
-
-
- -
-
+
+
@{{.userinfo.Username}}
+
+
+ {{.userinfo.Rank}} {{translator $.language "ui.personal.x_reputation"}} +
+
+ {{.userinfo.AnswerCount}} {{translator $.language "ui.personal.x_answers"}} +
+
+ {{.userinfo.QuestionCount}} {{translator $.language "ui.personal.x_questions"}} +
+
+ {{if .userinfo.Website }} + + {{else}} + {{end}} +
+
+
+
+
+
+
+
+
{{translator $.language "ui.personal.about_me"}}
+ {{if .bio }} +
{{.bio}}
+ {{else}} +
{{translator $.language "ui.personal.about_me_empty"}}
+ {{end}} +
+
+
+ +
+
+
+
{{template "footer" .}} diff --git a/ui/template/question-detail.html b/ui/template/question-detail.html index d0e6933d..fcf98c3d 100644 --- a/ui/template/question-detail.html +++ b/ui/template/question-detail.html @@ -19,9 +19,9 @@ --> {{template "header" . }} -
-
-
+
+
+

{{if $.useTitle }} @@ -46,14 +46,16 @@ -
- {{formatLinkNofollow .detail.HTML}} -
+
+
+ {{formatLinkNofollow .detail.HTML}} +
+
-
-
+ -
-
-
{{template "footer" .}} diff --git a/ui/template/question.html b/ui/template/question.html index 058645e5..ca7f1301 100644 --- a/ui/template/question.html +++ b/ui/template/question.html @@ -19,18 +19,19 @@ --> {{template "header" . }} -
-
-
+
+
+
{{translator $.language "ui.question.all_questions"}}
+ {{template "sort-btns" .}}
-
+
{{range .data}} -
+ -
+
{{range .questionList}} -
+
{{if $.useTitle }} - {{.Title}} + {{.Title}} {{else}} {{.Title}} {{end}}
-
-
-
- {{.Operator.DisplayName}}{{.Operator.Rank}} +
+
+
+ {{.Operator.DisplayName}}{{.Operator.Rank}}
• -
-
- {{.VoteCount}} - {{.AnswerCount}} - {{.ViewCount}} +
+
+ + {{.VoteCount}} +
+
+ + {{.AnswerCount}} +
+ + + {{.ViewCount}} +
-
+
{{range .Tags }} - + {{.SlugName}} {{end}} @@ -99,10 +86,14 @@
{{end}}
-
+
+ {{template "page" .}} +
-
{{template "page" .}}
+
+ {{template "hot-question" .}} +
{{template "footer" .}} diff --git a/ui/template/tags.html b/ui/template/tags.html index 292fd477..8821dd7b 100644 --- a/ui/template/tags.html +++ b/ui/template/tags.html @@ -19,48 +19,58 @@ --> {{template "header" . }} -
-
-
-
-
-
-

{{translator $.language "ui.page_title.tags"}}

-
-
-
- {{ range .data.List }} -
-
-
- {{.SlugName}} -

{{formatLinkNofollow .ParsedText}} -

-
- {{.QuestionCount}} - {{translator $.language "ui.tags.tag_label"}} -
-
-
-
- {{ end }} - -
-
- {{template "page" .}} +
+
+ +
+
+ {{ range .data.List }} +
+
+
+ {{.SlugName}} +
{{formatLinkNofollow .ParsedText}} +
+
+ {{.QuestionCount}} + {{translator $.language "ui.tags.tag_label"}} +
+
+
+
+ {{ end }} + +
+
+ {{template "page" .}} +
+
+
- - {{template "footer" .}} From 6fc8a6e9c7942ff32a5899f285643c50230cc69d Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Mon, 28 Oct 2024 13:06:23 +0800 Subject: [PATCH 299/336] fix: display timezone on Dashboard when set to UTC --- .../pages/Admin/Dashboard/components/HealthStatus/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx b/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx index 302cfae9..c19cddbd 100644 --- a/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx +++ b/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx @@ -94,7 +94,10 @@ const HealthStatus: FC = ({ data }) => { {t('timezone')} - {data.time_zone.split('/')?.[1]?.replaceAll('_', ' ')} + {(data.time_zone.split('/')?.[1] ?? data.time_zone).replaceAll( + '_', + ' ', + )} From fcecc07f5ed54658e4d897b4f62e11dbdb579727 Mon Sep 17 00:00:00 2001 From: robin Date: Wed, 13 Nov 2024 11:49:10 +0800 Subject: [PATCH 300/336] fix: update useRenderHtmlPlugin to target specific HTML element Related issue: https://github.com/apache/incubator-answer-plugins/issues/245 --- ui/src/pages/Questions/Detail/components/Answer/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Questions/Detail/components/Answer/index.tsx b/ui/src/pages/Questions/Detail/components/Answer/index.tsx index fb4de275..931b1a75 100644 --- a/ui/src/pages/Questions/Detail/components/Answer/index.tsx +++ b/ui/src/pages/Questions/Detail/components/Answer/index.tsx @@ -60,7 +60,7 @@ const Index: FC = ({ const [searchParams] = useSearchParams(); const answerRef = useRef(null); - useRenderHtmlPlugin(answerRef); + useRenderHtmlPlugin(answerRef.current?.querySelector('.fmt') as HTMLElement); const acceptAnswer = () => { acceptanceAnswer({ From fdd3b4dbf543c8babbc0f2ce97c3b7cbb3c6a1a4 Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Mon, 11 Nov 2024 15:51:41 +0800 Subject: [PATCH 301/336] fix: Tag summary display is not as expected on tag detail page --- i18n/en_US.yaml | 3 ++- i18n/zh_CN.yaml | 1 + ui/src/pages/Tags/Detail/index.tsx | 34 +++++++++++++++++++----------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 8c3c3ddd..9074c8a1 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1103,6 +1103,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1362,7 +1363,7 @@ ui: answers: answers linked_question: title: Linked Questions - description: Questions linked to + description: Questions linked to no_linked_question: No questions linked from this question. invite_to_answer: title: Invite People diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 3a0d56e8..85581968 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1086,6 +1086,7 @@ ui: search_placeholder: 通过标签名称过滤 no_desc: 此标签无描述。 more: 更多 + wiki: 维基 ask: title: 新增问题 edit_title: 编辑问题 diff --git a/ui/src/pages/Tags/Detail/index.tsx b/ui/src/pages/Tags/Detail/index.tsx index 33f65414..41b19022 100644 --- a/ui/src/pages/Tags/Detail/index.tsx +++ b/ui/src/pages/Tags/Detail/index.tsx @@ -38,7 +38,7 @@ import { } from '@/services'; import QuestionList, { QUESTION_ORDER_KEYS } from '@/components/QuestionList'; import HotQuestions from '@/components/HotQuestions'; -import { escapeRemove, guard } from '@/utils'; +import { guard } from '@/utils'; import { pathFactory } from '@/router/pathFactory'; const Index: FC = () => { @@ -143,12 +143,10 @@ const Index: FC = () => {

-

- {escapeRemove(tagInfo.excerpt) || t('no_desc')} - - [{t('more')}] - -

+
{tagInfo.is_follower ? ( @@ -156,6 +154,11 @@ const Index: FC = () => { + + {t('wiki')} + @@ -163,11 +166,18 @@ const Index: FC = () => {
) : ( - +
+ + + {t('wiki')} + +
)}
From 1fe3b7d8fcc700bb3f107cecd09a0c7f3a777c8d Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 14 Nov 2024 14:39:29 +0800 Subject: [PATCH 302/336] refactor(gomock): update gomock dependence and docs --- Makefile | 11 +++-- README.md | 12 +++--- cmd/main.go | 2 +- ...lang-mock.txt => LICENSE-uber-go-mock.txt} | 0 go.mod | 2 +- go.sum | 11 +---- internal/cli/build.go | 2 +- internal/service/mock/siteinfo_repo_mock.go | 41 +++++++++++-------- .../siteinfo_common/siteinfo_service_test.go | 2 +- ui/template/sort-btns.html | 20 +++++++++ 10 files changed, 64 insertions(+), 39 deletions(-) rename docs/release/licenses/{LICENSE-golang-mock.txt => LICENSE-uber-go-mock.txt} (100%) diff --git a/Makefile b/Makefile index 0e398f93..a980a047 100644 --- a/Makefile +++ b/Makefile @@ -21,15 +21,20 @@ universal: generate @rm -f ${BIN}_amd64 ${BIN}_arm64 generate: - @$(GO) get github.com/google/wire/cmd/wire@v0.5.0 - @$(GO) get github.com/golang/mock/mockgen@v1.6.0 @$(GO) get github.com/swaggo/swag/cmd/swag@v1.16.3 + @$(GO) get github.com/google/wire/cmd/wire@v0.5.0 + @$(GO) get go.uber.org/mock/mockgen@latest @$(GO) install github.com/swaggo/swag/cmd/swag@v1.16.3 @$(GO) install github.com/google/wire/cmd/wire@v0.5.0 - @$(GO) install github.com/golang/mock/mockgen@v1.6.0 + @$(GO) install go.uber.org/mock/mockgen@latest @$(GO) generate ./... @$(GO) mod tidy +check: + @mockgen -version + @swag -v + @wire flags + test: @$(GO) test ./internal/repo/repo_test diff --git a/README.md b/README.md index 351b5f67..4eb1cc7c 100644 --- a/README.md +++ b/README.md @@ -40,20 +40,20 @@ You can also check out the [plugins here](https://answer.apache.org/plugins). ### Prerequisites -- Golang >= 1.18 +- Golang >= 1.22 - Node.js >= 16.17 - pnpm >= 8 -- mockgen >= 1.6.0 -- wire >= 0.5.0 +- [mockgen](https://github.com/uber-go/mock?tab=readme-ov-file#installation) >= 1.6.0 +- [wire](https://github.com/google/wire/) >= 0.5.0 ### Build ```bash -# install wire and mockgen for building +# Install wire and mockgen for building. You can run `make check` to check if they are installed. $ make generate -# install frontend dependencies and build +# Install frontend dependencies and build $ make ui -# install backend dependencies and build +# Install backend dependencies and build $ make build ``` diff --git a/cmd/main.go b/cmd/main.go index 20cdf0f5..100c6261 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -49,7 +49,7 @@ var ( // Time is the build time of the project Time = "" // GoVersion is the go version of the project - GoVersion = "1.19" + GoVersion = "1.22" // log level logLevel = os.Getenv("LOG_LEVEL") // log path diff --git a/docs/release/licenses/LICENSE-golang-mock.txt b/docs/release/licenses/LICENSE-uber-go-mock.txt similarity index 100% rename from docs/release/licenses/LICENSE-golang-mock.txt rename to docs/release/licenses/LICENSE-uber-go-mock.txt diff --git a/go.mod b/go.mod index 34ceb7ad..6d8e8891 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,6 @@ require ( github.com/go-playground/validator/v10 v10.22.1 github.com/go-sql-driver/mysql v1.8.1 github.com/goccy/go-json v0.10.3 - github.com/golang/mock v1.6.0 github.com/google/uuid v1.6.0 github.com/google/wire v0.5.0 github.com/grokify/html-strip-tags-go v0.1.0 @@ -57,6 +56,7 @@ require ( github.com/swaggo/swag v1.16.3 github.com/tidwall/gjson v1.17.3 github.com/yuin/goldmark v1.7.4 + go.uber.org/mock v0.5.0 golang.org/x/crypto v0.27.0 golang.org/x/image v0.20.0 golang.org/x/net v0.29.0 diff --git a/go.sum b/go.sum index 62b94f92..446401f5 100644 --- a/go.sum +++ b/go.sum @@ -227,8 +227,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -640,7 +638,6 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= @@ -657,6 +654,8 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -703,7 +702,6 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= @@ -731,7 +729,6 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= @@ -745,7 +742,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -774,8 +770,6 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -823,7 +817,6 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= diff --git a/internal/cli/build.go b/internal/cli/build.go index 6af13c7a..bba075a9 100644 --- a/internal/cli/build.go +++ b/internal/cli/build.go @@ -62,7 +62,7 @@ func main() { ` goModTpl = `module answer -go 1.19 +go 1.22 ` ) diff --git a/internal/service/mock/siteinfo_repo_mock.go b/internal/service/mock/siteinfo_repo_mock.go index abc1fe07..42be1067 100644 --- a/internal/service/mock/siteinfo_repo_mock.go +++ b/internal/service/mock/siteinfo_repo_mock.go @@ -19,6 +19,11 @@ // Code generated by MockGen. DO NOT EDIT. // Source: ./siteinfo_service.go +// +// Generated by this command: +// +// mockgen -source=./siteinfo_service.go -destination=../mock/siteinfo_repo_mock.go -package=mock +// // Package mock is a generated GoMock package. package mock @@ -29,13 +34,14 @@ import ( entity "github.com/apache/incubator-answer/internal/entity" schema "github.com/apache/incubator-answer/internal/schema" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockSiteInfoRepo is a mock of SiteInfoRepo interface. type MockSiteInfoRepo struct { ctrl *gomock.Controller recorder *MockSiteInfoRepoMockRecorder + isgomock struct{} } // MockSiteInfoRepoMockRecorder is the mock recorder for MockSiteInfoRepo. @@ -66,7 +72,7 @@ func (m *MockSiteInfoRepo) GetByType(ctx context.Context, siteType string) (*ent } // GetByType indicates an expected call of GetByType. -func (mr *MockSiteInfoRepoMockRecorder) GetByType(ctx, siteType interface{}) *gomock.Call { +func (mr *MockSiteInfoRepoMockRecorder) GetByType(ctx, siteType any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByType", reflect.TypeOf((*MockSiteInfoRepo)(nil).GetByType), ctx, siteType) } @@ -80,7 +86,7 @@ func (m *MockSiteInfoRepo) SaveByType(ctx context.Context, siteType string, data } // SaveByType indicates an expected call of SaveByType. -func (mr *MockSiteInfoRepoMockRecorder) SaveByType(ctx, siteType, data interface{}) *gomock.Call { +func (mr *MockSiteInfoRepoMockRecorder) SaveByType(ctx, siteType, data any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveByType", reflect.TypeOf((*MockSiteInfoRepo)(nil).SaveByType), ctx, siteType, data) } @@ -89,6 +95,7 @@ func (mr *MockSiteInfoRepoMockRecorder) SaveByType(ctx, siteType, data interface type MockSiteInfoCommonService struct { ctrl *gomock.Controller recorder *MockSiteInfoCommonServiceMockRecorder + isgomock struct{} } // MockSiteInfoCommonServiceMockRecorder is the mock recorder for MockSiteInfoCommonService. @@ -117,7 +124,7 @@ func (m *MockSiteInfoCommonService) FormatAvatar(ctx context.Context, originalAv } // FormatAvatar indicates an expected call of FormatAvatar. -func (mr *MockSiteInfoCommonServiceMockRecorder) FormatAvatar(ctx, originalAvatarData, email, userStatus interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) FormatAvatar(ctx, originalAvatarData, email, userStatus any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FormatAvatar", reflect.TypeOf((*MockSiteInfoCommonService)(nil).FormatAvatar), ctx, originalAvatarData, email, userStatus) } @@ -131,7 +138,7 @@ func (m *MockSiteInfoCommonService) FormatListAvatar(ctx context.Context, userLi } // FormatListAvatar indicates an expected call of FormatListAvatar. -func (mr *MockSiteInfoCommonServiceMockRecorder) FormatListAvatar(ctx, userList interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) FormatListAvatar(ctx, userList any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FormatListAvatar", reflect.TypeOf((*MockSiteInfoCommonService)(nil).FormatListAvatar), ctx, userList) } @@ -146,7 +153,7 @@ func (m *MockSiteInfoCommonService) GetSiteBranding(ctx context.Context) (*schem } // GetSiteBranding indicates an expected call of GetSiteBranding. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteBranding(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteBranding(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteBranding", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteBranding), ctx) } @@ -161,7 +168,7 @@ func (m *MockSiteInfoCommonService) GetSiteCustomCssHTML(ctx context.Context) (* } // GetSiteCustomCssHTML indicates an expected call of GetSiteCustomCssHTML. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteCustomCssHTML(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteCustomCssHTML(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteCustomCssHTML", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteCustomCssHTML), ctx) } @@ -176,13 +183,13 @@ func (m *MockSiteInfoCommonService) GetSiteGeneral(ctx context.Context) (*schema } // GetSiteGeneral indicates an expected call of GetSiteGeneral. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteGeneral(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteGeneral(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteGeneral", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteGeneral), ctx) } // GetSiteInfoByType mocks base method. -func (m *MockSiteInfoCommonService) GetSiteInfoByType(ctx context.Context, siteType string, resp interface{}) error { +func (m *MockSiteInfoCommonService) GetSiteInfoByType(ctx context.Context, siteType string, resp any) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSiteInfoByType", ctx, siteType, resp) ret0, _ := ret[0].(error) @@ -190,7 +197,7 @@ func (m *MockSiteInfoCommonService) GetSiteInfoByType(ctx context.Context, siteT } // GetSiteInfoByType indicates an expected call of GetSiteInfoByType. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteInfoByType(ctx, siteType, resp interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteInfoByType(ctx, siteType, resp any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteInfoByType", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteInfoByType), ctx, siteType, resp) } @@ -205,7 +212,7 @@ func (m *MockSiteInfoCommonService) GetSiteInterface(ctx context.Context) (*sche } // GetSiteInterface indicates an expected call of GetSiteInterface. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteInterface(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteInterface(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteInterface", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteInterface), ctx) } @@ -220,7 +227,7 @@ func (m *MockSiteInfoCommonService) GetSiteLegal(ctx context.Context) (*schema.S } // GetSiteLegal indicates an expected call of GetSiteLegal. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteLegal(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteLegal(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteLegal", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteLegal), ctx) } @@ -235,7 +242,7 @@ func (m *MockSiteInfoCommonService) GetSiteLogin(ctx context.Context) (*schema.S } // GetSiteLogin indicates an expected call of GetSiteLogin. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteLogin(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteLogin(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteLogin", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteLogin), ctx) } @@ -250,7 +257,7 @@ func (m *MockSiteInfoCommonService) GetSiteSeo(ctx context.Context) (*schema.Sit } // GetSiteSeo indicates an expected call of GetSiteSeo. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteSeo(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteSeo(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteSeo", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteSeo), ctx) } @@ -265,7 +272,7 @@ func (m *MockSiteInfoCommonService) GetSiteTheme(ctx context.Context) (*schema.S } // GetSiteTheme indicates an expected call of GetSiteTheme. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteTheme(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteTheme(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteTheme", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteTheme), ctx) } @@ -280,7 +287,7 @@ func (m *MockSiteInfoCommonService) GetSiteUsers(ctx context.Context) (*schema.S } // GetSiteUsers indicates an expected call of GetSiteUsers. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteUsers(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteUsers(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteUsers", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteUsers), ctx) } @@ -295,7 +302,7 @@ func (m *MockSiteInfoCommonService) GetSiteWrite(ctx context.Context) (*schema.S } // GetSiteWrite indicates an expected call of GetSiteWrite. -func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteWrite(ctx interface{}) *gomock.Call { +func (mr *MockSiteInfoCommonServiceMockRecorder) GetSiteWrite(ctx any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSiteWrite", reflect.TypeOf((*MockSiteInfoCommonService)(nil).GetSiteWrite), ctx) } diff --git a/internal/service/siteinfo_common/siteinfo_service_test.go b/internal/service/siteinfo_common/siteinfo_service_test.go index bda2f368..387e1e2f 100644 --- a/internal/service/siteinfo_common/siteinfo_service_test.go +++ b/internal/service/siteinfo_common/siteinfo_service_test.go @@ -26,8 +26,8 @@ import ( "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/service/mock" - "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" ) var ( diff --git a/ui/template/sort-btns.html b/ui/template/sort-btns.html index 7da3485c..3ea41ec2 100644 --- a/ui/template/sort-btns.html +++ b/ui/template/sort-btns.html @@ -1,3 +1,23 @@ + {{define "sort-btns"}}
From f29b43b956659395133ee43c3d5501ae92d52cfe Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 14 Nov 2024 14:42:31 +0800 Subject: [PATCH 303/336] feat(file): update the max image size --- pkg/checker/file_type.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/checker/file_type.go b/pkg/checker/file_type.go index 6c61dca2..fffcd960 100644 --- a/pkg/checker/file_type.go +++ b/pkg/checker/file_type.go @@ -35,7 +35,7 @@ import ( ) const ( - maxImageSize = 8192 * 8192 + maxImageSize = 16384 * 16384 ) // IsSupportedImageFile currently answers support image type is From e7ee4ea91d3d6022fd4494b9817fbeb9e7a31ae2 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 14 Nov 2024 15:22:55 +0800 Subject: [PATCH 304/336] fix(review): reject the review when delete question --- cmd/wire_gen.go | 2 +- internal/repo/review/review_repo.go | 10 ++++++++++ internal/service/content/question_service.go | 12 ++++++++++++ internal/service/review/review_service.go | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 801c5a77..5e4d395b 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -202,7 +202,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, externalNotificationService := notification.NewExternalNotificationService(dataData, userNotificationConfigRepo, followRepo, emailService, userRepo, externalNotificationQueueService, userExternalLoginRepo, siteInfoCommonService) reviewRepo := review.NewReviewRepo(dataData) reviewService := review2.NewReviewService(reviewRepo, objService, userCommon, userRepo, questionRepo, answerRepo, userRoleRelService, externalNotificationQueueService, tagCommonService, questionCommon, notificationQueueService, siteInfoCommonService) - questionService := content.NewQuestionService(activityRepo, questionRepo, answerRepo, tagCommonService, tagService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService, eventQueueService) + questionService := content.NewQuestionService(activityRepo, questionRepo, answerRepo, tagCommonService, tagService, questionCommon, userCommon, userRepo, userRoleRelService, revisionService, metaCommonService, collectionCommon, answerActivityService, emailService, notificationQueueService, externalNotificationQueueService, activityQueueService, siteInfoCommonService, externalNotificationService, reviewService, configService, eventQueueService, reviewRepo) answerService := content.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo, emailService, userRoleRelService, notificationQueueService, externalNotificationQueueService, activityQueueService, reviewService, eventQueueService) reportHandle := report_handle.NewReportHandle(questionService, answerService, commentService) reportService := report2.NewReportService(reportRepo, objService, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService, eventQueueService) diff --git a/internal/repo/review/review_repo.go b/internal/repo/review/review_repo.go index 91bc046c..c87c814c 100644 --- a/internal/repo/review/review_repo.go +++ b/internal/repo/review/review_repo.go @@ -72,6 +72,16 @@ func (cr *reviewRepo) GetReview(ctx context.Context, reviewID int) ( return } +// GetReviewByObject get review by object +func (cr *reviewRepo) GetReviewByObject(ctx context.Context, objectID string) (review *entity.Review, exist bool, err error) { + review = &entity.Review{} + exist, err = cr.data.DB.Context(ctx).Desc("id").Where("object_id = ?", objectID).Get(review) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + // GetReviewCount get review count func (cr *reviewRepo) GetReviewCount(ctx context.Context, status int) (count int64, err error) { count, err = cr.data.DB.Context(ctx).Count(&entity.Review{Status: status}) diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index 51f0da9b..145f7da1 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -91,6 +91,7 @@ type QuestionService struct { reviewService *review.ReviewService configService *config.ConfigService eventQueueService event_queue.EventQueueService + reviewRepo review.ReviewRepo } func NewQuestionService( @@ -116,6 +117,7 @@ func NewQuestionService( reviewService *review.ReviewService, configService *config.ConfigService, eventQueueService event_queue.EventQueueService, + reviewRepo review.ReviewRepo, ) *QuestionService { return &QuestionService{ activityRepo: activityRepo, @@ -140,6 +142,7 @@ func NewQuestionService( reviewService: reviewService, configService: configService, eventQueueService: eventQueueService, + reviewRepo: reviewRepo, } } @@ -559,6 +562,15 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov } } + // If this question has been reviewed, then delete the review. + reviewInfo, exist, err := qs.reviewRepo.GetReviewByObject(ctx, questionInfo.ID) + if exist && err == nil { + err = qs.reviewRepo.UpdateReviewStatus(ctx, reviewInfo.ID, req.UserID, entity.ReviewStatusRejected) + if err != nil { + return errors.InternalServer(reason.DatabaseError) + } + } + //tag count tagIDs := make([]string, 0) Tags, tagerr := qs.tagCommon.GetObjectEntityTag(ctx, req.ID) diff --git a/internal/service/review/review_service.go b/internal/service/review/review_service.go index fb323178..dadf58ab 100644 --- a/internal/service/review/review_service.go +++ b/internal/service/review/review_service.go @@ -49,6 +49,7 @@ type ReviewRepo interface { AddReview(ctx context.Context, review *entity.Review) (err error) UpdateReviewStatus(ctx context.Context, reviewID int, reviewerUserID string, status int) (err error) GetReview(ctx context.Context, reviewID int) (review *entity.Review, exist bool, err error) + GetReviewByObject(ctx context.Context, objectID string) (review *entity.Review, exist bool, err error) GetReviewCount(ctx context.Context, status int) (count int64, err error) GetReviewPage(ctx context.Context, page, pageSize int, cond *entity.Review) (reviewList []*entity.Review, total int64, err error) } From ad956d686ef594b9560bd404e8e7af4bcf3ab03e Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Thu, 14 Nov 2024 15:45:31 +0800 Subject: [PATCH 305/336] fix: Markdown parsing without incrementing ordered list numbers --- pkg/converter/markdown.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/converter/markdown.go b/pkg/converter/markdown.go index af17d9bd..082a198a 100644 --- a/pkg/converter/markdown.go +++ b/pkg/converter/markdown.go @@ -60,6 +60,7 @@ func Markdown2HTML(source string) string { filter.RequireNoFollowOnFullyQualifiedLinks(false) filter.AllowElements("kbd") filter.AllowAttrs("title").Matching(regexp.MustCompile(`^[\p{L}\p{N}\s\-_',\[\]!\./\\\(\)]*$|^@embed?$`)).Globally() + filter.AllowAttrs("start").OnElements("ol") html = filter.Sanitize(html) return html } From 241d6f4c37e2a915bc988c033a06c78fa920b83b Mon Sep 17 00:00:00 2001 From: shuai Date: Thu, 14 Nov 2024 16:19:27 +0800 Subject: [PATCH 306/336] feat: actions add toast tips --- i18n/en_US.yaml | 13 ++++++++++++ .../Admin/Answers/components/Action/index.tsx | 9 +++++++++ ui/src/pages/Admin/Badges/index.tsx | 9 +++++++++ .../Questions/components/Action/index.tsx | 20 +++++++++++++++++-- .../Admin/Users/components/Action/index.tsx | 13 +++++++++++- ui/src/pages/Admin/Users/index.tsx | 6 +++++- 6 files changed, 66 insertions(+), 4 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 9074c8a1..cea0c12f 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -2250,6 +2250,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2258,3 +2259,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/ui/src/pages/Admin/Answers/components/Action/index.tsx b/ui/src/pages/Admin/Answers/components/Action/index.tsx index 7dc3bb33..81e21813 100644 --- a/ui/src/pages/Admin/Answers/components/Action/index.tsx +++ b/ui/src/pages/Admin/Answers/components/Action/index.tsx @@ -23,6 +23,7 @@ import { Link } from 'react-router-dom'; import { Icon, Modal } from '@/components'; import { changeAnswerStatus } from '@/services'; +import { toastStore } from '@/stores'; const AnswerActions = ({ itemData, curFilter, refreshList }) => { const { t } = useTranslation('translation', { keyPrefix: 'delete' }); @@ -37,6 +38,10 @@ const AnswerActions = ({ itemData, curFilter, refreshList }) => { confirmText: t('delete', { keyPrefix: 'btns' }), onConfirm: () => { changeAnswerStatus(itemData.id, 'deleted').then(() => { + toastStore.getState().show({ + msg: t('answer_deleted', { keyPrefix: 'messages' }), + variant: 'success', + }); refreshList(); }); }, @@ -52,6 +57,10 @@ const AnswerActions = ({ itemData, curFilter, refreshList }) => { confirmText: t('undelete', { keyPrefix: 'btns' }), onConfirm: () => { changeAnswerStatus(itemData.id, 'available').then(() => { + toastStore.getState().show({ + msg: t('answer_cancel_deleted', { keyPrefix: 'messages' }), + variant: 'success', + }); refreshList(); }); }, diff --git a/ui/src/pages/Admin/Badges/index.tsx b/ui/src/pages/Admin/Badges/index.tsx index 99bafb43..63b8f348 100644 --- a/ui/src/pages/Admin/Badges/index.tsx +++ b/ui/src/pages/Admin/Badges/index.tsx @@ -27,6 +27,7 @@ import classNames from 'classnames'; import { Empty, Icon, Pagination, QueryGroup } from '@/components'; import * as Type from '@/common/interface'; import { useQueryBadges, updateBadgeStatus } from '@/services/admin/badges'; +import { useToast } from '@/hooks'; import Action from './components/Action'; @@ -46,6 +47,7 @@ const Badges: FC = () => { const curPage = Number(urlSearchParams.get('page') || '1'); const curFilter = urlSearchParams.get('filter') || BadgeFilterKeys[0]; const curQuery = urlSearchParams.get('query') || ''; + const Toast = useToast(); const { data, isLoading, mutate } = useQueryBadges({ page: curPage, @@ -62,6 +64,13 @@ const Badges: FC = () => { const handleBadgeStatus = (badgeId, status) => { updateBadgeStatus({ id: badgeId, status }).then(() => { + Toast.onShow({ + msg: + status === 'inactive' + ? t('badge_inactivated', { keyPrefix: 'messages' }) + : t('badge_activated', { keyPrefix: 'messages' }), + variant: 'success', + }); mutate(); }); }; diff --git a/ui/src/pages/Admin/Questions/components/Action/index.tsx b/ui/src/pages/Admin/Questions/components/Action/index.tsx index 0dc1fefa..560d6e69 100644 --- a/ui/src/pages/Admin/Questions/components/Action/index.tsx +++ b/ui/src/pages/Admin/Questions/components/Action/index.tsx @@ -28,11 +28,19 @@ import { reopenQuestion, } from '@/services'; import { useReportModal, useToast } from '@/hooks'; +import { toastStore } from '@/stores'; const AnswerActions = ({ itemData, refreshList, curFilter, show, pin }) => { const { t } = useTranslation('translation', { keyPrefix: 'delete' }); - const closeModal = useReportModal(refreshList); const toast = useToast(); + const closeCallback = () => { + toastStore.getState().show({ + msg: t('post_closed', { keyPrefix: 'messages' }), + variant: 'success', + }); + refreshList(); + }; + const closeModal = useReportModal(closeCallback); const handleAction = (type) => { if (type === 'delete') { @@ -47,6 +55,10 @@ const AnswerActions = ({ itemData, refreshList, curFilter, show, pin }) => { confirmText: t('delete', { keyPrefix: 'btns' }), onConfirm: () => { changeQuestionStatus(itemData.id, 'deleted').then(() => { + toastStore.getState().show({ + msg: t('post_deleted', { keyPrefix: 'messages' }), + variant: 'success', + }); refreshList(); }); }, @@ -62,6 +74,10 @@ const AnswerActions = ({ itemData, refreshList, curFilter, show, pin }) => { confirmText: t('undelete', { keyPrefix: 'btns' }), onConfirm: () => { changeQuestionStatus(itemData.id, 'available').then(() => { + toastStore.getState().show({ + msg: t('post_cancel_deleted', { keyPrefix: 'messages' }), + variant: 'success', + }); refreshList(); }); }, @@ -86,7 +102,7 @@ const AnswerActions = ({ itemData, refreshList, curFilter, show, pin }) => { reopenQuestion({ question_id: itemData.id, }).then(() => { - toast.onShow({ + toastStore.getState().show({ msg: t('post_reopen', { keyPrefix: 'messages' }), variant: 'success', }); diff --git a/ui/src/pages/Admin/Users/components/Action/index.tsx b/ui/src/pages/Admin/Users/components/Action/index.tsx index fa79c24d..9f0847a2 100644 --- a/ui/src/pages/Admin/Users/components/Action/index.tsx +++ b/ui/src/pages/Admin/Users/components/Action/index.tsx @@ -33,6 +33,7 @@ import { changeUserStatus, updateUserProfile, } from '@/services'; +import { toastStore } from '@/stores'; interface Props { showActionPassword?: boolean; @@ -57,7 +58,13 @@ const UserOperation = ({ const Toast = useToast(); const changeUserRoleModal = useChangeUserRoleModal({ - callback: refreshUsers, + callback: () => { + Toast.onShow({ + msg: t('change_user_role', { keyPrefix: 'messages' }), + variant: 'success', + }); + refreshUsers?.(); + }, }); const changePasswordModal = useChangePasswordModal({ onConfirm: (rd) => { @@ -107,6 +114,10 @@ const UserOperation = ({ user_id: userData.user_id, status: statusType, }).then(() => { + toastStore.getState().show({ + msg: t(`user_${statusType}`, { keyPrefix: 'messages' }), + variant: 'success', + }); refreshUsers?.(); // onClose(); }); diff --git a/ui/src/pages/Admin/Users/index.tsx b/ui/src/pages/Admin/Users/index.tsx index cfabd20a..40152200 100644 --- a/ui/src/pages/Admin/Users/index.tsx +++ b/ui/src/pages/Admin/Users/index.tsx @@ -33,6 +33,7 @@ import { } from '@/components'; import * as Type from '@/common/interface'; import { useUserModal } from '@/hooks'; +import { toastStore, loggedUserInfoStore, userCenterStore } from '@/stores'; import { useQueryUsers, addUsers, @@ -40,7 +41,6 @@ import { AdminUcAgent, changeUserStatus, } from '@/services'; -import { loggedUserInfoStore, userCenterStore } from '@/stores'; import { formatCount } from '@/utils'; import DeleteUserModal from './components/DeleteUserModal'; @@ -139,6 +139,10 @@ const Users: FC = () => { status: 'deleted', remove_all_content: val, }).then(() => { + toastStore.getState().show({ + msg: t('user_deleted', { keyPrefix: 'messages' }), + variant: 'success', + }); changeDeleteUserModalState({ show: false, userId: '', From 9df9f7a12d796c3f3e713fea3854c47d7b9a5df1 Mon Sep 17 00:00:00 2001 From: Sonui Date: Thu, 14 Nov 2024 23:02:23 +0800 Subject: [PATCH 307/336] perf: add note to email body --- i18n/en_US.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index cea0c12f..6f3f5215 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -465,42 +465,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
\n
{{.ChangeEmailUrl}}

\n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
\n{{.ChangeEmailUrl}}

\n\nIf you did not request this change, please ignore this email.

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.AnswerSummary}}

\nView it on {{.SiteName}}

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

\n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
I think you may know the answer.

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
I think you may know the answer.

\nView it on {{.SiteName}}

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

\n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\nView it on {{.SiteName}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}

\n\n{{.DisplayName}}:
\n
{{.CommentSummary}}

\nView it on {{.SiteName}}

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

\n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\nUnsubscribe" + other: "{{.QuestionTitle}}
\n{{.Tags}}

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

\n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

\n\nIf it was not you, you can safely ignore this email.

\n\nClick the following link to choose a new password:
\n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

\n\nIf it was not you, you can safely ignore this email.

\n\nClick the following link to choose a new password:
\n{{.PassResetUrl}}\n

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

\n\nClick the following link to confirm and activate your new account:
\n{{.RegisterUrl}}

\n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

\n\nClick the following link to confirm and activate your new account:
\n{{.RegisterUrl}}

\n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

\n\n--
\nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote From 98eceff5494a2114cbe0c2846785320acc14addc Mon Sep 17 00:00:00 2001 From: sy-records <52o@qq52o.cn> Date: Thu, 14 Nov 2024 17:37:43 +0800 Subject: [PATCH 308/336] feat: Add key metrics to the dashboard --- i18n/en_US.yaml | 2 ++ i18n/zh_CN.yaml | 2 ++ internal/repo/question/question_repo.go | 23 +++++++++++++++ internal/schema/dashboard_schema.go | 4 +++ .../service/dashboard/dashboard_service.go | 29 ++++++++++++++++++- internal/service/question_common/question.go | 2 ++ ui/src/common/interface.ts | 4 +++ .../Dashboard/components/Statistics/index.tsx | 22 ++++++++++++++ 8 files changed, 87 insertions(+), 1 deletion(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 6f3f5215..775d7456 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1762,6 +1762,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Questions:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Answers:" comments: "Comments:" votes: "Votes:" diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index 85581968..d0feebb9 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -1722,6 +1722,8 @@ ui: welcome: 欢迎来到管理后台! site_statistics: 站点统计 questions: "问题:" + resolved: "已解决:" + unanswered: "未回复:" answers: "回答:" comments: "评论:" votes: "投票:" diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 16b6085f..1132501e 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -284,6 +284,29 @@ func (qr *questionRepo) GetQuestionCount(ctx context.Context) (count int64, err return count, nil } +func (qr *questionRepo) GetUnansweredQuestionCount(ctx context.Context) (count int64, err error) { + session := qr.data.DB.Context(ctx) + session.Where(builder.Lt{"status": entity.QuestionStatusDeleted}). + And(builder.Eq{"answer_count": 0}) + count, err = session.Count(&entity.Question{Show: entity.QuestionShow}) + if err != nil { + return 0, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return count, nil +} + +func (qr *questionRepo) GetResolvedQuestionCount(ctx context.Context) (count int64, err error) { + session := qr.data.DB.Context(ctx) + session.Where(builder.Lt{"status": entity.QuestionStatusDeleted}). + And(builder.Neq{"answer_count": 0}). + And(builder.Neq{"accepted_answer_id": 0}) + count, err = session.Count(&entity.Question{Show: entity.QuestionShow}) + if err != nil { + return 0, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return count, nil +} + func (qr *questionRepo) GetUserQuestionCount(ctx context.Context, userID string, show int) (count int64, err error) { session := qr.data.DB.Context(ctx) session.Where(builder.Lt{"status": entity.QuestionStatusDeleted}) diff --git a/internal/schema/dashboard_schema.go b/internal/schema/dashboard_schema.go index 2d780b8c..c2c7677d 100644 --- a/internal/schema/dashboard_schema.go +++ b/internal/schema/dashboard_schema.go @@ -30,6 +30,10 @@ const ( type DashboardInfo struct { QuestionCount int64 `json:"question_count"` + ResolvedCount int64 `json:"resolved_count"` + ResolvedRate string `json:"resolved_rate"` + UnansweredCount int64 `json:"unanswered_count"` + UnansweredRate string `json:"unanswered_rate"` AnswerCount int64 `json:"answer_count"` CommentCount int64 `json:"comment_count"` VoteCount int64 `json:"vote_count"` diff --git a/internal/service/dashboard/dashboard_service.go b/internal/service/dashboard/dashboard_service.go index 67abc2a7..ebc9a79d 100644 --- a/internal/service/dashboard/dashboard_service.go +++ b/internal/service/dashboard/dashboard_service.go @@ -103,7 +103,6 @@ func (ds *dashboardService) Statistical(ctx context.Context) (*schema.DashboardI dashboardInfo := ds.getFromCache(ctx) if dashboardInfo == nil { dashboardInfo = &schema.DashboardInfo{} - dashboardInfo.QuestionCount = ds.questionCount(ctx) dashboardInfo.AnswerCount = ds.answerCount(ctx) dashboardInfo.CommentCount = ds.commentCount(ctx) dashboardInfo.UserCount = ds.userCount(ctx) @@ -121,6 +120,18 @@ func (ds *dashboardService) Statistical(ctx context.Context) (*schema.DashboardI dashboardInfo.DatabaseSize = ds.GetDatabaseSize() } + dashboardInfo.QuestionCount = ds.questionCount(ctx) + dashboardInfo.UnansweredCount = ds.unansweredQuestionCount(ctx) + dashboardInfo.ResolvedCount = ds.resolvedQuestionCount(ctx) + + if dashboardInfo.QuestionCount == 0 { + dashboardInfo.ResolvedRate = "0.00" + dashboardInfo.UnansweredRate = "0.00" + } else { + dashboardInfo.ResolvedRate = fmt.Sprintf("%.2f", float64(dashboardInfo.ResolvedCount)/float64(dashboardInfo.QuestionCount)*100) + dashboardInfo.UnansweredRate = fmt.Sprintf("%.2f", float64(dashboardInfo.UnansweredCount)/float64(dashboardInfo.QuestionCount)*100) + } + dashboardInfo.ReportCount = ds.reportCount(ctx) dashboardInfo.SMTP = ds.smtpStatus(ctx) dashboardInfo.HTTPS = ds.httpsStatus(ctx) @@ -170,6 +181,22 @@ func (ds *dashboardService) questionCount(ctx context.Context) int64 { return questionCount } +func (ds *dashboardService) unansweredQuestionCount(ctx context.Context) int64 { + unansweredQuestionCount, err := ds.questionRepo.GetUnansweredQuestionCount(ctx) + if err != nil { + log.Errorf("get unanswered question count failed: %s", err) + } + return unansweredQuestionCount +} + +func (ds *dashboardService) resolvedQuestionCount(ctx context.Context) int64 { + resolvedQuestionCount, err := ds.questionRepo.GetResolvedQuestionCount(ctx) + if err != nil { + log.Errorf("get resolved question count failed: %s", err) + } + return resolvedQuestionCount +} + func (ds *dashboardService) answerCount(ctx context.Context) int64 { answerCount, err := ds.answerRepo.GetAnswerCount(ctx) if err != nil { diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index 13df3389..08c74f29 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -74,6 +74,8 @@ type QuestionRepo interface { FindByID(ctx context.Context, id []string) (questionList []*entity.Question, err error) AdminQuestionPage(ctx context.Context, search *schema.AdminQuestionPageReq) ([]*entity.Question, int64, error) GetQuestionCount(ctx context.Context) (count int64, err error) + GetUnansweredQuestionCount(ctx context.Context) (count int64, err error) + GetResolvedQuestionCount(ctx context.Context) (count int64, err error) GetUserQuestionCount(ctx context.Context, userID string, show int) (count int64, err error) SitemapQuestions(ctx context.Context, page, pageSize int) (questionIDList []*schema.SiteMapQuestionInfo, err error) RemoveAllUserQuestion(ctx context.Context, userID string) (err error) diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index 8a933471..903c5c28 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -524,6 +524,10 @@ export interface SearchRes extends ListResult { export interface AdminDashboard { info: { question_count: number; + resolved_count: number; + resolved_rate: string; + unanswered_count: number; + unanswered_rate: string; answer_count: number; comment_count: number; vote_count: number; diff --git a/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx b/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx index c95eaba7..a3077ba4 100644 --- a/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx +++ b/ui/src/pages/Admin/Dashboard/components/Statistics/index.tsx @@ -39,6 +39,28 @@ const Statistics: FC = ({ data }) => { {t('questions')} {data.question_count} + + {t('resolved')} + {data.resolved_count} + {data.resolved_count > 0 ? ( + + ({data.resolved_rate}%) + + ) : ( + '' + )} + + + {t('unanswered')} + {data.unanswered_count} + {data.unanswered_count > 0 ? ( + + ({data.unanswered_rate}%) + + ) : ( + '' + )} + {t('answers')} {data.answer_count} From 5060e08771f4a99940a431b5d641af3e391d634d Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 18 Nov 2024 16:05:01 +0800 Subject: [PATCH 309/336] fix(search): fix the wrong offset when searching --- internal/repo/search_common/search_repo.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/internal/repo/search_common/search_repo.go b/internal/repo/search_common/search_repo.go index cd7de696..1c4f04ab 100644 --- a/internal/repo/search_common/search_repo.go +++ b/internal/repo/search_common/search_repo.go @@ -99,7 +99,7 @@ func NewSearchRepo( } // SearchContents search question and answer data -func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs [][]string, userID string, votes int, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) { +func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs [][]string, userID string, votes int, page, pageSize int, order string) (resp []*schema.SearchResult, total int64, err error) { words = filterWords(words) var ( @@ -206,7 +206,8 @@ func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs return } - querySQL, _, err := builder.MySQL().Select("*").From(sql, "t").OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL() + startNum := (page - 1) * pageSize + querySQL, _, err := builder.MySQL().Select("*").From(sql, "t").OrderBy(sr.parseOrder(ctx, order)).Limit(pageSize, startNum).ToSQL() if err != nil { return } @@ -241,7 +242,7 @@ func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs } // SearchQuestions search question data -func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, tagIDs [][]string, notAccepted bool, views, answers int, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) { +func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, tagIDs [][]string, notAccepted bool, views, answers int, page, pageSize int, order string) (resp []*schema.SearchResult, total int64, err error) { words = filterWords(words) var ( qfs = qFields @@ -320,7 +321,8 @@ func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, tagID return } - querySQL, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL() + startNum := (page - 1) * pageSize + querySQL, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(pageSize, startNum).ToSQL() if err != nil { return } @@ -351,7 +353,7 @@ func (sr *searchRepo) SearchQuestions(ctx context.Context, words []string, tagID } // SearchAnswers search answer data -func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, tagIDs [][]string, accepted bool, questionID string, page, size int, order string) (resp []*schema.SearchResult, total int64, err error) { +func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, tagIDs [][]string, accepted bool, questionID string, page, pageSize int, order string) (resp []*schema.SearchResult, total int64, err error) { words = filterWords(words) var ( @@ -415,7 +417,8 @@ func (sr *searchRepo) SearchAnswers(ctx context.Context, words []string, tagIDs return } - querySQL, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(size, page-1).ToSQL() + startNum := (page - 1) * pageSize + querySQL, _, err := b.OrderBy(sr.parseOrder(ctx, order)).Limit(pageSize, startNum).ToSQL() if err != nil { return } From 655a7e48e0168bfc07d6eb0d906cc1de64f5a5e2 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 19 Nov 2024 18:01:38 +0800 Subject: [PATCH 310/336] feat(question): add linked count feature to question --- internal/entity/question_entity.go | 1 + internal/migrations/migrations.go | 1 + internal/migrations/v24.go | 34 +++++++++++++++++ internal/repo/question/question_repo.go | 40 ++++++++++++++++++++ internal/schema/question_schema.go | 4 +- internal/service/question_common/question.go | 23 +++++++++++ 6 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 internal/migrations/v24.go diff --git a/internal/entity/question_entity.go b/internal/entity/question_entity.go index 1931282c..9e5dcd11 100644 --- a/internal/entity/question_entity.go +++ b/internal/entity/question_entity.go @@ -73,6 +73,7 @@ type Question struct { LastAnswerID string `xorm:"not null default 0 BIGINT(20) last_answer_id"` PostUpdateTime time.Time `xorm:"post_update_time TIMESTAMP"` RevisionID string `xorm:"not null default 0 BIGINT(20) revision_id"` + LinkedCount int `xorm:"not null default 0 INT(11) linked_count"` } // TableName question table name diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index 81a54ae7..00e44198 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -99,6 +99,7 @@ var migrations = []Migration{ NewMigration("v1.3.6", "add hot score to question table", addQuestionHotScore, true), NewMigration("v1.4.0", "add badge/badge_group/badge_award table", addBadges, true), NewMigration("v1.4.1", "add question link", addQuestionLink, true), + NewMigration("v1.4.2", "add the number of question links", addQuestionLinkedCount, false), } func GetMigrations() []Migration { diff --git a/internal/migrations/v24.go b/internal/migrations/v24.go new file mode 100644 index 00000000..015352ae --- /dev/null +++ b/internal/migrations/v24.go @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package migrations + +import ( + "context" + "github.com/apache/incubator-answer/internal/entity" + + "xorm.io/xorm" +) + +func addQuestionLinkedCount(ctx context.Context, x *xorm.Engine) error { + type Question struct { + LinkedCount int `xorm:"not null default 0 INT(11) linked_count"` + } + return x.Context(ctx).Sync(new(entity.Question)) +} diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 1132501e..e1d94f2e 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -410,6 +410,8 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, case "unanswered": session.Where("question.answer_count = 0") session.OrderBy("question.pin desc,question.created_at DESC") + case "frequent": + session.OrderBy("question.pin DESC, question.linked_count DESC") } total, err = pager.Help(page, pageSize, &questionList, &entity.Question{}, session) @@ -708,6 +710,42 @@ func (qr *questionRepo) LinkQuestion(ctx context.Context, link ...*entity.Questi return } +// UpdateQuestionLinkCount update question link count +func (qr *questionRepo) UpdateQuestionLinkCount(ctx context.Context, questionID string) (err error) { + // count the number of links + count, err := qr.data.DB.Context(ctx). + Where("to_question_id = ?", questionID). + Where("status = ?", entity.QuestionLinkStatusAvailable). + Count(&entity.QuestionLink{}) + if err != nil { + return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + + // update the number of links + _, err = qr.data.DB.Context(ctx).ID(questionID). + Cols("linked_count").Update(&entity.Question{LinkedCount: int(count)}) + if err != nil { + return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + +// GetLinkedQuestionIDs get linked question ids +func (qr *questionRepo) GetLinkedQuestionIDs(ctx context.Context, questionID string, status int) ( + questionIDs []string, err error) { + questionIDs = make([]string, 0) + err = qr.data.DB.Context(ctx). + Select("to_question_id"). + Table(new(entity.QuestionLink).TableName()). + Where("from_question_id = ?", questionID). + Where("status = ?", status). + Find(&questionIDs) + if err != nil { + return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return questionIDs, nil +} + // RecoverQuestionLink batch recover question link func (qr *questionRepo) RecoverQuestionLink(ctx context.Context, links ...*entity.QuestionLink) (err error) { return qr.UpdateQuestionLinkStatus(ctx, entity.QuestionLinkStatusAvailable, links...) @@ -784,6 +822,8 @@ func (qr *questionRepo) GetQuestionLink(ctx context.Context, page, pageSize int, case "unanswered": session.Where("question.answer_count = 0") session.OrderBy("question.pin desc,question.created_at DESC") + case "frequent": + session.OrderBy("question.pin DESC, question.linked_count DESC") } if page > 0 && pageSize > 0 { diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index de19a8a5..accc3374 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -356,7 +356,7 @@ const ( type QuestionPageReq struct { Page int `validate:"omitempty,min=1" form:"page"` PageSize int `validate:"omitempty,min=1" form:"page_size"` - OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered recommend" form:"order"` + OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered recommend frequent" form:"order"` Tag string `validate:"omitempty,gt=0,lte=100" form:"tag"` Username string `validate:"omitempty,gt=0,lte=100" form:"username"` InDays int `validate:"omitempty,min=1" form:"in_days"` @@ -504,7 +504,7 @@ type GetQuestionLinkReq struct { Page int `validate:"omitempty,min=1" form:"page"` PageSize int `validate:"omitempty,min=1,max=100" form:"page_size"` QuestionID string `validate:"required" form:"question_id"` - OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered recommend" form:"order"` + OrderCond string `validate:"omitempty,oneof=newest active hot score unanswered recommend frequent" form:"order"` InDays int `validate:"omitempty,min=1" form:"in_days"` LoginUserID string `json:"-"` diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index 08c74f29..fc01159e 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -81,6 +81,8 @@ type QuestionRepo interface { RemoveAllUserQuestion(ctx context.Context, userID string) (err error) UpdateSearch(ctx context.Context, questionID string) (err error) LinkQuestion(ctx context.Context, link ...*entity.QuestionLink) (err error) + GetLinkedQuestionIDs(ctx context.Context, questionID string, status int) (questionIDs []string, err error) + UpdateQuestionLinkCount(ctx context.Context, questionID string) (err error) RemoveQuestionLink(ctx context.Context, link ...*entity.QuestionLink) (err error) RecoverQuestionLink(ctx context.Context, link ...*entity.QuestionLink) (err error) UpdateQuestionLinkStatus(ctx context.Context, status int, links ...*entity.QuestionLink) (err error) @@ -704,6 +706,17 @@ func (qs *QuestionCommon) UpdateQuestionLink(ctx context.Context, questionID, an if err != nil { return parsedText, err } + // Update the number of question links that have been removed + linkedQuestionIDs, err := qs.questionRepo.GetLinkedQuestionIDs(ctx, questionID, entity.QuestionLinkStatusDeleted) + if err != nil { + log.Errorf("get linked question ids error %v", err) + } else { + for _, id := range linkedQuestionIDs { + if err := qs.questionRepo.UpdateQuestionLinkCount(ctx, id); err != nil { + log.Errorf("update question link count error %v", err) + } + } + } links := checker.GetQuestionLink(originalText) if len(links) == 0 { @@ -799,6 +812,16 @@ func (qs *QuestionCommon) UpdateQuestionLink(ctx context.Context, questionID, an } } + // update question linked count + for _, link := range validLinks { + if len(link.ToQuestionID) == 0 { + continue + } + if err := qs.questionRepo.UpdateQuestionLinkCount(ctx, link.ToQuestionID); err != nil { + log.Errorf("update question link count error %v", err) + } + } + return parsedText, nil } From b9fb758910ae0ce730884e39f4001716fd6eb17b Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 19 Nov 2024 18:33:57 +0800 Subject: [PATCH 311/336] feat(question): sort questions by update time for frequent tab --- internal/repo/question/question_repo.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index e1d94f2e..9b1d212e 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -411,7 +411,7 @@ func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, session.Where("question.answer_count = 0") session.OrderBy("question.pin desc,question.created_at DESC") case "frequent": - session.OrderBy("question.pin DESC, question.linked_count DESC") + session.OrderBy("question.pin DESC, question.linked_count DESC, question.updated_at DESC") } total, err = pager.Help(page, pageSize, &questionList, &entity.Question{}, session) @@ -823,7 +823,7 @@ func (qr *questionRepo) GetQuestionLink(ctx context.Context, page, pageSize int, session.Where("question.answer_count = 0") session.OrderBy("question.pin desc,question.created_at DESC") case "frequent": - session.OrderBy("question.pin DESC, question.linked_count DESC") + session.OrderBy("question.pin DESC, question.linked_count DESC, question.updated_at DESC") } if page > 0 && pageSize > 0 { From a955ba065810651b967352928ff0daafa22ef606 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 21 Nov 2024 15:53:58 +0800 Subject: [PATCH 312/336] feat(upload): add support for file attachments and enhance image upload --- internal/base/constant/site_info.go | 6 ++ internal/controller/upload_controller.go | 6 +- internal/migrations/init.go | 6 +- internal/migrations/v24.go | 38 +++++++++++ internal/schema/siteinfo_schema.go | 36 +++++++++-- internal/service/uploader/upload.go | 81 ++++++++++++++++++++---- pkg/checker/file_type.go | 75 +++++++++++----------- plugin/storage.go | 7 +- 8 files changed, 198 insertions(+), 57 deletions(-) diff --git a/internal/base/constant/site_info.go b/internal/base/constant/site_info.go index 0509c359..2d666834 100644 --- a/internal/base/constant/site_info.go +++ b/internal/base/constant/site_info.go @@ -48,3 +48,9 @@ const ( const ( EmailConfigKey = "email.config" ) + +const ( + DefaultMaxImageMegapixel = 40 * 1000 * 1000 + DefaultMaxImageSize = 4 * 1024 * 1024 + DefaultMaxAttachmentSize = 8 * 1024 * 1024 +) diff --git a/internal/controller/upload_controller.go b/internal/controller/upload_controller.go index 56eba804..a43ccf64 100644 --- a/internal/controller/upload_controller.go +++ b/internal/controller/upload_controller.go @@ -32,6 +32,8 @@ import ( const ( // file is uploaded by markdown(or something else) editor fileFromPost = "post" + // file is used to upload the post attachment + fileFromPostAttachment = "post_attachment" // file is used to change the user's avatar fileFromAvatar = "avatar" // file is logo/icon images @@ -56,7 +58,7 @@ func NewUploadController(uploaderService uploader.UploaderService) *UploadContro // @Tags Upload // @Accept multipart/form-data // @Security ApiKeyAuth -// @Param source formData string true "identify the source of the file upload" Enums(post, avatar, branding) +// @Param source formData string true "identify the source of the file upload" Enums(post, post_attachment, avatar, branding) // @Param file formData file true "file" // @Success 200 {object} handler.RespBody{data=string} // @Router /answer/api/v1/file [post] @@ -74,6 +76,8 @@ func (uc *UploadController) UploadFile(ctx *gin.Context) { url, err = uc.uploaderService.UploadPostFile(ctx) case fileFromBranding: url, err = uc.uploaderService.UploadBrandingFile(ctx) + case fileFromPostAttachment: + url, err = uc.uploaderService.UploadPostAttachment(ctx) default: handler.HandleResponse(ctx, errors.BadRequest(reason.UploadFileSourceUnsupported), nil) return diff --git a/internal/migrations/init.go b/internal/migrations/init.go index 4558ef60..6b1055a0 100644 --- a/internal/migrations/init.go +++ b/internal/migrations/init.go @@ -253,7 +253,11 @@ func (m *Mentor) initSiteInfoPrivilegeRank() { func (m *Mentor) initSiteInfoWrite() { writeData := map[string]interface{}{ - "restrict_answer": true, + "restrict_answer": true, + "max_image_size": 4, + "max_attachment_size": 8, + "max_image_megapixel": 40, + "authorized_extensions": []string{"jpg", "jpeg", "png", "gif", "webp"}, } writeDataBytes, _ := json.Marshal(writeData) _, m.err = m.engine.Context(m.ctx).Insert(&entity.SiteInfo{ diff --git a/internal/migrations/v24.go b/internal/migrations/v24.go index 015352ae..907fd1ef 100644 --- a/internal/migrations/v24.go +++ b/internal/migrations/v24.go @@ -21,12 +21,50 @@ package migrations import ( "context" + "encoding/json" + "fmt" + "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/incubator-answer/internal/schema" "xorm.io/xorm" ) func addQuestionLinkedCount(ctx context.Context, x *xorm.Engine) error { + writeSiteInfo := &entity.SiteInfo{ + Type: constant.SiteTypeWrite, + } + exist, err := x.Context(ctx).Get(writeSiteInfo) + if err != nil { + return fmt.Errorf("get config failed: %w", err) + } + if exist { + type OldSiteWriteReq struct { + RestrictAnswer bool `json:"restrict_answer"` + RequiredTag bool `json:"required_tag"` + RecommendTags []*schema.SiteWriteTag `json:"recommend_tags"` + ReservedTags []*schema.SiteWriteTag `json:"reserved_tags"` + MaxImageSize int `json:"max_image_size"` + MaxAttachmentSize int `json:"max_attachment_size"` + MaxImageMegapixel int `json:"max_image_megapixel"` + AuthorizedImageExtensions []string `json:"authorized_image_extensions"` + AuthorizedAttachmentExtensions []string `json:"authorized_attachment_extensions"` + } + content := &OldSiteWriteReq{} + _ = json.Unmarshal([]byte(writeSiteInfo.Content), content) + content.MaxImageSize = 4 + content.MaxAttachmentSize = 8 + content.MaxImageMegapixel = 40 + content.AuthorizedImageExtensions = []string{"jpg", "jpeg", "png", "gif", "webp"} + content.AuthorizedAttachmentExtensions = []string{} + data, _ := json.Marshal(content) + writeSiteInfo.Content = string(data) + _, err = x.Context(ctx).ID(writeSiteInfo.ID).Cols("content").Update(writeSiteInfo) + if err != nil { + return fmt.Errorf("update site info failed: %w", err) + } + } + type Question struct { LinkedCount int `xorm:"not null default 0 INT(11) linked_count"` } diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go index 99266308..814465d9 100644 --- a/internal/schema/siteinfo_schema.go +++ b/internal/schema/siteinfo_schema.go @@ -72,11 +72,37 @@ type SiteBrandingReq struct { // SiteWriteReq site write request type SiteWriteReq struct { - RestrictAnswer bool `validate:"omitempty" json:"restrict_answer"` - RequiredTag bool `validate:"omitempty" json:"required_tag"` - RecommendTags []*SiteWriteTag `validate:"omitempty,dive" json:"recommend_tags"` - ReservedTags []*SiteWriteTag `validate:"omitempty,dive" json:"reserved_tags"` - UserID string `json:"-"` + RestrictAnswer bool `validate:"omitempty" json:"restrict_answer"` + RequiredTag bool `validate:"omitempty" json:"required_tag"` + RecommendTags []*SiteWriteTag `validate:"omitempty,dive" json:"recommend_tags"` + ReservedTags []*SiteWriteTag `validate:"omitempty,dive" json:"reserved_tags"` + MaxImageSize int `validate:"omitempty,gt=0" json:"max_image_size"` + MaxAttachmentSize int `validate:"omitempty,gt=0" json:"max_attachment_size"` + MaxImageMegapixel int `validate:"omitempty,gt=0" json:"max_image_megapixel"` + AuthorizedImageExtensions []string `validate:"omitempty,dive,gt=0,lte=128" json:"authorized_image_extensions"` + AuthorizedAttachmentExtensions []string `validate:"omitempty,dive,gt=0,lte=128" json:"authorized_attachment_extensions"` + UserID string `json:"-"` +} + +func (s *SiteWriteResp) GetMaxImageSize() int64 { + if s.MaxImageSize <= 0 { + return constant.DefaultMaxImageSize + } + return int64(s.MaxImageSize) * 1024 * 1024 +} + +func (s *SiteWriteResp) GetMaxAttachmentSize() int64 { + if s.MaxAttachmentSize <= 0 { + return constant.DefaultMaxAttachmentSize + } + return int64(s.MaxAttachmentSize) * 1024 * 1024 +} + +func (s *SiteWriteResp) GetMaxImageMegapixel() int { + if s.MaxImageMegapixel <= 0 { + return constant.DefaultMaxImageMegapixel + } + return s.MaxImageMegapixel * 1000 * 1000 } // SiteWriteTag site write response tag diff --git a/internal/service/uploader/upload.go b/internal/service/uploader/upload.go index 3619a6e1..9b810e53 100644 --- a/internal/service/uploader/upload.go +++ b/internal/service/uploader/upload.go @@ -69,6 +69,7 @@ var ( type UploaderService interface { UploadAvatarFile(ctx *gin.Context) (url string, err error) UploadPostFile(ctx *gin.Context) (url string, err error) + UploadPostAttachment(ctx *gin.Context) (url string, err error) UploadBrandingFile(ctx *gin.Context) (url string, err error) AvatarThumbFile(ctx *gin.Context, fileName string, size int) (url string, err error) } @@ -118,7 +119,7 @@ func (us *uploaderService) UploadAvatarFile(ctx *gin.Context) (url string, err e newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) avatarFilePath := path.Join(avatarSubPath, newFilename) - return us.uploadFile(ctx, fileHeader, avatarFilePath) + return us.uploadImageFile(ctx, fileHeader, avatarFilePath) } func (us *uploaderService) AvatarThumbFile(ctx *gin.Context, fileName string, size int) (url string, err error) { @@ -183,21 +184,56 @@ func (us *uploaderService) UploadPostFile(ctx *gin.Context) ( return url, nil } - // max size - ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, 10*1024*1024) + siteWrite, err := us.siteInfoService.GetSiteWrite(ctx) + if err != nil { + return "", err + } + + ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, siteWrite.GetMaxImageSize()) file, fileHeader, err := ctx.Request.FormFile("file") if err != nil { return "", errors.BadRequest(reason.RequestFormatError).WithError(err) } defer file.Close() - fileExt := strings.ToLower(path.Ext(fileHeader.Filename)) - if _, ok := plugin.DefaultFileTypeCheckMapping[plugin.UserPost][fileExt]; !ok { + if checker.IsUnAuthorizedExtension(fileHeader.Filename, siteWrite.AuthorizedImageExtensions) { return "", errors.BadRequest(reason.RequestFormatError).WithError(err) } + fileExt := strings.ToLower(path.Ext(fileHeader.Filename)) newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) avatarFilePath := path.Join(postSubPath, newFilename) - return us.uploadFile(ctx, fileHeader, avatarFilePath) + return us.uploadImageFile(ctx, fileHeader, avatarFilePath) +} + +func (us *uploaderService) UploadPostAttachment(ctx *gin.Context) ( + url string, err error) { + url, err = us.tryToUploadByPlugin(ctx, plugin.UserPostAttachment) + if err != nil { + return "", err + } + if len(url) > 0 { + return url, nil + } + + resp, err := us.siteInfoService.GetSiteWrite(ctx) + if err != nil { + return "", err + } + + ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, resp.GetMaxAttachmentSize()) + file, fileHeader, err := ctx.Request.FormFile("file") + if err != nil { + return "", errors.BadRequest(reason.RequestFormatError).WithError(err) + } + defer file.Close() + if checker.IsUnAuthorizedExtension(fileHeader.Filename, resp.AuthorizedAttachmentExtensions) { + return "", errors.BadRequest(reason.RequestFormatError).WithError(err) + } + + fileExt := strings.ToLower(path.Ext(fileHeader.Filename)) + newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) + avatarFilePath := path.Join(postSubPath, newFilename) + return us.uploadAttachmentFile(ctx, fileHeader, avatarFilePath) } func (us *uploaderService) UploadBrandingFile(ctx *gin.Context) ( @@ -210,8 +246,12 @@ func (us *uploaderService) UploadBrandingFile(ctx *gin.Context) ( return url, nil } - // max size - ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, 10*1024*1024) + siteWrite, err := us.siteInfoService.GetSiteWrite(ctx) + if err != nil { + return "", err + } + + ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, siteWrite.GetMaxImageSize()) file, fileHeader, err := ctx.Request.FormFile("file") if err != nil { return "", errors.BadRequest(reason.RequestFormatError).WithError(err) @@ -224,15 +264,19 @@ func (us *uploaderService) UploadBrandingFile(ctx *gin.Context) ( newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) avatarFilePath := path.Join(brandingSubPath, newFilename) - return us.uploadFile(ctx, fileHeader, avatarFilePath) + return us.uploadImageFile(ctx, fileHeader, avatarFilePath) } -func (us *uploaderService) uploadFile(ctx *gin.Context, file *multipart.FileHeader, fileSubPath string) ( +func (us *uploaderService) uploadImageFile(ctx *gin.Context, file *multipart.FileHeader, fileSubPath string) ( url string, err error) { siteGeneral, err := us.siteInfoService.GetSiteGeneral(ctx) if err != nil { return "", err } + siteWrite, err := us.siteInfoService.GetSiteWrite(ctx) + if err != nil { + return "", err + } filePath := path.Join(us.serviceConfig.UploadPath, fileSubPath) if err := ctx.SaveUploadedFile(file, filePath); err != nil { return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() @@ -244,7 +288,7 @@ func (us *uploaderService) uploadFile(ctx *gin.Context, file *multipart.FileHead } defer src.Close() - if !checker.IsSupportedImageFile(filePath) { + if !checker.DecodeAndCheckImageFile(filePath, siteWrite.GetMaxImageMegapixel()) { return "", errors.BadRequest(reason.UploadFileUnsupportedFileFormat) } @@ -256,6 +300,21 @@ func (us *uploaderService) uploadFile(ctx *gin.Context, file *multipart.FileHead return url, nil } +func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file *multipart.FileHeader, fileSubPath string) ( + url string, err error) { + siteGeneral, err := us.siteInfoService.GetSiteGeneral(ctx) + if err != nil { + return "", err + } + filePath := path.Join(us.serviceConfig.UploadPath, fileSubPath) + if err := ctx.SaveUploadedFile(file, filePath); err != nil { + return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() + } + + url = fmt.Sprintf("%s/uploads/%s", siteGeneral.SiteUrl, fileSubPath) + return url, nil +} + func (us *uploaderService) tryToUploadByPlugin(ctx *gin.Context, source plugin.UploadSource) ( url string, err error) { _ = plugin.CallStorage(func(fn plugin.Storage) error { diff --git a/pkg/checker/file_type.go b/pkg/checker/file_type.go index fffcd960..51f687d6 100644 --- a/pkg/checker/file_type.go +++ b/pkg/checker/file_type.go @@ -34,39 +34,42 @@ import ( "golang.org/x/image/webp" ) -const ( - maxImageSize = 16384 * 16384 -) - -// IsSupportedImageFile currently answers support image type is -// `image/jpeg, image/jpg, image/png, image/gif, image/webp` -func IsSupportedImageFile(localFilePath string) bool { - ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(localFilePath), ".")) - switch ext { - case "jpg", "jpeg", "png", "gif": // only allow for `image/jpeg,image/jpg,image/png, image/gif` - if !decodeAndCheckImageFile(localFilePath, standardImageConfigCheck) { +// IsUnAuthorizedExtension check whether the file extension is not in the allowedExtensions +// WANING Only checks the file extension is not reliable, but `http.DetectContentType` and `mimetype` are not reliable for all file types. +func IsUnAuthorizedExtension(fileName string, allowedExtensions []string) bool { + ext := strings.ToLower(strings.Trim(filepath.Ext(fileName), ".")) + for _, extension := range allowedExtensions { + if extension == ext { return false } - if !decodeAndCheckImageFile(localFilePath, standardImageCheck) { - return false - } - case "ico": - // TODO: There is currently no good Golang library to parse whether the image is in ico format. - return true - case "webp": - if !decodeAndCheckImageFile(localFilePath, webpImageConfigCheck) { - return false - } - if !decodeAndCheckImageFile(localFilePath, webpImageCheck) { - return false - } - default: - return false } return true } -func decodeAndCheckImageFile(localFilePath string, checker func(io.Reader) error) bool { +// DecodeAndCheckImageFile currently answers support image type is +// `image/jpeg, image/jpg, image/png, image/gif, image/webp` +func DecodeAndCheckImageFile(localFilePath string, maxImageMegapixel int) bool { + ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(localFilePath), ".")) + switch ext { + case "jpg", "jpeg", "png", "gif": // only allow for `image/jpeg, image/jpg, image/png, image/gif` + if !decodeAndCheckImageFile(localFilePath, maxImageMegapixel, standardImageConfigCheck) { + return false + } + if !decodeAndCheckImageFile(localFilePath, maxImageMegapixel, standardImageCheck) { + return false + } + case "webp": + if !decodeAndCheckImageFile(localFilePath, maxImageMegapixel, webpImageConfigCheck) { + return false + } + if !decodeAndCheckImageFile(localFilePath, maxImageMegapixel, webpImageCheck) { + return false + } + } + return true +} + +func decodeAndCheckImageFile(localFilePath string, maxImageMegapixel int, checker func(file io.Reader, maxImageMegapixel int) error) bool { file, err := os.Open(localFilePath) if err != nil { log.Errorf("open file error: %v", err) @@ -74,25 +77,25 @@ func decodeAndCheckImageFile(localFilePath string, checker func(io.Reader) error } defer file.Close() - if err = checker(file); err != nil { + if err = checker(file, maxImageMegapixel); err != nil { log.Errorf("check image format error: %v", err) return false } return true } -func standardImageConfigCheck(file io.Reader) error { +func standardImageConfigCheck(file io.Reader, maxImageMegapixel int) error { config, _, err := image.DecodeConfig(file) if err != nil { return fmt.Errorf("decode image config error: %v", err) } - if imageSizeTooLarge(config) { + if imageSizeTooLarge(config, maxImageMegapixel) { return fmt.Errorf("image size too large") } return nil } -func standardImageCheck(file io.Reader) error { +func standardImageCheck(file io.Reader, maxImageMegapixel int) error { _, _, err := image.Decode(file) if err != nil { return fmt.Errorf("decode image error: %v", err) @@ -100,18 +103,18 @@ func standardImageCheck(file io.Reader) error { return nil } -func webpImageConfigCheck(file io.Reader) error { +func webpImageConfigCheck(file io.Reader, maxImageMegapixel int) error { config, err := webp.DecodeConfig(file) if err != nil { return fmt.Errorf("decode webp image config error: %v", err) } - if imageSizeTooLarge(config) { + if imageSizeTooLarge(config, maxImageMegapixel) { return fmt.Errorf("image size too large") } return nil } -func webpImageCheck(file io.Reader) error { +func webpImageCheck(file io.Reader, maxImageMegapixel int) error { _, err := webp.Decode(file) if err != nil { return fmt.Errorf("decode webp image error: %v", err) @@ -119,6 +122,6 @@ func webpImageCheck(file io.Reader) error { return nil } -func imageSizeTooLarge(config image.Config) bool { - return config.Width*config.Height > maxImageSize +func imageSizeTooLarge(config image.Config, maxImageMegapixel int) bool { + return config.Width*config.Height > maxImageMegapixel } diff --git a/plugin/storage.go b/plugin/storage.go index c40a1710..39c29488 100644 --- a/plugin/storage.go +++ b/plugin/storage.go @@ -22,9 +22,10 @@ package plugin type UploadSource string const ( - UserAvatar UploadSource = "user_avatar" - UserPost UploadSource = "user_post" - AdminBranding UploadSource = "admin_branding" + UserAvatar UploadSource = "user_avatar" + UserPost UploadSource = "user_post" + UserPostAttachment UploadSource = "user_post_attachment" + AdminBranding UploadSource = "admin_branding" ) var ( From bc20a71a527a503d07fa191f4f2cd8b1ff52704c Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 22 Nov 2024 10:30:39 +0800 Subject: [PATCH 313/336] feat: The editor has added support for uploading attachments, and the management background has added file upload configuration information. --- i18n/en_US.yaml | 22 ++- ui/src/common/interface.ts | 10 +- ui/src/components/Editor/ToolBars/file.tsx | 130 ++++++++++++++++ ui/src/components/Editor/ToolBars/image.tsx | 86 ++++++++--- ui/src/components/Editor/ToolBars/index.ts | 2 + ui/src/components/Editor/index.tsx | 2 + ui/src/components/Editor/toolItem.tsx | 1 + ui/src/components/QueryGroup/index.tsx | 156 +++++++++++--------- ui/src/components/QuestionList/index.tsx | 5 +- ui/src/pages/Admin/Write/index.tsx | 151 ++++++++++++++++++- ui/src/pages/Tags/Detail/index.tsx | 2 +- ui/src/stores/writeSetting.ts | 5 + ui/src/utils/guard.ts | 7 +- 13 files changed, 482 insertions(+), 97 deletions(-) create mode 100644 ui/src/components/Editor/ToolBars/file.tsx diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 775d7456..776207c2 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -915,7 +915,7 @@ ui: msg: empty: File cannot be empty. only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: Image URL @@ -957,6 +957,10 @@ ui: text: Table heading: Heading cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: I am closing this post as... btn_cancel: Cancel @@ -1557,6 +1561,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -2051,6 +2056,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index 903c5c28..29967e0f 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -173,7 +173,7 @@ export interface UserInfoRes extends UserInfoBase { [prop: string]: any; } -export type UploadType = 'post' | 'avatar' | 'branding'; +export type UploadType = 'post' | 'avatar' | 'branding' | 'post_attachment'; export interface UploadReq { file: FormData; } @@ -301,7 +301,8 @@ export type QuestionOrderBy = | 'active' | 'hot' | 'score' - | 'unanswered'; + | 'unanswered' + | 'frequent'; export interface QueryQuestionsReq extends Paging { order: QuestionOrderBy; @@ -439,6 +440,11 @@ export interface AdminSettingsWrite { recommend_tags?: Tag[]; required_tag?: boolean; reserved_tags?: Tag[]; + max_image_size?: number; + max_attachment_size?: number; + max_image_megapixel?: number; + authorized_image_extensions?: string[]; + authorized_attachment_extensions?: string[]; } export interface AdminSettingsSeo { diff --git a/ui/src/components/Editor/ToolBars/file.tsx b/ui/src/components/Editor/ToolBars/file.tsx new file mode 100644 index 00000000..30544d3e --- /dev/null +++ b/ui/src/components/Editor/ToolBars/file.tsx @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { useState, memo, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { Modal as AnswerModal } from '@/components'; +import ToolItem from '../toolItem'; +import { IEditorContext, Editor } from '../types'; +import { uploadImage } from '@/services'; +import { writeSettingStore } from '@/stores'; + +let context: IEditorContext; +const Image = ({ editorInstance }) => { + const { t } = useTranslation('translation', { keyPrefix: 'editor' }); + const { max_attachment_size = 8, authorized_attachment_extensions = [] } = + writeSettingStore((state) => state.write); + const fileInputRef = useRef(null); + const [editor, setEditor] = useState(editorInstance); + + const item = { + label: 'paperclip', + tip: `${t('file.text')}`, + }; + + const addLink = (ctx) => { + context = ctx; + setEditor(context.editor); + fileInputRef.current?.click?.(); + }; + + const verifyFileSize = (files: FileList) => { + if (files.length === 0) { + return false; + } + const unSupportFiles = Array.from(files).filter((file) => { + const fileName = file.name.toLowerCase(); + return !authorized_attachment_extensions.find((v) => + fileName.endsWith(v), + ); + }); + + if (unSupportFiles.length > 0) { + AnswerModal.confirm({ + content: t('file.not_supported', { + file_type: authorized_attachment_extensions.join(', '), + }), + showCancel: false, + }); + return false; + } + + const attachmentOverSizeFiles = Array.from(files).filter( + (file) => file.size / 1024 / 1024 > max_attachment_size, + ); + if (attachmentOverSizeFiles.length > 0) { + AnswerModal.confirm({ + content: t('file.max_size', { size: max_attachment_size }), + showCancel: false, + }); + return false; + } + + return true; + }; + + const onUpload = async (e) => { + if (!editor) { + return; + } + const files = e.target?.files || []; + const bool = verifyFileSize(files); + + if (!bool) { + return; + } + const fileName = files[0].name; + const loadingText = `![${t('image.uploading')} ${fileName}...]()`; + const startPos = editor.getCursor(); + + const endPos = { ...startPos, ch: startPos.ch + loadingText.length }; + editor.replaceSelection(loadingText); + editor.setReadOnly(true); + + uploadImage({ file: e.target.files[0], type: 'post_attachment' }) + .then((url) => { + const text = `[${fileName}](${url})`; + editor.replaceRange('', startPos, endPos); + editor.replaceSelection(text); + }) + .finally(() => { + editor.setReadOnly(false); + editor.focus(); + }); + }; + + if (!authorized_attachment_extensions.length) { + return null; + } + + return ( + + + + ); +}; + +export default memo(Image); diff --git a/ui/src/components/Editor/ToolBars/image.tsx b/ui/src/components/Editor/ToolBars/image.tsx index 4f72e4e1..fa660944 100644 --- a/ui/src/components/Editor/ToolBars/image.tsx +++ b/ui/src/components/Editor/ToolBars/image.tsx @@ -25,11 +25,18 @@ import { Modal as AnswerModal } from '@/components'; import ToolItem from '../toolItem'; import { IEditorContext, Editor } from '../types'; import { uploadImage } from '@/services'; +import { writeSettingStore } from '@/stores'; let context: IEditorContext; const Image = ({ editorInstance }) => { const [editor, setEditor] = useState(editorInstance); const { t } = useTranslation('translation', { keyPrefix: 'editor' }); + const { + max_image_size = 4, + max_attachment_size = 8, + authorized_image_extensions = [], + authorized_attachment_extensions = [], + } = writeSettingStore((state) => state.write); const loadingText = `![${t('image.uploading')}...]()`; @@ -52,41 +59,85 @@ const Image = ({ editorInstance }) => { isInvalid: false, errorMsg: '', }); + const verifyImageSize = (files: FileList) => { if (files.length === 0) { return false; } - const filteredFiles = Array.from(files).filter( - (file) => file.type.indexOf('image') === -1, - ); - if (filteredFiles.length > 0) { + /** + * When allowing attachments to be uploaded, verification logic for attachment information has been added. In order to avoid abnormal judgment caused by the order of drag and drop upload, the drag and drop upload verification of attachments and the drag and drop upload of images are put together. + * + */ + const canUploadAttachment = authorized_attachment_extensions.length > 0; + const allowedAllType = [ + ...authorized_image_extensions, + ...authorized_attachment_extensions, + ]; + const unSupportFiles = Array.from(files).filter((file) => { + const fileName = file.name.toLowerCase(); + return canUploadAttachment + ? !allowedAllType.find((v) => fileName.endsWith(v)) + : file.type.indexOf('image') === -1; + }); + + if (unSupportFiles.length > 0) { AnswerModal.confirm({ - content: t('image.form_image.fields.file.msg.only_image'), + content: canUploadAttachment + ? t('file.not_supported', { file_type: allowedAllType.join(', ') }) + : t('image.form_image.fields.file.msg.only_image'), + showCancel: false, }); return false; } - const filteredImages = Array.from(files).filter( - (file) => file.size / 1024 / 1024 > 4, - ); - if (filteredImages.length > 0) { + const otherFiles = Array.from(files).filter((file) => { + return file.type.indexOf('image') === -1; + }); + + if (canUploadAttachment && otherFiles.length > 0) { + const attachmentOverSizeFiles = otherFiles.filter( + (file) => file.size / 1024 / 1024 > max_attachment_size, + ); + if (attachmentOverSizeFiles.length > 0) { + AnswerModal.confirm({ + content: t('file.max_size', { size: max_attachment_size }), + showCancel: false, + }); + return false; + } + } + + const imageFiles = Array.from(files).filter( + (file) => file.type.indexOf('image') > -1, + ); + const oversizedImages = imageFiles.filter( + (file) => file.size / 1024 / 1024 > max_image_size, + ); + if (oversizedImages.length > 0) { AnswerModal.confirm({ - content: t('image.form_image.fields.file.msg.max_size'), + content: t('image.form_image.fields.file.msg.max_size', { + size: max_image_size, + }), + showCancel: false, }); return false; } + return true; }; + const upload = ( files: FileList, - ): Promise<{ url: string; name: string }[]> => { + ): Promise<{ url: string; name: string; type: string }[]> => { const promises = Array.from(files).map(async (file) => { - const url = await uploadImage({ file, type: 'post' }); + const type = file.type.indexOf('image') > -1 ? 'post' : 'post_attachment'; + const url = await uploadImage({ file, type }); return { name: file.name, url, + type, }; }); @@ -103,7 +154,6 @@ const Image = ({ editorInstance }) => { } const drop = async (e) => { const fileList = e.dataTransfer.files; - const bool = verifyImageSize(fileList); if (!bool) { @@ -122,9 +172,9 @@ const Image = ({ editorInstance }) => { const text: string[] = []; if (Array.isArray(urls)) { - urls.forEach(({ name, url }) => { + urls.forEach(({ name, url, type }) => { if (name && url) { - text.push(`![${name}](${url})`); + text.push(`${type === 'post' ? '!' : ''}[${name}](${url})`); } }); } @@ -150,8 +200,8 @@ const Image = ({ editorInstance }) => { editor.replaceSelection(loadingText); editor.setReadOnly(true); const urls = await upload(clipboard.files); - const text = urls.map(({ name, url }) => { - return `![${name}](${url})`; + const text = urls.map(({ name, url, type }) => { + return `${type === 'post' ? '!' : ''}[${name}](${url})`; }); editor.replaceRange(text.join('\n'), startPos, endPos); @@ -252,6 +302,7 @@ const Image = ({ editorInstance }) => { uploadImage({ file: e.target.files[0], type: 'post' }).then((url) => { setLink({ ...link, value: url }); + setImageName({ ...imageName, value: files[0].name }); }); }; @@ -283,6 +334,7 @@ const Image = ({ editorInstance }) => { type="file" onChange={onUpload} isInvalid={currentTab === 'localImage' && link.isInvalid} + accept="image/*" /> diff --git a/ui/src/components/Editor/ToolBars/index.ts b/ui/src/components/Editor/ToolBars/index.ts index ce04587d..05912bc6 100644 --- a/ui/src/components/Editor/ToolBars/index.ts +++ b/ui/src/components/Editor/ToolBars/index.ts @@ -32,6 +32,7 @@ import BlockQuote from './blockquote'; import Image from './image'; import Help from './help'; import Chart from './chart'; +import File from './file'; export { Table, @@ -49,4 +50,5 @@ export { Image, Help, Chart, + File, }; diff --git a/ui/src/components/Editor/index.tsx b/ui/src/components/Editor/index.tsx index ead37653..45919b2c 100644 --- a/ui/src/components/Editor/index.tsx +++ b/ui/src/components/Editor/index.tsx @@ -45,6 +45,7 @@ import { Outdent, Table, UL, + File, } from './ToolBars'; import { htmlRender, useEditor } from './utils'; import Viewer from './Viewer'; @@ -130,6 +131,7 @@ const MDEditor: ForwardRefRenderFunction = (
+
    diff --git a/ui/src/components/Editor/toolItem.tsx b/ui/src/components/Editor/toolItem.tsx index 0c4ca2f1..e7b21867 100644 --- a/ui/src/components/Editor/toolItem.tsx +++ b/ui/src/components/Editor/toolItem.tsx @@ -93,6 +93,7 @@ const ToolItem: FC = (props) => { disabled={disable} tabIndex={-1} onClick={(e) => { + console.log('onClick', e); e.preventDefault(); onClick?.({ editor, diff --git a/ui/src/components/QueryGroup/index.tsx b/ui/src/components/QueryGroup/index.tsx index 9b37c6e9..7f6a0f3e 100644 --- a/ui/src/components/QueryGroup/index.tsx +++ b/ui/src/components/QueryGroup/index.tsx @@ -35,8 +35,8 @@ interface Props { className?: string; pathname?: string; wrapClassName?: string; + maxBtnCount?: number; } -const MAX_BUTTON_COUNT = 3; const Index: FC = ({ data = [], currentSort = '', @@ -45,6 +45,7 @@ const Index: FC = ({ className = '', pathname = '', wrapClassName = '', + maxBtnCount = 3, }) => { const [searchParams, setUrlSearchParams] = useSearchParams(); const navigate = useNavigate(); @@ -71,79 +72,94 @@ const Index: FC = ({ } } }; - - const filteredData = data.filter((_, index) => index > MAX_BUTTON_COUNT - 2); - const currentBtn = filteredData.find((btn) => { + const moreBtnData = data.length > 4 ? data.slice(maxBtnCount) : []; + const normalBtnData = data.length > 4 ? data.slice(0, maxBtnCount) : data; + const currentBtn = moreBtnData.find((btn) => { return (typeof btn === 'string' ? btn : btn.name) === currentSort; }); + return ( - - {data.map((btn, index) => { - const key = typeof btn === 'string' ? btn : btn.sort; - const name = typeof btn === 'string' ? btn : btn.name; - return ( - + ); + })} + {moreBtnData.length > 0 && ( + + {moreBtnData.map((btn) => { + const key = typeof btn === 'string' ? btn : btn.sort; + const name = typeof btn === 'string' ? btn : btn.name; + return ( + handleClick(evt, key)}> - {t(name)} - - ); - })} - {data.length > MAX_BUTTON_COUNT && ( - - {filteredData.map((btn) => { - const key = typeof btn === 'string' ? btn : btn.sort; - const name = typeof btn === 'string' ? btn : btn.name; - return ( - handleClick(evt, key)}> - {t(name)} - - ); - })} - - )} - + onClick={(evt) => handleClick(evt, key)}> + {t(name)} + + ); + })} + + )} + + + {data.map((btn) => { + const key = typeof btn === 'string' ? btn : btn.sort; + const name = typeof btn === 'string' ? btn : btn.name; + return ( + handleClick(evt, key)}> + {t(name)} + + ); + })} + + ); }; diff --git a/ui/src/components/QuestionList/index.tsx b/ui/src/components/QuestionList/index.tsx index 82baea6a..c849de56 100644 --- a/ui/src/components/QuestionList/index.tsx +++ b/ui/src/components/QuestionList/index.tsx @@ -40,10 +40,10 @@ import { useSkeletonControl } from '@/hooks'; export const QUESTION_ORDER_KEYS: Type.QuestionOrderBy[] = [ 'newest', 'active', - 'hot', - 'score', 'unanswered', 'recommend', + 'frequent', + 'score', ]; interface Props { source: 'questions' | 'tag' | 'linked'; @@ -83,6 +83,7 @@ const QuestionList: FC = ({ currentSort={curOrder} pathname={source === 'questions' ? '/questions' : ''} i18nKeyPrefix="question" + maxBtnCount={source === 'tag' ? 3 : 4} />
diff --git a/ui/src/pages/Admin/Write/index.tsx b/ui/src/pages/Admin/Write/index.tsx index 442c58f6..fcf99c1d 100644 --- a/ui/src/pages/Admin/Write/index.tsx +++ b/ui/src/pages/Admin/Write/index.tsx @@ -52,6 +52,31 @@ const initFormData = { errorMsg: '', isInvalid: false, }, + max_image_size: { + value: 4, + errorMsg: '', + isInvalid: false, + }, + max_attachment_size: { + value: 8, + errorMsg: '', + isInvalid: false, + }, + max_image_megapixel: { + value: 40, + errorMsg: '', + isInvalid: false, + }, + authorized_image_extensions: { + value: 'jpg, jpeg, png, gif, webp', + errorMsg: '', + isInvalid: false, + }, + authorized_attachment_extensions: { + value: '', + errorMsg: '', + isInvalid: false, + }, }; const Index: FC = () => { @@ -111,6 +136,18 @@ const Index: FC = () => { reserved_tags: formData.reserved_tags.value, required_tag: formData.required_tag.value, restrict_answer: formData.restrict_answer.value, + max_image_size: Number(formData.max_image_size.value), + max_attachment_size: Number(formData.max_attachment_size.value), + max_image_megapixel: Number(formData.max_image_megapixel.value), + authorized_image_extensions: formData.authorized_image_extensions.value + .split(',') + ?.map((item) => item.trim().toLowerCase()), + authorized_attachment_extensions: + formData.authorized_attachment_extensions.value.length > 0 + ? formData.authorized_attachment_extensions.value + .split(',') + ?.map((item) => item.trim().toLowerCase()) + : [], }; postRequireAndReservedTag(reqParams) .then(() => { @@ -120,7 +157,7 @@ const Index: FC = () => { }); writeSettingStore .getState() - .update({ restrict_answer: reqParams.restrict_answer }); + .update({ restrict_answer: reqParams.restrict_answer, ...reqParams }); }) .catch((err) => { if (err.isError) { @@ -142,6 +179,13 @@ const Index: FC = () => { if (Array.isArray(res.reserved_tags)) { formData.reserved_tags.value = res.reserved_tags; } + formData.max_image_size.value = res.max_image_size; + formData.max_attachment_size.value = res.max_attachment_size; + formData.max_image_megapixel.value = res.max_image_megapixel; + formData.authorized_image_extensions.value = + res.authorized_image_extensions?.join(', ').toLowerCase(); + formData.authorized_attachment_extensions.value = + res.authorized_attachment_extensions?.join(', ').toLowerCase(); setFormData({ ...formData }); }); }; @@ -243,6 +287,111 @@ const Index: FC = () => { + + {t('image_size.label')} + { + handleValueChange({ + max_image_size: { + value: evt.target.value, + errorMsg: '', + isInvalid: false, + }, + }); + }} + /> + {t('image_size.text')} + + {formData.max_image_size.errorMsg} + + + + + {t('attachment_size.label')} + { + handleValueChange({ + max_attachment_size: { + value: evt.target.value, + errorMsg: '', + isInvalid: false, + }, + }); + }} + /> + {t('attachment_size.text')} + + {formData.max_attachment_size.errorMsg} + + + + + {t('image_megapixels.label')} + { + handleValueChange({ + max_image_megapixel: { + value: evt.target.value, + errorMsg: '', + isInvalid: false, + }, + }); + }} + /> + {t('image_megapixels.text')} + + {formData.max_image_megapixel.errorMsg} + + + + + {t('image_extensions.label')} + { + handleValueChange({ + authorized_image_extensions: { + value: evt.target.value.toLowerCase(), + errorMsg: '', + isInvalid: false, + }, + }); + }} + /> + {t('image_extensions.text')} + + {formData.authorized_image_extensions.errorMsg} + + + + + {t('attachment_extensions.label')} + { + handleValueChange({ + authorized_attachment_extensions: { + value: evt.target.value.toLowerCase(), + errorMsg: '', + isInvalid: false, + }, + }); + }} + /> + {t('attachment_extensions.text')} + + {formData.authorized_attachment_extensions.errorMsg} + + + diff --git a/ui/src/pages/Tags/Detail/index.tsx b/ui/src/pages/Tags/Detail/index.tsx index 41b19022..8bfd5ee8 100644 --- a/ui/src/pages/Tags/Detail/index.tsx +++ b/ui/src/pages/Tags/Detail/index.tsx @@ -186,7 +186,7 @@ const Index: FC = () => { source="tag" data={listData} order={curOrder} - orderList={QUESTION_ORDER_KEYS.slice(0, 5)} + orderList={QUESTION_ORDER_KEYS.filter((k) => k !== 'recommend')} isLoading={listLoading} /> diff --git a/ui/src/stores/writeSetting.ts b/ui/src/stores/writeSetting.ts index 8e7c1f52..f3a5613c 100644 --- a/ui/src/stores/writeSetting.ts +++ b/ui/src/stores/writeSetting.ts @@ -32,6 +32,11 @@ const Index = create((set) => ({ recommend_tags: [], required_tag: false, reserved_tags: [], + max_image_size: 4, + max_attachment_size: 8, + max_image_megapixel: 40, + authorized_image_extensions: [], + authorized_attachment_extensions: [], }, update: (params) => set((state) => { diff --git a/ui/src/utils/guard.ts b/ui/src/utils/guard.ts index 5f2e7b52..f3ba4235 100644 --- a/ui/src/utils/guard.ts +++ b/ui/src/utils/guard.ts @@ -408,9 +408,10 @@ export const initAppSettingsStore = async () => { customizeStore.getState().update(appSettings.custom_css_html); themeSettingStore.getState().update(appSettings.theme); seoSettingStore.getState().update(appSettings.site_seo); - writeSettingStore - .getState() - .update({ restrict_answer: appSettings.site_write.restrict_answer }); + writeSettingStore.getState().update({ + restrict_answer: appSettings.site_write.restrict_answer, + ...appSettings.site_write, + }); } }; From 4831f6ef13c1003b0571230d3cc9a0e35828ba2d Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 22 Nov 2024 11:31:53 +0800 Subject: [PATCH 314/336] fix: Add file upload error handling --- ui/src/components/Editor/ToolBars/file.tsx | 3 ++ ui/src/components/Editor/ToolBars/image.tsx | 34 +++++++++++++-------- ui/src/pages/Admin/Write/index.tsx | 26 +++++++++++----- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/ui/src/components/Editor/ToolBars/file.tsx b/ui/src/components/Editor/ToolBars/file.tsx index 30544d3e..869d1dc6 100644 --- a/ui/src/components/Editor/ToolBars/file.tsx +++ b/ui/src/components/Editor/ToolBars/file.tsx @@ -104,6 +104,9 @@ const Image = ({ editorInstance }) => { editor.replaceRange('', startPos, endPos); editor.replaceSelection(text); }) + .catch(() => { + editor.replaceRange('', startPos, endPos); + }) .finally(() => { editor.setReadOnly(false); editor.focus(); diff --git a/ui/src/components/Editor/ToolBars/image.tsx b/ui/src/components/Editor/ToolBars/image.tsx index fa660944..322da08d 100644 --- a/ui/src/components/Editor/ToolBars/image.tsx +++ b/ui/src/components/Editor/ToolBars/image.tsx @@ -166,9 +166,14 @@ const Image = ({ editorInstance }) => { editor.replaceSelection(loadingText); editor.setReadOnly(true); - const urls = await upload(fileList).catch((ex) => { - console.error('upload file error: ', ex); - }); + const urls = await upload(fileList) + .catch(() => { + editor.replaceRange('', startPos, endPos); + }) + .finally(() => { + editor.setReadOnly(false); + editor.focus(); + }); const text: string[] = []; if (Array.isArray(urls)) { @@ -183,8 +188,6 @@ const Image = ({ editorInstance }) => { } else { editor.replaceRange('', startPos, endPos); } - editor.setReadOnly(false); - editor.focus(); }; const paste = async (event) => { @@ -199,14 +202,21 @@ const Image = ({ editorInstance }) => { editor.replaceSelection(loadingText); editor.setReadOnly(true); - const urls = await upload(clipboard.files); - const text = urls.map(({ name, url, type }) => { - return `${type === 'post' ? '!' : ''}[${name}](${url})`; - }); + upload(clipboard.files) + .then((urls) => { + const text = urls.map(({ name, url, type }) => { + return `${type === 'post' ? '!' : ''}[${name}](${url})`; + }); - editor.replaceRange(text.join('\n'), startPos, endPos); - editor.setReadOnly(false); - editor.focus(); + editor.replaceRange(text.join('\n'), startPos, endPos); + }) + .catch(() => { + editor.replaceRange('', startPos, endPos); + }) + .finally(() => { + editor.setReadOnly(false); + editor.focus(); + }); return; } diff --git a/ui/src/pages/Admin/Write/index.tsx b/ui/src/pages/Admin/Write/index.tsx index fcf99c1d..d82f5aa0 100644 --- a/ui/src/pages/Admin/Write/index.tsx +++ b/ui/src/pages/Admin/Write/index.tsx @@ -139,9 +139,12 @@ const Index: FC = () => { max_image_size: Number(formData.max_image_size.value), max_attachment_size: Number(formData.max_attachment_size.value), max_image_megapixel: Number(formData.max_image_megapixel.value), - authorized_image_extensions: formData.authorized_image_extensions.value - .split(',') - ?.map((item) => item.trim().toLowerCase()), + authorized_image_extensions: + formData.authorized_image_extensions.value.length > 0 + ? formData.authorized_image_extensions.value + .split(',') + ?.map((item) => item.trim().toLowerCase()) + : [], authorized_attachment_extensions: formData.authorized_attachment_extensions.value.length > 0 ? formData.authorized_attachment_extensions.value @@ -287,11 +290,12 @@ const Index: FC = () => { - + {t('image_size.label')} { handleValueChange({ max_image_size: { @@ -308,11 +312,12 @@ const Index: FC = () => { - + {t('attachment_size.label')} { handleValueChange({ max_attachment_size: { @@ -329,10 +334,11 @@ const Index: FC = () => { - + {t('image_megapixels.label')} { handleValueChange({ @@ -350,11 +356,12 @@ const Index: FC = () => { - + {t('image_extensions.label')} { handleValueChange({ authorized_image_extensions: { @@ -371,11 +378,14 @@ const Index: FC = () => { - + {t('attachment_extensions.label')} { handleValueChange({ authorized_attachment_extensions: { From aac2370fe8948acc51bb1099e9e0231c7ecde2a4 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Thu, 21 Nov 2024 15:53:58 +0800 Subject: [PATCH 315/336] feat(upload): add support for file attachments and enhance image upload --- internal/schema/siteinfo_schema.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go index 814465d9..fee6b8cb 100644 --- a/internal/schema/siteinfo_schema.go +++ b/internal/schema/siteinfo_schema.go @@ -79,8 +79,8 @@ type SiteWriteReq struct { MaxImageSize int `validate:"omitempty,gt=0" json:"max_image_size"` MaxAttachmentSize int `validate:"omitempty,gt=0" json:"max_attachment_size"` MaxImageMegapixel int `validate:"omitempty,gt=0" json:"max_image_megapixel"` - AuthorizedImageExtensions []string `validate:"omitempty,dive,gt=0,lte=128" json:"authorized_image_extensions"` - AuthorizedAttachmentExtensions []string `validate:"omitempty,dive,gt=0,lte=128" json:"authorized_attachment_extensions"` + AuthorizedImageExtensions []string `validate:"omitempty" json:"authorized_image_extensions"` + AuthorizedAttachmentExtensions []string `validate:"omitempty" json:"authorized_attachment_extensions"` UserID string `json:"-"` } From 4e792ea460d0811072b84ca0a3a6de0c04623009 Mon Sep 17 00:00:00 2001 From: shuai Date: Fri, 22 Nov 2024 12:42:05 +0800 Subject: [PATCH 316/336] fix: length error --- ui/src/components/Editor/ToolBars/file.tsx | 2 +- ui/src/pages/Admin/Write/index.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/components/Editor/ToolBars/file.tsx b/ui/src/components/Editor/ToolBars/file.tsx index 869d1dc6..15238379 100644 --- a/ui/src/components/Editor/ToolBars/file.tsx +++ b/ui/src/components/Editor/ToolBars/file.tsx @@ -113,7 +113,7 @@ const Image = ({ editorInstance }) => { }); }; - if (!authorized_attachment_extensions.length) { + if (!authorized_attachment_extensions?.length) { return null; } diff --git a/ui/src/pages/Admin/Write/index.tsx b/ui/src/pages/Admin/Write/index.tsx index d82f5aa0..91e41493 100644 --- a/ui/src/pages/Admin/Write/index.tsx +++ b/ui/src/pages/Admin/Write/index.tsx @@ -140,13 +140,13 @@ const Index: FC = () => { max_attachment_size: Number(formData.max_attachment_size.value), max_image_megapixel: Number(formData.max_image_megapixel.value), authorized_image_extensions: - formData.authorized_image_extensions.value.length > 0 + formData.authorized_image_extensions.value?.length > 0 ? formData.authorized_image_extensions.value .split(',') ?.map((item) => item.trim().toLowerCase()) : [], authorized_attachment_extensions: - formData.authorized_attachment_extensions.value.length > 0 + formData.authorized_attachment_extensions.value?.length > 0 ? formData.authorized_attachment_extensions.value .split(',') ?.map((item) => item.trim().toLowerCase()) From 7b4044c15d313926bb297fc3a78ab5851deca121 Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 25 Nov 2024 10:31:38 +0800 Subject: [PATCH 317/336] fix: Optimize the mobile style of QueryGroup component --- ui/src/components/QueryGroup/index.scss | 16 ++++++++++++++++ ui/src/components/QueryGroup/index.tsx | 10 +++++----- 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 ui/src/components/QueryGroup/index.scss diff --git a/ui/src/components/QueryGroup/index.scss b/ui/src/components/QueryGroup/index.scss new file mode 100644 index 00000000..9ab5b36d --- /dev/null +++ b/ui/src/components/QueryGroup/index.scss @@ -0,0 +1,16 @@ +.md-show { + display: flex !important; +} +.md-hide { + display: none; +} + + +@media screen and (max-width: 768px) { + .md-show { + display: none !important; + } + .md-hide { + display: block; + } +} diff --git a/ui/src/components/QueryGroup/index.tsx b/ui/src/components/QueryGroup/index.tsx index 7f6a0f3e..52fca616 100644 --- a/ui/src/components/QueryGroup/index.tsx +++ b/ui/src/components/QueryGroup/index.tsx @@ -27,6 +27,8 @@ import classNames from 'classnames'; import { REACT_BASE_PATH } from '@/router/alias'; import { floppyNavigation } from '@/utils'; +import './index.scss'; + interface Props { data; i18nKeyPrefix: string; @@ -80,9 +82,7 @@ const Index: FC = ({ return ( <> - + {normalBtnData.map((btn) => { const key = typeof btn === 'string' ? btn : btn.sort; const name = typeof btn === 'string' ? btn : btn.name; @@ -132,8 +132,8 @@ const Index: FC = ({ {data.map((btn) => { const key = typeof btn === 'string' ? btn : btn.sort; From 4f01ccd5ded3d980863b67718340c88cde81cbd7 Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 25 Nov 2024 11:22:54 +0800 Subject: [PATCH 318/336] fix: Optimize the mobile style of QueryGroup component dropdown btns --- ui/src/components/QueryGroup/index.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui/src/components/QueryGroup/index.tsx b/ui/src/components/QueryGroup/index.tsx index 52fca616..878e8ed6 100644 --- a/ui/src/components/QueryGroup/index.tsx +++ b/ui/src/components/QueryGroup/index.tsx @@ -143,11 +143,7 @@ const Index: FC = ({ as="a" key={key} active={currentSort === name} - className={classNames( - 'text-capitalize', - 'd-block d-sm-none', - className, - )} + className={classNames('text-capitalize', className)} href={ pathname ? `${REACT_BASE_PATH}${pathname}${handleParams(key)}` From 1ea056609b7b485c1de99889596f2d104c44f883 Mon Sep 17 00:00:00 2001 From: shuai Date: Mon, 25 Nov 2024 11:45:54 +0800 Subject: [PATCH 319/336] fix: The pre tag sets the maximum height #1168 --- ui/src/index.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/index.scss b/ui/src/index.scss index 6da6d336..7586e9a1 100644 --- a/ui/src/index.scss +++ b/ui/src/index.scss @@ -250,6 +250,7 @@ img[src=""] { background-color: var(--an-e9ecef); border-radius: 0.25rem; padding: 1rem; + max-height: 38rem; } blockquote { border-left: 0.25rem solid #ced4da; From 73eb2a1133b96a4f64d6ad40ed180eed923820f2 Mon Sep 17 00:00:00 2001 From: wxt <3264117476@qq.com> Date: Mon, 25 Nov 2024 14:18:57 +0800 Subject: [PATCH 320/336] test: fix TestGetAvatarURL --- pkg/gravatar/gravatar_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/gravatar/gravatar_test.go b/pkg/gravatar/gravatar_test.go index 50bd79b4..cedbb1a3 100644 --- a/pkg/gravatar/gravatar_test.go +++ b/pkg/gravatar/gravatar_test.go @@ -38,7 +38,7 @@ func TestGetAvatarURL(t *testing.T) { { name: "answer@answer.com", args: args{email: "answer@answer.com"}, - want: "https://www.gravatar.com/avatar/b2be4e4438f08a5e885be8de5f41fdd7", + want: "https://www.gravatar.com/avatar/7296942c1f63d97f6c124705142009867638f7b3dbcdadd0cb1bcb40e427eb8e", }, } for _, tt := range tests { From 43a474b417a1f85fce4407cd5870936335c9e18a Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 26 Nov 2024 15:23:33 +0800 Subject: [PATCH 321/336] feat(storage): add upload file condition to plugin upload --- internal/controller/upload_controller.go | 5 +++++ internal/service/uploader/upload.go | 22 +++++++++++++++++++--- plugin/storage.go | 17 ++++++++++++++++- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/internal/controller/upload_controller.go b/internal/controller/upload_controller.go index a43ccf64..753be375 100644 --- a/internal/controller/upload_controller.go +++ b/internal/controller/upload_controller.go @@ -21,6 +21,7 @@ package controller import ( "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/middleware" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/schema" "github.com/apache/incubator-answer/internal/service/uploader" @@ -75,6 +76,10 @@ func (uc *UploadController) UploadFile(ctx *gin.Context) { case fileFromPost: url, err = uc.uploaderService.UploadPostFile(ctx) case fileFromBranding: + if !middleware.GetIsAdminFromContext(ctx) { + handler.HandleResponse(ctx, errors.Forbidden(reason.ForbiddenError), nil) + return + } url, err = uc.uploaderService.UploadBrandingFile(ctx) case fileFromPostAttachment: url, err = uc.uploaderService.UploadPostAttachment(ctx) diff --git a/internal/service/uploader/upload.go b/internal/service/uploader/upload.go index 9b810e53..a8d9c0cc 100644 --- a/internal/service/uploader/upload.go +++ b/internal/service/uploader/upload.go @@ -105,8 +105,12 @@ func (us *uploaderService) UploadAvatarFile(ctx *gin.Context) (url string, err e return url, nil } - // max size - ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, 5*1024*1024) + siteWrite, err := us.siteInfoService.GetSiteWrite(ctx) + if err != nil { + return "", err + } + + ctx.Request.Body = http.MaxBytesReader(ctx.Writer, ctx.Request.Body, siteWrite.GetMaxImageSize()) file, fileHeader, err := ctx.Request.FormFile("file") if err != nil { return "", errors.BadRequest(reason.RequestFormatError).WithError(err) @@ -317,8 +321,20 @@ func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file *multipar func (us *uploaderService) tryToUploadByPlugin(ctx *gin.Context, source plugin.UploadSource) ( url string, err error) { + siteWrite, err := us.siteInfoService.GetSiteWrite(ctx) + if err != nil { + return "", err + } + cond := plugin.UploadFileCondition{ + Source: source, + MaxImageSize: siteWrite.MaxImageSize, + MaxAttachmentSize: siteWrite.MaxAttachmentSize, + MaxImageMegapixel: siteWrite.MaxImageMegapixel, + AuthorizedImageExtensions: siteWrite.AuthorizedImageExtensions, + AuthorizedAttachmentExtensions: siteWrite.AuthorizedAttachmentExtensions, + } _ = plugin.CallStorage(func(fn plugin.Storage) error { - resp := fn.UploadFile(ctx, source) + resp := fn.UploadFile(ctx, cond) if resp.OriginalError != nil { log.Errorf("upload file by plugin failed, err: %v", resp.OriginalError) err = errors.BadRequest("").WithMsg(resp.DisplayErrorMsg.Translate(ctx)).WithError(err) diff --git a/plugin/storage.go b/plugin/storage.go index 39c29488..599a41c4 100644 --- a/plugin/storage.go +++ b/plugin/storage.go @@ -52,6 +52,21 @@ var ( } ) +type UploadFileCondition struct { + // Source is the source of the file + Source UploadSource + // MaxImageSize is the maximum size of the image in MB + MaxImageSize int + // MaxAttachmentSize is the maximum size of the attachment in MB + MaxAttachmentSize int + // MaxImageMegapixel is the maximum megapixel of the image + MaxImageMegapixel int + // AuthorizedImageExtensions is the list of authorized image extensions + AuthorizedImageExtensions []string + // AuthorizedAttachmentExtensions is the list of authorized attachment extensions + AuthorizedAttachmentExtensions []string +} + type UploadFileResponse struct { // FullURL is the URL that can be used to access the file FullURL string @@ -66,7 +81,7 @@ type Storage interface { // UploadFile uploads a file to storage. // The file is in the Form of the ctx and the key is "file" - UploadFile(ctx *GinContext, source UploadSource) UploadFileResponse + UploadFile(ctx *GinContext, condition UploadFileCondition) UploadFileResponse } var ( From b558de8a236476c3dc5f338174d3ac663c48d4c7 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Fri, 29 Nov 2024 15:15:23 +0800 Subject: [PATCH 322/336] feat(user): add top questions and answers to user homepage --- internal/controller/template_controller.go | 12 ++++++-- ui/template/homepage.html | 33 +++++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index df10931e..0b22360f 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -546,12 +546,20 @@ func (tc *TemplateController) UserInfo(ctx *gin.Context) { return } + questionList, answerList, err := tc.questionService.SearchUserTopList(ctx, req.Username, "") + if err != nil { + tc.Page404(ctx) + return + } + siteInfo := tc.SiteInfo(ctx) siteInfo.Canonical = fmt.Sprintf("%s/users/%s", siteInfo.General.SiteUrl, username) siteInfo.Title = fmt.Sprintf("%s - %s", username, siteInfo.General.Name) tc.html(ctx, http.StatusOK, "homepage.html", siteInfo, gin.H{ - "userinfo": userinfo, - "bio": template.HTML(userinfo.BioHTML), + "userinfo": userinfo, + "bio": template.HTML(userinfo.BioHTML), + "topQuestions": questionList, + "topAnswers": answerList, }) } diff --git a/ui/template/homepage.html b/ui/template/homepage.html index 2f68200d..84887a09 100644 --- a/ui/template/homepage.html +++ b/ui/template/homepage.html @@ -63,10 +63,41 @@
{{translator $.language "ui.personal.about_me"}}
{{if .bio }} -
{{.bio}}
+
{{.bio}}
{{else}}
{{translator $.language "ui.personal.about_me_empty"}}
{{end}} +
+
+
Top Answers
+
    + {{ range .topAnswers }} +
  1. + {{.QuestionInfo.Title}} +
    + {{.VoteCount}} votes +
    +
  2. + {{ end }} +
+
+
+
Top Questions
+
    + {{ range .topQuestions }} +
  1. + {{.Title}} +
    + {{.VoteCount}} votes +
    + {{.AnswerCount}} answers +
    +
    +
  2. + {{ end }} +
+
+
From e41a8522fc0f76c6e76f5f195873cafce4f17e5e Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Fri, 29 Nov 2024 15:37:31 +0800 Subject: [PATCH 323/336] fix: administrator add user failure --- docs/docs.go | 2 +- docs/swagger.json | 2 +- docs/swagger.yaml | 2 +- internal/schema/backyard_user_schema.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 424bd669..9863b0c0 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -7829,7 +7829,7 @@ const docTemplate = `{ "display_name": { "type": "string", "maxLength": 30, - "minLength": 4 + "minLength": 2 }, "email": { "type": "string", diff --git a/docs/swagger.json b/docs/swagger.json index 7ec493b2..5c2f459c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -7802,7 +7802,7 @@ "display_name": { "type": "string", "maxLength": 30, - "minLength": 4 + "minLength": 2 }, "email": { "type": "string", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4622e964..811b3c28 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -270,7 +270,7 @@ definitions: properties: display_name: maxLength: 30 - minLength: 4 + minLength: 2 type: string email: maxLength: 500 diff --git a/internal/schema/backyard_user_schema.go b/internal/schema/backyard_user_schema.go index 9f8733b2..7c690aee 100644 --- a/internal/schema/backyard_user_schema.go +++ b/internal/schema/backyard_user_schema.go @@ -120,7 +120,7 @@ type EditUserProfileReq struct { // AddUserReq add user request type AddUserReq struct { - DisplayName string `validate:"required,gte=4,lte=30" json:"display_name"` + DisplayName string `validate:"required,gte=2,lte=30" json:"display_name"` Email string `validate:"required,email,gt=0,lte=500" json:"email"` Password string `validate:"required,gte=8,lte=32" json:"password"` LoginUserID string `json:"-"` From 565ee3cc1b49ed0f836ba6fc1eef9b028abaab49 Mon Sep 17 00:00:00 2001 From: shuai Date: Tue, 3 Dec 2024 10:18:18 +0800 Subject: [PATCH 324/336] fix: Attachment accept type adjustment, editor plug-in insertion position added conditional restrictions --- ui/src/components/Editor/ToolBars/file.tsx | 4 +++- ui/src/components/PluginRender/index.tsx | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ui/src/components/Editor/ToolBars/file.tsx b/ui/src/components/Editor/ToolBars/file.tsx index 15238379..9e6e7399 100644 --- a/ui/src/components/Editor/ToolBars/file.tsx +++ b/ui/src/components/Editor/ToolBars/file.tsx @@ -122,7 +122,9 @@ const Image = ({ editorInstance }) => { diff --git a/ui/src/components/PluginRender/index.tsx b/ui/src/components/PluginRender/index.tsx index 9de283f5..002d5a58 100644 --- a/ui/src/components/PluginRender/index.tsx +++ b/ui/src/components/PluginRender/index.tsx @@ -20,6 +20,7 @@ import React, { FC, ReactNode } from 'react'; import PluginKit, { Plugin, PluginType } from '@/utils/pluginKit'; +import { writeSettingStore } from '@/stores'; /** * Note:Please set at least either of the `slug_name` and `type` attributes, otherwise no plugins will be rendered. * @@ -47,6 +48,9 @@ const Index: FC = ({ }) => { const pluginSlice: Plugin[] = []; const plugins = PluginKit.getPlugins().filter((plugin) => plugin.activated); + const { authorized_attachment_extensions = [] } = writeSettingStore( + (state) => state.write, + ); plugins.forEach((plugin) => { if (type && slug_name) { @@ -76,8 +80,10 @@ const Index: FC = ({ } if (type === 'editor') { + const showAttachFile = authorized_attachment_extensions?.length > 0; + const pendIndex = showAttachFile ? 16 : 15; const nodes = React.Children.map(children, (child, index) => { - if (index === 15) { + if (index === pendIndex) { return ( <> {child} From 9fcf1836537597eee425361f99fa5ce7345a238e Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 3 Dec 2024 15:41:19 +0800 Subject: [PATCH 325/336] refactor: remove unused heading options and clean up icon styles --- ui/src/components/Editor/ToolBars/heading.tsx | 7 +- ui/src/components/Editor/index.scss | 75 ------------------- 2 files changed, 1 insertion(+), 81 deletions(-) diff --git a/ui/src/components/Editor/ToolBars/heading.tsx b/ui/src/components/Editor/ToolBars/heading.tsx index 123b5579..8b0cb604 100644 --- a/ui/src/components/Editor/ToolBars/heading.tsx +++ b/ui/src/components/Editor/ToolBars/heading.tsx @@ -28,11 +28,6 @@ let context: IEditorContext; const Heading = () => { const { t } = useTranslation('translation', { keyPrefix: 'editor' }); const headerList = [ - { - text: `

${t('heading.options.h1')}

`, - level: 1, - label: t('heading.options.h1'), - }, { text: `

${t('heading.options.h2')}

`, level: 2, @@ -60,7 +55,7 @@ const Heading = () => { }, ]; const item = { - label: 'type', + label: 'type-h2', keyMap: ['Ctrl-h'], tip: `${t('heading.text')} (Ctrl+h)`, }; diff --git a/ui/src/components/Editor/index.scss b/ui/src/components/Editor/index.scss index 6cdc4b8c..afd15871 100644 --- a/ui/src/components/Editor/index.scss +++ b/ui/src/components/Editor/index.scss @@ -69,81 +69,6 @@ &:focus { background-color: var(--ans-editor-toolbar-focus); } - &.icon-heading { - background-position: 0px -144px; - } - &.icon-bold { - background-position: -24px -144px; - } - &.icon-italic { - background-position: -48px -144px; - } - - &.icon-code { - background-position: -72px -144px; - } - - &.icon-link { - background-position: -120px -144px; - } - &.icon-blockquote { - background-position: -144px -144px; - } - &.icon-image { - background-position: -168px -144px; - } - &.icon-video { - background-position: -192px -144px; - } - &.icon-table { - background-position: -216px -144px; - &.disabled { - background-position: -216px -168px !important; - } - } - - &.icon-formula { - background-position: -528px -144px; - } - &.icon-indent { - background-position: -288px -144px; - } - &.icon-outdent { - background-position: -312px -144px; - } - &.icon-orderedList { - background-position: -240px -144px; - } - &.icon-unorderedList { - background-position: -264px -144px; - } - &.icon-hr { - background-position: -336px -144px; - } - &.icon-help { - background-position: -360px -144px; - } - &.icon-full { - background-position: -456px -144px; - } - &.icon-exit-sync-scroll { - background-position: -432px -144px; - } - &.icon-sync-scroll { - background-position: -432px -192px; - } - &.icon-exit-preview { - background-position: -408px -144px; - } - &.icon-preview { - background-position: -408px -192px; - } - &.icon-exit-full { - background-position: -480px -144px; - } - &.icon-chart { - background-position: -552px -144px; - } } .popup-wrap { position: absolute; From 7f77647048000c31c51d0736ff0ae254dda12a0f Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 3 Dec 2024 15:43:14 +0800 Subject: [PATCH 326/336] refactor(i18n): update formatting instructions to mention post IDs --- i18n/en_US.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 776207c2..f4c67a18 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -789,7 +789,7 @@ ui: how_to_format: title: How to Format desc: >- -
  • link question or answer: #10010000000000001

  • +
    • mention a post: #post_id

    • to make links

      <https://url.com>

      [Title](https://url.com)
    • put returns between paragraphs

    • Date: Tue, 3 Dec 2024 17:36:01 +0800 Subject: [PATCH 327/336] feat(file): implement file download functionality --- internal/router/static_router.go | 17 +++++++++++++++++ internal/service/uploader/upload.go | 19 ++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/internal/router/static_router.go b/internal/router/static_router.go index 5b087431..3fbb12da 100644 --- a/internal/router/static_router.go +++ b/internal/router/static_router.go @@ -22,6 +22,8 @@ package router import ( "github.com/apache/incubator-answer/internal/service/service_config" "github.com/gin-gonic/gin" + "path/filepath" + "strings" ) // StaticRouter static api router @@ -39,4 +41,19 @@ func NewStaticRouter(serviceConfig *service_config.ServiceConfig) *StaticRouter // RegisterStaticRouter register static api router func (a *StaticRouter) RegisterStaticRouter(r *gin.RouterGroup) { r.Static("/uploads", a.serviceConfig.UploadPath) + + r.GET("/download/*filepath", func(c *gin.Context) { + // The filePath such as /download/hash/123.png + filePath := c.Param("filepath") + // The download filename is 123.png + downloadFilename := filepath.Base(filePath) + + // After trimming, the downloadLink is /uploads/hash + downloadLink := strings.TrimSuffix(filePath, "/"+downloadFilename) + // After add the extension, the downloadLink is /uploads/hash.png + downloadLink += filepath.Ext(downloadFilename) + + downloadLink = filepath.Join(a.serviceConfig.UploadPath, downloadLink) + c.FileAttachment(downloadLink, downloadFilename) + }) } diff --git a/internal/service/uploader/upload.go b/internal/service/uploader/upload.go index a8d9c0cc..6baf00d1 100644 --- a/internal/service/uploader/upload.go +++ b/internal/service/uploader/upload.go @@ -25,6 +25,7 @@ import ( "io" "mime/multipart" "net/http" + "net/url" "os" "path" "path/filepath" @@ -237,7 +238,7 @@ func (us *uploaderService) UploadPostAttachment(ctx *gin.Context) ( fileExt := strings.ToLower(path.Ext(fileHeader.Filename)) newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) avatarFilePath := path.Join(postSubPath, newFilename) - return us.uploadAttachmentFile(ctx, fileHeader, avatarFilePath) + return us.uploadAttachmentFile(ctx, fileHeader, fileHeader.Filename, avatarFilePath) } func (us *uploaderService) UploadBrandingFile(ctx *gin.Context) ( @@ -304,8 +305,8 @@ func (us *uploaderService) uploadImageFile(ctx *gin.Context, file *multipart.Fil return url, nil } -func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file *multipart.FileHeader, fileSubPath string) ( - url string, err error) { +func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file *multipart.FileHeader, originalFilename, fileSubPath string) ( + downloadUrl string, err error) { siteGeneral, err := us.siteInfoService.GetSiteGeneral(ctx) if err != nil { return "", err @@ -315,8 +316,16 @@ func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file *multipar return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() } - url = fmt.Sprintf("%s/uploads/%s", siteGeneral.SiteUrl, fileSubPath) - return url, nil + // The original filename is 123.png + // The local saved path is /UploadPath/hash.png + // The download link wil be /download/hash/123.png. + // When downloading, the download link will be redirect to the local saved path. And the download filename will be 123.png. + ext := filepath.Ext(fileSubPath) + // Need url encode the original filename. Because the filename may contain special characters that conflict with the markdown syntax. + originalFilename = url.QueryEscape(originalFilename) + downloadPath := strings.TrimSuffix(fileSubPath, ext) + "/" + originalFilename + downloadUrl = fmt.Sprintf("%s/download/%s", siteGeneral.SiteUrl, downloadPath) + return downloadUrl, nil } func (us *uploaderService) tryToUploadByPlugin(ctx *gin.Context, source plugin.UploadSource) ( From 7a8cc6a5712401904a9bb5c600530b777f63064f Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 4 Dec 2024 14:55:19 +0800 Subject: [PATCH 328/336] refactor(uploader): improve file upload and download functionality subpath constants - Adjust file download --- internal/base/constant/upload.go | 9 ++++++ internal/router/static_router.go | 28 ++++++++--------- internal/service/uploader/upload.go | 48 +++++++++++++---------------- 3 files changed, 44 insertions(+), 41 deletions(-) create mode 100644 internal/base/constant/upload.go diff --git a/internal/base/constant/upload.go b/internal/base/constant/upload.go new file mode 100644 index 00000000..5a884ae7 --- /dev/null +++ b/internal/base/constant/upload.go @@ -0,0 +1,9 @@ +package constant + +const ( + AvatarSubPath = "avatar" + AvatarThumbSubPath = "avatar_thumb" + PostSubPath = "post" + BrandingSubPath = "branding" + FilesPostSubPath = "files/post" +) diff --git a/internal/router/static_router.go b/internal/router/static_router.go index 3fbb12da..71457f49 100644 --- a/internal/router/static_router.go +++ b/internal/router/static_router.go @@ -20,6 +20,7 @@ package router import ( + "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/service/service_config" "github.com/gin-gonic/gin" "path/filepath" @@ -40,20 +41,19 @@ func NewStaticRouter(serviceConfig *service_config.ServiceConfig) *StaticRouter // RegisterStaticRouter register static api router func (a *StaticRouter) RegisterStaticRouter(r *gin.RouterGroup) { - r.Static("/uploads", a.serviceConfig.UploadPath) - - r.GET("/download/*filepath", func(c *gin.Context) { - // The filePath such as /download/hash/123.png + r.Static("/uploads/"+constant.AvatarSubPath, filepath.Join(a.serviceConfig.UploadPath, constant.AvatarSubPath)) + r.Static("/uploads/"+constant.AvatarThumbSubPath, filepath.Join(a.serviceConfig.UploadPath, constant.AvatarThumbSubPath)) + r.Static("/uploads/"+constant.PostSubPath, filepath.Join(a.serviceConfig.UploadPath, constant.PostSubPath)) + r.Static("/uploads/"+constant.BrandingSubPath, filepath.Join(a.serviceConfig.UploadPath, constant.BrandingSubPath)) + r.GET("/uploads/"+constant.FilesPostSubPath+"/*filepath", func(c *gin.Context) { + // The filepath such as hash/123.pdf filePath := c.Param("filepath") - // The download filename is 123.png - downloadFilename := filepath.Base(filePath) - - // After trimming, the downloadLink is /uploads/hash - downloadLink := strings.TrimSuffix(filePath, "/"+downloadFilename) - // After add the extension, the downloadLink is /uploads/hash.png - downloadLink += filepath.Ext(downloadFilename) - - downloadLink = filepath.Join(a.serviceConfig.UploadPath, downloadLink) - c.FileAttachment(downloadLink, downloadFilename) + // The original filename is 123.pdf + originalFilename := filepath.Base(filePath) + // The real filename is hash.pdf + realFilename := strings.TrimSuffix(filePath, "/"+originalFilename) + filepath.Ext(originalFilename) + // The file local path is /uploads/files/post/hash.pdf + fileLocalPath := filepath.Join(a.serviceConfig.UploadPath, constant.FilesPostSubPath, realFilename) + c.FileAttachment(fileLocalPath, originalFilename) }) } diff --git a/internal/service/uploader/upload.go b/internal/service/uploader/upload.go index 6baf00d1..8530d17f 100644 --- a/internal/service/uploader/upload.go +++ b/internal/service/uploader/upload.go @@ -31,6 +31,7 @@ import ( "path/filepath" "strings" + "github.com/apache/incubator-answer/internal/base/constant" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/service/service_config" "github.com/apache/incubator-answer/internal/service/siteinfo_common" @@ -45,19 +46,13 @@ import ( "github.com/segmentfault/pacman/log" ) -const ( - avatarSubPath = "avatar" - avatarThumbSubPath = "avatar_thumb" - postSubPath = "post" - brandingSubPath = "branding" -) - var ( subPathList = []string{ - avatarSubPath, - avatarThumbSubPath, - postSubPath, - brandingSubPath, + constant.AvatarSubPath, + constant.AvatarThumbSubPath, + constant.PostSubPath, + constant.BrandingSubPath, + constant.FilesPostSubPath, } supportedThumbFileExtMapping = map[string]imaging.Format{ ".jpg": imaging.JPEG, @@ -123,7 +118,7 @@ func (us *uploaderService) UploadAvatarFile(ctx *gin.Context) (url string, err e } newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) - avatarFilePath := path.Join(avatarSubPath, newFilename) + avatarFilePath := path.Join(constant.AvatarSubPath, newFilename) return us.uploadImageFile(ctx, fileHeader, avatarFilePath) } @@ -131,19 +126,19 @@ func (us *uploaderService) AvatarThumbFile(ctx *gin.Context, fileName string, si fileSuffix := path.Ext(fileName) if _, ok := supportedThumbFileExtMapping[fileSuffix]; !ok { // if file type is not supported, return original file - return path.Join(us.serviceConfig.UploadPath, avatarSubPath, fileName), nil + return path.Join(us.serviceConfig.UploadPath, constant.AvatarSubPath, fileName), nil } if size > 1024 { size = 1024 } thumbFileName := fmt.Sprintf("%d_%d@%s", size, size, fileName) - thumbFilePath := fmt.Sprintf("%s/%s/%s", us.serviceConfig.UploadPath, avatarThumbSubPath, thumbFileName) + thumbFilePath := fmt.Sprintf("%s/%s/%s", us.serviceConfig.UploadPath, constant.AvatarThumbSubPath, thumbFileName) avatarFile, err := os.ReadFile(thumbFilePath) if err == nil { return thumbFilePath, nil } - filePath := fmt.Sprintf("%s/%s/%s", us.serviceConfig.UploadPath, avatarSubPath, fileName) + filePath := fmt.Sprintf("%s/%s/%s", us.serviceConfig.UploadPath, constant.AvatarSubPath, fileName) avatarFile, err = os.ReadFile(filePath) if err != nil { return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() @@ -160,11 +155,11 @@ func (us *uploaderService) AvatarThumbFile(ctx *gin.Context, fileName string, si return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() } - if err = dir.CreateDirIfNotExist(path.Join(us.serviceConfig.UploadPath, avatarThumbSubPath)); err != nil { + if err = dir.CreateDirIfNotExist(path.Join(us.serviceConfig.UploadPath, constant.AvatarThumbSubPath)); err != nil { return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() } - avatarFilePath := path.Join(avatarThumbSubPath, thumbFileName) + avatarFilePath := path.Join(constant.AvatarThumbSubPath, thumbFileName) saveFilePath := path.Join(us.serviceConfig.UploadPath, avatarFilePath) out, err := os.Create(saveFilePath) if err != nil { @@ -206,7 +201,7 @@ func (us *uploaderService) UploadPostFile(ctx *gin.Context) ( fileExt := strings.ToLower(path.Ext(fileHeader.Filename)) newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) - avatarFilePath := path.Join(postSubPath, newFilename) + avatarFilePath := path.Join(constant.PostSubPath, newFilename) return us.uploadImageFile(ctx, fileHeader, avatarFilePath) } @@ -237,7 +232,7 @@ func (us *uploaderService) UploadPostAttachment(ctx *gin.Context) ( fileExt := strings.ToLower(path.Ext(fileHeader.Filename)) newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) - avatarFilePath := path.Join(postSubPath, newFilename) + avatarFilePath := path.Join(constant.FilesPostSubPath, newFilename) return us.uploadAttachmentFile(ctx, fileHeader, fileHeader.Filename, avatarFilePath) } @@ -268,7 +263,7 @@ func (us *uploaderService) UploadBrandingFile(ctx *gin.Context) ( } newFilename := fmt.Sprintf("%s%s", uid.IDStr12(), fileExt) - avatarFilePath := path.Join(brandingSubPath, newFilename) + avatarFilePath := path.Join(constant.BrandingSubPath, newFilename) return us.uploadImageFile(ctx, fileHeader, avatarFilePath) } @@ -316,15 +311,14 @@ func (us *uploaderService) uploadAttachmentFile(ctx *gin.Context, file *multipar return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack() } - // The original filename is 123.png - // The local saved path is /UploadPath/hash.png - // The download link wil be /download/hash/123.png. - // When downloading, the download link will be redirect to the local saved path. And the download filename will be 123.png. - ext := filepath.Ext(fileSubPath) // Need url encode the original filename. Because the filename may contain special characters that conflict with the markdown syntax. originalFilename = url.QueryEscape(originalFilename) - downloadPath := strings.TrimSuffix(fileSubPath, ext) + "/" + originalFilename - downloadUrl = fmt.Sprintf("%s/download/%s", siteGeneral.SiteUrl, downloadPath) + + // The original filename is 123.pdf + // The local saved path is /UploadPath/hash.pdf + // When downloading, the download link will be redirect to the local saved path. And the download filename will be 123.png. + downloadPath := strings.TrimSuffix(fileSubPath, filepath.Ext(fileSubPath)) + "/" + originalFilename + downloadUrl = fmt.Sprintf("%s/uploads/%s", siteGeneral.SiteUrl, downloadPath) return downloadUrl, nil } From 9c266c5f33e63333bd372f0f1c9afff0f53ca156 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Wed, 4 Dec 2024 14:58:27 +0800 Subject: [PATCH 329/336] feat(upload): add support for attachment uploads and improve image handling --- docs/docs.go | 49 ++++++++++++++++++++++++- docs/swagger.json | 49 ++++++++++++++++++++++++- docs/swagger.yaml | 31 ++++++++++++++++ internal/base/constant/upload.go | 19 ++++++++++ ui/src/components/QueryGroup/index.scss | 19 ++++++++++ 5 files changed, 163 insertions(+), 4 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 9863b0c0..da050e10 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -3145,6 +3145,7 @@ const docTemplate = `{ { "enum": [ "post", + "post_attachment", "avatar", "branding" ], @@ -4483,7 +4484,8 @@ const docTemplate = `{ "hot", "score", "unanswered", - "recommend" + "recommend", + "frequent" ], "type": "string", "name": "order", @@ -9666,7 +9668,8 @@ const docTemplate = `{ "hot", "score", "unanswered", - "recommend" + "recommend", + "frequent" ] }, "page": { @@ -10641,6 +10644,27 @@ const docTemplate = `{ "schema.SiteWriteReq": { "type": "object", "properties": { + "authorized_attachment_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "authorized_image_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "max_attachment_size": { + "type": "integer" + }, + "max_image_megapixel": { + "type": "integer" + }, + "max_image_size": { + "type": "integer" + }, "recommend_tags": { "type": "array", "items": { @@ -10664,6 +10688,27 @@ const docTemplate = `{ "schema.SiteWriteResp": { "type": "object", "properties": { + "authorized_attachment_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "authorized_image_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "max_attachment_size": { + "type": "integer" + }, + "max_image_megapixel": { + "type": "integer" + }, + "max_image_size": { + "type": "integer" + }, "recommend_tags": { "type": "array", "items": { diff --git a/docs/swagger.json b/docs/swagger.json index 5c2f459c..bcce7817 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -3118,6 +3118,7 @@ { "enum": [ "post", + "post_attachment", "avatar", "branding" ], @@ -4456,7 +4457,8 @@ "hot", "score", "unanswered", - "recommend" + "recommend", + "frequent" ], "type": "string", "name": "order", @@ -9639,7 +9641,8 @@ "hot", "score", "unanswered", - "recommend" + "recommend", + "frequent" ] }, "page": { @@ -10614,6 +10617,27 @@ "schema.SiteWriteReq": { "type": "object", "properties": { + "authorized_attachment_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "authorized_image_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "max_attachment_size": { + "type": "integer" + }, + "max_image_megapixel": { + "type": "integer" + }, + "max_image_size": { + "type": "integer" + }, "recommend_tags": { "type": "array", "items": { @@ -10637,6 +10661,27 @@ "schema.SiteWriteResp": { "type": "object", "properties": { + "authorized_attachment_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "authorized_image_extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "max_attachment_size": { + "type": "integer" + }, + "max_image_megapixel": { + "type": "integer" + }, + "max_image_size": { + "type": "integer" + }, "recommend_tags": { "type": "array", "items": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 811b3c28..5e22186a 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1556,6 +1556,7 @@ definitions: - score - unanswered - recommend + - frequent type: string page: minimum: 1 @@ -2221,6 +2222,20 @@ definitions: type: object schema.SiteWriteReq: properties: + authorized_attachment_extensions: + items: + type: string + type: array + authorized_image_extensions: + items: + type: string + type: array + max_attachment_size: + type: integer + max_image_megapixel: + type: integer + max_image_size: + type: integer recommend_tags: items: $ref: '#/definitions/schema.SiteWriteTag' @@ -2236,6 +2251,20 @@ definitions: type: object schema.SiteWriteResp: properties: + authorized_attachment_extensions: + items: + type: string + type: array + authorized_image_extensions: + items: + type: string + type: array + max_attachment_size: + type: integer + max_image_megapixel: + type: integer + max_image_size: + type: integer recommend_tags: items: $ref: '#/definitions/schema.SiteWriteTag' @@ -4767,6 +4796,7 @@ paths: - description: identify the source of the file upload enum: - post + - post_attachment - avatar - branding in: formData @@ -5601,6 +5631,7 @@ paths: - score - unanswered - recommend + - frequent in: query name: order type: string diff --git a/internal/base/constant/upload.go b/internal/base/constant/upload.go index 5a884ae7..c01c9279 100644 --- a/internal/base/constant/upload.go +++ b/internal/base/constant/upload.go @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + package constant const ( diff --git a/ui/src/components/QueryGroup/index.scss b/ui/src/components/QueryGroup/index.scss index 9ab5b36d..3a05069f 100644 --- a/ui/src/components/QueryGroup/index.scss +++ b/ui/src/components/QueryGroup/index.scss @@ -1,3 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + .md-show { display: flex !important; } From a4752957841a9c524325f535aadad685ce2be571 Mon Sep 17 00:00:00 2001 From: Luffy <52o@qq52o.cn> Date: Fri, 6 Dec 2024 14:34:30 +0800 Subject: [PATCH 330/336] feat: Add delete external user login info by user ID --- cmd/wire_gen.go | 2 +- .../user_external_login/user_external_login_repo.go | 10 ++++++++++ internal/service/user_admin/user_backyard.go | 11 +++++++++++ .../user_external_login_service.go | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 5e4d395b..3f267984 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -228,7 +228,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, revisionController := controller.NewRevisionController(contentRevisionService, rankService) rankController := controller.NewRankController(rankService) userAdminRepo := user.NewUserAdminRepo(dataData, authRepo) - userAdminService := user_admin.NewUserAdminService(userAdminRepo, userRoleRelService, authService, userCommon, userActiveActivityRepo, siteInfoCommonService, emailService, questionRepo, answerRepo, commentCommonRepo) + userAdminService := user_admin.NewUserAdminService(userAdminRepo, userRoleRelService, authService, userCommon, userActiveActivityRepo, siteInfoCommonService, emailService, questionRepo, answerRepo, commentCommonRepo, userExternalLoginRepo) userAdminController := controller_admin.NewUserAdminController(userAdminService) reasonRepo := reason.NewReasonRepo(configService) reasonService := reason2.NewReasonService(reasonRepo) diff --git a/internal/repo/user_external_login/user_external_login_repo.go b/internal/repo/user_external_login/user_external_login_repo.go index 8b78b8b4..c2d13108 100644 --- a/internal/repo/user_external_login/user_external_login_repo.go +++ b/internal/repo/user_external_login/user_external_login_repo.go @@ -104,6 +104,16 @@ func (ur *userExternalLoginRepo) DeleteUserExternalLogin(ctx context.Context, us return } +// DeleteUserExternalLoginByUserID delete external user login info by user ID +func (ur *userExternalLoginRepo) DeleteUserExternalLoginByUserID(ctx context.Context, userID string) (err error) { + cond := &entity.UserExternalLogin{} + _, err = ur.data.DB.Context(ctx).Where("user_id = ?", userID).Delete(cond) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + // SetCacheUserExternalLoginInfo cache user info for external login func (ur *userExternalLoginRepo) SetCacheUserExternalLoginInfo( ctx context.Context, key string, info *schema.ExternalLoginUserInfoCache) (err error) { diff --git a/internal/service/user_admin/user_backyard.go b/internal/service/user_admin/user_backyard.go index 52c0d630..ebe1ea74 100644 --- a/internal/service/user_admin/user_backyard.go +++ b/internal/service/user_admin/user_backyard.go @@ -45,6 +45,7 @@ import ( "github.com/apache/incubator-answer/internal/service/role" "github.com/apache/incubator-answer/internal/service/siteinfo_common" usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/incubator-answer/internal/service/user_external_login" "github.com/apache/incubator-answer/pkg/checker" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" @@ -76,6 +77,7 @@ type UserAdminService struct { questionCommonRepo questioncommon.QuestionRepo answerCommonRepo answercommon.AnswerRepo commentCommonRepo comment_common.CommentCommonRepo + userExternalLoginRepo user_external_login.UserExternalLoginRepo } // NewUserAdminService new user admin service @@ -90,6 +92,7 @@ func NewUserAdminService( questionCommonRepo questioncommon.QuestionRepo, answerCommonRepo answercommon.AnswerRepo, commentCommonRepo comment_common.CommentCommonRepo, + userExternalLoginRepo user_external_login.UserExternalLoginRepo, ) *UserAdminService { return &UserAdminService{ userRepo: userRepo, @@ -102,6 +105,7 @@ func NewUserAdminService( questionCommonRepo: questionCommonRepo, answerCommonRepo: answerCommonRepo, commentCommonRepo: commentCommonRepo, + userExternalLoginRepo: userExternalLoginRepo, } } @@ -148,6 +152,13 @@ func (us *UserAdminService) UpdateUserStatus(ctx context.Context, req *schema.Up us.removeAllUserCreatedContent(ctx, userInfo.ID) } + if req.IsDeleted() { + err := us.userExternalLoginRepo.DeleteUserExternalLoginByUserID(ctx, userInfo.ID) + if err != nil { + log.Errorf("remove all user external login error: %v", err) + } + } + // if user reputation is zero means this user is inactive, so try to activate this user. if req.IsNormal() && userInfo.Rank == 0 { return us.userActivity.UserActive(ctx, userInfo.ID) diff --git a/internal/service/user_external_login/user_external_login_service.go b/internal/service/user_external_login/user_external_login_service.go index e0afbd37..9107fcc0 100644 --- a/internal/service/user_external_login/user_external_login_service.go +++ b/internal/service/user_external_login/user_external_login_service.go @@ -51,6 +51,7 @@ type UserExternalLoginRepo interface { GetByUserID(ctx context.Context, provider, userID string) (userInfo *entity.UserExternalLogin, exist bool, err error) GetUserExternalLoginList(ctx context.Context, userID string) (resp []*entity.UserExternalLogin, err error) DeleteUserExternalLogin(ctx context.Context, userID, externalID string) (err error) + DeleteUserExternalLoginByUserID(ctx context.Context, userID string) (err error) SetCacheUserExternalLoginInfo(ctx context.Context, key string, info *schema.ExternalLoginUserInfoCache) (err error) GetCacheUserExternalLoginInfo(ctx context.Context, key string) (info *schema.ExternalLoginUserInfoCache, err error) } From f6d517b93025104fdf66591d4cc8ffd811281762 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 9 Dec 2024 11:43:23 +0800 Subject: [PATCH 331/336] docs(Makefile): upgrade version to 1.4.2 --- Makefile | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a980a047..8b054aab 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: build clean ui -VERSION=1.4.1 +VERSION=1.4.2 BIN=answer DIR_SRC=./cmd/answer DOCKER_CMD=docker diff --git a/README.md b/README.md index 4eb1cc7c..bdf036c7 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ To learn more about the project, visit [answer.apache.org](https://answer.apache ### Running with docker ```bash -docker run -d -p 9080:80 -v answer-data:/data --name answer apache/answer:1.4.1 +docker run -d -p 9080:80 -v answer-data:/data --name answer apache/answer:1.4.2 ``` For more information, see [Installation](https://answer.apache.org/docs/installation). From 6ae189010b8e87d303465dbdb91e164954826373 Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 9 Dec 2024 14:40:43 +0800 Subject: [PATCH 332/336] Update translation (#1199) --- i18n/cs_CZ.yaml | 510 ++++++----- i18n/cy_GB.yaml | 56 +- i18n/da_DK.yaml | 56 +- i18n/de_DE.yaml | 56 +- i18n/es_ES.yaml | 56 +- i18n/fa_IR.yaml | 56 +- i18n/fr_FR.yaml | 56 +- i18n/hi_IN.yaml | 56 +- i18n/id_ID.yaml | 56 +- i18n/it_IT.yaml | 58 +- i18n/ja_JP.yaml | 2188 ++++++++++++++++++++++++----------------------- i18n/ko_KR.yaml | 56 +- i18n/ml_IN.yaml | 40 +- i18n/pl_PL.yaml | 74 +- i18n/pt_PT.yaml | 76 +- i18n/ro_RO.yaml | 62 +- i18n/ru_RU.yaml | 58 +- i18n/sk_SK.yaml | 56 +- i18n/sv_SE.yaml | 70 +- i18n/te_IN.yaml | 56 +- i18n/tr_TR.yaml | 56 +- i18n/uk_UA.yaml | 1196 +++++++++++++------------- i18n/vi_VN.yaml | 56 +- i18n/zh_CN.yaml | 57 +- i18n/zh_TW.yaml | 66 +- 25 files changed, 3041 insertions(+), 2142 deletions(-) diff --git a/i18n/cs_CZ.yaml b/i18n/cs_CZ.yaml index 65438419..72179edf 100644 --- a/i18n/cs_CZ.yaml +++ b/i18n/cs_CZ.yaml @@ -19,116 +19,116 @@ backend: base: success: - other: Success. + other: Úspěch. unknown: - other: Unknown error. + other: Neznámá chyba. request_format_error: - other: Request format is not valid. + other: Formát požadavku není platný. unauthorized_error: - other: Unauthorized. + other: Neautorizováno. database_error: - other: Data server error. + other: Chyba datového serveru. forbidden_error: - other: Forbidden. + other: Zakázáno. duplicate_request_error: - other: Duplicate submission. + other: Duplicitní odeslání. action: report: - other: Flag + other: Nahlásit edit: - other: Edit + other: Upravit delete: - other: Delete + other: Smazat close: - other: Close + other: Zavřít reopen: - other: Reopen + other: Znovu otevřít forbidden_error: - other: Forbidden. + other: Zakázáno. pin: - other: Pin + other: Připnout hide: - other: Unlist + other: Skrýt unpin: - other: Unpin + other: Odepnout show: - other: List + other: Zobrazit invite_someone_to_answer: - other: Edit + other: Upravit undelete: - other: Undelete + other: Obnovit role: name: user: - other: User + other: Uživatel admin: - other: Admin + other: Administrátor moderator: - other: Moderator + other: Moderátor description: user: - other: Default with no special access. + other: Výchozí bez zvláštního přístupu. admin: - other: Have the full power to access the site. + other: Má plnou kontrolu nad stránkou. moderator: - other: Has access to all posts except admin settings. + other: Má přístup ke všem příspěvkům kromě admin nastavení. privilege: level_1: description: - other: Level 1 (less reputation required for private team, group) + other: Úroveň 1 (méně reputace je vyžadováno pro soukromý tým, skupinu) level_2: description: - other: Level 2 (low reputation required for startup community) + other: Úroveň 2 (nízká reputace je vyžadována pro startovací komunitu) level_3: description: - other: Level 3 (high reputation required for mature community) + other: Úroveň 3 (vysoká reputace je vyžadována pro vyspělou komunitu) level_custom: description: - other: Custom Level + other: Vlastní úroveň rank_question_add_label: - other: Ask question + other: Položit dotaz rank_answer_add_label: - other: Write answer + other: Napsat odpověď rank_comment_add_label: - other: Write comment + other: Napsat komentář rank_report_add_label: - other: Flag + other: Nahlásit rank_comment_vote_up_label: - other: Upvote comment + other: Hlasovat pro komentář rank_link_url_limit_label: - other: Post more than 2 links at a time + other: Zveřejnit více než 2 odkazy najednou rank_question_vote_up_label: - other: Upvote question + other: Hlasovat pro dotaz rank_answer_vote_up_label: - other: Upvote answer + other: Hlasovat pro odpověď rank_question_vote_down_label: - other: Downvote question + other: Hlasovat proti otázce rank_answer_vote_down_label: - other: Downvote answer + other: Hlasovat proti odpovědi rank_invite_someone_to_answer_label: - other: Invite someone to answer + other: Pozvěte někoho, aby odpověděl rank_tag_add_label: - other: Create new tag + other: Vytvořit nový štítek rank_tag_edit_label: - other: Edit tag description (need to review) + other: Upravit popis štítku (vyžaduje kontrolu) rank_question_edit_label: - other: Edit other's question (need to review) + other: Upravit dotaz někoho jiného (vyžaduje kontrolu) rank_answer_edit_label: - other: Edit other's answer (need to review) + other: Upravit odpověď někoho jiného (vyžaduje kontrolu) rank_question_edit_without_review_label: - other: Edit other's question without review + other: Upravit dotaz někoho jiného (bez kontroly) rank_answer_edit_without_review_label: - other: Edit other's answer without review + other: Upravit odpověď někoho jiného (bez kontroly) rank_question_audit_label: - other: Review question edits + other: Zkontrolovat úpravy dotazu rank_answer_audit_label: - other: Review answer edits + other: Zkontrolovat úpravy odpovědí rank_tag_audit_label: - other: Review tag edits + other: Zkontrolovat úpravy štítků rank_tag_edit_without_review_label: - other: Edit tag description without review + other: Upravit popis štítku (bez kontroly) rank_tag_synonym_label: - other: Manage tag synonyms + other: Správa synonym štítků email: other: Email e_mail: @@ -136,17 +136,17 @@ backend: password: other: Heslo pass: - other: Password + other: Heslo original_text: - other: This post + other: Tento příspěvek email_or_password_wrong_error: - other: Email and password do not match. + other: Email a heslo nesouhlasí. error: common: invalid_url: - other: Invalid URL. + other: Neplatná URL. status_invalid: - other: Invalid status. + other: Neplatný stav. password: space_invalid: other: Heslo nesmí obsahovat mezery. @@ -154,7 +154,7 @@ backend: cannot_update_their_password: other: Nemůžete změnit své heslo. cannot_edit_their_profile: - other: You cannot modify your profile. + other: Nemůžete upravovat svůj profil. cannot_modify_self_status: other: Nemůžete změnit svůj stav. email_or_password_wrong: @@ -167,7 +167,7 @@ backend: cannot_update: other: Nemáte právo aktualizovat. question_closed_cannot_add: - other: Otázky jsou uzavřené a není možno je přidávat. + other: Dotazy jsou uzavřené a není možno je přidávat. comment: edit_without_permission: other: Nejsou povoleny úpravy komentáře. @@ -186,375 +186,375 @@ backend: other: Email z této domény není povolen. Použijte jinou doménu. lang: not_found: - other: Language file not found. + other: Jazykový soubor nenalezen. object: captcha_verification_failed: other: Nesprávně vyplněná Captcha. disallow_follow: - other: You are not allowed to follow. + other: Nemáte oprávnění sledovat. disallow_vote: - other: You are not allowed to vote. + other: Nemáte oprávnění hlasovat. disallow_vote_your_self: - other: You can't vote for your own post. + other: Nemůžete hlasovat pro svůj vlastní příspěvek. not_found: - other: Object not found. + other: Objekt nenalezen. verification_failed: - other: Verification failed. + other: Ověření se nezdařilo. email_or_password_incorrect: - other: Email and password do not match. + other: Email a heslo nesouhlasí. old_password_verification_failed: - other: The old password verification failed + other: Ověření starého hesla selhalo new_password_same_as_previous_setting: - other: The new password is the same as the previous one. + other: Nové heslo je stejné jako předchozí. already_deleted: - other: This post has been deleted. + other: Tento příspěvek byl odstraněn. meta: object_not_found: - other: Meta object not found + other: Meta objekt nenalezen question: already_deleted: - other: This post has been deleted. + other: Tento příspěvek byl odstraněn. under_review: - other: Your post is awaiting review. It will be visible after it has been approved. + other: Váš příspěvek čeká na kontrolu. Bude viditelný po jeho schválení. not_found: - other: Question not found. + other: Dotaz nenalezen. cannot_deleted: - other: No permission to delete. + other: Nemáte oprávnění k mazání. cannot_close: - other: No permission to close. + other: Nemáte oprávnění k uzavření. cannot_update: - other: No permission to update. + other: Nemáte oprávnění pro aktualizaci. rank: fail_to_meet_the_condition: - other: Reputation rank fail to meet the condition. + other: Hodnost reputace nesplňuje podmínku. vote_fail_to_meet_the_condition: - other: Thanks for the feedback. You need at least {{.Rank}} reputation to cast a vote. + other: Děkujeme za zpětnou vazbu. Potřebujete alespoň úroveň {{.Rank}}, abyste mohli hlasovat. no_enough_rank_to_operate: - other: You need at least {{.Rank}} reputation to do this. + other: Potřebujete alespoň úroveň {{.Rank}} k provedení této akce. report: handle_failed: - other: Report handle failed. + other: Report selhal. not_found: - other: Report not found. + other: Report nebyl nalezen. tag: already_exist: - other: Tag already exists. + other: Štítek již existuje. not_found: - other: Tag not found. + other: Štítek nebyl nalezen. recommend_tag_not_found: - other: Recommend tag is not exist. + other: Doporučený štítek nebyl nalezen. recommend_tag_enter: - other: Please enter at least one required tag. + other: Zadejte prosím alespoň jeden povinný štítek. not_contain_synonym_tags: - other: Should not contain synonym tags. + other: Nemělo by obsahovat synonyma štítků. cannot_update: - other: No permission to update. + other: Nemáte oprávnění pro aktualizaci. is_used_cannot_delete: - other: You cannot delete a tag that is in use. + other: Nemůžete odstranit štítek, který se používá. cannot_set_synonym_as_itself: - other: You cannot set the synonym of the current tag as itself. + other: Aktuální štítek nelze jako synonymum stejného štítku. smtp: config_from_name_cannot_be_email: - other: The from name cannot be a email address. + other: Jméno odesílatele nemůže být emailová adresa. theme: not_found: - other: Theme not found. + other: Motiv nebyl nalezen. revision: review_underway: - other: Can't edit currently, there is a version in the review queue. + other: V současné době nelze upravit, čeká na kontrolu. no_permission: - other: No permission to revise. + other: Nemáte oprávnění k revizi. user: external_login_missing_user_id: - other: The third-party platform does not provide a unique UserID, so you cannot login, please contact the website administrator. + other: Platforma třetí strany neposkytuje unikátní UserID, takže se nemůžete přihlásit, kontaktujte prosím správce webových stránek. external_login_unbinding_forbidden: - other: Please set a login password for your account before you remove this login. + other: Před odebráním tohoto typu přihlášení nastavte přihlašovací heslo pro svůj účet. email_or_password_wrong: other: - other: Email and password do not match. + other: Email a heslo nesouhlasí. not_found: - other: User not found. + other: Uživatel nebyl nalezen. suspended: - other: User has been suspended. + other: Uživatelský účet byl pozastaven. username_invalid: - other: Username is invalid. + other: Uživatelské jméno je neplatné. username_duplicate: - other: Username is already in use. + other: Uživatelské jméno je již použito. set_avatar: - other: Avatar set failed. + other: Nastavení avataru se nezdařilo. cannot_update_your_role: - other: You cannot modify your role. + other: Nemůžete upravovat svoji roli. not_allowed_registration: - other: Currently the site is not open for registration. + other: Registrace nejsou povolené. not_allowed_login_via_password: - other: Currently the site is not allowed to login via password. + other: Přihlášení přes heslo není povolené. access_denied: - other: Access denied + other: Přístup zamítnut page_access_denied: - other: You do not have access to this page. + other: Nemáte přístup k této stránce. add_bulk_users_format_error: - other: "Error {{.Field}} format near '{{.Content}}' at line {{.Line}}. {{.ExtraMessage}}" + other: "Chyba formátu pole {{.Field}} poblíž '{{.Content}}' na řádku {{.Line}}. {{.ExtraMessage}}" add_bulk_users_amount_error: - other: "The number of users you add at once should be in the range of 1-{{.MaxAmount}}." + other: "Počet uživatelů, které přidáte najednou, by měl být v rozsahu 1-{{.MaxAmount}}." config: read_config_failed: - other: Read config failed + other: Načtení konfigurace selhalo database: connection_failed: - other: Database connection failed + other: Spojení s databází selhalo create_table_failed: - other: Create table failed + other: Vytvoření tabulky selhalo install: create_config_failed: - other: Can't create the config.yaml file. + other: Soubor config.yaml nelze vytvořit. upload: unsupported_file_format: - other: Unsupported file format. + other: Nepodporovaný formát souboru. site_info: config_not_found: - other: Site config not found. + other: Konfigurace webu nebyla nalezena. badge: object_not_found: - other: Badge object not found + other: Objekt odznaku nebyl nalezen reason: spam: name: other: spam desc: - other: This post is an advertisement, or vandalism. It is not useful or relevant to the current topic. + other: Tento příspěvek je reklama nebo vandalismus. Není užitečný ani relevantní pro aktuální téma. rude_or_abusive: name: - other: rude or abusive + other: hrubý nebo zneužívající desc: - other: "A reasonable person would find this content inappropriate for respectful discourse." + other: "Rozumný člověk by tento obsah považoval za nevhodný pro slušnou konverzaci." a_duplicate: name: - other: a duplicate + other: duplicita desc: - other: This question has been asked before and already has an answer. + other: Tento dotaz byl položen dříve a již má odpověď. placeholder: - other: Enter the existing question link + other: Zadejte existující odkaz na dotaz not_a_answer: name: - other: not an answer + other: není odpověď desc: - other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." + other: "Toto bylo zveřejněno jako odpověď, ale nesnaží se odpovědět na dotaz. Měla by to být úprava, komentář, nebo úplně jiný dotaz." no_longer_needed: name: - other: no longer needed + other: již není potřeba desc: - other: This comment is outdated, conversational or not relevant to this post. + other: Tento komentář je zastaralý, konverzační nebo není relevantní pro tento příspěvek. something: name: - other: something else + other: jiný důvod desc: - other: This post requires staff attention for another reason not listed above. + other: Tento příspěvek vyžaduje pozornost moderátorů z jiného důvodu, který není uveden výše. placeholder: - other: Let us know specifically what you are concerned about + other: Dejte nám vědět konkrétně, v čem je problém community_specific: name: - other: a community-specific reason + other: důvod specifický pro komunitu desc: - other: This question doesn't meet a community guideline. + other: Tento dotaz nesplňuje pravidla komunity. not_clarity: name: - other: needs details or clarity + other: vyžaduje detaily nebo upřesnění desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: Tento dotaz v současné době obsahuje více otázek. Měl by se zaměřit pouze na jeden problém. looks_ok: name: - other: looks OK + other: vypadá v pořádku desc: - other: This post is good as-is and not low quality. + other: Tento příspěvek je dobrý tak jak je, nemá nízkou kvalitu. needs_edit: name: - other: needs edit, and I did it + other: potřebuje úpravu, kterou jsem udělal(a) desc: - other: Improve and correct problems with this post yourself. + other: Zlepšete a opravte problémy s tímto příspěvkem. needs_close: name: - other: needs close + other: potřebuje zavřít desc: - other: A closed question can't answer, but still can edit, vote and comment. + other: Na uzavřený dotaz není možné odpovídat, ale stále může být upraven a je možné pro něj hlasovat a komentovat jej. needs_delete: name: - other: needs delete + other: potřebuje smazat desc: - other: This post will be deleted. + other: Tento příspěvek bude odstraněn. question: close: duplicate: name: other: spam desc: - other: This question has been asked before and already has an answer. + other: Tento dotaz byl položena dříve a již má odpověď. guideline: name: - other: a community-specific reason + other: důvod specifický pro komunitu desc: - other: This question doesn't meet a community guideline. + other: Tento dotaz nesplňuje pravidla komunity. multiple: name: - other: needs details or clarity + other: vyžaduje detaily nebo upřesnění desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: Tento dotaz v současné době obsahuje více otázek. Měla by se zaměřit pouze na jeden problém. other: name: - other: something else + other: jiný důvod desc: - other: This post requires another reason not listed above. + other: Tento příspěvek vyžaduje pozornost moderátorů z jiného důvodu, který není uveden výše. operation_type: asked: - other: asked + other: dotázáno answered: - other: answered + other: zodpovězeno modified: - other: modified + other: upraveno deleted_title: - other: Deleted question + other: Smazat dotaz questions_title: - other: Questions + other: Dotazy tag: tags_title: - other: Tags + other: Štítky no_description: - other: The tag has no description. + other: Štítek nemá žádný popis. notification: action: update_question: - other: updated question + other: upravený dotaz answer_the_question: - other: answered question + other: položil(a) dotaz update_answer: - other: updated answer + other: upravil(a) odpověď accept_answer: - other: accepted answer + other: přijal(a) odpověď comment_question: - other: commented question + other: okomentoval(a) dotaz comment_answer: - other: commented answer + other: okomentoval(a) odpověď reply_to_you: - other: replied to you + other: vám odpověděl(a) mention_you: - other: mentioned you + other: vás zmínil(a) your_question_is_closed: - other: Your question has been closed + other: Váš dotaz byl uzavřen your_question_was_deleted: - other: Your question has been deleted + other: Váš dotaz byl odstraněn your_answer_was_deleted: - other: Your answer has been deleted + other: Vaše odpověď byla smazána your_comment_was_deleted: - other: Your comment has been deleted + other: Váš komentář byl odstraněn up_voted_question: - other: upvoted question + other: hlasoval(a) pro dotaz down_voted_question: - other: downvoted question + other: hlasoval(a) proti dotazu up_voted_answer: - other: upvoted answer + other: hlasoval(a) pro odpověď down_voted_answer: - other: downvoted answer + other: hlasoval(a) proti odpovědi up_voted_comment: - other: upvoted comment + other: hlasoval(a) pro komentář invited_you_to_answer: - other: invited you to answer + other: vás pozval, abyste odpověděl(a) earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Získali jste odznak "{{.BadgeName}}" email_tpl: change_email: title: - other: "[{{.SiteName}}] Confirm your new email address" + other: "[{{.SiteName}}] Potvrďte svůj nový email" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: - other: "[{{.SiteName}}] {{.DisplayName}} answered your question" + other: "[{{.SiteName}}] {{.DisplayName}} odpověděl(a) na váš dotaz" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n

      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: - other: "[{{.SiteName }}] Password reset" + other: "[{{.SiteName }}] Obnova hesla" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: - other: "[{{.SiteName}}] Confirm your new account" + other: "[{{.SiteName}}] Potvrďte svůj nový účet" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: - other: "[{{.SiteName}}] Test Email" + other: "[{{.SiteName}}] Zkušební email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: - other: upvote + other: hlasovat pro upvoted: - other: upvoted + other: hlasováno pro downvote: - other: downvote + other: hlasovat proti downvoted: - other: downvoted + other: hlasováno proti accept: - other: accept + other: přijmout accepted: - other: accepted + other: přijato edit: - other: edit + other: upravit review: queued_post: - other: Queued post + other: Příspěvek ve frontě flagged_post: - other: Flagged post + other: Nahlášený příspěvek suggested_post_edit: - other: Suggested edits + other: Navrhované úpravy reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} a {{ .Count }} dalších..." badge: default_badges: autobiographer: name: - other: Autobiographer + other: Životopisec desc: - other: Filled out profile information. + other: Profil vyplněn. certified: name: - other: Certified + other: Certifikovaný desc: - other: Completed our new user tutorial. + other: Tutoriál pro nové uživatele dokončen. editor: name: other: Editor desc: - other: First post edit. + other: První úprava příspěvku. first_flag: name: - other: First Flag + other: První nahlášení desc: - other: First flagged a post. + other: První nahlášení příspěvku. first_upvote: name: - other: First Upvote + other: První hlas pro desc: - other: First up voted a post. + other: První hlas pro příspěvek. first_link: name: - other: First Link + other: První odkaz desc: other: First dirst added a link to another post. first_reaction: @@ -564,9 +564,9 @@ backend: other: First reacted to the post. first_share: name: - other: First Share + other: První sdílení desc: - other: First shared a post. + other: První sdílení příspěvku. scholar: name: other: Scholar @@ -576,67 +576,67 @@ backend: name: other: Commentator desc: - other: Leave 5 comments. + other: Napište 5 komentářů. new_user_of_the_month: name: - other: New User of the Month + other: Nový uživatel měsíce desc: - other: Outstanding contributions in their first month. + other: Výjimečný přínos ve svém prvním měsíci na stránce. read_guidelines: name: - other: Read Guidelines + other: Přečíst pravidla desc: - other: Read the [community guidelines]. + other: Přečtěte si [pravidla komunity]. reader: name: - other: Reader + other: Čtenář desc: - other: Read every answers in a topic with more than 10 answers. + other: Přečtěte si všechny odpovědi v tématu s více než 10 odpověďmi. welcome: name: - other: Welcome + other: Vítejte desc: - other: Received a up vote. + other: Obdržel(a) hlas. nice_share: name: - other: Nice Share + other: Povedené sdílení desc: - other: Shared a post with 25 unique visitors. + other: Sdílel(a) příspěvek s 25 unikátními návštěvníky. good_share: name: - other: Good Share + other: Dobré sdílení desc: - other: Shared a post with 300 unique visitors. + other: Sdílel(a) příspěvek s 300 unikátními návštěvníky. great_share: name: - other: Great Share + other: Skvělé sdílení desc: - other: Shared a post with 1000 unique visitors. + other: Sdílel(a) příspěvek s 1000 unikátními návštěvníky. out_of_love: name: - other: Out of Love + other: Optimista desc: - other: Used 50 up votes in a day. + other: Využito 50 hlasů pro za den. higher_love: name: - other: Higher Love + other: Vytrvalý optimista desc: - other: Used 50 up votes in a day 5 times. + other: 5 krát využito 50 hlasů pro za den. crazy_in_love: name: - other: Crazy in Love + other: Bláznivý optimista desc: - other: Used 50 up votes in a day 20 times. + other: 20 krát využito 50 hlasů pro za den. promoter: name: - other: Promoter + other: Promotér desc: - other: Invited a user. + other: Pozval(a) uživatele. campaigner: name: other: Campaigner desc: - other: Invited 3 basic users. + other: Pozval(a) 3 uživatele. champion: name: other: Champion @@ -787,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Prev next: Next @@ -904,7 +904,7 @@ ui: msg: empty: File cannot be empty. only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: Image URL @@ -946,6 +946,10 @@ ui: text: Table heading: Heading cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: I am closing this post as... btn_cancel: Cancel @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1339,8 +1344,8 @@ ui: description: Questions linked to no_linked_question: No questions linked from this question. invite_to_answer: - title: People Asked - desc: Select people who you think might know the answer. + title: Pozvěte další uživatele + desc: Pozvěte lidi, o kterých si myslíte, že mohou odpovědět. invite: Invite to answer add: Add people search: Search people @@ -1522,6 +1527,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Questions:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Answers:" comments: "Comments:" votes: "Votes:" @@ -1994,7 +2002,7 @@ ui: page_title: Write restrict_answer: title: Answer write - label: Each user can only write one answer for each question + label: Každý uživatel může napsat pouze jednu odpověď na stejný dotaz text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." recommend_tags: label: Recommend tags @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/cy_GB.yaml b/i18n/cy_GB.yaml index af605269..9283c851 100644 --- a/i18n/cy_GB.yaml +++ b/i18n/cy_GB.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: Sut i Fformatio desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Cynt next: Nesaf @@ -904,7 +904,7 @@ ui: msg: empty: Ni all ffeil fod yn wag. only_image: Dim ond ffeiliau delwedd a ganiateir. - max_size: Ni all maint y ffeil fod yn fwy na 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Disgrifiad tab_url: URL delwedd @@ -946,6 +946,10 @@ ui: text: Tabl heading: Pennawd cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Rwy'n cau'r post hon fel... btn_cancel: Canslo @@ -1086,6 +1090,7 @@ ui: search_placeholder: Hidlo yn ôl enw tag no_desc: Nid oes gan y tag unrhyw ddisgrifiad. more: Mwy + wiki: Wiki ask: title: Ychwanegu Cwestiwn edit_title: Golygu Cwestiwn @@ -1522,6 +1527,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Questions:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Answers:" comments: "Comments:" votes: "Votes:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/da_DK.yaml b/i18n/da_DK.yaml index bd19779f..a9b23acf 100644 --- a/i18n/da_DK.yaml +++ b/i18n/da_DK.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Bekræft din nye e-mailadresse" body: - other: "Bekræft din nye e-mailadresse for {{.SiteName}} ved at klikke på følgende link:
      \n{{.ChangeEmailUrl}}

      \n\nHvis du ikke anmodede om denne ændring, ignorér venligst denne e-mail.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} besvarede dit spørgsmål" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nSe den på {{.SiteName}}

      \n\n--
      \nAfmeld" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} inviterede dig til at svare" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Jeg tror du måske kender svaret.

      \nSe den på {{.SiteName}}

      \n\n--
      \nAfmeld" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} kommenterede dit indlæg" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nSe den på {{.SiteName}}

      \n\n--
      \nAfmeld" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Nyt spørgsmål: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nAfmeld" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Nulstilling af adgangskode" body: - other: "Nogen bad om at nulstille din adgangskode på {{.SiteName}}.

      \n\nHvis det ikke var dig, kan du trygt ignorere denne e-mail.

      \n\nKlik på følgende link for at vælge en ny adgangskode:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Bekræft din nye konto" body: - other: "Velkommen til {{.SiteName}}!

      \n\nKlik på følgende link for at bekræfte og aktivere din nye konto:
      \n{{.RegisterUrl}}

      \n\nHvis ovenstående link ikke kan klikkes på, prøv at kopiere og indsætte det i adresselinjen i din webbrowser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test E-Mail" body: - other: "Dette er en test e-mail." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: stem op @@ -787,7 +787,7 @@ ui: how_to_format: title: Sådan formaterer du desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Forrige next: Næste @@ -904,7 +904,7 @@ ui: msg: empty: Filen skal udfyldes. only_image: Kun billedfiler er tilladt. - max_size: Filstørrelse må ikke overstige 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Beskriveslse tab_url: Billede-URL @@ -946,6 +946,10 @@ ui: text: Tabel heading: Overskrift cell: Celle + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Jeg lukker dette indlæg fordi... btn_cancel: Annuller @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtrer efter tag-navn no_desc: Tag har ingen beskrivelse. more: Mere + wiki: Wiki ask: title: Tilføj spørgsmål edit_title: Rediger spørgsmål @@ -1522,6 +1527,7 @@ ui: newest: Nyeste active: Aktiv hot: Populært + frequent: Frequent recommend: Recommend score: Bedømmelse unanswered: Ubesvaret @@ -1721,6 +1727,8 @@ ui: welcome: Velkommen til Administration! site_statistics: Statistik for webstedet questions: "Spørgsmål:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Svar:" comments: "Kommentarer:" votes: "Stemmer:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserverede tags text: "Reserverede tags kan kun bruges af moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Er du sikker på, at du vil kassere dit udkast? messages: post_deleted: Dette indlæg er blevet slettet. + post_cancel_deleted: This post has been undeleted. post_pin: Dette indlæg er blevet fastgjort. post_unpin: Dette indlæg er blevet frigjort. post_hide_list: Dette indlæg er blevet skjult fra listen. @@ -2219,3 +2243,15 @@ ui: post_list: Dette indlæg er blevet listet. post_unlist: Dette indlæg er blevet aflistet. post_pending: Dit indlæg afventer gennemgang. Dette er en forhåndsvisning, det vil være synligt, når det er blevet godkendt. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/de_DE.yaml b/i18n/de_DE.yaml index 9eee7c03..42a02493 100644 --- a/i18n/de_DE.yaml +++ b/i18n/de_DE.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Bestätige deine neue E-Mail-Adresse" body: - other: "Bestätige deine neue E-Mail-Adresse für {{.SiteName}}, indem du auf den folgenden Link klickst:
      \n{{.ChangeEmailUrl}}

      \n\nWenn du diese Änderung nicht beantragt hast, ignoriere bitte diese E-Mail." + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} hat deine Frage beantwortet" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nAuf {{.SiteName}} ansehen

      \n\n--
      \nAbbestellen" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} hat dich eingeladen zu antworten" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Ich glaube, du kennst die Antwort.

      \nAuf {{.SiteName}} ansehen

      \n\n--
      \nAbbestellen" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} hat deinen Beitrag kommentiert" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nAuf {{.SiteName}} ansehen

      \n\n--
      \nAbbestellen" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Neue Frage: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nAbbestellen" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Passwort zurücksetzen" body: - other: "Jemand hat dich gebeten, dein Passwort auf {{.SiteName}} zurückzusetzen.

      \n\nWenn du es nicht warst, kannst du diese E-Mail getrost ignorieren.

      \n\nKlicke auf den folgenden Link, um ein neues Passwort zu wählen:
      \n{{.PassResetUrl}}" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Bestätige dein neues Konto" body: - other: "Willkommen bei {{.SiteName}}!

      \n\nKlicke auf den folgenden Link, um dein neues Konto zu bestätigen und zu aktivieren:
      \n{{.RegisterUrl}}

      \n\nWenn du den obigen Link nicht anklicken kannst, kopiere ihn und füge ihn in die Adresszeile deines Webbrowsers ein." + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test-E-Mail" body: - other: "Dies ist eine Test-Email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: positiv bewerten @@ -787,7 +787,7 @@ ui: how_to_format: title: Wie man formatiert desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Zurück next: Weiter @@ -904,7 +904,7 @@ ui: msg: empty: Datei darf nicht leer sein. only_image: Nur Bilddateien sind erlaubt. - max_size: Die Dateigröße darf 4 MB nicht überschreiten. + max_size: File size cannot exceed {{size}} MB. desc: label: Beschreibung tab_url: Bild URL @@ -946,6 +946,10 @@ ui: text: Tabelle heading: Überschrift cell: Zelle + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Ich schließe diesen Beitrag als... btn_cancel: Abbrechen @@ -1086,6 +1090,7 @@ ui: search_placeholder: Nach Tagnamen filtern no_desc: Der Tag hat keine Beschreibung. more: Mehr + wiki: Wiki ask: title: Frage stellen edit_title: Frage bearbeiten @@ -1522,6 +1527,7 @@ ui: newest: Neueste active: Aktiv hot: Hot + frequent: Frequent recommend: Recommend score: Punktzahl unanswered: Unbeantwortet @@ -1721,6 +1727,8 @@ ui: welcome: Willkommen im Admin Bereich! site_statistics: Website-Statistiken questions: "Fragen:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Antworten:" comments: "Kommentare:" votes: "Stimmen:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reservierte Tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Bist du sicher, dass du deinen Entwurf verwerfen willst? messages: post_deleted: Dieser Beitrag wurde gelöscht. + post_cancel_deleted: This post has been undeleted. post_pin: Dieser Beitrag wurde angepinnt. post_unpin: Dieser Beitrag wurde losgelöst. post_hide_list: Dieser Beitrag wurde aus der Liste verborgen. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/es_ES.yaml b/i18n/es_ES.yaml index 561b461d..7165aa54 100644 --- a/i18n/es_ES.yaml +++ b/i18n/es_ES.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirma tu nueva dirección de correo" body: - other: "Confirme su nueva dirección de correo para {{.SiteName}} haciendo clic en el siguiente enlace:
      \n{{.ChangeEmailUrl}}

      \n\nSi no ha solicitado este cambio, por favor ignore este correo.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} respondió tu pregunta" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nMirarlo en {{.SiteName}}

      \n\n--
      \nDesuscribirse" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} te invitó a responder" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Creo que podrías saber la respuesta.

      \nMirarlo en {{.SiteName}}

      \n\n--
      \nDesuscribirse" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} comentó en tu publicación" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nMirarlo en {{.SiteName}}

      \n\n--
      \nDesuscribirse" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Nueva pregunta: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nDesuscribirse" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Reestablecimiento de contraseña" body: - other: "Alguien solicitó restablecer tu contraseña en {{.SiteName}}.

      \n\nSi no fuiste tú, puedes ignorar este correo.

      \n\nHaz clic en el siguiente enlace para elegir una nueva contraseña:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirma tu nueva cuenta" body: - other: "Bienvenido a {{.SiteName}}!

      \n\nHaz clic en el siguiente enlace para confirmar y activar tu nueva cuenta:
      \n{{.RegisterUrl}}

      \n\nSi el enlace de arriba no es cliqueable, intenta copiar y pegar en la barra de direcciones de tu navegador.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Correo de prueba" body: - other: "Este es un correo de prueba." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: votar a favor @@ -787,7 +787,7 @@ ui: how_to_format: title: Cómo formatear desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Anterior next: Siguiente @@ -904,7 +904,7 @@ ui: msg: empty: El título no puede estar vacío. only_image: Solo se permiten archivos de imagen. - max_size: El tamaño del archivo no puede superar 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Descripción tab_url: URL de la imagen @@ -946,6 +946,10 @@ ui: text: Tabla heading: Encabezado cell: Celda + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Estoy cerrando este post como... btn_cancel: Cancelar @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtrar por nombre de etiqueta no_desc: La etiqueta no tiene descripción. more: Mas + wiki: Wiki ask: title: Agregar una pregunta edit_title: Editar pregunta @@ -1522,6 +1527,7 @@ ui: newest: Más reciente active: Activo hot: Hot + frequent: Frequent recommend: Recommend score: Puntuación unanswered: Sin respuesta @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Estadísticas del sitio questions: "Preguntas:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Respuestas:" comments: "Comentarios:" votes: "Votos:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Etiquetas reservadas text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: '¿Está seguro de que desea descartar este borrador?' messages: post_deleted: Esta publicación ha sido eliminada. + post_cancel_deleted: This post has been undeleted. post_pin: Esta publicación ha sido fijada. post_unpin: Esta publicación ha sido desfijada. post_hide_list: Esta publicación ha sido ocultada de la lista. @@ -2219,3 +2243,15 @@ ui: post_list: Esta publicación ha sido listada. post_unlist: Esta publicación ha sido retirado de la lista.. post_pending: Su publicación está pendiente de revisión. Esto es una vista previa, será visible después de que haya sido aprobado. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/fa_IR.yaml b/i18n/fa_IR.yaml index 55cc9805..332ea8fc 100644 --- a/i18n/fa_IR.yaml +++ b/i18n/fa_IR.yaml @@ -464,42 +464,42 @@ backend: title: other: "آدرس ایمیل جدید خود را تایید کنید{{.SiteName}}" body: - other: "آدرس ایمیل جدید خود را برای {{.SiteName}} با کلیک بر روی پیوند زیر تأیید کنید:\n
      \n{{.ChangeEmailUrl}}

      \n\nاگر این تغییر را درخواست نکرده‌اید، لطفاً این ایمیل را نادیده بگیرید.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} به سؤال شما پاسخ داد" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nمشاهده آن در {{.SiteName}}

      \n\n--
      \nلغو اشتراک" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} شما را به پاسخ دعوت کرد" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      من فکر می کنم شما ممکن است پاسخ را بدانید.

      \nمشاهده آن در {{.SiteName}}

      \n\n--
      \nلغو اشتراک" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} روی پست شما نظر داد" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nمشاهده آن در {{.SiteName}}

      \n\n--
      \nلغو اشتراک" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] سؤال جدید: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nلغو اشتراک" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] گذرواژه بازنشانی شد" body: - other: "شخصی بازنشانی رمز عبور شما در {{.SiteName}} می‌باشد.

      \n\nاگر این شخص شما نبوده اید، می‌توانید با خیال راحت این ایمیل را نادیده بگیرید.

      \n\nبرای انتخاب رمز عبور جدید روی پیوند زیر کلیک کنید:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] حساب کاربری جدید خود را تأیید کنید" body: - other: "به {{.SiteName}} خوش آمدید!

      \n\nبرای تأیید و فعال سازی حساب کاربری جدید خود روی پیوند زیر کلیک کنید:
      \n{{.RegisterUrl}}

      \n\nاگر پیوند بالا قابل بازشدن نیست، آن را کپی کرده و در نوار آدرس مرورگر وب خود قرار دهید.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] ایمیل آزمایشی" body: - other: "این یک ایمیل تست است." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: رأی مثبت @@ -787,7 +787,7 @@ ui: how_to_format: title: نحوه فرمت کردن desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: قبلی next: بعدی @@ -904,7 +904,7 @@ ui: msg: empty: فایل نمی تواند خالی باشد. only_image: فقط فایل های تصویری مجاز هستند. - max_size: حجم فایل نباید بیشتر از 4 مگابایت باشد. + max_size: File size cannot exceed {{size}} MB. desc: label: توضیحات tab_url: لینک عکس @@ -946,6 +946,10 @@ ui: text: جدول heading: سرفصل cell: تلفن همراه + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: این پست را می بندم بدلیل... btn_cancel: لغو @@ -1086,6 +1090,7 @@ ui: search_placeholder: فیلتر بر اساس اسم برچسب no_desc: برچسب هیچ توضیحی ندارد. more: بیشتر + wiki: Wiki ask: title: سوالی اضافه کنید edit_title: سوال را ویرایش کنید @@ -1522,6 +1527,7 @@ ui: newest: جدیدترین active: فعال hot: Hot + frequent: Frequent recommend: Recommend score: امتیاز unanswered: بدون پاسخ @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "سوالات:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "جواب ها:" comments: "نظرات:" votes: "آرا:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: بهینه‌سازی عملیات موتورهای جستجو permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/fr_FR.yaml b/i18n/fr_FR.yaml index 52ad1375..b08ee953 100644 --- a/i18n/fr_FR.yaml +++ b/i18n/fr_FR.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirmez votre nouvelle adresse e-mail" body: - other: "Confirmez votre nouvelle adresse e-mail pour {{.SiteName}} en cliquant sur le lien suivant :
      \n{{.ChangeEmailUrl}}

      \n\nSi vous n'avez pas demandé ce changement, veuillez ignorer cet e-mail.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} a répondu à votre question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nVoir sur {{.SiteName}}

      \n\n--
      \nDésabonnez-vous" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} vous a invité à répondre" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Je pense que vous connaissez la réponse.

      \nVoir sur {{.SiteName}}

      \n\n--
      \nDésabonnez-vous" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} a commenté votre message" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nVoir sur {{.SiteName}}

      \n\n--
      \nDésabonnez-vous" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Nouvelle question : {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nDésabonnez-vous" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Réinitialisation du mot de passe" body: - other: "Quelqu'un a demandé à réinitialiser votre mot de passe sur {{.SiteName}}.

      \n\nSi ce n'était pas vous, vous pouvez ignorer cet e-mail en toute sécurité.

      \n\nCliquez sur le lien suivant pour choisir un nouveau mot de passe :
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirmez la création de votre compte" body: - other: "Bienvenue sur {{.SiteName}} !

      \n\nCliquez sur le lien suivant pour confirmer et activer votre nouveau compte :
      {{.RegisterUrl}}

      \n\nSi le lien ci-dessus n'est pas cliquable, essayez de le copier et coller dans la barre d'adresse de votre navigateur web.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Email de test" body: - other: "Ceci est un mail de test." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: Comment mettre en forme desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Préc next: Suivant @@ -904,7 +904,7 @@ ui: msg: empty: Le fichier ne doit pas être vide. only_image: Seules les images sont autorisées. - max_size: La taille du fichier ne doit pas dépasser 4 Mo. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: URL de l'image @@ -946,6 +946,10 @@ ui: text: Tableau heading: Titre cell: Cellule + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Je ferme ce post comme... btn_cancel: Annuler @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtrer par étiquette no_desc: L'étiquette n'a pas de description. more: Plus + wiki: Wiki ask: title: Ajouter une question edit_title: Modifier la question @@ -1522,6 +1527,7 @@ ui: newest: Les plus récents active: Actif hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Sans réponse @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Statistiques du site questions: "Questions :" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Réponses :" comments: "Commentaires:" votes: "Votes :" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Tags réservés text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Êtes-vous sûr de vouloir abandonner ce brouillon ? messages: post_deleted: Ce message a été supprimé. + post_cancel_deleted: This post has been undeleted. post_pin: Ce message a été épinglé. post_unpin: Ce message a été déépinglé. post_hide_list: Ce message a été masqué de la liste. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/hi_IN.yaml b/i18n/hi_IN.yaml index 8a9da4d5..5577e1e9 100644 --- a/i18n/hi_IN.yaml +++ b/i18n/hi_IN.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Prev next: Next @@ -904,7 +904,7 @@ ui: msg: empty: File cannot be empty. only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: Image URL @@ -946,6 +946,10 @@ ui: text: Table heading: Heading cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: I am closing this post as... btn_cancel: Cancel @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1522,6 +1527,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Questions:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Answers:" comments: "Comments:" votes: "Votes:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/id_ID.yaml b/i18n/id_ID.yaml index bf8e827d..8ab840a0 100644 --- a/i18n/id_ID.yaml +++ b/i18n/id_ID.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: Cara memformat desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Sebelumnya next: Selanjutnya @@ -904,7 +904,7 @@ ui: msg: empty: File tidak boleh kosong. only_image: Hanya file Gambar yang diperbolehkan. - max_size: Ukuran file tidak boleh melebihi 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: URL gambar @@ -946,6 +946,10 @@ ui: text: Table heading: Heading cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Postingan ini saya tutup sebagai... btn_cancel: Batal @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1522,6 +1527,7 @@ ui: newest: Terbaru active: Aktif hot: Hot + frequent: Frequent recommend: Recommend score: Nilai unanswered: Belum dijawab @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Pertanyaan:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Jawaban:" comments: "Komentar:" votes: "Vote:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/it_IT.yaml b/i18n/it_IT.yaml index 3cc90171..84eb5ab4 100644 --- a/i18n/it_IT.yaml +++ b/i18n/it_IT.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Conferma il tuo nuovo indirizzo email" body: - other: "Conferma il tuo nuovo indirizzo email per {{.SiteName}} cliccando sul seguente link:
      \n{{.ChangeEmailUrl}}

      \n\nSe non hai richiesto questa modifica, ignora questa email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} ha risposto alla tua domanda" body: - other: "\n{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nVisualizzalo su {{.SiteName}}

      \n\n--
      \nAnnulla iscrizione" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} ti ha invitato a rispondere" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Credo che potresti sapere la risposta.

      \nVisualizzalo su {{.SiteName}}

      \n\n--
      \nAnnulla iscrizione" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} ha commentato il tuo post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nVisualizzalo su {{.SiteName}}

      \n\n--
      \nAnnulla iscrizione" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Nuova domanda: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nAnnulla l'iscrizione" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Reimpostazione della password" body: - other: "Qualcuno ha chiesto di reimpostare la tua password su {{.SiteName}}.

      \n\nSe non sei stato tu, ignora questa email.

      \n\nClicca sul seguente link per scegliere una nuova password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Conferma il tuo nuovo account" body: - other: "Benvenuto su {{.SiteName}}!

      \n\nClicca il seguente link per confermare e attivare il tuo nuovo account:
      \n{{.RegisterUrl}}

      \n\nSe il link qui sopra non è cliccabile, prova a copiarlo e incollarlo nella barra degli indirizzi del tuo browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Email di prova" body: - other: "Questa è una email di prova." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: voto a favore @@ -787,7 +787,7 @@ ui: how_to_format: title: Come formattare desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Prec next: Successivo @@ -904,7 +904,7 @@ ui: msg: empty: Il file non può essere vuoto. only_image: Sono ammesse solo le immagini - max_size: La dimensione del file non può superare i 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Descrizione tab_url: Url dell'Immagine @@ -946,6 +946,10 @@ ui: text: Tabella heading: Intestazione cell: Cella + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Sto chiudendo questo post come... btn_cancel: Cancella @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtra per nome del tag no_desc: Il tag non ha descrizioni. more: Altro + wiki: Wiki ask: title: Aggiungi una domanda edit_title: Modifica Domanda @@ -1522,6 +1527,7 @@ ui: newest: Più recenti active: Attivo hot: Caldo + frequent: Frequent recommend: Raccomandato score: Punteggio unanswered: Senza risposta @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Statistiche del sito questions: "Domande:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Risposte:" comments: "Commenti:" votes: "Voti:" @@ -1814,7 +1822,7 @@ ui: msg: "Inserisci l'email dell'utente, una per riga." display_name: label: Nome da visualizzare - msg: Il nome visualizzato deve avere una lunghezza compresa tra 2 e 30 caratteri. + msg: Il nome visualizzato deve avere una lunghezza compresa tra 4 e 30 caratteri. email: label: E-mail msg: L'email non è valida. @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Tag riservati text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Sei sicuro di voler eliminare la bozza? messages: post_deleted: Questo post è stato eliminato. + post_cancel_deleted: This post has been undeleted. post_pin: Questo post è stato selezionato. post_unpin: Questo post è stato sbloccato. post_hide_list: Questo post è stato nascosto dall'elenco. @@ -2219,3 +2243,15 @@ ui: post_list: Questo post è stato inserito. post_unlist: Questo post è stato rimosso. post_pending: Il tuo post è in attesa di revisione. Sarà visibile dopo essere stato approvato. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/ja_JP.yaml b/i18n/ja_JP.yaml index 433831f4..0ffce9d0 100644 --- a/i18n/ja_JP.yaml +++ b/i18n/ja_JP.yaml @@ -29,34 +29,34 @@ backend: database_error: other: データサーバーエラー forbidden_error: - other: Forbidden. + other: アクセス権限がありません。 duplicate_request_error: - other: Duplicate submission. + other: 重複しています action: report: - other: フラグ + other: 通報 edit: other: 編集 delete: other: 削除 close: - other: 閉じる + other: 解決済み reopen: - other: Reopen + other: 再オープン forbidden_error: - other: Forbidden. + other: アクセス権限がありません。 pin: - other: Pin + other: ピン留めする hide: - other: Unlist + other: 限定公開にする unpin: - other: Unpin + other: ピン留め解除 show: - other: リスト + other: 限定公開を解除する invite_someone_to_answer: other: 編集 undelete: - other: Undelete + other: 復元する role: name: user: @@ -67,24 +67,24 @@ backend: other: モデレーター description: user: - other: Default with no special access. + other: 一般的なアクセスしか持ちません。 admin: - other: Have the full power to access the site. + other: すべてにアクセスできる大いなる力を持っています。 moderator: - other: Has access to all posts except admin settings. + other: 管理者以外のすべての投稿へのアクセス権を持っています。 privilege: level_1: description: - other: Level 1 (less reputation required for private team, group) + other: レベル1 必要最低の評判レベルで利用可(クローズサイト・グループ・特定の人数下での利用) level_2: description: - other: Level 2 (low reputation required for startup community) + other: レベル2 少しだけ評判レベルが必要(スタートアップコミュニティ・不特定多数の人数での利用) level_3: description: - other: Level 3 (high reputation required for mature community) + other: レベル3 高い評判レベルが必要(成熟したコミュニティ) level_custom: description: - other: Custom Level + other: カスタムレベル rank_question_add_label: other: 質問する rank_answer_add_label: @@ -92,69 +92,69 @@ backend: rank_comment_add_label: other: コメントを書く rank_report_add_label: - other: フラグ + other: 通報 rank_comment_vote_up_label: - other: Upvote comment + other: コメントを高評価 rank_link_url_limit_label: - other: Post more than 2 links at a time + other: 一度に2つ以上のリンクを投稿する rank_question_vote_up_label: - other: Upvote question + other: 質問を高評価 rank_answer_vote_up_label: - other: Upvote answer + other: 回答を高評価 rank_question_vote_down_label: - other: Downvote question + other: 質問を低評価 rank_answer_vote_down_label: - other: Downvote answer + other: 回答を低評価 rank_invite_someone_to_answer_label: - other: Invite someone to answer + other: 誰かを回答に招待する rank_tag_add_label: other: 新しいタグを作成 rank_tag_edit_label: - other: Edit tag description (need to review) + other: タグの説明を編集(レビューが必要) rank_question_edit_label: - other: Edit other's question (need to review) + other: 他の質問を編集(レビューが必要) rank_answer_edit_label: - other: Edit other's answer (need to review) + other: 他の回答を編集(レビューが必要) rank_question_edit_without_review_label: - other: Edit other's question without review + other: レビューなしで他の質問を編集する rank_answer_edit_without_review_label: - other: Edit other's answer without review + other: レビューなしで他の回答を編集する rank_question_audit_label: - other: Review question edits + other: 質問の編集をレビュー rank_answer_audit_label: - other: Review answer edits + other: 回答の編集をレビュー rank_tag_audit_label: - other: Review tag edits + other: タグの編集をレビュー rank_tag_edit_without_review_label: - other: Edit tag description without review + other: レビューなしでタグの説明を編集 rank_tag_synonym_label: - other: Manage tag synonyms + other: タグの同義語を管理する email: other: メールアドレス e_mail: - other: Email + other: メールアドレス password: other: パスワード pass: other: パスワード original_text: - other: This post + other: 投稿 email_or_password_wrong_error: other: メールアドレスとパスワードが一致しません。 error: common: invalid_url: - other: Invalid URL. + other: 無効なURL status_invalid: - other: Invalid status. + other: 無効なステータス password: space_invalid: - other: Password cannot contain spaces. + other: パスワードにスペースを含めることはできません。 admin: cannot_update_their_password: other: パスワードは変更できません。 cannot_edit_their_profile: - other: You cannot modify your profile. + other: プロフィールを変更できません。 cannot_modify_self_status: other: ステータスを変更できません。 email_or_password_wrong: @@ -183,7 +183,7 @@ backend: verify_url_expired: other: メール認証済みURLの有効期限が切れています。メールを再送信してください。 illegal_email_domain_error: - other: Email is not allowed from that email domain. Please use another one. + other: そのメールドメインからのメールは許可されていません。別のメールアドレスを使用してください。 lang: not_found: other: 言語ファイルが見つかりません。 @@ -207,15 +207,15 @@ backend: new_password_same_as_previous_setting: other: 新しいパスワードは前のパスワードと同じです。 already_deleted: - other: This post has been deleted. + other: この投稿は削除されました。 meta: object_not_found: - other: Meta object not found + other: メタオブジェクトが見つかりません question: already_deleted: other: この投稿は削除されました。 under_review: - other: Your post is awaiting review. It will be visible after it has been approved. + other: あなたの投稿はレビュー待ちです。承認されると表示されます。 not_found: other: 質問が見つかりません。 cannot_deleted: @@ -226,11 +226,11 @@ backend: other: 更新する権限がありません。 rank: fail_to_meet_the_condition: - other: Reputation rank fail to meet the condition. + other: 評判ランクが条件を満たしていません vote_fail_to_meet_the_condition: - other: Thanks for the feedback. You need at least {{.Rank}} reputation to cast a vote. + other: フィードバックをありがとうございます。投票には少なくとも {{.Rank}} の評判が必要です。 no_enough_rank_to_operate: - other: You need at least {{.Rank}} reputation to do this. + other: 少なくとも {{.Rank}} の評判が必要です。 report: handle_failed: other: レポートの処理に失敗しました。 @@ -242,167 +242,167 @@ backend: not_found: other: タグが見つかりません。 recommend_tag_not_found: - other: Recommend tag is not exist. + other: おすすめタグは存在しません。 recommend_tag_enter: other: 少なくとも 1 つの必須タグを入力してください。 not_contain_synonym_tags: other: 同義語のタグを含めないでください。 cannot_update: - other: No permission to update. + other: 更新する権限がありません。 is_used_cannot_delete: - other: You cannot delete a tag that is in use. + other: 使用中のタグは削除できません。 cannot_set_synonym_as_itself: - other: You cannot set the synonym of the current tag as itself. + other: 現在のタグの同義語をそのものとして設定することはできません。 smtp: config_from_name_cannot_be_email: - other: The from name cannot be a email address. + other: Fromの名前はメールアドレスにできません。 theme: not_found: other: テーマが見つかりません。 revision: review_underway: - other: Can't edit currently, there is a version in the review queue. + other: 現在編集できません。レビューキューにバージョンがあります。 no_permission: - other: No permission to revise. + other: 編集する権限がありません。 user: external_login_missing_user_id: - other: The third-party platform does not provide a unique UserID, so you cannot login, please contact the website administrator. + other: サードパーティのプラットフォームは一意のユーザーIDを提供していないため、ログインできません。ウェブサイト管理者にお問い合わせください。 external_login_unbinding_forbidden: - other: Please set a login password for your account before you remove this login. + other: ログインを削除する前に、アカウントのログインパスワードを設定してください。 email_or_password_wrong: other: other: メールアドレスとパスワードが一致しません。 not_found: other: ユーザーが見つかりません。 suspended: - other: User has been suspended. + other: このユーザーは凍結されています username_invalid: - other: Username is invalid. + other: 無効なユーザー名です! username_duplicate: - other: Username is already in use. + other: ユーザー名は既に使用されています! set_avatar: - other: Avatar set failed. + other: アバターを設定できませんでした cannot_update_your_role: - other: You cannot modify your role. + other: ロールを変更できません not_allowed_registration: - other: Currently the site is not open for registration. + other: 現在、このサイトは新規登録を受け付けておりません not_allowed_login_via_password: - other: Currently the site is not allowed to login via password. + other: 現在、このサイトはパスワードでログインできません access_denied: other: アクセスが拒否されました page_access_denied: - other: You do not have access to this page. + other: このページへのアクセス権がありません add_bulk_users_format_error: other: "Error {{.Field}} format near '{{.Content}}' at line {{.Line}}. {{.ExtraMessage}}" add_bulk_users_amount_error: - other: "The number of users you add at once should be in the range of 1-{{.MaxAmount}}." + other: "一度に追加するユーザーの数は、1 -{{.MaxAmount}} の範囲にする必要があります。" config: read_config_failed: - other: Read config failed + other: configの読み込みに失敗しました database: connection_failed: - other: Database connection failed + other: データベースの接続が失敗しました create_table_failed: other: テーブルの作成に失敗しました install: create_config_failed: - other: Can't create the config.yaml file. + other: config.yaml を作成できません。 upload: unsupported_file_format: - other: Unsupported file format. + other: サポートされていないファイル形式です。 site_info: config_not_found: - other: Site config not found. + other: configが見つかりません。 badge: object_not_found: - other: Badge object not found + other: バッジオブジェクトが見つかりません reason: spam: name: - other: spam + other: スパム desc: - other: This post is an advertisement, or vandalism. It is not useful or relevant to the current topic. + other: この投稿は広告です。現在のトピックには有用ではありません。 rude_or_abusive: name: - other: rude or abusive + other: 誹謗中傷 desc: - other: "A reasonable person would find this content inappropriate for respectful discourse." + other: "合理的な人は、このコンテンツを尊重する言説には不適切と判断するでしょう。" a_duplicate: name: - other: a duplicate + other: 重複 desc: - other: This question has been asked before and already has an answer. + other: この質問は以前に質問されており、すでに回答があります。 placeholder: - other: Enter the existing question link + other: 既存の質問リンクを入力してください not_a_answer: name: - other: not an answer + other: 回答では無い desc: - other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." + other: "これは答えとして投稿されましたが、質問に答えようとしません。 それはおそらく編集、コメント、別の質問、または完全に削除されるべきです。" no_longer_needed: name: - other: no longer needed + other: 必要では無い desc: - other: This comment is outdated, conversational or not relevant to this post. + other: このコメントは古く、この投稿とは関係がありません。 something: name: - other: something else + other: その他 desc: - other: This post requires staff attention for another reason not listed above. + other: 上記以外の理由でスタッフの注意が必要です。 placeholder: - other: Let us know specifically what you are concerned about + other: あなたが懸念していることを私たちに教えてください community_specific: name: - other: a community-specific reason + other: コミュニティ固有の理由です desc: - other: This question doesn't meet a community guideline. + other: この質問はコミュニティガイドラインを満たしていません not_clarity: name: - other: needs details or clarity + other: 詳細や明快さが必要です desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: この質問には現在複数の質問が含まれています。1つの問題にのみ焦点を当てる必要があります。 looks_ok: name: - other: looks OK + other: LGTM desc: - other: This post is good as-is and not low quality. + other: この投稿はそのままで良く、改善する必要はありません! needs_edit: name: - other: needs edit, and I did it + other: 編集する必要があったため変更しました。 desc: - other: Improve and correct problems with this post yourself. + other: 自分自身でこの投稿の問題を改善し修正します。 needs_close: name: - other: needs close + other: クローズする必要がある desc: - other: A closed question can't answer, but still can edit, vote and comment. + other: クローズされた質問は回答できませんが、編集、投票、コメントはできます。 needs_delete: name: - other: needs delete + other: 削除が必要です desc: - other: This post will be deleted. + other: この投稿は削除されました question: close: duplicate: name: other: スパム desc: - other: This question has been asked before and already has an answer. + other: この質問は以前に質問されており、すでに回答があります。 guideline: name: - other: a community-specific reason + other: コミュニティ固有の理由です desc: - other: This question doesn't meet a community guideline. + other: この質問はコミュニティガイドラインを満たしていません multiple: name: - other: needs details or clarity + other: 詳細や明快さが必要です desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: この質問には現在複数の質問が含まれています。1つの問題にのみ焦点を当てる必要があります。 other: name: - other: something else + other: その他 desc: - other: This post requires another reason not listed above. + other: 上記以外の理由でスタッフの注意が必要です。 operation_type: asked: other: 質問済み @@ -411,383 +411,383 @@ backend: modified: other: 修正済み deleted_title: - other: Deleted question + other: 質問を削除 questions_title: - other: Questions + other: 質問 tag: tags_title: - other: Tags + other: タグ no_description: - other: The tag has no description. + other: タグには説明がありません。 notification: action: update_question: - other: updated question + other: 質問を更新 answer_the_question: - other: answered question + other: 回答済みの質問 update_answer: - other: updated answer + other: 回答を更新 accept_answer: - other: accepted answer + other: 承認された回答 comment_question: - other: commented question + other: コメントされた質問 comment_answer: - other: commented answer + other: コメントされた回答 reply_to_you: - other: replied to you + other: あなたへの返信 mention_you: - other: mentioned you + other: メンションされました your_question_is_closed: - other: Your question has been closed + other: あなたの質問はクローズされました your_question_was_deleted: - other: Your question has been deleted + other: あなたの質問は削除されました your_answer_was_deleted: - other: Your answer has been deleted + other: あなたの質問は削除されました your_comment_was_deleted: - other: Your comment has been deleted + other: あなたのコメントは削除されました up_voted_question: - other: upvoted question + other: 質問を高評価 down_voted_question: - other: downvoted question + other: 質問を低評価 up_voted_answer: - other: upvoted answer + other: 回答を高評価 down_voted_answer: - other: downvoted answer + other: 回答を低評価 up_voted_comment: - other: upvoted comment + other: コメントを高評価 invited_you_to_answer: - other: invited you to answer + other: あなたを回答に招待しました earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: '"{{.BadgeName}}"バッジを獲得しました' email_tpl: change_email: title: - other: "[{{.SiteName}}] Confirm your new email address" + other: "[{{.SiteName}}] 新しいメールアドレスを確認してください" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: - other: "[{{.SiteName}}] {{.DisplayName}} answered your question" + other: "[{{.SiteName}}] {{.DisplayName}} があなたの質問に回答しました" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: - other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" + other: "[{{.SiteName}}] {{.DisplayName}} があなたを回答に招待しました" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: - other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" + other: "[{{.SiteName}}] {{.DisplayName}} があなたの投稿にコメントしました" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: - other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" + other: "[{{.SiteName}}] 新しい質問: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: - other: "[{{.SiteName }}] Password reset" + other: "[{{.SiteName }}] パスワードリセット" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: - other: "[{{.SiteName}}] Confirm your new account" + other: "[{{.SiteName}}] 新しいアカウントを確認" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: - other: "[{{.SiteName}}] Test Email" + other: "[{{.SiteName}}] テストメール" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: - other: upvote + other: 高評価 upvoted: - other: upvoted + other: 高評価しました downvote: - other: downvote + other: 低評価 downvoted: - other: downvoted + other: 低評価しました accept: - other: accept + other: 承認 accepted: - other: accepted + other: 承認済み edit: - other: edit + other: 編集 review: queued_post: - other: Queued post + other: キューに入れられた投稿 flagged_post: - other: Flagged post + other: 投稿を通報 suggested_post_edit: - other: Suggested edits + other: 提案された編集 reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} と {{ .Count }} もっと..." badge: default_badges: autobiographer: name: - other: Autobiographer + other: 自伝作家 desc: - other: Filled out profile information. + other: プロファイル 情報を入力しました。 certified: name: - other: Certified + other: 認定済み desc: - other: Completed our new user tutorial. + other: 新しいユーザーがチュートリアルを完了しました。 editor: name: - other: Editor + other: 編集者 desc: - other: First post edit. + other: 最初の投稿の編集 first_flag: name: - other: First Flag + other: 初めての報告 desc: - other: First flagged a post. + other: 初めての報告 first_upvote: name: - other: First Upvote + other: はじめての高評価 desc: - other: First up voted a post. + other: はじめて投稿に高評価した first_link: name: - other: First Link + other: はじめてのリンク desc: - other: First dirst added a link to another post. + other: "初めて別の記事へのリンクを追加した。\n" first_reaction: name: - other: First Reaction + other: 初めてのリアクション desc: - other: First reacted to the post. + other: はじめて投稿にリアクションした first_share: name: - other: First Share + other: はじめての共有 desc: - other: First shared a post. + other: はじめて投稿を共有した scholar: name: - other: Scholar + other: 研究生 desc: - other: Asked a question and accepted an answer. + other: 質問をして回答が承認された commentator: name: - other: Commentator + other: コメントマン desc: - other: Leave 5 comments. + other: 5つコメントをした new_user_of_the_month: name: - other: New User of the Month + other: 今月の新しいユーザー desc: - other: Outstanding contributions in their first month. + other: 最初の月に優れた貢献 read_guidelines: name: - other: Read Guidelines + other: ガイドラインを読んだ desc: - other: Read the [community guidelines]. + other: '「コミュニティガイドライン」をご覧ください。' reader: name: - other: Reader + other: リーダー desc: - other: Read every answers in a topic with more than 10 answers. + other: 10以上の回答を持つトピックのすべての回答を読んだ welcome: name: - other: Welcome + other: ようこそ! desc: - other: Received a up vote. + other: 高評価をされた nice_share: name: other: Nice Share desc: - other: Shared a post with 25 unique visitors. + other: 25人の訪問者と投稿を共有した good_share: name: other: Good Share desc: - other: Shared a post with 300 unique visitors. + other: 300の訪問者と投稿を共有した great_share: name: other: Great Share desc: - other: Shared a post with 1000 unique visitors. + other: 1000人の訪問者と投稿を共有した out_of_love: name: - other: Out of Love + other: お隣さん desc: - other: Used 50 up votes in a day. + other: 1日に50票いれた higher_love: name: - other: Higher Love + other: お友達 desc: - other: Used 50 up votes in a day 5 times. + other: 5日目に50回投票した crazy_in_love: name: - other: Crazy in Love + other: 崇拝 desc: - other: Used 50 up votes in a day 20 times. + other: 一日に50回投票を20回した promoter: name: - other: Promoter + other: プロモーター desc: - other: Invited a user. + other: ユーザーを招待した campaigner: name: - other: Campaigner + other: キャンペーン desc: - other: Invited 3 basic users. + other: 3人のベーシックユーザーを招待しました。 champion: name: - other: Champion + other: チャンピオン desc: - other: Invited 5 members. + other: 5人のメンバーを招待しました。 thank_you: name: - other: Thank You + other: Thank you desc: - other: Has 20 up voted posts and gave 10 up votes. + other: 投稿が20件!投票数が10件! gives_back: name: - other: Gives Back + other: 返品 desc: - other: Has 100 up voted posts and gave 100 up votes. + other: 投稿が100件 !?!? 投票数が100件 !?!? empathetic: name: - other: Empathetic + other: 共感性 desc: - other: Has 500 up voted posts and gave 1000 up votes. + other: 500の投稿を投票し、1000の投票を与えた。 enthusiast: name: - other: Enthusiast + other: 楽天家 desc: - other: Visited 10 consecutive days. + other: 10日間連続ログイン aficionado: name: other: Aficionado desc: - other: Visited 100 consecutive days. + other: 100日連続ログイン!!! devotee: name: - other: Devotee + other: 献身者 desc: - other: Visited 365 consecutive days. + other: 365日連続訪問!!!!!!!! anniversary: name: - other: Anniversary + other: 周年記念 desc: - other: Active member for a year, posted at least once. + other: 年に一回は... appreciated: name: - other: Appreciated + other: ありがとう! desc: - other: Received 1 up vote on 20 posts. + other: 20件の投稿に1件の投票を受け取った respected: name: - other: Respected + other: 尊敬される desc: - other: Received 2 up votes on 100 posts. + other: 100件の投稿で2件の投票を受け取った admired: name: - other: Admired + other: 崇拝された desc: - other: Received 5 up votes on 300 posts. + other: 300の投稿に5票を獲得した solved: name: - other: Solved + other: 解決 desc: - other: Have an answer be accepted. + other: 答えを受け入れられた guidance_counsellor: name: - other: Guidance Counsellor + other: アドバイザー desc: - other: Have 10 answers be accepted. + other: 10個の回答が承認された know_it_all: name: - other: Know-it-All + other: 物知り博士 desc: - other: Have 50 answers be accepted. + other: 50個の回答が承認された solution_institution: name: - other: Solution Institution + other: 解決機関 desc: - other: Have 150 answers be accepted. + other: 150個の回答が承認された nice_answer: name: - other: Nice Answer + other: 素敵な回答 desc: - other: Answer score of 10 or more. + other: 回答スコアは10以上!! good_answer: name: - other: Good Answer + other: 良い回答 desc: - other: Answer score of 25 or more. + other: 回答スコアは25以上!?! great_answer: name: - other: Great Answer + other: 素晴らしい回答 desc: - other: Answer score of 50 or more. + other: 回答スコアは50以上!!!!1 nice_question: name: - other: Nice Question + other: ナイスな質問 desc: - other: Question score of 10 or more. + other: 質問スコアは10以上!! good_question: name: - other: Good Question + other: よい質問 desc: - other: Question score of 25 or more. + other: 質問スコアは25以上!?! great_question: name: - other: Great Question + other: 素晴らしい質問 desc: - other: Question score of 50 or more. + other: 50人の閲覧者!! popular_question: name: - other: Popular Question + other: 人気のある質問 desc: - other: Question with 500 views. + other: 500人の閲覧者!!! notable_question: name: - other: Notable Question + other: 注目すべき質問 desc: - other: Question with 1,000 views. + other: 1,000人の閲覧者!!!! famous_question: name: - other: Famous Question + other: 偉大な質問 desc: - other: Question with 5,000 views. + other: 5,000人の閲覧者!!!!! popular_link: name: - other: Popular Link + other: 人気のリンク desc: - other: Posted an external link with 50 clicks. + other: 外部リンクを50回クリック hot_link: name: - other: Hot Link + other: 激アツリンク desc: - other: Posted an external link with 300 clicks. + other: 外部リンクを300回クリック famous_link: name: - other: Famous Link + other: 有名なリンク desc: - other: Posted an external link with 100 clicks. + other: 外部リンクを100回クリック default_badge_groups: getting_started: name: - other: Getting Started + other: はじめに community: name: - other: Community + other: コミュニティ posting: name: - other: Posting + other: 投稿中 # The following fields are used for interface presentation(Front-end) ui: how_to_format: - title: How to Format + title: 書式設定 desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: 前へ next: 次へ @@ -796,79 +796,79 @@ ui: questions: 質問 tag: タグ tags: タグ - tag_wiki: tag wiki + tag_wiki: タグ wiki create_tag: タグを作成 edit_tag: タグを編集 ask_a_question: 質問を追加 edit_question: 質問を編集 edit_answer: 回答を編集 search: 検索 - posts_containing: Posts containing + posts_containing: 記事を含む投稿 settings: 設定 - notifications: Notifications + notifications: お知らせ login: ログイン sign_up: 新規登録 account_recovery: アカウントの復旧 - account_activation: Account Activation + account_activation: アカウント有効化 confirm_email: メールアドレスを確認 - account_suspended: Account Suspended + account_suspended: アカウントは凍結されています admin: 管理者 change_email: メールアドレスを変更 - install: Answer Installation - upgrade: Answer Upgrade - maintenance: Website Maintenance + install: 回答に応答する + upgrade: 回答を改善する + maintenance: ウェブサイトのメンテナンス users: ユーザー - oauth_callback: Processing + oauth_callback: 処理中 http_404: HTTP エラー 404 http_50X: HTTP エラー 500 http_403: HTTP エラー 403 - logout: Log Out + logout: ログアウト notifications: title: 通知 inbox: 受信トレイ - achievement: Achievements - new_alerts: New alerts - all_read: Mark all as read + achievement: 実績 + new_alerts: 新しい通知 + all_read: すべて既読にする show_more: もっと見る - someone: Someone + someone: 誰か inbox_type: all: すべて posts: 投稿 invites: 招待 votes: 投票 - answer: Answer - question: Question - badge_award: Badge + answer: 回答 + question: 質問 + badge_award: バッジ suspended: title: あなたのアカウントは停止されています。 until_time: "あなたのアカウントは {{ time }} まで停止されました。" forever: このユーザーは永久に停止されました。 - end: You don't meet a community guideline. + end: コミュニティガイドラインを満たしていません。 contact_us: お問い合わせ editor: blockquote: text: 引用 bold: - text: Strong + text: 強い chart: - text: Chart + text: チャート flow_chart: フローチャート - sequence_diagram: Sequence diagram - class_diagram: Class diagram - state_diagram: State diagram - entity_relationship_diagram: Entity relationship diagram - user_defined_diagram: User defined diagram - gantt_chart: Gantt chart - pie_chart: Pie chart + sequence_diagram: シーケンス図 + class_diagram: クラス図 + state_diagram: 状態図 + entity_relationship_diagram: ER図 + user_defined_diagram: ユーザー定義図 + gantt_chart: ガントチャート + pie_chart: 円グラフ code: - text: Code Sample - add_code: Add code sample + text: コードサンプル + add_code: コードサンプルを追加 form: fields: code: label: コード msg: - empty: Code cannot be empty. + empty: Code を空にすることはできません。 language: label: 言語 placeholder: 自動検出 @@ -877,8 +877,8 @@ ui: formula: text: 数式 options: - inline: Inline formula - block: Block formula + inline: インライン数式 + block: ブロック数式 heading: text: 見出し options: @@ -891,7 +891,7 @@ ui: help: text: ヘルプ hr: - text: Horizontal rule + text: 水平方向の罫線 image: text: 画像 add_image: 画像を追加する @@ -899,12 +899,12 @@ ui: form_image: fields: file: - label: Image file + label: 画像ファイル btn: 画像を選択する msg: empty: ファイルは空にできません。 only_image: 画像ファイルのみが許可されています。 - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: 説明 tab_url: 画像URL @@ -922,12 +922,12 @@ ui: indent: text: インデント outdent: - text: Outdent + text: アウトデント italic: - text: Emphasis + text: 斜体 link: - text: Hyperlink - add_link: Add hyperlink + text: ハイパーリンク + add_link: ハイパーリンクを追加 form: fields: url: @@ -939,15 +939,19 @@ ui: btn_cancel: キャンセル btn_confirm: 追加 ordered_list: - text: Numbered list + text: 順序付きリスト unordered_list: - text: Bulleted list + text: 箇条書きリスト table: text: ' テーブル' heading: 見出し cell: セル + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: - title: I am closing this post as... + title: この投稿を次のように閉じます... btn_cancel: キャンセル btn_submit: 送信 remark: @@ -955,25 +959,25 @@ ui: msg: empty: 理由を選んでください。 report_modal: - flag_title: I am flagging to report this post as... - close_title: I am closing this post as... - review_question_title: Review question - review_answer_title: Review answer - review_comment_title: Review comment + flag_title: この投稿を報告するフラグを立てています... + close_title: この投稿を次のように閉じます... + review_question_title: 質問の編集をレビュー + review_answer_title: 答えをレビューする + review_comment_title: レビューコメント btn_cancel: キャンセル btn_submit: 送信 remark: empty: 入力してください。 msg: empty: 理由を選んでください。 - not_a_url: URL format is incorrect. - url_not_match: URL origin does not match the current website. + not_a_url: URL形式が正しくありません。 + url_not_match: URL の原点が現在のウェブサイトと一致しません。 tag_modal: title: 新しいタグを作成 form: fields: display_name: - label: Display name + label: 表示名 msg: empty: 表示名を入力してください。 range: 表示名は最大 35 文字までです。 @@ -982,16 +986,16 @@ ui: desc: '文字セット「a-z」、「0-9」、「+ # -」を使用する必要があります。' msg: empty: URL スラッグを空にすることはできません。 - range: URL slug up to 35 characters. - character: URL slug contains unallowed character set. + range: タイトルは最大35文字までです. + character: URL スラグに許可されていない文字セットが含まれています。 desc: label: 説明 revision: - label: Revision + label: 修正 edit_summary: - label: Edit summary + label: 概要を編集 placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) + 簡単にあなたの変更を説明します(修正スペル、固定文法、改善されたフォーマット) btn_cancel: キャンセル btn_submit: 送信 btn_post: 新しいタグを投稿 @@ -1001,61 +1005,61 @@ ui: history: 履歴 synonyms: title: 類義語 - text: The following tags will be remapped to - empty: No synonyms found. - btn_add: Add a synonym + text: 次のタグが再マップされます + empty: 同義語は見つかりません。 + btn_add: 同義語を追加 btn_edit: 編集 btn_save: 保存 - synonyms_text: The following tags will be remapped to + synonyms_text: 次のタグが再マップされます delete: title: このタグを削除 tip_with_posts: >- -

      We do not allow deleting tag with posts.

      Please remove this tag from the posts first.

      +

      同義語でタグを削除することはできません。

      最初にこのタグから同義語を削除してください。

      tip_with_synonyms: >- -

      We do not allow deleting tag with synonyms.

      Please remove the synonyms from this tag first.

      - tip: Are you sure you wish to delete? - close: 閉じる +

      同義語でタグを削除することはできません。

      最初にこのタグから同義語を削除してください。

      + tip: 本当に削除してもよろしいですか? + close: クローズ edit_tag: title: タグを編集 default_reason: タグを編集 - default_first_reason: Add tag - btn_save_edits: Save edits + default_first_reason: タグを追加 + btn_save_edits: 編集を保存 btn_cancel: キャンセル dates: long_date: MMM D - long_date_with_year: "MMM D, YYYY" + long_date_with_year: "YYYY年MM月D日" long_date_with_time: "MMM D, YYYY [at] HH:mm" - now: now - x_seconds_ago: "{{count}}s ago" - x_minutes_ago: "{{count}}m ago" - x_hours_ago: "{{count}}h ago" + now: 今 + x_seconds_ago: "{{count}}秒前" + x_minutes_ago: "{{count}}分前" + x_hours_ago: "{{count}}時間前" hour: 時 day: 日 hours: 時 days: 日 reaction: - heart: heart - smile: smile - frown: frown - btn_label: add or remove reactions - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} - unreact_emoji: unreact with {{ emoji }} + heart: ハート + smile: 笑顔 + frown: 眉をひそめる + btn_label: リアクションの追加または削除 + undo_emoji: '{{ emoji }} のリアクションを元に戻す' + react_emoji: '{{ emoji }} に反応する' + unreact_emoji: '{{ emoji }} に反応しない' comment: btn_add_comment: コメントを追加 - reply_to: Reply to + reply_to: 返信: btn_reply: 返信 btn_edit: 編集 btn_delete: 削除 btn_flag: フラグ btn_save_edits: 編集内容を保存 btn_cancel: キャンセル - show_more: "{{count}} more comments" + show_more: "{{count}} 件のその他のコメント" tip_question: >- - Use comments to ask for more information or suggest improvements. Avoid answering questions in comments. + コメントを使用して、より多くの情報を求めたり、改善を提案したりします。コメントで質問に答えることは避けてください。 tip_answer: >- - Use comments to reply to other users or notify them of changes. If you are adding new information, edit your post instead of commenting. - tip_vote: It adds something useful to the post + コメントを使用して他のユーザーに返信したり、変更を通知します。新しい情報を追加する場合は、コメントの代わりに投稿を編集します。 + tip_vote: 投稿に役に立つものを追加します edit_answer: title: 回答を編集 default_reason: 回答を編集 @@ -1063,16 +1067,16 @@ ui: form: fields: revision: - label: Revision + label: 修正 answer: - label: Answer + label: 回答 feedback: - characters: content must be at least 6 characters in length. + characters: コンテンツは6文字以上でなければなりません。 edit_summary: - label: Edit summary + label: 概要を編集 placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) - btn_save_edits: Save edits + 簡単にあなたの変更を説明します(修正スペル、固定文法、改善されたフォーマット) + btn_save_edits: 編集を保存 btn_cancel: キャンセル tags: title: タグ @@ -1084,8 +1088,9 @@ ui: button_following: フォロー中 tag_label: 質問 search_placeholder: タグ名でフィルタ - no_desc: The tag has no description. - more: More + no_desc: タグには説明がありません。 + more: もっと見る + wiki: Wiki ask: title: 質問を追加 edit_title: 質問を編集 @@ -1095,53 +1100,53 @@ ui: form: fields: revision: - label: Revision + label: 修正 title: - label: Title - placeholder: Be specific and imagine you're asking a question to another person + label: タイトル + placeholder: 具体的にして、あなたが他の人に質問していると想像してください msg: - empty: Title cannot be empty. - range: Title up to 150 characters + empty: タイトルを空にすることはできません。 + range: タイトルは最大150文字までです body: - label: Body + label: 本文 msg: - empty: Body cannot be empty. + empty: 本文を空にすることはできません。 tags: - label: Tags + label: タグ msg: - empty: Tags cannot be empty. + empty: 少なくとも一つ以上のタグが必要です。 answer: - label: Answer + label: 回答 msg: - empty: Answer cannot be empty. + empty: 回答は空欄にできません edit_summary: - label: Edit summary + label: 概要を編集 placeholder: >- - Briefly explain your changes (corrected spelling, fixed grammar, improved formatting) - btn_post_question: Post your question - btn_save_edits: Save edits - answer_question: Answer your own question - post_question&answer: Post your question and answer + 簡単にあなたの変更を説明します(修正スペル、固定文法、改善されたフォーマット) + btn_post_question: 質問を投稿する + btn_save_edits: 編集内容を保存 + answer_question: ご自身の質問に答えてください + post_question&answer: 質問と回答を投稿する tag_selector: - add_btn: Add tag - create_btn: Create new tag - search_tag: Search tag - hint: "Describe what your question is about, at least one tag is required." - no_result: No tags matched - tag_required_text: Required tag (at least one) + add_btn: タグを追加 + create_btn: 新しタグを作成 + search_tag: タグを検索 + hint: "質問について説明してください。少なくとも1つのタグが必要です。" + no_result: 一致するタグはありません + tag_required_text: 必須タグ (少なくとも 1 つ) header: nav: - question: Questions - tag: Tags - user: Users - badges: Badges - profile: Profile - setting: Settings - logout: Log out + question: 質問 + tag: タグ + user: ユーザー + badges: バッジ + profile: プロフィール + setting: 設定 + logout: ログアウト admin: 管理者 review: レビュー bookmark: ブックマーク - moderation: Moderation + moderation: モデレーション search: placeholder: 検索 footer: @@ -1151,35 +1156,35 @@ ui: name: 変更 loading: 読み込み中… pic_auth_code: - title: Captcha - placeholder: Type the text above + title: CAPTCHA + placeholder: 上記のテキストを入力してください msg: - empty: Captcha cannot be empty. + empty: Code を空にすることはできません。 inactive: first: >- - You're almost done! We sent an activation mail to {{mail}}. Please follow the instructions in the mail to activate your account. - info: "If it doesn't arrive, check your spam folder." + {{mail}}にアクティベーションメールを送信しました。メールの指示に従ってアカウントをアクティベーションしてください。 + info: "届かない場合は、迷惑メールフォルダを確認してください。" another: >- - We sent another activation email to you at {{mail}}. It might take a few minutes for it to arrive; be sure to check your spam folder. - btn_name: Resend activation email + {{mail}}に別のアクティベーションメールを送信しました。 到着には数分かかる場合があります。スパムフォルダを確認してください。 + btn_name: 認証メールを再送信 change_btn_name: メールアドレスを変更 msg: - empty: Cannot be empty. + empty: 空にすることはできません resend_email: - url_label: Are you sure you want to resend the activation email? - url_text: You can also give the activation link above to the user. + url_label: 本当に認証メールを再送信してもよろしいですか? + url_text: ユーザーに上記のアクティベーションリンクを渡すこともできます。 login: - login_to_continue: Log in to continue - info_sign: Don't have an account? <1>Sign up - info_login: Already have an account? <1>Log in - agreements: By registering, you agree to the <1>privacy policy and <3>terms of service. + login_to_continue: ログインして続行 + info_sign: アカウントをお持ちではありませんか?<1>サインアップ + info_login: すでにアカウントをお持ちですか?<1>ログイン + agreements: 登録することにより、<1>プライバシーポリシーおよび<3>サービス規約に同意するものとします。 forgot_pass: パスワードをお忘れですか? name: - label: Name + label: 名前 msg: - empty: Name cannot be empty. - range: Name must be between 2 to 30 characters in length. - character: 'Must use the character set "a-z", "A-Z", "0-9", " - . _"' + empty: 名前を空にすることはできません。 + range: 2~30文字の名前を設定してください。 + character: '文字セット "a-z", "A-Z", "0-9", " - " を使用する必要があります。' email: label: メールアドレス msg: @@ -1188,12 +1193,12 @@ ui: label: パスワード msg: empty: パスワードを入力してください。 - different: The passwords entered on both sides are inconsistent + different: 入力されたパスワードが一致しません account_forgot: page_title: パスワードを忘れた方はこちら - btn_name: Send me recovery email + btn_name: 回復用のメールを送る send_success: >- - If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + アカウントが {{mail}}と一致する場合は、パスワードをすぐにリセットする方法に関するメールが送信されます。 email: label: メールアドレス msg: @@ -1202,333 +1207,336 @@ ui: btn_cancel: キャンセル btn_update: メールアドレスを更新 send_success: >- - If an account matches {{mail}}, you should receive an email with instructions on how to reset your password shortly. + アカウントが {{mail}}と一致する場合は、パスワードをすぐにリセットする方法に関するメールが送信されます。 email: - label: New email + label: 新しいメールアドレス msg: - empty: Email cannot be empty. + empty: メールアドレス欄を空白にしておくことはできません oauth: - connect: Connect with {{ auth_name }} - remove: Remove {{ auth_name }} + connect: '{{ auth_name }} と接続' + remove: '{{ auth_name }} を削除' oauth_bind_email: - subtitle: Add a recovery email to your account. - btn_update: Update email address + subtitle: アカウントに回復用のメールアドレスを追加します。 + btn_update: メールアドレスを更新 email: - label: Email + label: メールアドレス msg: - empty: Email cannot be empty. - modal_title: Email already existes. - modal_content: This email address already registered. Are you sure you want to connect to the existing account? - modal_cancel: Change email - modal_confirm: Connect to the existing account + empty: メールアドレスは空にできません。 + modal_title: このメールアドレスはすでに存在しています。 + modal_content: このメールアドレスは既に登録されています。既存のアカウントに接続してもよろしいですか? + modal_cancel: メールアドレスを変更する + modal_confirm: 既存のアカウントに接続 password_reset: page_title: パスワード再設定 btn_name: パスワードをリセット reset_success: >- - You successfully changed your password; you will be redirected to the log in page. + パスワードを変更しました。ログインページにリダイレクトされます。 link_invalid: >- - Sorry, this password reset link is no longer valid. Perhaps your password is already reset? - to_login: Continue to log in page + 申し訳ありませんが、このパスワードリセットのリンクは無効になりました。パスワードが既にリセットされている可能性がありますか? + to_login: ログインページへ password: label: パスワード msg: empty: パスワードを入力してください。 - length: The length needs to be between 8 and 32 - different: The passwords entered on both sides are inconsistent + length: 長さは 8 から 32 の間である必要があります + different: 両側に入力されたパスワードが一致しません password_confirm: - label: Confirm new password + label: 新しいパスワードの確認 settings: page_title: 設定 - goto_modify: Go to modify + goto_modify: 変更を開く nav: - profile: Profile - notification: Notifications - account: Account - interface: Interface + profile: プロフィール + notification: お知らせ + account: アカウント + interface: 外観 profile: - heading: Profile - btn_name: Save + heading: プロフィール + btn_name: 保存 display_name: - label: Display name - msg: Display name cannot be empty. - msg_range: Display name up to 30 characters. + label: 表示名 + msg: 表示名は必須です。 + msg_range: 表示名は最大 30 文字までです。 username: label: ユーザー名 - caption: People can mention you as "@username". - msg: Username cannot be empty. - msg_range: Username up to 30 characters. - character: 'Must use the character set "a-z", "0-9", " - . _"' + caption: ユーザーは "@username" としてあなたをメンションできます。 + msg: ユーザー名は空にできません。 + msg_range: 表示名は最大 30 文字までです。 + character: '文字セット "a-z", "0-9", " - . _" を使用してください。' avatar: label: プロフィール画像 gravatar: Gravatar - gravatar_text: You can change image on - custom: Custom - custom_text: You can upload your image. + gravatar_text: 画像を変更できます: + custom: カスタム + custom_text: 画像をアップロードできます。 default: システム - msg: Please upload an avatar + msg: アバターをアップロードしてください bio: - label: About me + label: 自己紹介 website: label: ウェブサイト placeholder: "http://example.com" - msg: Website incorrect format + msg: ウェブサイトの形式が正しくありません location: - label: Location - placeholder: "City, Country" + label: ロケーション + placeholder: "都道府県,国" notification: - heading: Email Notifications - turn_on: Turn on + heading: メール通知 + turn_on: ONにする inbox: - label: Inbox notifications - description: Answers to your questions, comments, invites, and more. + label: 受信トレイの通知 + description: 質問、コメント、招待状などへの回答。 all_new_question: - label: All new questions - description: Get notified of all new questions. Up to 50 questions per week. + label: すべての新規質問 + description: すべての新しい質問の通知を受け取ります。週に最大50問まで。 all_new_question_for_following_tags: - label: All new questions for following tags - description: Get notified of new questions for following tags. + label: 以下のタグに対するすべての新しい質問 + description: タグをフォローするための新しい質問の通知を受け取る。 account: heading: アカウント change_email_btn: メールアドレスを変更する change_pass_btn: パスワードを変更する change_email_info: >- - We've sent an email to that address. Please follow the confirmation instructions. + このアドレスにメールを送信しました。メールの指示に従って確認処理を行ってください。 email: - label: Email + label: メールアドレス new_email: - label: New email - msg: New email cannot be empty. + label: 新しいメールアドレス + msg: 新しいメールアドレスは空にできません。 pass: - label: Current password - msg: Password cannot be empty. + label: 現在のパスワード + msg: パスワードは空白にできません password_title: パスワード current_pass: - label: Current password + label: 現在のパスワード msg: - empty: Current password cannot be empty. - length: The length needs to be between 8 and 32. - different: The two entered passwords do not match. + empty: 現在のパスワードが空欄です + length: 長さは 8 から 32 の間である必要があります. + different: パスワードが一致しません。 new_pass: - label: New password + label: 新しいパスワード pass_confirm: - label: Confirm new password + label: 新しいパスワードの確認 interface: - heading: Interface + heading: 外観 lang: - label: Interface language - text: User interface language. It will change when you refresh the page. + label: インタフェース言語 + text: ユーザーインターフェイスの言語。ページを更新すると変更されます。 my_logins: - title: My logins - label: Log in or sign up on this site using these accounts. - modal_title: Remove login - modal_content: Are you sure you want to remove this login from your account? - modal_confirm_btn: Remove - remove_success: Removed successfully + title: ログイン情報 + label: これらのアカウントを使用してログインまたはこのサイトでサインアップします。 + modal_title: ログイン情報を削除 + modal_content: このログイン情報をアカウントから削除してもよろしいですか? + modal_confirm_btn: 削除 + remove_success: 削除に成功しました toast: - update: update success - update_password: Password changed successfully. - flag_success: Thanks for flagging. - forbidden_operate_self: Forbidden to operate on yourself - review: Your revision will show after review. - sent_success: Sent successfully + update: 更新に成功しました + update_password: パスワードの変更に成功しました。 + flag_success: フラグを付けてくれてありがとう + forbidden_operate_self: 自分自身で操作することはできません + review: レビュー後にあなたのリビジョンが表示されます。 + sent_success: 正常に送信されました。 related_question: - title: Related Questions - answers: answers + title: 関係のある質問 + answers: 回答 linked_question: - title: Linked Questions - description: Questions linked to - no_linked_question: No questions linked from this question. + title: リンクされた質問 + description: リンクされている質問 + no_linked_question: この質問からリンクされた質問はありません。 invite_to_answer: title: People Asked desc: Select people who you think might know the answer. - invite: Invite to answer - add: Add people - search: Search people + invite: 回答に招待する + add: ユーザーを追加 + search: ユーザーを検索 question_detail: - action: Action - Asked: Asked - asked: asked - update: Modified - edit: edited - commented: commented - Views: Viewed - Follow: Follow - Following: Following - follow_tip: Follow this question to receive notifications - answered: answered - closed_in: Closed in - show_exist: Show existing question. - useful: Useful - question_useful: It is useful and clear - question_un_useful: It is unclear or not useful - question_bookmark: Bookmark this question - answer_useful: It is useful - answer_un_useful: It is not useful + action: 動作 + Asked: 質問済み + asked: 質問済み + update: 修正済み + edit: 編集済み + commented: コメントしました + Views: 閲覧回数 + Follow: フォロー + Following: フォロー中 + follow_tip: この質問をフォローして通知を受け取る + answered: 回答済み + closed_in: クローズまで + show_exist: 既存の質問を表示します + useful: 役に立った + question_useful: それは有用で明確です。 + question_un_useful: 不明確または有用ではない + question_bookmark: この質問をブックマークする + answer_useful: 役に立った + answer_un_useful: 役に立たない answers: title: 回答 score: スコア newest: 最新 - oldest: Oldest + oldest: 古い順 btn_accept: 承認 - btn_accepted: Accepted + btn_accepted: 承認済み write_answer: - title: Your Answer - edit_answer: Edit my existing answer - btn_name: Post your answer - add_another_answer: Add another answer - confirm_title: Continue to answer - continue: Continue + title: あなたの回答 + edit_answer: 既存の回答を編集する + btn_name: 回答を投稿する + add_another_answer: 別の回答を追加 + confirm_title: 回答を続ける + continue: 続行 confirm_info: >- -

      Are you sure you want to add another answer?

      You could use the edit link to refine and improve your existing answer, instead.

      - empty: Answer cannot be empty. - characters: content must be at least 6 characters in length. +

      本当に別の答えを追加したいのですか?

      代わりに、編集リンクを使って既存の答えを洗練させ、改善することができます。

      + empty: 回答は空欄にできません + characters: コンテンツは6文字以上でなければなりません。 tips: - header_1: Thanks for your answer - li1_1: Please be sure to answer the question. Provide details and share your research. - li1_2: Back up any statements you make with references or personal experience. - header_2: But avoid ... - li2_1: Asking for help, seeking clarification, or responding to other answers. + header_1: ご回答ありがとうございます。 + li1_1: " 必ず質問に答えてください。詳細を述べ、あなたの研究を共有してください。\n" + li1_2: 参考文献や個人的な経験による裏付けを取ること。. + header_2: しかし、 を避けてください... + li2_1: 助けを求める、説明を求める、または他の答えに応答する。 reopen: - confirm_btn: Reopen - title: Reopen this post - content: Are you sure you want to reopen? + confirm_btn: 再オープン + title: この投稿を再度開く + content: 再オープンしてもよろしいですか? list: - confirm_btn: List - title: List this post - content: Are you sure you want to list? + confirm_btn: 一覧 + title: この投稿の一覧 + content: 一覧表示してもよろしいですか? unlist: - confirm_btn: Unlist - title: Unlist this post - content: Are you sure you want to unlist? + confirm_btn: 限定公開にする + title: この投稿を元に戻す + content: 本当に元に戻しますか? pin: - title: Pin this post - content: Are you sure you wish to pinned globally? This post will appear at the top of all post lists. - confirm_btn: Pin + title: この投稿をピン留めする + content: "グローバルに固定してもよろしいですか?\nこの投稿はすべての投稿リストの上部に表示されます。" + confirm_btn: ピン留めする delete: - title: Delete this post + title: この投稿を削除 question: >- - We do not recommend deleting questions with answers because doing so deprives future readers of this knowledge.

      Repeated deletion of answered questions can result in your account being blocked from asking. Are you sure you wish to delete? +

      承認された回答を削除することはお勧めしません。削除すると、今後の読者がこの知識を得られなくなってしまうからです。

      承認された回答を繰り返し削除すると、回答機能が制限され、アカウントがブロックされる場合があります。本当に削除しますか? + answer_accepted: >- -

      We do not recommend deleting accepted answer because doing so deprives future readers of this knowledge.

      Repeated deletion of accepted answers can result in your account being blocked from answering. Are you sure you wish to delete? - other: Are you sure you wish to delete? - tip_answer_deleted: This answer has been deleted - undelete_title: Undelete this post - undelete_desc: Are you sure you wish to undelete? +

      承認された回答を削除することはお勧めしません。削除すると、今後の読者がこの知識を得られなくなってしまうからです。

      承認された回答を繰り返し削除すると、回答機能が制限され、アカウントがブロックされる場合があります。本当に削除しますか? + + other: 本当に削除してもよろしいですか? + tip_answer_deleted: この回答は削除されました + undelete_title: この投稿を元に戻す + undelete_desc: 本当に元に戻しますか? btns: - confirm: Confirm - cancel: Cancel - edit: Edit - save: Save - delete: Delete - undelete: Undelete - list: List - unlist: Unlist - unlisted: Unlisted - login: Log in + confirm: 確認 + cancel: キャンセル + edit: 編集 + save: 保存 + delete: 削除 + undelete: 元に戻す + list: 限定公開を解除する + unlist: 限定公開にする + unlisted: 限定公開済み + login: ログイン signup: 新規登録 - logout: Log out - verify: Verify - add_question: Add question - approve: Approve - reject: Reject - skip: Skip - discard_draft: Discard draft - pinned: Pinned - all: All - question: Question - answer: Answer - comment: Comment - refresh: Refresh - resend: Resend - deactivate: Deactivate - active: Active - suspend: Suspend - unsuspend: Unsuspend - close: Close - reopen: Reopen + logout: ログアウト + verify: 認証 + add_question: 質問を追加 + approve: 承認 + reject: 却下 + skip: スキップする + discard_draft: 下書きを破棄 + pinned: ピン留めしました + all: すべて + question: 質問 + answer: 回答 + comment: コメント + refresh: 更新 + resend: 再送 + deactivate: 無効化する + active: 有効 + suspend: 凍結 + unsuspend: 凍結解除 + close: クローズ + reopen: 再オープン ok: OK - light: Light - dark: Dark - system_setting: System setting - default: Default - reset: Reset - tag: Tag - post_lowercase: post - filter: Filter - ignore: Ignore - submit: Submit - normal: Normal - closed: Closed - deleted: Deleted - pending: Pending - more: More + light: ライト + dark: ダーク + system_setting: システム設定 + default: 既定 + reset: リセット + tag: タグ + post_lowercase: 投稿 + filter: フィルター + ignore: 除外 + submit: 送信 + normal: 通常 + closed: クローズ済み + deleted: 削除済み + pending: 処理待ち + more: もっと見る search: - title: Search Results - keywords: Keywords - options: Options - follow: Follow - following: Following - counts: "{{count}} Results" - more: More + title: 検索結果 + keywords: キーワード + options: オプション + follow: フォロー + following: フォロー中 + counts: "結果:{{count}}" + more: もっと見る sort_btns: - relevance: Relevance - newest: Newest - active: Active - score: Score - more: More + relevance: 関連性 + newest: 最新 + active: アクティブ + score: スコア + more: もっと見る tips: - title: Advanced Search Tips - tag: "<1>[tag] search with a tag" - user: "<1>user:username search by author" - answer: "<1>answers:0 unanswered questions" - score: "<1>score:3 posts with a 3+ score" - question: "<1>is:question search questions" - is_answer: "<1>is:answer search answers" - empty: We couldn't find anything.
      Try different or less specific keywords. + title: 詳細検索のヒント + tag: "<1>[tag] タグで検索" + user: "<1>ユーザー:ユーザー名作成者による検索" + answer: "<1>回答:0未回答の質問" + score: "<1>スコア:33以上のスコアを持つ投稿" + question: "<1>質問質問を検索" + is_answer: "<1>は答え答えを検索" + empty: 何も見つかりませんでした。
      別のキーワードまたはそれ以下の特定のキーワードをお試しください。 share: name: シェア copy: リンクをコピー - via: Share post via... - copied: Copied + via: 投稿を共有... + copied: コピーしました facebook: Facebookで共有 twitter: Twitterで共有 - cannot_vote_for_self: You can't vote for your own post. + cannot_vote_for_self: 自分の投稿には投票できません。 modal_confirm: - title: Error... + title: エラー... account_result: - success: Your new account is confirmed; you will be redirected to the home page. - link: Continue to homepage - oops: Oops! - invalid: The link you used no longer works. - confirm_new_email: Your email has been updated. + success: 新しいアカウントが確認されました。ホームページにリダイレクトされます。 + link: ホームページへ + oops: おっと! + invalid: 使用したリンクは機能しません。 + confirm_new_email: メールアドレスが更新されました。 confirm_new_email_invalid: >- - Sorry, this confirmation link is no longer valid. Perhaps your email was already changed? + 申し訳ありませんが、この確認リンクは無効です。メールアドレスが既に変更されている可能性があります。 unsubscribe: - page_title: Unsubscribe - success_title: Unsubscribe Successful - success_desc: You have been successfully removed from this subscriber list and won't receive any further emails from us. - link: Change settings + page_title: 購読解除 + success_title: 購読解除成功 + success_desc: 配信リストから削除され、その他のメールの送信が停止されました。 + link: 設定の変更 question: - following_tags: Following Tags - edit: Edit - save: Save - follow_tag_tip: Follow tags to curate your list of questions. - hot_questions: Hot Questions - all_questions: All Questions - x_questions: "{{ count }} Questions" - x_answers: "{{ count }} answers" + following_tags: フォロー中のタグ + edit: 編集 + save: 保存 + follow_tag_tip: タグに従って質問のリストをキュレートします。 + hot_questions: ホットな質問 + all_questions: すべての質問 + x_questions: "{{ count }} の質問" + x_answers: "{{ count }} の回答" questions: 質問 answers: 回答 newest: 最新 active: 有効 - hot: Hot - recommend: Recommend + hot: 人気 + frequent: Frequent + recommend: おすすめ score: スコア unanswered: 未回答 modified: 修正済み answered: 回答済み asked: 質問済み - closed: 終了 + closed: 解決済み follow_a_tag: タグをフォロー more: その他 personal: @@ -1536,686 +1544,716 @@ ui: answers: 回答 answer: 回答 questions: 質問 - question: question - bookmarks: Bookmarks - reputation: Reputation - comments: Comments - votes: Votes - badges: Badges - newest: Newest - score: Score - edit_profile: Edit profile - visited_x_days: "Visited {{ count }} days" - viewed: Viewed - joined: Joined + question: 質問 + bookmarks: ブックマーク + reputation: 評判 + comments: コメント + votes: 投票 + badges: バッジ + newest: 最新 + score: スコア + edit_profile: プロファイルを編集 + visited_x_days: "{{ count }}人の閲覧者" + viewed: 閲覧回数 + joined: 参加しました comma: "," - last_login: Seen - about_me: About Me + last_login: 閲覧数 + about_me: 自己紹介 about_me_empty: "// Hello, World !" - top_answers: Top Answers - top_questions: Top Questions - stats: Stats - list_empty: No posts found.
      Perhaps you'd like to select a different tab? - content_empty: No posts found. - accepted: Accepted - answered: answered + top_answers: よくある回答 + top_questions: よくある質問 + stats: 統計情報 + list_empty: 投稿が見つかりませんでした。
      他のタブを選択しますか? + content_empty: 投稿が見つかりませんでした。 + accepted: 承認済み + answered: 回答済み asked: 質問済み - downvoted: downvoted + downvoted: 低評価しました mod_short: MOD mod_long: モデレーター - x_reputation: reputation - x_votes: votes received + x_reputation: 評価 + x_votes: 投票を受け取りました x_answers: 回答 x_questions: 質問 - recent_badges: Recent Badges + recent_badges: 最近のバッジ install: title: Installation next: 次へ done: 完了 - config_yaml_error: Can't create the config.yaml file. + config_yaml_error: config.yaml を作成できません。 lang: - label: Please choose a language + label: 言語を選択してください db_type: - label: Database engine + label: データベースエンジン db_username: label: ユーザー名 placeholder: root - msg: Username cannot be empty. + msg: ユーザー名は空にできません。 db_password: label: パスワード placeholder: root msg: パスワードを入力してください。 db_host: - label: Database host + label: データベースのホスト。 placeholder: "db:3306" - msg: Database host cannot be empty. + msg: データベースホストは空にできません。 db_name: - label: Database name - placeholder: answer - msg: Database name cannot be empty. + label: データベース名 + placeholder: 回答 + msg: データベース名を空にすることはできません。 db_file: - label: Database file + label: データベースファイル placeholder: /data/answer.db - msg: Database file cannot be empty. + msg: データベースファイルは空にできません。 config_yaml: - title: Create config.yaml - label: The config.yaml file created. + title: config.yamlを作成 + label: config.yaml ファイルが作成されました。 desc: >- - You can create the <1>config.yaml file manually in the <1>/var/wwww/xxx/ directory and paste the following text into it. - info: After you've done that, click "Next" button. - site_information: Site Information + <1>/var/www/xxx/ディレクトリに<1>config.yamlファイルを手動で作成し、その中に次のテキストを貼り付けます。 + info: 完了したら、「次へ」ボタンをクリックします。 + site_information: サイト情報 admin_account: 管理者アカウント site_name: - label: Site name - msg: Site name cannot be empty. - msg_max_length: Site name must be at maximum 30 characters in length. + label: サイト名: + msg: サイト名は空にできません. + msg_max_length: サイト名は最大30文字でなければなりません。 site_url: label: サイトURL - text: The address of your site. + text: あなたのサイトのアドレス msg: - empty: Site URL cannot be empty. - incorrect: Site URL incorrect format. - max_length: Site URL must be at maximum 512 characters in length. + empty: サイト URL は空にできません. + incorrect: サイトURLの形式が正しくありません。 + max_length: サイトのURLは最大512文字でなければなりません contact_email: - label: Contact email - text: Email address of key contact responsible for this site. + label: 連絡先メール アドレス + text: このサイトを担当するキーコンタクトのメールアドレスです。 msg: - empty: Contact email cannot be empty. - incorrect: Contact email incorrect format. + empty: 連絡先メールアドレスを空にすることはできません。 + incorrect: 連絡先メールアドレスの形式が正しくありません。 login_required: - label: Private - switch: Login required - text: Only logged in users can access this community. + label: 非公開 + switch: ログインが必要です + text: ログインしているユーザーのみがこのコミュニティにアクセスできます。 admin_name: - label: Name - msg: Name cannot be empty. - character: 'Must use the character set "a-z", "0-9", " - . _"' - msg_max_length: Name must be at maximum 30 characters in length. + label: 名前 + msg: 名前を空にすることはできません。 + character: '文字セット "a-z", "0-9", " - . _" を使用してください。' + msg_max_length: 名前は最大30文字でなければなりません。 admin_password: label: パスワード text: >- - You will need this password to log in. Please store it in a secure location. - msg: Password cannot be empty. - msg_min_length: Password must be at least 8 characters in length. - msg_max_length: Password must be at maximum 32 characters in length. + ログインするにはこのパスワードが必要です。安全な場所に保存してください。 + msg: パスワードは空白にできません + msg_min_length: パスワードは8文字以上でなければなりません。 + msg_max_length: パスワードは最大 32 文字でなければなりません。 admin_email: label: メールアドレス - text: You will need this email to log in. + text: ログインするにはこのメールアドレスが必要です。 msg: - empty: Email cannot be empty. - incorrect: Email incorrect format. - ready_title: Your site is ready + empty: メールアドレスは空にできません。 + incorrect: メールアドレスの形式が正しくありません. + ready_title: サイトの準備ができました ready_desc: >- - If you ever feel like changing more settings, visit <1>admin section; find it in the site menu. - good_luck: "Have fun, and good luck!" - warn_title: Warning + もっと設定を変更したいと思ったことがある場合は、<1>管理者セクションをご覧ください。サイトメニューで見つけてください。 + good_luck: "楽しんで、幸運を!" + warn_title: 警告 warn_desc: >- - The file <1>config.yaml already exists. If you need to reset any of the configuration items in this file, please delete it first. - install_now: You may try <1>installing now. - installed: Already installed + ファイル<1>config.yamlは既に存在します。このファイルのいずれかの設定アイテムをリセットする必要がある場合は、最初に削除してください。 + install_now: <1>今すぐインストールを試してみてください。 + installed: 既にインストール済みです installed_desc: >- - You appear to have already installed. To reinstall please clear your old database tables first. - db_failed: Database connection failed + 既にインストールされているようです。再インストールするには、最初に古いデータベーステーブルをクリアしてください。 + db_failed: データベースの接続が失敗しました db_failed_desc: >- - This either means that the database information in your <1>config.yaml file is incorrect or that contact with the database server could not be established. This could mean your host's database server is down. + これは、<1>設定内のデータベース情報を意味します。 amlファイルが正しくないか、データベースサーバーとの連絡先が確立できませんでした。ホストのデータベースサーバーがダウンしている可能性があります。 counts: - views: views - votes: votes - answers: answers - accepted: Accepted + views: ビュー + votes: 投票数 + answers: 回答 + accepted: 承認済み page_error: http_error: HTTP Error {{ code }} - desc_403: You don't have permission to access this page. - desc_404: Unfortunately, this page doesn't exist. - desc_50X: The server encountered an error and could not complete your request. - back_home: Back to homepage + desc_403: このページにアクセスする権限がありません。 + desc_404: 残念ながら、このページは存在しません。 + desc_50X: サーバーにエラーが発生し、リクエストを完了できませんでした。 + back_home: ホームページに戻ります page_maintenance: - desc: "We are under maintenance, we'll be back soon." + desc: "メンテナンス中です。まもなく戻ります。" nav_menus: - dashboard: Dashboard - contents: Contents - questions: Questions - answers: Answers - users: Users - badges: Badges + dashboard: ダッシュボード + contents: コンテンツ + questions: 質問 + answers: 回答 + users: ユーザー + badges: バッジ flags: フラグ settings: 設定 general: 一般 interface: 外観 smtp: SMTP - branding: Branding - legal: Legal - write: Write - tos: Terms of Service - privacy: Privacy + branding: ブランディング + legal: 法的事項 + write: 書き + tos: 利用規約 + privacy: プライバシー seo: SEO customize: カスタマイズ themes: テーマ css_html: CSS/HTML login: ログイン - privileges: Privileges - plugins: Plugins - installed_plugins: Installed Plugins - website_welcome: Welcome to {{site_name}} + privileges: 特典 + plugins: プラグイン + installed_plugins: 使用中のプラグイン + website_welcome: '{{site_name}} へようこそ' user_center: - login: Login - qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. - login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + login: ログイン + qrcode_login_tip: QRコードをスキャンしてログインするには {{ agentName }} を使用してください。 + login_failed_email_tip: ログインに失敗しました。もう一度やり直す前に、このアプリがあなたのメール情報にアクセスすることを許可してください。 badges: modal: - title: Congratulations - content: You've earned a new badge. - close: Close - confirm: View badges - title: Badges - awarded: Awarded - earned_×: Earned ×{{ number }} - ×_awarded: "{{ number }} awarded" - can_earn_multiple: You can earn this multiple times. - earned: Earned + title: お疲れ様でした! + content: 新しいバッジを獲得しました。 + close: クローズ + confirm: バッジを表示 + title: バッジ + awarded: 受賞済み + earned_×: 獲得×{{ number }} + ×_awarded: "{{ number }} 受賞" + can_earn_multiple: これを複数回獲得できます。 + earned: 獲得済み admin: admin_header: title: 管理者 dashboard: title: ダッシュボード - welcome: Welcome to Admin! - site_statistics: Site statistics + welcome: Adminへようこそ! + site_statistics: サイト統計 questions: "質問:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "回答:" comments: "評論:" votes: "投票:" - users: "Users:" - flags: "Flags:" - reviews: "Reviews:" - site_health: Site health - version: "Version:" - https: "HTTPS:" - upload_folder: "Upload folder:" - run_mode: "Running mode:" - private: Private - public: Public + users: "ユーザー数:" + flags: "フラグ:" + reviews: "レビュー:" + site_health: サイトの状態 + version: "バージョン:" + https: "HTTPS:" + upload_folder: "フォルダを上げる" + run_mode: "実行中モード:" + private: 非公開 + public: 公開 smtp: "SMTP:" timezone: "Timezone:" - system_info: System info - go_version: "Go version:" - database: "Database:" - database_size: "Database size:" - storage_used: "Storage used:" - uptime: "Uptime:" - links: Links - plugins: Plugins + system_info: システム情報 + go_version: "バージョン:" + database: "データベース:" + database_size: "データベースのサイズ:" + storage_used: "使用されているストレージ" + uptime: "稼働時間:" + links: リンク + plugins: プラグイン github: GitHub - blog: Blog - contact: Contact + blog: ブログ + contact: 連絡先 forum: Forum - documents: Documents + documents: ドキュメント feedback: フィードバック support: サポート review: レビュー config: 設定 - update_to: Update to - latest: Latest - check_failed: Check failed + update_to: 更新日時 + latest: 最新 + check_failed: チェックに失敗しました "yes": "はい" "no": "いいえ" - not_allowed: Not allowed - allowed: Allowed - enabled: Enabled - disabled: Disabled - writable: Writable - not_writable: Not writable + not_allowed: 許可されていません + allowed: 許可 + enabled: 有効 + disabled: 無効 + writable: 書き込み可 + not_writable: 書き込み不可 flags: - title: Flags - pending: Pending - completed: Completed - flagged: Flagged - flagged_type: Flagged {{ type }} - created: Created - action: Action - review: Review + title: フラグ + pending: 処理待ち + completed: 完了済 + flagged: フラグ付き + flagged_type: フラグを立てた {{ type }} + created: 作成 + action: 動作 + review: レビュー user_role_modal: - title: Change user role to... - btn_cancel: Cancel - btn_submit: Submit + title: ユーザーロールを変更... + btn_cancel: キャンセル + btn_submit: 送信 new_password_modal: - title: Set new password + title: 新しいパスワードを設定 form: fields: password: - label: Password - text: The user will be logged out and need to login again. - msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + label: パスワード + text: ユーザーはログアウトされ、再度ログインする必要があります。 + msg: パスワードの長さは 8 ~ 32 文字である必要があります。 + btn_cancel: キャンセル + btn_submit: 送信 edit_profile_modal: - title: Edit profile + title: プロファイルを編集 form: fields: display_name: - label: Display name - msg_range: Display name up to 30 characters. + label: 表示名 + msg_range: 表示名は最大 30 文字までです。 username: - label: Username - msg_range: Username up to 30 characters. + label: ユーザー名 + msg_range: ユーザー名は30文字までです。 email: - label: Email - msg_invalid: Invalid Email Address. - edit_success: Edited successfully - btn_cancel: Cancel - btn_submit: Submit + label: メールアドレス + msg_invalid: 無効なメールアドレス + edit_success: 更新が成功しました + btn_cancel: キャンセル + btn_submit: 送信 user_modal: - title: Add new user + title: 新しいユーザーを追加 form: fields: users: - label: Bulk add user + label: ユーザーを一括追加 placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" - text: Separate “name, email, password” with commas. One user per line. - msg: "Please enter the user's email, one per line." + text: '「名前、メールアドレス、パスワード」をカンマで区切ってください。' + msg: "ユーザーのメールアドレスを1行に1つ入力してください。" display_name: - label: Display name - msg: Display name must be 2-30 characters in length. + label: 表示名 + msg: 表示名の長さは 2 ~ 30 文字にする必要があります。 email: - label: Email - msg: Email is not valid. + label: メールアドレス + msg: メールアドレスが無効です。 password: - label: Password - msg: Password must be at 8-32 characters in length. - btn_cancel: Cancel - btn_submit: Submit + label: パスワード + msg: パスワードの長さは 8 ~ 32 文字である必要があります。 + btn_cancel: キャンセル + btn_submit: 送信 users: - title: Users - name: Name + title: ユーザー + name: 名前 email: メールアドレス - reputation: Reputation - created_at: Created Time - delete_at: Deleted Time - suspend_at: Suspended Time - status: Status - role: Role - action: Action - change: Change - all: All - staff: Staff - more: More - inactive: Inactive - suspended: Suspended - deleted: Deleted - normal: Normal + reputation: 評価 + created_at: 作成日時 + delete_at: 削除日時 + suspend_at: サスペンド時間 + status: ステータス + role: ロール + action: 操作 + change: 変更 + all: すべて + staff: スタッフ + more: もっと見る + inactive: 非アクティブ + suspended: 凍結済み + deleted: 削除済み + normal: 通常 Moderator: モデレーター Admin: 管理者 User: ユーザー filter: - placeholder: "Filter by name, user:id" + placeholder: "ユーザー名でフィルタ" set_new_password: 新しいパスワードを設定します。 - edit_profile: Edit profile + edit_profile: プロファイルを編集 change_status: ステータスを変更 change_role: ロールを変更 show_logs: ログを表示 add_user: ユーザを追加 deactivate_user: - title: Deactivate user - content: An inactive user must re-validate their email. + title: ユーザーを非アクティブにする + content: アクティブでないユーザーはメールアドレスを再認証する必要があります。 delete_user: - title: Delete this user - content: Are you sure you want to delete this user? This is permanent! - remove: Remove their content - label: Remove all questions, answers, comments, etc. - text: Don’t check this if you wish to only delete the user’s account. + title: このユーザの削除 + content: このユーザーを削除してもよろしいですか?これは永久的です! + remove: このコンテンツを削除 + label: すべての質問、回答、コメントなどを削除 + text: ユーザーのアカウントのみ削除したい場合は、これを確認しないでください。 suspend_user: - title: Suspend this user - content: A suspended user can't log in. + title: ユーザーをサスペンドにする + content: 一時停止中のユーザーはログインできません。 questions: page_title: 質問 - unlisted: Unlisted + unlisted: 限定公開済み post: 投稿 votes: 投票 answers: 回答 created: 作成 status: ステータス - action: Action - change: Change - pending: Pending + action: 動作 + change: 変更 + pending: 処理待ち filter: - placeholder: "Filter by title, question:id" + placeholder: "タイトル、質問:id でフィルター" answers: - page_title: Answers - post: Post - votes: Votes - created: Created - status: Status - action: Action - change: Change + page_title: 回答 + post: 投稿 + votes: 投票 + created: 作成 + status: ステータス + action: 操作 + change: 変更 filter: - placeholder: "Filter by title, answer:id" + placeholder: "タイトル、質問:id でフィルター" general: - page_title: General + page_title: 一般 name: - label: Site name - msg: Site name cannot be empty. - text: "The name of this site, as used in the title tag." + label: サイト名 + msg: サイト名は空にできません. + text: "タイトルタグで使用されるこのサイトの名前。" site_url: label: サイトURL - msg: Site url cannot be empty. - validate: Please enter a valid URL. - text: The address of your site. + msg: サイト URL は空にできません. + validate: 正しいURLを入力してください。 + text: あなたのサイトのアドレス short_desc: - label: Short site description - msg: Short site description cannot be empty. - text: "Short description, as used in the title tag on homepage." + label: 短いサイトの説明 + msg: 短いサイト説明は空にできません. + text: "ホームページのタイトルタグで使用されている簡単な説明。" desc: - label: Site description - msg: Site description cannot be empty. - text: "Describe this site in one sentence, as used in the meta description tag." + label: サイトの説明 + msg: サイト説明を空にすることはできません。 + text: "メタ説明タグで使用されるように、このサイトを1つの文で説明します。" contact_email: - label: Contact email - msg: Contact email cannot be empty. - validate: Contact email is not valid. - text: Email address of key contact responsible for this site. + label: 連絡先メール アドレス + msg: 連絡先メールアドレスを空にすることはできません。 + validate: 連絡先のメールアドレスが無効です。 + text: このサイトを担当するキーコンタクトのメールアドレスです。 check_update: - label: Software updates - text: Automatically check for updates + label: ソフトウェアアップデート + text: 自動的に更新を確認 interface: - page_title: Interface + page_title: 外観 language: - label: Interface language - msg: Interface language cannot be empty. - text: User interface language. It will change when you refresh the page. + label: インタフェース言語 + msg: インターフェース言語は空にできません。 + text: ユーザーインターフェイスの言語。ページを更新すると変更されます。 time_zone: - label: Timezone - msg: Timezone cannot be empty. - text: Choose a city in the same timezone as you. + label: タイムゾーン + msg: タイムゾーンを空にすることはできません。 + text: あなたのタイムゾーンを選択してください。 smtp: page_title: SMTP from_email: - label: From email - msg: From email cannot be empty. - text: The email address which emails are sent from. + label: 差出人 + msg: 差出人メールアドレスは空にできません。 + text: 送信元のメールアドレス from_name: - label: From name - msg: From name cannot be empty. - text: The name which emails are sent from. + label: 差出人名 + msg: 差出人名は空にできません + text: メールの送信元の名前 smtp_host: - label: SMTP host - msg: SMTP host cannot be empty. - text: Your mail server. + label: SMTP ホスト + msg: SMTPホストは空にできません。 + text: メールサーバー encryption: - label: Encryption - msg: Encryption cannot be empty. - text: For most servers SSL is the recommended option. + label: 暗号化 + msg: 暗号化は空にできません。 + text: ほとんどのサーバではSSLが推奨されます。 ssl: SSL tls: TLS none: なし smtp_port: - label: SMTP port + label: SMTPポート msg: SMTPポートは1〜65535でなければなりません。 - text: The port to your mail server. + text: メールサーバーへのポート番号 smtp_username: - label: SMTP username + label: SMTPユーザ名 msg: SMTP ユーザー名を空にすることはできません。 smtp_password: - label: SMTP password + label: SMTPパスワード msg: SMTP パスワードを入力してください。 test_email_recipient: - label: Test email recipients - text: Provide email address that will receive test sends. - msg: Test email recipients is invalid + label: テストメールの受信者 + text: テスト送信を受信するメールアドレスを入力してください。 + msg: テストメールの受信者が無効です smtp_authentication: - label: Enable authentication - title: SMTP authentication - msg: SMTP authentication cannot be empty. + label: 認証を有効にする + title: SMTP認証 + msg: SMTP認証は空にできません。 "yes": "はい" "no": "いいえ" branding: - page_title: Branding + page_title: ブランディング logo: - label: Logo - msg: Logo cannot be empty. - text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown. + label: ロゴ + msg: ロゴは空にできません。 + text: あなたのサイトの左上にあるロゴ画像。 高さが56、アスペクト比が3:1を超える広い矩形画像を使用します。 空白の場合、サイトタイトルテキストが表示されます。 mobile_logo: - label: Mobile logo - text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the "logo" setting will be used. + label: モバイルロゴ + text: サイトのモバイル版で使用されるロゴです。高さが56の横長の長方形の画像を使用してください。空白のままにすると、"ロゴ"設定の画像が使用されます。 square_icon: - label: Square icon - msg: Square icon cannot be empty. - text: Image used as the base for metadata icons. Should ideally be larger than 512x512. + label: アイコン画像 + msg: アイコン画像は空にできません。 + text: メタデータアイコンのベースとして使用される画像。理想的には512x512より大きくなければなりません。 favicon: label: Favicon - text: A favicon for your site. To work correctly over a CDN it must be a png. Will be resized to 32x32. If left blank, "square icon" will be used. + text: あなたのサイトのファビコン。CDN上で正しく動作するにはpngである必要があります。 32x32にリサイズされます。空白の場合は、"正方形のアイコン"が使用されます。 legal: - page_title: Legal + page_title: 法的情報 terms_of_service: - label: Terms of service - text: "You can add terms of service content here. If you already have a document hosted elsewhere, provide the full URL here." + label: 利用規約 + text: "ここで利用規約のサービスコンテンツを追加できます。すでに他の場所でホストされているドキュメントがある場合は、こちらにフルURLを入力してください。" privacy_policy: - label: Privacy policy - text: "You can add privacy policy content here. If you already have a document hosted elsewhere, provide the full URL here." + label: プライバシーポリシー + text: "ここにプライバシーポリシーの内容を追加できます。すでに他の場所でホストされているドキュメントを持っている場合は、こちらにフルURLを入力してください。" write: - page_title: Write + page_title: 編集 restrict_answer: - title: Answer write - label: Each user can only write one answer for each question - text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + title: 回答を書く + label: 各ユーザーは同じ質問に対して1つの回答しか書けません + text: "ユーザが同じ質問に複数の回答を書き込めるようにするにはオフにします。これにより回答がフォーカスされていない可能性があります。" recommend_tags: - label: Recommend tags - text: "Recommend tags will show in the dropdown list by default." + label: おすすめタグ + text: "デフォルトでドロップダウンリストに推奨タグが表示されます。" msg: - contain_reserved: "recommended tags cannot contain reserved tags" + contain_reserved: "推奨されるタグは予約済みタグを含めることはできません" required_tag: - title: Set required tags - label: Set “Recommend tags” as required tags - text: "Every new question must have at least one recommend tag." + title: 必須タグを設定 + label: 必須タグに「推奨タグ」を設定 + text: "新しい質問には少なくとも1つの推奨タグが必要です。" reserved_tags: - label: Reserved tags - text: "Reserved tags can only be used by moderator." + label: 予約済みタグ + text: "予約済みのタグはモデレータのみ使用できます。" + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: - label: Permalink - text: Custom URL structures can improve the usability, and forward-compatibility of your links. + label: 固定リンク + text: カスタム URL 構造は、ユーザビリティとリンクの前方互換性を向上させることができます。 robots: label: robots.txt - text: This will permanently override any related site settings. + text: これにより、関連するサイト設定が永久に上書きされます。 themes: - page_title: Themes + page_title: テーマ themes: - label: Themes - text: Select an existing theme. + label: テーマ + text: 既存のテーマを選択してください color_scheme: - label: Color scheme + label: 配色 navbar_style: - label: Navbar style + label: ナビゲーションバーのスタイル primary_color: - label: Primary color - text: Modify the colors used by your themes + label: メインカラー + text: テーマで使用される色を変更する css_and_html: - page_title: CSS and HTML + page_title: CSS と HTML custom_css: - label: Custom CSS + label: カスタム CSS text: > head: - label: Head + label: ヘッド text: > header: - label: Header + label: ヘッダー text: > footer: - label: Footer - text: This will insert before </body>. + label: フッター + text: これは </body> の前に挿入されます。 sidebar: - label: Sidebar - text: This will insert in sidebar. + label: サイドバー + text: サイドバーに挿入されます。 login: - page_title: Login + page_title: ログイン membership: - title: Membership - label: Allow new registrations - text: Turn off to prevent anyone from creating a new account. + title: メンバー + label: 新しい登録を許可する + text: 誰もが新しいアカウントを作成できないようにするには、オフにしてください。 email_registration: - title: Email registration - label: Allow email registration - text: Turn off to prevent anyone creating new account through email. + title: メールアドレスの登録 + label: メールアドレスの登録を許可 + text: オフにすると、メールで新しいアカウントを作成できなくなります。 allowed_email_domains: - title: Allowed email domains - text: Email domains that users must register accounts with. One domain per line. Ignored when empty. + title: 許可されたメールドメイン + text: ユーザーがアカウントを登録する必要があるメールドメインです。1行に1つのドメインがあります。空の場合は無視されます。 private: - title: Private - label: Login required - text: Only logged in users can access this community. + title: 非公開 + label: ログインが必要です + text: ログインしているユーザーのみがこのコミュニティにアクセスできます。 password_login: - title: Password login - label: Allow email and password login - text: "WARNING: If turn off, you may be unable to log in if you have not previously configured other login method." + title: パスワードログイン + label: メールアドレスとパスワードのログインを許可する + text: "警告: オフにすると、他のログイン方法を設定していない場合はログインできない可能性があります。" installed_plugins: - title: Installed Plugins - plugin_link: Plugins extend and expand the functionality. You may find plugins in the <1>Plugin Repository. + title: インストール済みプラグイン + plugin_link: プラグインは機能を拡張します。<1>プラグインリポジトリにプラグインがあります。 filter: - all: All - active: Active - inactive: Inactive - outdated: Outdated + all: すべて + active: アクティブ + inactive: 非アクティブ + outdated: 期限切れ plugins: - label: Plugins - text: Select an existing plugin. + label: プラグイン + text: 既存のプラグインを選択します name: 名前 - version: Version - status: Status - action: Action - deactivate: Deactivate - activate: Activate - settings: Settings + version: バージョン + status: ステータス + action: 操作 + deactivate: 非アクティブ化 + activate: アクティベート + settings: 設定 settings_users: - title: Users + title: ユーザー avatar: - label: Default avatar - text: For users without a custom avatar of their own. + label: デフォルトのアバター + text: 自分のカスタムアバターのないユーザー向け。 gravatar_base_url: label: Gravatar Base URL - text: URL of the Gravatar provider's API base. Ignored when empty. + text: GravatarプロバイダーのAPIベースのURL。空の場合は無視されます。 profile_editable: - title: Profile editable + title: プロフィール編集可能 allow_update_display_name: - label: Allow users to change their display name + label: ユーザーが表示名を変更できるようにする allow_update_username: - label: Allow users to change their username + label: ユーザー名の変更を許可する allow_update_avatar: - label: Allow users to change their profile image + label: ユーザーのプロフィール画像の変更を許可する allow_update_bio: - label: Allow users to change their about me + label: ユーザーが自分についての変更を許可する allow_update_website: - label: Allow users to change their website + label: ユーザーのウェブサイトの変更を許可する allow_update_location: - label: Allow users to change their location + label: ユーザーの位置情報の変更を許可する privilege: - title: Privileges + title: 特権 level: - label: Reputation required level - text: Choose the reputation required for the privileges + label: 評判の必要レベル + text: 特権に必要な評判を選択します msg: - should_be_number: the input should be number - number_larger_1: number should be equal or larger than 1 + should_be_number: 入力は数値でなければなりません + number_larger_1: 数値は 1 以上でなければなりません badges: - action: Action - active: Active - activate: Activate - all: All - awards: Awards - deactivate: Deactivate + action: 操作 + active: アクティブ + activate: アクティベート + all: すべて + awards: 賞 + deactivate: 非アクティブ化 filter: - placeholder: Filter by name, badge:id - group: Group - inactive: Inactive - name: Name - show_logs: Show logs - status: Status - title: Badges + placeholder: 名前、バッジ:id でフィルター + group: グループ + inactive: 非アクティブ + name: 名前 + show_logs: ログを表示 + status: ステータス + title: バッジ form: - optional: (optional) - empty: cannot be empty - invalid: is invalid + optional: (任意) + empty: 空にすることはできません + invalid: 無効です btn_submit: 保存 - not_found_props: "Required property {{ key }} not found." - select: Select + not_found_props: "必須プロパティ {{ key }} が見つかりません。" + select: 選択 page_review: - review: Review - proposed: proposed - question_edit: Question edit - answer_edit: Answer edit - tag_edit: Tag edit - edit_summary: Edit summary - edit_question: Edit question - edit_answer: Edit answer - edit_tag: Edit tag - empty: No review tasks left. - approve_revision_tip: Do you approve this revision? - approve_flag_tip: Do you approve this flag? - approve_post_tip: Do you approve this post? - approve_user_tip: Do you approve this user? - suggest_edits: Suggested edits - flag_post: Flag post - flag_user: Flag user - queued_post: Queued post - queued_user: Queued user - filter_label: Type - reputation: reputation - flag_post_type: Flagged this post as {{ type }}. - flag_user_type: Flagged this user as {{ type }}. - edit_post: Edit post - list_post: List post - unlist_post: Unlist post + review: レビュー + proposed: 提案された + question_edit: 質問の編集 + answer_edit: 回答の編集 + tag_edit: タグの編集 + edit_summary: 概要を編集 + edit_question: 質問を編集 + edit_answer: 回答を編集 + edit_tag: タグを編集 + empty: レビュータスクは残っていません。 + approve_revision_tip: この修正を承認しますか? + approve_flag_tip: このフラグを承認しますか? + approve_post_tip: この投稿を承認しますか? + approve_user_tip: このユーザーを承認しますか? + suggest_edits: 提案された編集 + flag_post: 報告された投稿 + flag_user: 報告されたユーザー + queued_post: キューに入れられた投稿 + queued_user: キューに入れられたユーザー + filter_label: タイプ + reputation: 評価 + flag_post_type: この投稿は {{ type }} として報告されました + flag_user_type: このユーザーは {{ type }} として報告されました + edit_post: 投稿を編集 + list_post: 投稿一覧 + unlist_post: 限定公開投稿 timeline: - undeleted: undeleted - deleted: deleted - downvote: downvote - upvote: upvote - accept: accept - cancelled: cancelled - commented: commented + undeleted: 復元する + deleted: 削除済み + downvote: 低評価 + upvote: 高評価 + accept: 承認 + cancelled: キャンセル済み + commented: コメントしました rollback: rollback - edited: edited - answered: answered - asked: asked - closed: closed - reopened: reopened - created: created - pin: pinned - unpin: unpinned - show: listed - hide: unlisted - title: "History for" - tag_title: "Timeline for" - show_votes: "Show votes" + edited: 編集済み + answered: 回答済み + asked: 質問済み + closed: クローズ済み + reopened: 再オープン + created: 作成済み + pin: ピン留め済 + unpin: ピン留め解除 + show: 限定公開解除済み + hide: 限定公開済み + title: "履歴:" + tag_title: "タイムライン:" + show_votes: "投票を表示" n_or_a: N/A - title_for_question: "Timeline for" - title_for_answer: "Timeline for answer to {{ title }} by {{ author }}" - title_for_tag: "Timeline for tag" - datetime: Datetime - type: Type + title_for_question: "タイムライン:" + title_for_answer: "{{ title }} の {{ author }} 回答のタイムライン" + title_for_tag: "タグのタイムライン:" + datetime: 日付時刻 + type: タイプ by: By - comment: Comment - no_data: "We couldn't find anything." + comment: コメント + no_data: "何も見つけられませんでした" users: title: ユーザー - users_with_the_most_reputation: Users with the highest reputation scores this week - users_with_the_most_vote: Users who voted the most this week - staffs: Our community staff - reputation: reputation - votes: votes + users_with_the_most_reputation: 今週最も高い評価スコアを持つユーザ + users_with_the_most_vote: 今週一番多く投票したユーザー + staffs: コミュニティのスタッフ + reputation: 評価 + votes: 投票 prompt: - leave_page: Are you sure you want to leave the page? - changes_not_save: Your changes may not be saved. + leave_page: このページから移動してもよろしいですか? + changes_not_save: 変更が保存されない可能性があります draft: - discard_confirm: Are you sure you want to discard your draft? + discard_confirm: 下書きを破棄してもよろしいですか? messages: - post_deleted: This post has been deleted. - post_pin: This post has been pinned. - post_unpin: This post has been unpinned. - post_hide_list: This post has been hidden from list. - post_show_list: This post has been shown to list. - post_reopen: This post has been reopened. - post_list: This post has been listed. - post_unlist: This post has been unlisted. + post_deleted: この投稿は削除されました。 + post_cancel_deleted: This post has been undeleted. + post_pin: この投稿はピン留めされています。 + post_unpin: この投稿のピン留めが解除されました。 + post_hide_list: この投稿は一覧から非表示になっています。 + post_show_list: この投稿は一覧に表示されています。 + post_reopen: この投稿は再オープンされました。 + post_list: この投稿は一覧に表示されています。 + post_unlist: この投稿は一覧に登録されていません。 post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/ko_KR.yaml b/i18n/ko_KR.yaml index 53b413f3..9fca850f 100644 --- a/i18n/ko_KR.yaml +++ b/i18n/ko_KR.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] 새 이메일 주소 확인" body: - other: "{{.SiteName}}에서 새 이메일 주소를 확인하세요. 다음 링크를 클릭하여 확인하세요:
      \n{{.ChangeEmailUrl}}

      \n\n이 변경을 요청하지 않았다면 이 이메일을 무시해 주세요.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} 님이 답변을 작성했습니다" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}} 님이 답변을 작성했습니다:
      \n
      {{.AnswerSummary}}

      \n자세히 보기 ({{.SiteName}})

      \n\n--
      \n구독 취소" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} 님이 답변을 요청했습니다" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}} 님이 답변을 요청했습니다:
      \n
      아마 당신이 답을 알고 있을 것입니다.

      \n자세히 보기 ({{.SiteName}})

      \n\n--
      \n구독 취소" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} 님이 당신의 게시물에 댓글을 남겼습니다" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}} 님이 당신의 게시물에 댓글을 남겼습니다:
      \n
      {{.CommentSummary}}

      \n자세히 보기 ({{.SiteName}})

      \n\n--
      \n구독 취소" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] 새 질문: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \n구독 취소" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] 비밀번호 재설정" body: - other: "{{.SiteName}}에서 비밀번호 재설정 요청이 있었습니다.

      \n\n만약 이 요청이 여러분이 하지 않았다면, 이 이메일을 무시하셔도 됩니다.

      \n\n새 비밀번호를 설정하려면 다음 링크를 클릭하세요:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] 새 계정 확인" body: - other: "{{.SiteName}}에 오신 것을 환영합니다!

      \n\n다음 링크를 클릭하여 계정을 확인하고 활성화하세요:
      \n{{.RegisterUrl}}

      \n\n위 링크가 클릭이 되지 않을 경우, 웹 브라우저 주소창에 복사하여 붙여넣어 보세요.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] 테스트 이메일" body: - other: "이것은 테스트용 이메일입니다." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: 추천 @@ -787,7 +787,7 @@ ui: how_to_format: title: 포맷 방법 desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: 이전 next: 다음 @@ -904,7 +904,7 @@ ui: msg: empty: 파일을 선택하세요. only_image: 이미지 파일만 허용됩니다. - max_size: 파일 크기는 4MB를 초과할 수 없습니다. + max_size: File size cannot exceed {{size}} MB. desc: label: 설명 tab_url: 이미지 URL @@ -946,6 +946,10 @@ ui: text: 표 heading: 제목 cell: 셀 + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: 이 게시물을 다음과 같은 이유로 닫습니다... btn_cancel: 취소 @@ -1086,6 +1090,7 @@ ui: search_placeholder: 태그 이름으로 필터링 no_desc: 이 태그에는 설명이 없습니다. more: 더 보기 + wiki: Wiki ask: title: 질문 하기 edit_title: 질문 수정 @@ -1522,6 +1527,7 @@ ui: newest: 최신순 active: 활성순 hot: Hot + frequent: Frequent recommend: Recommend score: 평점순 unanswered: 답변이 없는 질문 @@ -1721,6 +1727,8 @@ ui: welcome: 관리자에 오신 것을 환영합니다! site_statistics: 사이트 통계 questions: "질문:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "답변:" comments: "댓글:" votes: "투표:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: 예약된 태그 text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: 검색 엔진 최적화 permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: 초안을 삭제하시겠습니까? messages: post_deleted: 이 게시물은 삭제되었습니다. + post_cancel_deleted: This post has been undeleted. post_pin: 이 게시물이 고정되었습니다. post_unpin: 이 게시물의 고정이 해제되었습니다. post_hide_list: 이 게시물이 목록에서 숨겨졌습니다. @@ -2219,3 +2243,15 @@ ui: post_list: 이 게시물이 목록에 등록되었습니다. post_unlist: 이 게시물이 목록에서 등록 해제되었습니다. post_pending: 회원님의 게시물이 검토를 기다리고 있습니다. 미리보기입니다. 승인 후에 공개됩니다. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/ml_IN.yaml b/i18n/ml_IN.yaml index c2d2af8f..0783863b 100644 --- a/i18n/ml_IN.yaml +++ b/i18n/ml_IN.yaml @@ -787,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Prev next: Next @@ -904,7 +904,7 @@ ui: msg: empty: File cannot be empty. only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: Image URL @@ -946,6 +946,10 @@ ui: text: Table heading: Heading cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: I am closing this post as... btn_cancel: Cancel @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1522,6 +1527,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Questions:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Answers:" comments: "Comments:" votes: "Votes:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/pl_PL.yaml b/i18n/pl_PL.yaml index 9c0adc78..df4f6c1f 100644 --- a/i18n/pl_PL.yaml +++ b/i18n/pl_PL.yaml @@ -315,7 +315,7 @@ backend: other: Nie znaleziono konfiguracji strony. badge: object_not_found: - other: Badge object not found + other: Nie znaleziono obiektu odznaki reason: spam: name: @@ -326,7 +326,7 @@ backend: name: other: niegrzeczny lub obraźliwy desc: - other: "A reasonable person would find this content inappropriate for respectful discourse." + other: "Rozsądna osoba uznałaby tę treść za nieodpowiednią do dyskusji opartej na szacunku." a_duplicate: name: other: duplikat @@ -338,7 +338,7 @@ backend: name: other: nie jest odpowiedzią desc: - other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." + other: "Ta wiadomość została zamieszczona jako odpowiedź, ale nie próbuje odpowiedzieć na pytanie. Powinna być prawdopodobnie edycją, komentarzem, kolejnym pytaniem lub całkowicie usunięta." no_longer_needed: name: other: nie jest już potrzebne @@ -397,7 +397,7 @@ backend: name: other: wymaga szczegółów lub wyjaśnienia desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: To pytanie obecnie zawiera wiele pytań w jednym. Powinno się skupić tylko na jednym problemie. other: name: other: coś innego @@ -458,48 +458,48 @@ backend: invited_you_to_answer: other: zaproszono Cię do odpowiedzi earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Zdobyłeś odznakę "{{.BadgeName}}" email_tpl: change_email: title: other: "[{{.SiteName}}] Potwierdź swój nowy adres e-mail" body: - other: "Potwierdź swój nowy adres e-mail dla {{.SiteName}} klikając na poniższy link:

      \n{{.ChangeEmailUrl}}

      \n\nJeśli to nie Ty wysyłałeś to żądanie zignoruj ten e-mail.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} odpowiedział(-a) na pytanie" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nZobacz to na {{.SiteName}}

      \n\n--
      \nZrezygnuj z subskrypcji" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} zaprosił(a) Cię do odpowiedzi" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Myślę, że na to pytani możesz znać odpowiedź.

      \nZobacz to na {{.SiteName}}

      \n\n--
      \nZrezygnuj z subskrypcji" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} skomentował/-a Twój wpis" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nZobacz to na {{.SiteName}}

      \n\n--
      \nZrezygnuj z subskrypcji" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Nowe pytanie: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nZrezygnuj z subskrypcji" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Reset hasła" body: - other: "Ktoś poprosił o zresetowanie hasła [{{.SiteName}}].

      \n\nJeśli to nie Ty, możesz bezpiecznie zignorować ten e-mail.

      \n\nKliknij na poniższy link, aby utworzyć nowe hasło:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Potwierdź swoje nowe konto" body: - other: "Witaj w {{.SiteName}}

      \n\nKliknij na poniższy link, aby potwierdzić i aktywować nowe konto:
      \n{{.RegisterUrl}}

      \n\nJeśli w powyższy link nie można kliknąć, spróbuj skopiować i wkleić go do paska adresu przeglądarki internetowej.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Wiadomość testowa" body: - other: "To jest wiadomość testowa." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: oceń pozytywnie @@ -531,7 +531,7 @@ backend: name: other: Autobiografista desc: - other: Filled out profile information. + other: Wypełniono informacje profil. certified: name: other: Certyfikowany @@ -541,12 +541,12 @@ backend: name: other: Edytor desc: - other: First post edit. + other: Pierwsza edycja posta. first_flag: name: other: Pierwsza flaga desc: - other: First flagged a post. + other: Po raz pierwszy oznaczono post. first_upvote: name: other: Pierwszy pozytywny głos @@ -787,7 +787,7 @@ ui: how_to_format: title: Jak formatować desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Poprzedni next: Następny @@ -904,7 +904,7 @@ ui: msg: empty: Plik nie może być pusty. only_image: Dozwolone są tylko pliki obrazków. - max_size: Rozmiar pliku nie może przekroczyć 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Opis tab_url: Adres URL obrazka @@ -946,6 +946,10 @@ ui: text: Tabela heading: Nagłówek cell: Komórka + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Zamykam ten post jako... btn_cancel: Anuluj @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtruj według nazwy tagu no_desc: Tag nie posiada opisu. more: Więcej + wiki: Wiki ask: title: Dodaj pytanie edit_title: Edytuj pytanie @@ -1178,7 +1183,7 @@ ui: label: Imię msg: empty: Imię nie może być puste. - range: Długość nazwy powinna wynosić od 2 do 30 znaków. + range: Name must be between 2 to 30 characters in length. character: 'Możesz użyć dozwolone znaki "a-z", "A-Z", "0-9", " - . _"' email: label: Adres e-mail @@ -1522,6 +1527,7 @@ ui: newest: Najnowsze active: Aktywne hot: Gorące + frequent: Frequent recommend: Polecane score: Ocena unanswered: Bez odpowiedzi @@ -1721,6 +1727,8 @@ ui: welcome: Witaj Administratorze! site_statistics: Statystyki witryny questions: "Pytania:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Odpowiedzi:" comments: "Komentarze:" votes: "Głosy:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Zarezerwowane tagi text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Czy na pewno chcesz odrzucić swoją wersję roboczą? messages: post_deleted: Ten post został usunięty. + post_cancel_deleted: This post has been undeleted. post_pin: Ten post został przypięty. post_unpin: Ten post został odpięty. post_hide_list: Ten post został ukryty na liście. @@ -2219,3 +2243,15 @@ ui: post_list: Ten wpis został umieszczony na liście. post_unlist: Ten wpis został usunięty z listy. post_pending: Twój wpis oczekuje na recenzje. Będzie widoczny po jej akceptacji. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/pt_PT.yaml b/i18n/pt_PT.yaml index 670fc83f..0526b64c 100644 --- a/i18n/pt_PT.yaml +++ b/i18n/pt_PT.yaml @@ -326,7 +326,7 @@ backend: name: other: rude ou abusivo desc: - other: "A reasonable person would find this content inappropriate for respectful discourse." + other: "Uma pessoa razoável consideraria esse conteúdo inapropriado para um discurso respeitoso." a_duplicate: name: other: uma duplicação @@ -338,7 +338,7 @@ backend: name: other: não é uma resposta desc: - other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." + other: "Foi apresentada como resposta, mas não tenta responder à pergunta. Talvez deva ser uma edição, um comentário, outra pergunta ou totalmente apagada." no_longer_needed: name: other: não é mais necessário @@ -397,7 +397,7 @@ backend: name: other: precisa de detalhes ou clareza desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: Esta pergunta atualmente inclui várias perguntas em uma. Deve se concentrar em apenas um problema. other: name: other: algo mais @@ -464,32 +464,32 @@ backend: title: other: "[{{.SiteName}}] Confirme seu novo endereço de e-mail" body: - other: "Confirme seu novo endereço de e-mail para o {{.SiteName}} clicando no seguinte link:
      \n{{.ChangeEmailUrl}}

      \n\nSe você não solicitou esta alteração, por favor, ignore este e-mail.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} respondeu à sua pergunta" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nVisualizado em {{.SiteName}}

      \n\n--
      \nCancelar inscrição" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} convidou-lhe para responder" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I ach que sei a resposta.

      \nVisualiza em {{.SiteName}}

      \n\n--
      \nCancelar inscrição" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} comentou em sua publicação" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nVisualizar no {{.SiteName}}

      \n\n--
      \nCancelar inscrição" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Nova pergunta: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nCancelar inscrição" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Redefinição de senha" body: - other: "Alguém pediu para redefinir a sua senha em {{.SiteName}}.

      \n\nSe não foi você, você pode ignorar este e-mail.

      \n\nClique no seguinte link para escolher uma nova senha:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirme seu novo endereço de e-mail" @@ -499,7 +499,7 @@ backend: title: other: "[{{.SiteName}}] E-mail de teste" body: - other: "Esse é um email de teste." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: voto positivo @@ -787,7 +787,7 @@ ui: how_to_format: title: Como formatar desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Anterior next: Próximo @@ -904,7 +904,7 @@ ui: msg: empty: Arquivo não pode ser vazio. only_image: Somente um arquivo de imagem é permitido. - max_size: O tamanho do arquivo não pode exceder 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Descrição (opcional) tab_url: URL da imagem @@ -946,6 +946,10 @@ ui: text: Tabela heading: heading cell: Célula + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Estou fechando este post como... btn_cancel: Cancelar @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtrar por nome de marcador no_desc: O marcador não possui descrição. more: Mais + wiki: Wiki ask: title: Adicionar Pergunta edit_title: Editar Pergunta @@ -1146,7 +1151,7 @@ ui: placeholder: Procurar footer: build_on: >- - . + Powered by <1> Apache Answer - the open-source software that powers Q&A communities.
      Made with love © {{cc}}. upload_img: name: Mudar loading: carregando... @@ -1335,9 +1340,9 @@ ui: title: Perguntas relacionadas answers: respostas linked_question: - title: Linked Questions - description: Questions linked to - no_linked_question: No questions linked from this question. + title: Perguntas relacionadas + description: Questões ligadas a + no_linked_question: Nenhuma pergunta relacionada a esta questão. invite_to_answer: title: Pessoas Perguntaram desc: Select people who you think might know the answer. @@ -1522,6 +1527,7 @@ ui: newest: Mais recente active: Ativo hot: Popular + frequent: Frequent recommend: Recomendado score: Pontuação unanswered: Não Respondido @@ -1556,7 +1562,7 @@ ui: top_questions: Melhores Perguntas stats: Estatísticas list_empty: Postagens não encontradas.
      Talvez você queira selecionar uma guia diferente? - content_empty: No posts found. + content_empty: Nenhum post encontrado. accepted: Aceito answered: respondido asked: perguntado @@ -1615,7 +1621,7 @@ ui: msg: empty: Site URL não pode ser vazio. incorrect: URL do site está incorreto. - max_length: A URL do site deve ter no máximo 512 caracteres. + max_length: O nome do site deve ter no máximo 512 caracteres. contact_email: label: E-mail par contato text: O endereço de e-mail do contato principal deste site. @@ -1721,6 +1727,8 @@ ui: welcome: Bem-vindo ao Admin! site_statistics: Estatísticas do site questions: "Perguntas:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Respostas:" comments: "Comentários:" votes: "Votos:" @@ -1747,7 +1755,7 @@ ui: github: GitHub blog: Blog contact: Contato - forum: Forum + forum: Fórum documents: Documentos feedback: Opinião support: Supporte @@ -1814,7 +1822,7 @@ ui: msg: "Por favor insira o e-mail do usuário, um por linha." display_name: label: Nome de exibição - msg: O nome de exibição deve ter de 2 a 30 caracteres. + msg: O nome de exibição deve ter de 2-30 caracteres. email: label: E-mail msg: E-mail inválido. @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved Marcadores text: "Tags reservadas só podem ser usadas pelo moderador." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Tem certeza que deseja descartar o rascunho? messages: post_deleted: Esta publicação foi removida. + post_cancel_deleted: This post has been undeleted. post_pin: Esta publicação foi fixada. post_unpin: Esta postagem foi desafixada. post_hide_list: Esta postagem foi ocultada da lista. @@ -2219,3 +2243,15 @@ ui: post_list: Esta postagem foi listada. post_unlist: Esta publicação foi removida da lista. post_pending: A sua postagem está aguardando revisão. Ela ficará visível depois que for aprovada. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/ro_RO.yaml b/i18n/ro_RO.yaml index 9b7ed200..c124206e 100644 --- a/i18n/ro_RO.yaml +++ b/i18n/ro_RO.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirmați noua dvs. adresă de e-mail" body: - other: "Confirmați noua dvs. adresă de e-mail pentru {{.SiteName}} făcând clic pe următorul link:
      \n{{.ChangeEmailUrl}}

      \n\nDacă nu ați solicitat această modificare, vă rugăm să ignorați acest e-mail.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} a răspuns la întrebarea dvs" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nVizualizați-l pe {{.SiteName}}

      \n\n--
      \nDezabonare" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} vă invită să răspundeți" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Cred că ai putea ști răspunsul.

      \nVizualizaţi-l pe {{.SiteName}}

      \n\n--
      \nDezabonare" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} a răspuns la întrebarea dvs" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nVizualizați-l pe {{.SiteName}}

      \n\n--
      \nDezabonare" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Întrebare nouă: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nDezabonare" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Resetare parolă" body: - other: "Cineva a cerut resetarea parolei pe {{.SiteName}}.

      \n\nDacă nu ai fost, poți ignora în siguranță acest e-mail.

      \n\nFaceţi clic pe următorul link pentru a alege o parolă nouă:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirmă noul tău cont" body: - other: "Bun venit la {{.SiteName}}!

      \n\nFaceţi clic pe următorul link pentru a confirma şi activa noul cont:
      \n{{.RegisterUrl}}

      \n\nDacă link-ul de mai sus nu este clickabil, încearcă să o copiezi și să o inserezi în bara de adrese a browser-ului tău.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test de e-mail" body: - other: "Acesta este un e-mail de test." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: votat @@ -581,7 +581,7 @@ backend: name: other: New User of the Month desc: - other: Outstanding contributions in their first month. + other: Contribuții restante în prima lor lună. read_guidelines: name: other: Read Guidelines @@ -609,7 +609,7 @@ backend: other: Shared a post with 300 unique visitors. great_share: name: - other: Great Share + other: Distribuire grozavă desc: other: Shared a post with 1000 unique visitors. out_of_love: @@ -787,7 +787,7 @@ ui: how_to_format: title: Cum se formatează desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Înapoi next: Înainte @@ -904,7 +904,7 @@ ui: msg: empty: Fișierul nu poate fi gol. only_image: Sunt permise doar fișierele imagine. - max_size: Dimensiunea fişierului nu poate depăşi 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Descriere tab_url: URL-ul imaginii @@ -946,6 +946,10 @@ ui: text: Tabelă heading: Titlu cell: Celulă + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Închid această postare ca... btn_cancel: Anulează @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtrare după numele etichetei no_desc: Această echipă nu are o descriere. more: Mai multe + wiki: Wiki ask: title: Adăugați întrebarea edit_title: Editați întrebarea @@ -1522,6 +1527,7 @@ ui: newest: Cele mai noi active: Activ hot: Hot + frequent: Frequent recommend: Recommend score: Scor unanswered: Fără răspuns @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Statisticile site-ului questions: "Întrebări:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Răspunsuri:" comments: "Comentarii:" votes: "Voturi:" @@ -1814,7 +1822,7 @@ ui: msg: "Te rugăm să introduci e-mailul utilizatorului, câte unul pe linie." display_name: label: Nume afișat - msg: Numele afișat trebuie să aibă între 2 și 30 de caractere. + msg: Display name must be 2-30 characters in length. email: label: E-mail msg: E-mail nu este validă. @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Etichete rezervate text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Ești sigur că vrei să renunți la ciornă? messages: post_deleted: Această postare a fost ștearsă. + post_cancel_deleted: This post has been undeleted. post_pin: Această postare a fost fixată. post_unpin: Această postare nu a fost fixată. post_hide_list: Această postare a fost ascunsă din listă. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/ru_RU.yaml b/i18n/ru_RU.yaml index 1e370b5c..fdb42739 100644 --- a/i18n/ru_RU.yaml +++ b/i18n/ru_RU.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Подтвердите новый адрес электронной почты" body: - other: "Подтвердите свой новый адрес электронной почты для {{.SiteName}}, перейдя по следующей ссылке:
      {{.ChangeEmailUrl}}

      Если вы не запрашивали это изменение, пожалуйста, проигнорируйте это электронное письмо.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} ответил на ваш вопрос" body: - other: "{{.QuestionTitle}}

      {{.DisplayName}}:
      \n
      Я думаю, вы можете знать ответ.

      Просмотрите его на {{.SiteName}}

      --
      Отказаться от подписки" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} приглашает вас в Answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Я думаю что вы знаете ответ на этот вопрос.

      \nОткрыть вопрос в {{.SiteName}}

      \n\n--
      \nОтписаться" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} прокомментировал под вашей публикацией" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nОткрыть вопрос в {{.SiteName}}

      \n\n--
      \nОтписаться" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Новый вопрос: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nОтписаться" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Пароль сброшен" body: - other: "Кто-то сделал запрос на сброс пароля на {{.SiteName}}.

      \n\nЕсли это были не Вы, можете проигнорировать это письмо.

      \n\nНажмите на следующую ссылку, чтобы выбрать новый пароль:
      {{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Подтвердите Ваш новый аккаунт" body: - other: "Добро пожаловать в {{.SiteName}}!

      Перейдите по следующей ссылке, чтобы подтвердить и активировать свою новую учетную запись:
      {{.RegisterUrl}}

      Если приведенная выше ссылка недоступна, попробуйте скопировать и вставить ее в адресную строку вашего веб-браузера.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Проверочное электронное письмо" body: - other: "Это тестовое письмо." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: проголосовать за @@ -787,7 +787,7 @@ ui: how_to_format: title: 'Форматирование:' desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Назад next: Следующий @@ -904,7 +904,7 @@ ui: msg: empty: Файл не может быть пустым. only_image: Разрешены только изображения. - max_size: Размер файла не может превышать 4МБ. + max_size: File size cannot exceed {{size}} MB. desc: label: Описание tab_url: URL изображения @@ -946,6 +946,10 @@ ui: text: Таблица heading: Заголовок cell: Ячейка + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Я закрываю этот пост как... btn_cancel: Отменить @@ -1086,6 +1090,7 @@ ui: search_placeholder: Фильтр по названию тега no_desc: Тег не имеет описания. more: Подробнее + wiki: Wiki ask: title: Задать вопрос edit_title: Редактировать вопрос @@ -1522,6 +1527,7 @@ ui: newest: Последние active: Активные hot: Hot + frequent: Frequent recommend: Recommend score: Оценка unanswered: Без ответа @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Статистика сайта questions: "Вопросы:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Ответы:" comments: "Комментарии:" votes: "Голоса:" @@ -1814,7 +1822,7 @@ ui: msg: "Пожалуйста, введите адрес электронной почты пользователя, по одному на строку." display_name: label: Отображаемое имя - msg: Отображаемое имя должно содержать не менее 2-30 символов. + msg: Display name must be 2-30 characters in length. email: label: Email msg: Некорректный email. @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Зарезервированные теги text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Вы уверены, что хотите отказаться от своего черновика? messages: post_deleted: Этот пост был удалён. + post_cancel_deleted: This post has been undeleted. post_pin: Этот пост был закреплен. post_unpin: Этот пост был откреплен. post_hide_list: Это сообщение было скрыто из списка. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/sk_SK.yaml b/i18n/sk_SK.yaml index 28e77be0..53bdf38f 100644 --- a/i18n/sk_SK.yaml +++ b/i18n/sk_SK.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: Ako formátovať desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Predch next: Ďalšie @@ -904,7 +904,7 @@ ui: msg: empty: Názov súboru nemôže byť prázdny. only_image: Povolené sú iba obrázkové súbory. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Popis tab_url: URL obrázka @@ -946,6 +946,10 @@ ui: text: Table heading: Heading cell: Bunka + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Tento príspevok uzatváram ako... btn_cancel: Zrušiť @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filtrujte podľa názvu značky no_desc: Značka nemá popis. more: Viac + wiki: Wiki ask: title: Pridať otázku edit_title: Upraviť otázku @@ -1522,6 +1527,7 @@ ui: newest: Najnovšie active: Aktívne hot: Hot + frequent: Frequent recommend: Recommend score: Skóre unanswered: Nezodpovedané @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Otázky:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Odpovede:" comments: "Komentáre:" votes: "Hlasy:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Naozaj chcete zahodiť svoj koncept? messages: post_deleted: Tento príspevok bol odstránený. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/sv_SE.yaml b/i18n/sv_SE.yaml index 93dbb962..b9ba3cec 100644 --- a/i18n/sv_SE.yaml +++ b/i18n/sv_SE.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Bekräfta din nya e-postadress" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Ny fråga: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Bekräfta ditt nya konto" body: - other: "Välkommen till {{.SiteName}}!

      \n\nKlicka på följande länk för att bekräfta och aktivera ditt nya konto:
      \n{{.RegisterUrl}}

      \n\nOm ovanstående länk inte går att klicka på, kan du kopiera och klistra in den i adressfältet i din webbläsare.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Prev next: Nästa @@ -832,7 +832,7 @@ ui: show_more: Visa mer someone: Someone inbox_type: - all: All + all: Alla posts: Inlägg invites: Inbjudningar votes: Röster @@ -904,7 +904,7 @@ ui: msg: empty: File cannot be empty. only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Beskrivning tab_url: Image URL @@ -946,6 +946,10 @@ ui: text: Tabell heading: Heading cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: I am closing this post as... btn_cancel: Avbryt @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1236,7 +1241,7 @@ ui: length: The length needs to be between 8 and 32 different: The passwords entered on both sides are inconsistent password_confirm: - label: Confirm new password + label: Bekräfta nytt lösenord settings: page_title: Inställningar goto_modify: Go to modify @@ -1522,6 +1527,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Frågor:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Svar:" comments: "Kommentarer:" votes: "Röster:" @@ -1788,21 +1796,21 @@ ui: btn_cancel: Avbryt btn_submit: Skicka edit_profile_modal: - title: Edit profile + title: Redigera profil form: fields: display_name: label: Visningsnamn msg_range: Display name up to 30 characters. username: - label: Username + label: Användarnamn msg_range: Username up to 30 characters. email: label: Email - msg_invalid: Invalid Email Address. + msg_invalid: Ogiltig e-postadress. edit_success: Edited successfully - btn_cancel: Cancel - btn_submit: Submit + btn_cancel: Avbryt + btn_submit: Skicka user_modal: title: Lägg till ny användare form: @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/te_IN.yaml b/i18n/te_IN.yaml index 2b9ea470..19ab2e31 100644 --- a/i18n/te_IN.yaml +++ b/i18n/te_IN.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: మునుపటి next: Next @@ -904,7 +904,7 @@ ui: msg: empty: File cannot be empty. only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: Image URL @@ -946,6 +946,10 @@ ui: text: Table heading: Heading cell: Cell + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: I am closing this post as... btn_cancel: Cancel @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1522,6 +1527,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Questions:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Answers:" comments: "Comments:" votes: "Votes:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/tr_TR.yaml b/i18n/tr_TR.yaml index 5bfb1bbd..232ea498 100644 --- a/i18n/tr_TR.yaml +++ b/i18n/tr_TR.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: How to Format desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Önceki next: Sonraki @@ -904,7 +904,7 @@ ui: msg: empty: File cannot be empty. only_image: Only image files are allowed. - max_size: File size cannot exceed 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Description tab_url: Image URL @@ -946,6 +946,10 @@ ui: text: Tablo heading: Başlık cell: Hücre + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: I am closing this post as... btn_cancel: İptal Et @@ -1086,6 +1090,7 @@ ui: search_placeholder: Filter by tag name no_desc: The tag has no description. more: More + wiki: Wiki ask: title: Add Question edit_title: Edit Question @@ -1522,6 +1527,7 @@ ui: newest: Newest active: Active hot: Hot + frequent: Frequent recommend: Recommend score: Score unanswered: Unanswered @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "Questions:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Answers:" comments: "Comments:" votes: "Votes:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/uk_UA.yaml b/i18n/uk_UA.yaml index a8f29b30..65c89f16 100644 --- a/i18n/uk_UA.yaml +++ b/i18n/uk_UA.yaml @@ -326,7 +326,7 @@ backend: name: other: грубо чи образливо desc: - other: "A reasonable person would find this content inappropriate for respectful discourse." + other: "Розумна людина вважатиме такий зміст неприйнятним для ввічливого спілкування." a_duplicate: name: other: дублікат @@ -338,7 +338,7 @@ backend: name: other: не відповідь desc: - other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question,or deleted altogether." + other: "Це повідомлення було опубліковане як відповідь, але воно не є спробою відповісти на запитання. Можливо, його слід відредагувати, прокоментувати, поставити інше запитання або взагалі видалити." no_longer_needed: name: other: більше не потрібно @@ -397,7 +397,7 @@ backend: name: other: потребує деталей або ясності desc: - other: This question currently includes multiple questions in one. It should focus on one problem only. + other: Наразі це питання включає кілька запитань в одному. Воно має зосереджуватися лише на одній проблемі. other: name: other: інше @@ -418,13 +418,13 @@ backend: tags_title: other: Теґи no_description: - other: The tag has no description. + other: Тег не має опису. notification: action: update_question: other: оновлене питання answer_the_question: - other: answered question + other: питання з відповіддю update_answer: other: оновлена відповідь accept_answer: @@ -446,60 +446,60 @@ backend: your_comment_was_deleted: other: Ваш коментар видалено up_voted_question: - other: upvoted question + other: питання, за яке найбільше проголосували down_voted_question: - other: downvoted question + other: питання, за яке проголосували менше up_voted_answer: - other: upvoted answer + other: відповідь, за яку проголосували найбільше down_voted_answer: other: downvoted answer up_voted_comment: - other: upvoted comment + other: коментар, за який проголосували invited_you_to_answer: other: запросив(-ла) вас відповісти earned_badge: - other: You've earned the "{{.BadgeName}}" badge + other: Ви заробили бейдж "{{.BadgeName}}" email_tpl: change_email: title: other: "[{{.SiteName}}] Підтвердіть нову адресу електронної пошти" body: - other: "Підтвердіть нову електронну адресу для {{.SiteName}}, натиснувши на наступне посилання:
      {{.ChangeEmailUrl}}

      \n\nЯкщо ви не надсилали запит на цю зміну, не звертайте уваги на цей електронний лист.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} відповів(-ла) на ваше запитання" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}
      \n
      {{.AnswerSummary}}

      \nПереглянути на {{.SiteName}}

      \n\n--
      \nВідписатися" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} запросив(-ла) вас відповісти" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Я думаю, ти маєш знати відповідь.

      \nПереглянути на {{.SiteName}}

      \n\n--
      \nВідписатися" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} прокоментували ваш допис" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nПереглянути на {{.SiteName}}

      \n\n--
      \nВідписатися" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Нове питання: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nВідписатися" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Скидання пароля" body: - other: "Хтось попросив скинути ваш пароль на сайті {{.SiteName}}.

      \n\nЯкщо це були не ви, можете спокійно проігнорувати цей електронний лист.

      \n\nНатисніть це посилання, щоб вибрати новий пароль:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Підтвердьте свій новий обліковий запис" body: - other: "Вітаємо на {{.SiteName}}!

      \n\nНатисніть це посилання, щоб підтвердити й активувати свій новий обліковий запис:
      \n{{.RegisterUrl}}

      \n\nЯкщо наведене вище посилання не можна натиснути, спробуйте скопіювати та вставити його в адресний рядок веб-переглядача.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Тестовий електронний лист" body: - other: "Це тестовий електронний лист." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: підтримати @@ -517,26 +517,26 @@ backend: other: редагувати review: queued_post: - other: Queued post + other: Допис у черзі flagged_post: other: Відмічений пост suggested_post_edit: - other: Suggested edits + other: Запропоновані зміни reaction: tooltip: - other: "{{ .Names }} and {{ .Count }} more..." + other: "{{ .Names }} і {{ .Count }} більше..." badge: default_badges: autobiographer: name: - other: Autobiographer + other: Автобіограф desc: - other: Filled out profile information. + other: Заповнена інформація про профіль. certified: name: other: Підтверджений desc: - other: Completed our new user tutorial. + other: Завершено наш новий посібник користувача. editor: name: other: Редактор @@ -544,34 +544,34 @@ backend: other: Перше редагування посту. first_flag: name: - other: First Flag + other: Перший прапор desc: - other: First flagged a post. + other: Спочатку позначено допис. first_upvote: name: - other: First Upvote + other: Перший голос за desc: - other: First up voted a post. + other: Першим голосував за допис. first_link: name: other: Перше посилання desc: - other: First dirst added a link to another post. + other: Перший дирст додав посилання на інший допис. first_reaction: name: other: Перша реакція desc: - other: First reacted to the post. + other: Першим відреагував на допис. first_share: name: - other: First Share + other: Перше поширення desc: - other: First shared a post. + other: Перший поділився публікацією. scholar: name: other: Вчений desc: - other: Asked a question and accepted an answer. + other: Поставив питання і прийняв відповідь. commentator: name: other: Коментатор @@ -581,17 +581,17 @@ backend: name: other: Новий користувач місяця desc: - other: Outstanding contributions in their first month. + other: Видатні внески за їх перший місяць. read_guidelines: name: - other: Read Guidelines + other: Прочитайте Інструкцію desc: other: Прочитайте [рекомендації для спільноти]. reader: name: other: Читач desc: - other: Read every answers in a topic with more than 10 answers. + other: Прочитайте кожну відповідь у темі з більш ніж 10 відповідями. welcome: name: other: Ласкаво просимо @@ -599,34 +599,34 @@ backend: other: Отримав голос. nice_share: name: - other: Nice Share + other: Гарне поширення desc: - other: Shared a post with 25 unique visitors. + other: Поділилися постом з 25 унікальними відвідувачами. good_share: name: - other: Good Share + other: Хороше поширення desc: - other: Shared a post with 300 unique visitors. + other: Поділилися постом з 300 унікальними відвідувачами. great_share: name: - other: Great Share + other: Відмінне поширення desc: - other: Shared a post with 1000 unique visitors. + other: Поділилися постом з 1000 унікальними відвідувачами. out_of_love: name: - other: Out of Love + other: З любові desc: - other: Used 50 up votes in a day. + other: Використав 50 голосів «за» за день. higher_love: name: - other: Higher Love + other: Вище кохання desc: - other: Used 50 up votes in a day 5 times. + other: Використав 50 голосів «за» за день 5 разів. crazy_in_love: name: - other: Crazy in Love + other: Божевільний в любові desc: - other: Used 50 up votes in a day 20 times. + other: Використав 50 голосів «за» за день 20 разів. promoter: name: other: Промоутер @@ -634,9 +634,9 @@ backend: other: Запросив користувача. campaigner: name: - other: Campaigner + other: Агітатор desc: - other: Invited 3 basic users. + other: Запрошено 3 основних користувачів. champion: name: other: Чемпіон @@ -646,148 +646,148 @@ backend: name: other: Дякую desc: - other: Has 20 up voted posts and gave 10 up votes. + other: Має 20 дописів, за які проголосували, і віддав 10 голосів «за». gives_back: name: - other: Gives Back + other: Дає назад desc: - other: Has 100 up voted posts and gave 100 up votes. + other: Має 100 дописів, за які проголосували, і віддав 100 голосів «за». empathetic: name: - other: Empathetic + other: Емпатичний desc: - other: Has 500 up voted posts and gave 1000 up votes. + other: Має 500 дописів, за які проголосували, і віддав 1000 голосів «за». enthusiast: name: - other: Enthusiast + other: Ентузіаст desc: - other: Visited 10 consecutive days. + other: Відвідано 10 днів поспіль. aficionado: name: - other: Aficionado + other: Шанувальник desc: - other: Visited 100 consecutive days. + other: Відвідано 100 днів поспіль. devotee: name: - other: Devotee + other: Відданий desc: - other: Visited 365 consecutive days. + other: Відвідано 365 днів поспіль. anniversary: name: - other: Anniversary + other: Річниця desc: - other: Active member for a year, posted at least once. + other: Активний учасник на рік, опублікував принаймні один раз. appreciated: name: - other: Appreciated + other: Оцінений desc: - other: Received 1 up vote on 20 posts. + other: Отримано 1 голос за 20 дописів. respected: name: other: Шанований desc: - other: Received 2 up votes on 100 posts. + other: Отримано 2 голоси за 100 дописів. admired: name: - other: Admired + other: Захоплений desc: - other: Received 5 up votes on 300 posts. + other: Отримано 5 голосів за 300 дописів. solved: name: other: Вирішено desc: - other: Have an answer be accepted. + other: Нехай відповідь буде прийнята. guidance_counsellor: name: - other: Guidance Counsellor + other: Радник супроводу desc: - other: Have 10 answers be accepted. + other: Прийміть 10 відповідей. know_it_all: name: - other: Know-it-All + other: Усезнайко desc: - other: Have 50 answers be accepted. + other: Було прийнято 50 відповідей. solution_institution: name: - other: Solution Institution + other: Інституція рішення desc: - other: Have 150 answers be accepted. + other: Було прийнято 150 відповідей. nice_answer: name: - other: Nice Answer + other: Чудова відповідь desc: - other: Answer score of 10 or more. + other: Оцінка відповіді на 10 або більше. good_answer: name: - other: Good Answer + other: Гарна відповідь desc: - other: Answer score of 25 or more. + other: Оцінка відповіді на 25 або більше. great_answer: name: - other: Great Answer + other: Чудова відповідь desc: - other: Answer score of 50 or more. + other: Оцінка відповіді на 50 або більше. nice_question: name: - other: Nice Question + other: Гарне питання desc: - other: Question score of 10 or more. + other: Оцінка питання на 10 або більше. good_question: name: - other: Good Question + other: Хороше питання desc: - other: Question score of 25 or more. + other: Оцінка питання на 25 або більше. great_question: name: - other: Great Question + other: Відмінне питання desc: - other: Question score of 50 or more. + other: Оцінка питання на 50 або більше. popular_question: name: - other: Popular Question + other: Популярне питання desc: - other: Question with 500 views. + other: Питання з 500 переглядами. notable_question: name: - other: Notable Question + other: Помітне питання desc: - other: Question with 1,000 views. + other: Питання з 1000 переглядами. famous_question: name: - other: Famous Question + other: Знамените питання desc: - other: Question with 5,000 views. + other: Питання з 5000 переглядами. popular_link: name: - other: Popular Link + other: Популярне посилання desc: - other: Posted an external link with 50 clicks. + other: Опубліковано зовнішнє посилання з 50 натисканнями. hot_link: name: - other: Hot Link + other: Гаряче посилання desc: - other: Posted an external link with 300 clicks. + other: Опубліковано зовнішнє посилання з 300 натисканнями. famous_link: name: - other: Famous Link + other: Знамените Посилання desc: - other: Posted an external link with 100 clicks. + other: Опубліковано зовнішнє посилання зі 100 натисканнями. default_badge_groups: getting_started: name: - other: Getting Started + other: Початок роботи community: name: other: Спільнота posting: name: - other: Posting + other: Публікація # The following fields are used for interface presentation(Front-end) ui: how_to_format: title: Як відформатувати desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Назад next: Далі @@ -796,7 +796,7 @@ ui: questions: Запитання tag: Теґ tags: Теґи - tag_wiki: tag wiki + tag_wiki: тег вікі create_tag: Створити теґ edit_tag: Редагувати теґ ask_a_question: Додати запитання @@ -837,8 +837,8 @@ ui: invites: Запрошення votes: Голоси answer: Відповідь - question: Question - badge_award: Badge + question: Запитання + badge_award: Значок suspended: title: Ваш обліковий запис було призупинено until_time: "Ваш обліковий запис призупинено до {{ time }}." @@ -847,16 +847,16 @@ ui: contact_us: Зв'яжіться з нами editor: blockquote: - text: Blockquote + text: Блок Цитування bold: - text: Strong + text: Надійний chart: text: Діаграма flow_chart: Блок-схема sequence_diagram: Діаграма послідовності class_diagram: Діаграма класів state_diagram: Діаграма станів - entity_relationship_diagram: Entity relationship diagram + entity_relationship_diagram: Діаграма зв'язків сутностей user_defined_diagram: Визначена користувачем діаграма gantt_chart: Діаграма Ґанта pie_chart: Кругова діаграма @@ -878,7 +878,7 @@ ui: text: Формула options: inline: Вбудована формула - block: Block formula + block: Формула блоку heading: text: Заголовок options: @@ -904,7 +904,7 @@ ui: msg: empty: Файл не може бути порожнім. only_image: Допустимі лише файли зображень. - max_size: Розмір файлу не може перевищувати 4 МБ. + max_size: File size cannot exceed {{size}} MB. desc: label: Опис tab_url: URL зображення @@ -924,7 +924,7 @@ ui: outdent: text: Відступ italic: - text: Emphasis + text: Акцент link: text: Гіперпосилання add_link: Додати гіперпосилання @@ -946,10 +946,14 @@ ui: text: Таблиця heading: Заголовок cell: Клітинка + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Я закриваю цей пост, оскільки... btn_cancel: Скасувати - btn_submit: Submit + btn_submit: Надіслати remark: empty: Не може бути порожнім. msg: @@ -961,13 +965,13 @@ ui: review_answer_title: Переглянути відповідь review_comment_title: Переглянути коментар btn_cancel: Скасувати - btn_submit: Submit + btn_submit: Надіслати remark: empty: Не може бути порожнім. msg: empty: Будь ласка, оберіть причину. - not_a_url: URL format is incorrect. - url_not_match: URL origin does not match the current website. + not_a_url: Формат URL неправильний. + url_not_match: Походження URL не збігається з поточним вебсайтом. tag_modal: title: Створити новий теґ form: @@ -978,22 +982,22 @@ ui: empty: Ім'я для відображення не може бути порожнім. range: Ім'я для відображення до 35 символів. slug_name: - label: URL slug - desc: URL slug up to 35 characters. + label: Скорочена URL-адреса + desc: Скорочення URL до 35 символів. msg: - empty: URL slug cannot be empty. - range: URL slug up to 35 characters. - character: URL slug contains unallowed character set. + empty: Скорочення URL не може бути пустим. + range: Скорочення URL до 35 символів. + character: Скорочення URL містить незадовільний набір символів. desc: label: Опис revision: - label: Revision + label: Редакція edit_summary: - label: Edit summary + label: Підсумок редагування placeholder: >- Коротко поясніть ваші зміни (виправлена орфографія, виправлена граматика, покращене форматування) btn_cancel: Скасувати - btn_submit: Submit + btn_submit: Надіслати btn_post: Опублікувати новий теґ tag_info: created_at: Створено @@ -1010,9 +1014,9 @@ ui: delete: title: Видалити цей теґ tip_with_posts: >- -

      We do not allow deleting tag with posts.

      Please remove this tag from the posts first.

      +

      Ми не дозволяємо видаляти тег з дописами.

      Передусім, будь ласка, вилучіть цей тег з дописів.

      tip_with_synonyms: >- -

      We do not allow deleting tag with synonyms.

      Please remove the synonyms from this tag first.

      +

      Ми не дозволяємо видаляти тег із синонімами.

      Передусім, будь ласка, вилучіть синоніми з цього тега.

      tip: Ви впевнені, що хочете видалити? close: Закрити edit_tag: @@ -1026,21 +1030,21 @@ ui: long_date_with_year: "МММ Д, РРРР" long_date_with_time: "МММ Д, РРРР [о] ГГ:хв" now: зараз - x_seconds_ago: "{{count}}s ago" - x_minutes_ago: "{{count}}m ago" - x_hours_ago: "{{count}}h ago" - hour: hour + x_seconds_ago: "{{count}}сек назад" + x_minutes_ago: "{{count}}хв назад" + x_hours_ago: "{{count}}год назад" + hour: година day: день - hours: hours + hours: годин days: дні reaction: - heart: heart + heart: серце smile: посмішка - frown: frown - btn_label: add or remove reactions - undo_emoji: undo {{ emoji }} reaction - react_emoji: react with {{ emoji }} - unreact_emoji: unreact with {{ emoji }} + frown: насупився + btn_label: додавати або вилучати реакції + undo_emoji: скасувати реакцію {{ emoji }} + react_emoji: реагувати з {{ emoji }} + unreact_emoji: не реагувати з {{ emoji }} comment: btn_add_comment: Додати коментар reply_to: Відповісти на @@ -1086,6 +1090,7 @@ ui: search_placeholder: Фільтрувати за назвою теґу no_desc: Цей теґ не має опису. more: Більше + wiki: Wiki ask: title: Додати питання edit_title: Редагувати питання @@ -1134,7 +1139,7 @@ ui: question: Запитання tag: Теґи user: Користувачі - badges: Badges + badges: Значки profile: Профіль setting: Налаштування logout: Вийти @@ -1178,7 +1183,7 @@ ui: label: Ім’я msg: empty: Ім'я не може бути порожнім. - range: Довжина імені має бути від 2 до 30 символів. + range: Ім'я повинно мати довжину від 2 до 30 символів. character: 'Необхідно використовувати набір символів "a-z", "A-Z", "0-9", " - . _"' email: label: Електронна пошта @@ -1228,7 +1233,7 @@ ui: Ви успішно змінили пароль; вас буде перенаправлено на сторінку входу в систему. link_invalid: >- На жаль, це посилання для зміни пароля більше недійсне. Можливо, ваш пароль уже скинуто? - to_login: Continue to log in page + to_login: Продовжити вхід на сторінку password: label: Пароль msg: @@ -1335,9 +1340,9 @@ ui: title: Пов'язані запитання answers: відповіді linked_question: - title: Linked Questions - description: Questions linked to - no_linked_question: No questions linked from this question. + title: Пов'язані питання + description: Питання, пов'язані з + no_linked_question: Немає питань, пов'язаних з цього питання. invite_to_answer: title: Люди запитували desc: Виберіть людей, які, на вашу думку, можуть знати відповідь. @@ -1346,7 +1351,7 @@ ui: search: Шукати людей question_detail: action: Дія - Asked: Asked + Asked: Запитали asked: запитали update: Змінено edit: відредаговано @@ -1355,51 +1360,51 @@ ui: Follow: Підписатися Following: Підписані follow_tip: Підпишіться на це запитання, щоб отримувати сповіщення - answered: answered - closed_in: Closed in + answered: дано відповідь + closed_in: Зачинено в show_exist: Показати наявне запитання. useful: Корисне - question_useful: It is useful and clear - question_un_useful: It is unclear or not useful - question_bookmark: Bookmark this question - answer_useful: It is useful - answer_un_useful: It is not useful + question_useful: Це корисно і ясно + question_un_useful: Це неясно або некорисно + question_bookmark: Додати в закладки це питання + answer_useful: Це корисно + answer_un_useful: Це некорисно answers: - title: Answers - score: Score - newest: Newest - oldest: Oldest + title: Відповіді + score: Оцінка + newest: Найновіші + oldest: Найдавніші btn_accept: Прийняти - btn_accepted: Accepted + btn_accepted: Прийнято write_answer: title: Ваша відповідь - edit_answer: Edit my existing answer - btn_name: Post your answer - add_another_answer: Add another answer - confirm_title: Continue to answer - continue: Continue + edit_answer: Редагувати мою чинну відповідь + btn_name: Опублікувати свою відповідь + add_another_answer: Додати ще одну відповідь + confirm_title: Перейти до відповіді + continue: Продовжити confirm_info: >- -

      Are you sure you want to add another answer?

      You could use the edit link to refine and improve your existing answer, instead.

      +

      Ви впевнені, що хочете додати ще одну відповідь?

      Натомість ви можете скористатися посиланням редагування, щоб уточнити та покращити вже існуючу відповідь.

      empty: Відповідь не може бути порожньою. characters: вміст має бути не менше 6 символів. tips: header_1: Дякуємо за відповідь li1_1: Будь ласка, не забудьте відповісти на запитання. Надайте детальну інформацію та поділіться своїми дослідженнями. li1_2: Підкріплюйте будь-які ваші твердження посиланнями чи особистим досвідом. - header_2: But avoid ... - li2_1: Asking for help, seeking clarification, or responding to other answers. + header_2: Але уникайте... + li2_1: Просити про допомогу, шукати роз'яснення або реагувати на інші відповіді. reopen: confirm_btn: Відкрити знову title: Повторно відкрити цей допис content: Ви впевнені, що хочете повторно відкрити? list: - confirm_btn: List - title: List this post - content: Are you sure you want to list? + confirm_btn: Список + title: Показати цей допис + content: Ви впевнені, що хочете скласти список? unlist: - confirm_btn: Unlist - title: Unlist this post - content: Are you sure you want to unlist? + confirm_btn: Вилучити зі списку + title: Вилучити допис зі списку + content: Ви впевнені, що хочете вилучити зі списку? pin: title: Закріпити цей допис content: Ви впевнені, що хочете закріпити глобально? Цей допис відображатиметься вгорі всіх списків публікацій. @@ -1423,116 +1428,117 @@ ui: undelete: Скасувати видалення list: Список unlist: Вилучити зі списку - unlisted: Unlisted + unlisted: Вилучене зі списку login: Увійти signup: Зареєструватися logout: Вийти verify: Підтвердити add_question: Додати питання - approve: Approve - reject: Reject + approve: Затвердити + reject: Відхилити skip: Пропустити discard_draft: Видалити чернетку - pinned: Pinned - all: All + pinned: Закріплено + all: Усі question: Запитання answer: Відповідь comment: Коментар refresh: Оновити resend: Надіслати повторно deactivate: Деактивувати - active: Active - suspend: Suspend - unsuspend: Unsuspend + active: Активні + suspend: Призупинити + unsuspend: Відновити close: Закрити reopen: Відкрити знову ok: ОК light: Світла dark: Темна system_setting: Налаштування системи - default: Default + default: За замовчуванням reset: Скинути - tag: Tag - post_lowercase: post - filter: Filter - ignore: Ignore - submit: Submit - normal: Normal - closed: Closed + tag: Тег + post_lowercase: допис + filter: Фільтр + ignore: Ігнорувати + submit: Надіслати + normal: Нормальний + closed: Закриті deleted: Видалені - pending: Pending - more: More + pending: Очікування + more: Більше search: title: Результати пошуку keywords: Ключові слова - options: Options + options: Параметри follow: Підписатися following: Підписані - counts: "{{count}} Results" - more: More + counts: "{{count}} Результатів" + more: Більше sort_btns: - relevance: Relevance - newest: Newest - active: Active - score: Score - more: More + relevance: Релевантність + newest: Найновіші + active: Активні + score: Оцінка + more: Більше tips: - title: Advanced Search Tips - tag: "<1>[tag] search with a tag" - user: "<1>user:username search by author" - answer: "<1>answers:0 unanswered questions" - score: "<1>score:3 posts with a 3+ score" - question: "<1>is:question search questions" - is_answer: "<1>is:answer search answers" - empty: We couldn't find anything.
      Try different or less specific keywords. + title: Підказки щодо розширеного пошуку + tag: "<1>[tag] шукати за тегом" + user: "<1>користувач:ім'я користувача пошук за автором" + answer: "<1>відповіді:0 питання без відповіді" + score: "<1>рахунок: 3 записи із 3+ рахунком" + question: "<1>є:питання пошукові питання" + is_answer: "<1>є:відповідь пошукові відповіді" + empty: Ми не змогли нічого знайти.
      Спробуйте різні або менш конкретні ключові слова. share: - name: Share - copy: Copy link - via: Share post via... - copied: Copied - facebook: Share to Facebook - twitter: Share to Twitter - cannot_vote_for_self: You can't vote for your own post. + name: Поділитись + copy: Копіювати посилання + via: Поділитися дописом через... + copied: Скопійовано + facebook: Поділитись на Facebook + twitter: Поділитися в Twitter + cannot_vote_for_self: Ви не можете проголосувати за власну публікацію. modal_confirm: title: Помилка... account_result: - success: Your new account is confirmed; you will be redirected to the home page. + success: Ваш новий обліковий запис підтверджено; вас буде перенаправлено на головну сторінку. link: Перейти на головну сторінку oops: Йой! - invalid: The link you used no longer works. - confirm_new_email: Your email has been updated. + invalid: Посилання, яке ви використовували, більше не працює. + confirm_new_email: Вашу адресу електронної пошти було оновлено. confirm_new_email_invalid: >- - Sorry, this confirmation link is no longer valid. Perhaps your email was already changed? + На жаль, це посилання для підтвердження більше не дійсне. Можливо, ваша електронна пошта вже була змінена? unsubscribe: - page_title: Unsubscribe - success_title: Unsubscribe Successful - success_desc: You have been successfully removed from this subscriber list and won't receive any further emails from us. - link: Change settings + page_title: Відписатися + success_title: Ви успішно відписалися + success_desc: Вас успішно вилучено з цього списку підписників, і ви більше не будете отримувати від нас електронні листи. + link: Змінити налаштування question: following_tags: Підписки на теги - edit: Edit + edit: Редагувати save: Зберегти follow_tag_tip: Підпишіться на теги, щоб упорядкувати свій список запитань. - hot_questions: Hot Questions + hot_questions: Гарячі питання all_questions: Всі питання - x_questions: "{{ count }} Questions" - x_answers: "{{ count }} answers" + x_questions: "{{ count }} Питань" + x_answers: "{{ count }} відповідей" questions: Запитання answers: Відповіді newest: Найновіші active: Активні - hot: Hot - recommend: Recommend + hot: Гаряче + frequent: Frequent + recommend: Рекомендовано score: Оцінка unanswered: Без відповідей - modified: modified - answered: answered - asked: asked - closed: closed + modified: змінено + answered: дано відповідь + asked: запитано + closed: закрито follow_a_tag: Підписатися на тег more: Більше personal: - overview: Overview + overview: Загальний огляд answers: Відповіді answer: відповідь questions: Запитання @@ -1541,77 +1547,77 @@ ui: reputation: Репутація comments: Коментарі votes: Голоси - badges: Badges + badges: Значки newest: Найновіше - score: Score + score: Оцінка edit_profile: Редагувати профіль - visited_x_days: "Visited {{ count }} days" - viewed: Viewed - joined: Joined + visited_x_days: "Відвідано {{ count }} днів" + viewed: Переглянуто + joined: Приєднано comma: "," - last_login: Seen + last_login: Переглянуто about_me: Про мене about_me_empty: "// Привіт, світ!" top_answers: Найкращі відповіді top_questions: Найкращі запитання stats: Статистика - list_empty: No posts found.
      Perhaps you'd like to select a different tab? - content_empty: No posts found. - accepted: Accepted - answered: answered - asked: asked - downvoted: downvoted + list_empty: Не знайдено жодного допису.
      Можливо, ви хочете вибрати іншу вкладку? + content_empty: Постів не знайдено. + accepted: Прийнято + answered: дано відповідь + asked: запитано + downvoted: проголосовано проти mod_short: MOD mod_long: Модератори x_reputation: репутація x_votes: отримані голоси x_answers: відповіді x_questions: запитання - recent_badges: Recent Badges + recent_badges: Нещодавні значки install: - title: Installation + title: Встановлення next: Далі - done: Done - config_yaml_error: Can't create the config.yaml file. + done: Готово + config_yaml_error: Не вдалося створити config.yaml файл. lang: label: Будь ласка, виберіть мову db_type: - label: Database engine + label: Рушій бази даних db_username: label: Ім'я користувача - placeholder: root - msg: Username cannot be empty. + placeholder: корінь + msg: Ім’я користувача не може бути порожнім. db_password: label: Пароль - placeholder: root + placeholder: корінь msg: Поле паролю не може бути порожнім. db_host: - label: Database host + label: Хост бази даних placeholder: "db:3306" - msg: Database host cannot be empty. + msg: Хост бази даних не може бути порожнім. db_name: - label: Database name - placeholder: answer - msg: Database name cannot be empty. + label: Назва бази даних + placeholder: відповідь + msg: Назва бази даних не може бути порожня. db_file: - label: Database file + label: Файл бази даних placeholder: /data/answer.db - msg: Database file cannot be empty. + msg: Файл бази даних не може бути порожнім. config_yaml: - title: Create config.yaml - label: The config.yaml file created. + title: Створити config.yaml + label: Файл config.yaml створено. desc: >- Ви можете створити файл <1>config.yaml вручну в каталозі <1>/var/www/xxx/ і вставити в нього наступний текст. - info: After you've done that, click "Next" button. - site_information: Site Information - admin_account: Admin Account + info: Після цього натисніть кнопку "Далі". + site_information: Інформація про сайт + admin_account: Обліковий запис адміністратора site_name: - label: Site name - msg: Site name cannot be empty. - msg_max_length: Site name must be at maximum 30 characters in length. + label: Назва сайту + msg: Назва сайту не може бути порожньою. + msg_max_length: Назва сайту повинна містити не більше 30 символів. site_url: - label: Site URL - text: The address of your site. + label: URL сайту + text: Адреса вашого сайту. msg: empty: URL-адреса сайту не може бути пустою. incorrect: Неправильний формат URL-адреси сайту. @@ -1623,8 +1629,8 @@ ui: empty: Контактна електронна адреса не може бути порожньою. incorrect: Неправильний формат контактної електронної пошти. login_required: - label: Private - switch: Login required + label: Приватний + switch: Вхід обов'язковий text: Лише авторизовані користувачі можуть отримати доступ до цієї спільноти. admin_name: label: Ім’я @@ -1643,118 +1649,120 @@ ui: text: Вам знадобиться ця електронна адреса для входу. msg: empty: Поле електронної пошти не може бути пустим. - incorrect: Email incorrect format. - ready_title: Your site is ready + incorrect: Невірний формат електронної пошти. + ready_title: Ваш сайт готовий ready_desc: >- - If you ever feel like changing more settings, visit <1>admin section; find it in the site menu. + Якщо ви коли-небудь захочете змінити інші налаштування, відвідайте <1>розділ адміністрування; знайдіть його в меню сайту. good_luck: "Веселіться, і хай щастить!" - warn_title: Warning + warn_title: Попередження warn_desc: >- - The file <1>config.yaml already exists. If you need to reset any of the configuration items in this file, please delete it first. - install_now: You may try <1>installing now. + Файл <1>config.yaml вже існує. Якщо вам потрібно скинути будь-який з елементів конфігурації в цьому файлі, будь ласка, спочатку видаліть його. + install_now: Ви можете спробувати <1>встановити зараз. installed: Уже встановлено installed_desc: >- Ви, здається, уже встановили. Щоб перевстановити, спочатку очистіть старі таблиці бази даних. - db_failed: Database connection failed + db_failed: Не вдалося встановити з'єднання з базою даних db_failed_desc: >- - This either means that the database information in your <1>config.yaml file is incorrect or that contact with the database server could not be established. This could mean your host's database server is down. + Це означає, що інформація про базу даних у вашому файлі <1>config.yaml невірна або що не вдалося встановити контакт із сервером бази даних. Це може означати, що сервер бази даних вашого хоста не працює. counts: - views: views - votes: votes - answers: answers + views: перегляди + votes: голоси + answers: відповіді accepted: Схвалено page_error: - http_error: HTTP Error {{ code }} - desc_403: You don't have permission to access this page. - desc_404: Unfortunately, this page doesn't exist. - desc_50X: The server encountered an error and could not complete your request. - back_home: Back to homepage + http_error: Помилка HTTP {{ code }} + desc_403: Ви не маєте дозволу на доступ до цієї сторінки. + desc_404: На жаль, такої сторінки не існує. + desc_50X: Сервер виявив помилку і не зміг виконати ваш запит. + back_home: Повернутися на головну сторінку page_maintenance: - desc: "We are under maintenance, we'll be back soon." + desc: "Ми технічно обслуговуємось, ми скоро повернемося." nav_menus: - dashboard: Dashboard - contents: Contents - questions: Questions - answers: Answers - users: Users - badges: Badges + dashboard: Панель + contents: Зміст + questions: Питання + answers: Відповіді + users: Користувачі + badges: Значки flags: Відмітки settings: Налаштування - general: General - interface: Interface + general: Основне + interface: Інтерфейс smtp: SMTP - branding: Branding - legal: Legal + branding: Брендинг + legal: Правила та умови write: Написати - tos: Terms of Service - privacy: Privacy + tos: Умови використання + privacy: Приватність seo: SEO customize: Персоналізувати - themes: Themes + themes: Теми css_html: CSS/HTML - login: Login - privileges: Privileges - plugins: Plugins - installed_plugins: Installed Plugins - website_welcome: Welcome to {{site_name}} + login: Вхід + privileges: Привілеї + plugins: Плагіни + installed_plugins: Встановлені плагіни + website_welcome: Ласкаво просимо до {{site_name}} user_center: - login: Login - qrcode_login_tip: Please use {{ agentName }} to scan the QR code and log in. - login_failed_email_tip: Login failed, please allow this app to access your email information before try again. + login: Вхід + qrcode_login_tip: Будь ласка, використовуйте {{ agentName }}, щоб просканувати QR-код і увійти в систему. + login_failed_email_tip: Не вдалося увійти, будь ласка, дозвольте цьому додатку отримати доступ до вашої електронної пошти, перш ніж спробувати ще раз. badges: modal: - title: Congratulations - content: You've earned a new badge. + title: Вітаємо + content: Ти отримав новий значок. close: Закрити - confirm: View badges - title: Badges - awarded: Awarded - earned_×: Earned ×{{ number }} - ×_awarded: "{{ number }} awarded" - can_earn_multiple: You can earn this multiple times. + confirm: Переглянути значки + title: Значки + awarded: Присвоєно + earned_×: Зароблено ×{{ number }} + ×_awarded: "Присвоєно {{ number }}" + can_earn_multiple: Ви можете заробити це багато разів. earned: Зароблено admin: admin_header: title: Адмін dashboard: - title: Dashboard - welcome: Welcome to Admin! - site_statistics: Site statistics + title: Панель + welcome: Ласкаво просимо до адміністратора! + site_statistics: Статистика сайту questions: "Запитання:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Відповіді:" comments: "Коментарі:" votes: "Голоси:" users: "Користувачі:" flags: "Відмітки:" - reviews: "Reviews:" - site_health: Site health - version: "Version:" + reviews: "Відгуки:" + site_health: Стан сайту + version: "Версія:" https: "HTTPS:" upload_folder: "Завантажити теку:" - run_mode: "Running mode:" - private: Private - public: Public + run_mode: "Активний режим:" + private: Приватний + public: Публічний smtp: "SMTP:" timezone: "Часовий пояс:" system_info: Інформація про систему - go_version: "Go version:" + go_version: "Перейти до версії:" database: "База даних:" database_size: "Розмір бази даних:" storage_used: "Використаний обсяг пам’яті:" - uptime: "Uptime:" + uptime: "Час роботи:" links: Посилання plugins: Плаґіни github: GitHub blog: Блоґ contact: Контакт - forum: Forum + forum: Форум documents: Документи feedback: Відгук support: Підтримка - review: Review + review: Огляд config: Конфігурація - update_to: Update to - latest: Latest + update_to: Оновити до + latest: Останній check_failed: Не вдалося перевірити "yes": "Так" "no": "Ні" @@ -1762,8 +1770,8 @@ ui: allowed: Дозволено enabled: Увімкнено disabled: Вимкнено - writable: Writable - not_writable: Not writable + writable: Записуваний + not_writable: Не можна записувати flags: title: Відмітки pending: В очікуванні @@ -1774,7 +1782,7 @@ ui: action: Дія review: Огляд user_role_modal: - title: Change user role to... + title: Змінити роль користувача на... btn_cancel: Скасувати btn_submit: Надіслати new_password_modal: @@ -1783,8 +1791,8 @@ ui: fields: password: label: Пароль - text: The user will be logged out and need to login again. - msg: Password must be at 8-32 characters in length. + text: Користувача буде виведено з системи, і йому потрібно буде увійти знову. + msg: Пароль повинен мати довжину від 8 до 32 символів. btn_cancel: Скасувати btn_submit: Надіслати edit_profile_modal: @@ -1792,15 +1800,15 @@ ui: form: fields: display_name: - label: Display name - msg_range: Display name up to 30 characters. + label: Зображуване ім'я + msg_range: Зображуване ім'я до 30 символів. username: - label: Username - msg_range: Username up to 30 characters. + label: Ім'я користувача + msg_range: Ім'я користувача до 30 символів. email: label: Електронна пошта - msg_invalid: Invalid Email Address. - edit_success: Edited successfully + msg_invalid: Невірна адреса електронної пошти. + edit_success: Успішно відредаговано btn_cancel: Скасувати btn_submit: Надіслати user_modal: @@ -1808,50 +1816,50 @@ ui: form: fields: users: - label: Bulk add user - placeholder: "John Smith, john@example.com, BUSYopr2\nAlice, alice@example.com, fpDntV8q" - text: Separate “name, email, password” with commas. One user per line. - msg: "Please enter the user's email, one per line." + label: Масове додавання користувача + placeholder: "Джон Сміт, john@example.com, BUSYopr2\nАліса, alice@example.com, fpDntV8q" + text: '“Ім''я, електронну пошту, пароль” розділити комами. Один користувач у рядку.' + msg: "Будь ласка, введіть електронну пошту користувача, по одній на рядок." display_name: label: Ім'я для відображення - msg: Ім'я для відображення повинно мати довжину від 2 до 30 символів. + msg: Ім'я для показу повинно мати довжину від 2 до 30 символів. email: label: Електронна пошта - msg: Email is not valid. + msg: Електронна пошта недійсна. password: label: Пароль - msg: Password must be at 8-32 characters in length. + msg: Пароль повинен мати довжину від 8 до 32 символів. btn_cancel: Скасувати btn_submit: Надіслати users: title: Користувачі name: Ім’я email: Електронна пошта - reputation: Reputation - created_at: Created Time - delete_at: Deleted Time + reputation: Репутація + created_at: Створений час + delete_at: Видалений час suspend_at: Час призупинення status: Статус role: Роль - action: Action - change: Change - all: All - staff: Staff + action: Дія + change: Зміна + all: Усі + staff: Персонал more: Більше - inactive: Inactive - suspended: Suspended - deleted: Deleted - normal: Normal + inactive: Неактивні + suspended: Призупинено + deleted: Видалено + normal: Нормальний Moderator: Модератор Admin: Адмін User: Користувач filter: - placeholder: "Filter by name, user:id" + placeholder: "Фільтр на ім'я, користувач:id" set_new_password: Встановити новий пароль - edit_profile: Edit profile + edit_profile: Редагувати профіль change_status: Змінити статус change_role: Змінити роль - show_logs: Show logs + show_logs: Показати записи журналу add_user: Додати користувача deactivate_user: title: Деактивувати користувача @@ -1859,72 +1867,72 @@ ui: delete_user: title: Видалити цього користувача content: Ви впевнені, що хочете видалити цього користувача? Це назавжди! - remove: Remove their content + remove: Вилучити їх вміст label: Видалити всі запитання, відповіді, коментарі тощо. - text: Don’t check this if you wish to only delete the user’s account. + text: Не позначайте цю опцію, якщо ви хочете лише видалити обліковий запис користувача. suspend_user: title: Призупинити цього користувача content: Призупинений користувач не може увійти в систему. questions: page_title: Запитання - unlisted: Unlisted + unlisted: Вилучене зі списку post: Опублікувати - votes: Votes - answers: Answers + votes: Голоси + answers: Відповіді created: Створені status: Статус - action: Action - change: Change - pending: Pending + action: Дія + change: Зміна + pending: Очікування filter: - placeholder: "Filter by title, question:id" + placeholder: "Фільтр за назвою, питання:id" answers: page_title: Відповіді - post: Post - votes: Votes - created: Created + post: Допис + votes: Голоси + created: Створено status: Статус - action: Action - change: Change + action: Дія + change: Зміна filter: - placeholder: "Filter by title, answer:id" + placeholder: "Фільтр за назвою, відповідь:id" general: - page_title: General + page_title: Основне name: - label: Site name - msg: Site name cannot be empty. - text: "The name of this site, as used in the title tag." + label: Назва сайту + msg: Назва сайту не може бути порожньою. + text: "Назва цього сайту як зазначено у заголовку тегу." site_url: - label: Site URL - msg: Site url cannot be empty. - validate: Please enter a valid URL. - text: The address of your site. + label: URL сайту + msg: Url сайту не може бути порожньою. + validate: Будь ласка, введіть дійсну URL. + text: Адреса вашого сайту. short_desc: - label: Short site description - msg: Short site description cannot be empty. - text: "Short description, as used in the title tag on homepage." + label: Короткий опис сайту + msg: Короткий опис сайту не може бути пустим. + text: "Короткий опис, як використовується в заголовку на головній сторінці." desc: - label: Site description - msg: Site description cannot be empty. - text: "Describe this site in one sentence, as used in the meta description tag." + label: Опис сайту + msg: Опис сайту не може бути порожнім. + text: "Опишіть цей сайт одним реченням, як у тезі метаопису." contact_email: - label: Contact email - msg: Contact email cannot be empty. - validate: Contact email is not valid. - text: Email address of key contact responsible for this site. + label: Контактна електронна пошта + msg: Контактна електронна пошта не може бути порожньою. + validate: Контактна електронна пошта недійсна. + text: Адреса електронної пошти ключової особи, відповідальної за цей сайт. check_update: - label: Software updates - text: Automatically check for updates + label: Оновлення програмного забезпечення + text: Автоматично перевіряти оновлення interface: - page_title: Interface + page_title: Інтерфейс language: - label: Interface language - msg: Interface language cannot be empty. - text: User interface language. It will change when you refresh the page. + label: Мова інтерфейсу + msg: Мова інтерфейсу не може бути пустою. + text: Мова інтерфейсу користувача. Зміниться, коли ви оновите сторінку. time_zone: - label: Timezone - msg: Timezone cannot be empty. - text: Choose a city in the same timezone as you. + label: Часовий пояс + msg: Часовий пояс не може бути пустим. + text: Виберіть місто в тому ж часовому поясі, що й ви. smtp: page_title: SMTP from_email: @@ -1934,56 +1942,56 @@ ui: from_name: label: Від імені msg: Поле від імені не може бути пустим. - text: The name which emails are sent from. + text: Ім'я, з якого надсилаються електронні листи. smtp_host: - label: SMTP host - msg: SMTP host cannot be empty. + label: SMTP-хост + msg: SMTP хост не може бути порожнім. text: Ваш поштовий сервер. encryption: label: Шифрування msg: Поле шифрування не може бути пустим. - text: For most servers SSL is the recommended option. + text: Для більшості серверів SSL є рекомендованим параметром. ssl: SSL tls: TLS - none: None + none: Нічого smtp_port: - label: SMTP port - msg: SMTP port must be number 1 ~ 65535. - text: The port to your mail server. + label: SMTP порт + msg: SMTP порт має бути числом 1 ~ 65535. + text: Порт на ваш поштовий сервер. smtp_username: - label: SMTP username - msg: SMTP username cannot be empty. + label: Ім'я користувача SMTP + msg: Ім'я користувача SMTP не може бути порожнім. smtp_password: - label: SMTP password - msg: SMTP password cannot be empty. + label: Пароль SMTP + msg: Пароль до SMTP не може бути порожнім. test_email_recipient: - label: Test email recipients + label: Тест отримувачів електронної пошти text: Вкажіть адресу електронної пошти, на яку будуть надходити тестові надсилання. - msg: Test email recipients is invalid + msg: Тест отримувачів електронної пошти не вірний smtp_authentication: label: Увімкнути автентифікацію - title: SMTP authentication - msg: SMTP authentication cannot be empty. + title: SMTP аутентифікація + msg: SMTP аутентифікація не може бути порожньою. "yes": "Так" "no": "Ні" branding: - page_title: Branding + page_title: Брендинг logo: - label: Logo - msg: Logo cannot be empty. - text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown. + label: Логотип + msg: Логотип не може бути порожнім. + text: Зображення логотипу у верхньому лівому кутку вашого сайту. Використовуйте широке прямокутне зображення з висотою 56 і співвідношенням сторін більше 3:1. Якщо залишити це поле порожнім, буде показано текст заголовка сайту. mobile_logo: - label: Mobile logo - text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the "logo" setting will be used. + label: Мобільний логотип + text: Логотип, що використовується на мобільній версії вашого сайту. Використовуйте широке прямокутне зображення висотою 56. Якщо залишити поле порожнім, буде використано зображення з налаштування "логотип". square_icon: - label: Square icon - msg: Square icon cannot be empty. - text: Image used as the base for metadata icons. Should ideally be larger than 512x512. + label: Квадратна іконка + msg: Квадратна іконка не може бути пустою. + text: Зображення, що використовується як основа для іконок метаданих. В ідеалі має бути більшим за 512x512. favicon: label: Favicon - text: A favicon for your site. To work correctly over a CDN it must be a png. Will be resized to 32x32. If left blank, "square icon" will be used. + text: Іконка для вашого сайту. Для коректної роботи через CDN має бути у форматі png. Буде змінено розмір до 32x32. Якщо залишити порожнім, буде використовуватися "квадратна іконка". legal: - page_title: Legal + page_title: Правила та умови terms_of_service: label: Умови використання text: "Ви можете додати вміст про умови використання тут. Якщо у вас уже є документ, розміщений деінде, надайте тут повну URL-адресу." @@ -1993,229 +2001,257 @@ ui: write: page_title: Написати restrict_answer: - title: Answer write + title: Відповідь на запис label: Кожен користувач може написати лише одну відповідь на кожне запитання - text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused." + text: "Вимкнути, щоб дозволити користувачам писати кілька відповідей на одне і те ж питання, що може призвести до розфокусування відповідей." recommend_tags: - label: Recommend tags - text: "Recommend tags will show in the dropdown list by default." + label: Рекомендовані теги + text: "За замовчуванням рекомендовані теги будуть показані у спадному списку." msg: - contain_reserved: "recommended tags cannot contain reserved tags" + contain_reserved: "рекомендовані теги не можуть містити зарезервовані теги" required_tag: - title: Set required tags - label: Set “Recommend tags” as required tags - text: "Every new question must have at least one recommend tag." + title: Встановіть необхідні теги + label: Встановіть “Рекомендовані теги” як необхідні теги + text: "Кожне нове питання повинно мати принаймні один рекомендований тег." reserved_tags: - label: Reserved tags - text: "Reserved tags can only be used by moderator." + label: Зарезервовані теги + text: "Зарезервовані теги можуть використовуватися лише модератором." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: - label: Permalink - text: Custom URL structures can improve the usability, and forward-compatibility of your links. + label: Постійне посилання + text: Користувацькі структури URL можуть покращити уміння та сумісність з надсиланням посилань. robots: label: robots.txt - text: This will permanently override any related site settings. + text: Це назавжди замінить будь-які відповідні налаштування сайту. themes: - page_title: Themes + page_title: Теми themes: - label: Themes - text: Select an existing theme. + label: Теми + text: Виберіть наявну тему. color_scheme: - label: Color scheme + label: Схема кольорів navbar_style: - label: Navbar style + label: Стиль панелі навігації primary_color: label: Основний колір - text: Modify the colors used by your themes + text: Змінюйте кольори, що використовуються у ваших темах css_and_html: - page_title: CSS and HTML + page_title: CSS та HTML custom_css: - label: Custom CSS + label: Користувацький CSS text: > head: - label: Head + label: Головний text: > header: - label: Header + label: Заголовок text: > footer: - label: Footer - text: This will insert before </body>. + label: Низ + text: Це вставить перед </body>. sidebar: - label: Sidebar - text: This will insert in sidebar. + label: Бічна панель + text: Це буде вставлено в бічну панель. login: page_title: Увійти membership: - title: Membership + title: Членство label: Дозволити нові реєстрації - text: Turn off to prevent anyone from creating a new account. + text: Вимкнути, щоб ніхто не міг створити новий обліковий запис. email_registration: title: Реєстрація за електронною поштою label: Дозволити реєстрацію за електронною поштою - text: Turn off to prevent anyone creating new account through email. + text: Вимкніть, щоб запобігти створенню нових облікових записів через електронну пошту. allowed_email_domains: - title: Allowed email domains - text: Email domains that users must register accounts with. One domain per line. Ignored when empty. + title: Дозволені домени електронної пошти + text: Домени електронної пошти, на які користувачі повинні зареєструвати облікові записи. Один домен у рядку. Ігнорується, якщо порожній. private: - title: Private - label: Login required - text: Only logged in users can access this community. + title: Приватний + label: Вхід обов'язковий + text: Доступ до цієї спільноти мають лише зареєстровані користувачі. password_login: - title: Password login - label: Allow email and password login - text: "WARNING: If turn off, you may be unable to log in if you have not previously configured other login method." + title: Вхід через пароль + label: Дозволити вхід через електронну пошту і пароль + text: "ПОПЕРЕДЖЕННЯ: Якщо вимкнути, ви не зможете увійти в систему, якщо раніше не налаштували інший метод входу." installed_plugins: - title: Installed Plugins - plugin_link: Plugins extend and expand the functionality. You may find plugins in the <1>Plugin Repository. + title: Встановлені плагіни + plugin_link: Плагіни розширюють і поглиблюють функціональність. Ви можете знайти плагіни у <1>Сховищі плагінів. filter: - all: All - active: Active - inactive: Inactive - outdated: Outdated + all: Усі + active: Активні + inactive: Неактивні + outdated: Застарілі plugins: - label: Plugins - text: Select an existing plugin. + label: Плагіни + text: Виберіть наявний плагін. name: Ім’я - version: Version - status: Status - action: Action - deactivate: Deactivate - activate: Activate + version: Версія + status: Статус + action: Дія + deactivate: Деактивувати + activate: Активувати settings: Налаштування settings_users: title: Користувачі avatar: - label: Default avatar - text: For users without a custom avatar of their own. + label: Аватар за замовчуванням + text: Для користувачів без аватара власного. gravatar_base_url: - label: Gravatar base URL - text: URL of the Gravatar provider's API base. Ignored when empty. + label: Основна URL Gravatar + text: URL бази API постачальника Gravatar. Ігнорується, якщо порожній. profile_editable: - title: Profile editable + title: Профіль можна редагувати allow_update_display_name: label: Дозволити користувачам змінювати ім'я для відображення allow_update_username: - label: Allow users to change their username + label: Дозволити користувачам змінювати своє ім'я користувача allow_update_avatar: - label: Allow users to change their profile image + label: Дозволити користувачам змінювати зображення свого профілю allow_update_bio: - label: Allow users to change their about me + label: Дозволити користувачам змінювати дані про себе allow_update_website: - label: Allow users to change their website + label: Дозволити користувачам змінювати свій вебсайт allow_update_location: - label: Allow users to change their location + label: Дозволити користувачам змінювати своє місцеперебування privilege: - title: Privileges + title: Привілеї level: - label: Reputation required level - text: Choose the reputation required for the privileges + label: Рівень репутації необхідний + text: Виберіть репутацію, необхідну для привілеїв msg: - should_be_number: the input should be number - number_larger_1: number should be equal or larger than 1 + should_be_number: введення має бути числом + number_larger_1: число має бути рівним або більшим за 1 badges: - action: Action - active: Active - activate: Activate - all: All - awards: Awards - deactivate: Deactivate + action: Дія + active: Активні + activate: Активувати + all: Усі + awards: Нагороди + deactivate: Деактивувати filter: - placeholder: Filter by name, badge:id - group: Group - inactive: Inactive + placeholder: Фільтрувати за іменем, значок:id + group: Група + inactive: Неактивні name: Ім’я - show_logs: Show logs - status: Status - title: Badges + show_logs: Показати записи журналу + status: Статус + title: Значки form: - optional: (optional) + optional: (необов'язково) empty: не може бути порожнім - invalid: is invalid + invalid: недійсне btn_submit: Зберегти - not_found_props: "Required property {{ key }} not found." + not_found_props: "Необхідний параметр {{ key }} не знайдено." select: Вибрати page_review: - review: Review - proposed: proposed - question_edit: Question edit - answer_edit: Answer edit - tag_edit: Tag edit - edit_summary: Edit summary - edit_question: Edit question - edit_answer: Edit answer - edit_tag: Edit tag - empty: No review tasks left. - approve_revision_tip: Do you approve this revision? + review: Огляд + proposed: запропоновано + question_edit: Редагування питання + answer_edit: Редагування відповіді + tag_edit: Редагування тегу + edit_summary: Редагувати звіт + edit_question: Редагувати питання + edit_answer: Редагувати відповідь + edit_tag: Редагувати тег + empty: Не залишилось завдань огляду. + approve_revision_tip: Ви схвалюєте цю редакцію? approve_flag_tip: Ви схвалюєте цю відмітку? - approve_post_tip: Do you approve this post? - approve_user_tip: Do you approve this user? - suggest_edits: Suggested edits + approve_post_tip: Ви схвалюєте цей допис? + approve_user_tip: Ви схвалюєте цього користувача? + suggest_edits: Запропоновані зміни flag_post: Відмітити публікацію flag_user: Відмітити користувача - queued_post: Queued post - queued_user: Queued user - filter_label: Type - reputation: reputation + queued_post: Черговий допис + queued_user: Черговий користувач + filter_label: Тип + reputation: репутація flag_post_type: Відмічено цей пост як {{ type }}. flag_user_type: Відмічено цього користувача як {{ type }}. - edit_post: Edit post - list_post: List post - unlist_post: Unlist post + edit_post: Редагувати допис + list_post: Додати допис до списку + unlist_post: Видалити допис зі списку timeline: - undeleted: undeleted - deleted: deleted - downvote: downvote - upvote: upvote - accept: accept - cancelled: cancelled - commented: commented - rollback: rollback - edited: edited - answered: answered - asked: asked - closed: closed - reopened: reopened - created: created - pin: pinned - unpin: unpinned - show: listed - hide: unlisted - title: "History for" - tag_title: "Timeline for" - show_votes: "Show votes" - n_or_a: N/A - title_for_question: "Timeline for" - title_for_answer: "Timeline for answer to {{ title }} by {{ author }}" - title_for_tag: "Timeline for tag" - datetime: Datetime - type: Type - by: By - comment: Comment - no_data: "We couldn't find anything." + undeleted: не видалений + deleted: видалений + downvote: голос "проти" + upvote: голос "за" + accept: прийняти + cancelled: скасовано + commented: прокоментовано + rollback: відкат назад + edited: відредаговано + answered: дано відповідь + asked: запитано + closed: закрито + reopened: знову відкрито + created: створено + pin: закріплено + unpin: відкріплено + show: додано до списку + hide: не внесено до списку + title: "Історія для" + tag_title: "Хронологія для" + show_votes: "Показати голоси" + n_or_a: Н/Д + title_for_question: "Хронологія для" + title_for_answer: "Часова шкала для відповіді на {{ title }} від {{ author }}" + title_for_tag: "Часова шкала для тега" + datetime: Дата й час + type: Тип + by: Від + comment: Коментар + no_data: "Ми не змогли нічого знайти." users: - title: Users - users_with_the_most_reputation: Users with the highest reputation scores this week - users_with_the_most_vote: Users who voted the most this week - staffs: Our community staff - reputation: reputation - votes: votes + title: Користувачі + users_with_the_most_reputation: Користувачі з найвищою репутацією на цьому тижні + users_with_the_most_vote: Користувачі, які голосували за найбільше цього тижня + staffs: Персонал нашої спільноти + reputation: репутація + votes: голоси prompt: - leave_page: Are you sure you want to leave the page? - changes_not_save: Your changes may not be saved. + leave_page: Ви дійсно хочете покинути сторінку? + changes_not_save: Ваші зміни можуть не зберегтися. draft: - discard_confirm: Are you sure you want to discard your draft? + discard_confirm: Ви дійсно бажаєте скасувати чернетку? messages: - post_deleted: This post has been deleted. - post_pin: This post has been pinned. - post_unpin: This post has been unpinned. - post_hide_list: This post has been hidden from list. - post_show_list: This post has been shown to list. - post_reopen: This post has been reopened. - post_list: This post has been listed. - post_unlist: This post has been unlisted. - post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_deleted: Цей допис було видалено. + post_cancel_deleted: This post has been undeleted. + post_pin: Цей допис було закріплено. + post_unpin: Цей допис було відкріплено. + post_hide_list: Цей допис було приховано зі списку. + post_show_list: Цей допис було показано у списку. + post_reopen: Цей допис було знову відкрито. + post_list: Цей допис було додано до списку. + post_unlist: Цей допис було приховано. + post_pending: Ваш допис очікує на розгляд. Це попередній перегляд, його буде видно після того, як його буде схвалено. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/vi_VN.yaml b/i18n/vi_VN.yaml index 495d9333..247fd2e0 100644 --- a/i18n/vi_VN.yaml +++ b/i18n/vi_VN.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Xác nhận địa chỉ email mới của bạn" body: - other: "Xác nhận địa chỉ email mới của bạn cho {{.SiteName}} bằng cách nhấp vào liên kết sau:
      \n{{.ChangeEmailUrl}}

      \n\nNếu bạn không yêu cầu thay đổi này, vui lòng bỏ qua email này.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} đã trả lời câu hỏi của bạn" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nXem trên {{.SiteName}}

      \n\n--
      \nHủy đăng ký" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} mời bạn trả lời" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      Tôi nghĩ bạn có thể biết câu trả lời.

      \nXem trên {{.SiteName}}

      \n\n--
      \nHủy đăng ký" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} đã bình luận về bài đăng của bạn" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nXem trên {{.SiteName}}

      \n\n--
      \nHủy đăng ký" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] Câu hỏi mới: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nHủy đăng ký" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName}}] Đặt lại mật khẩu" body: - other: "Ai đó đã yêu cầu đặt lại mật khẩu của bạn trên {{.SiteName}}.

      \n\nNếu đó không phải là bạn, bạn có thể bỏ qua email này.

      \n\nNhấp vào liên kết sau để chọn một mật khẩu mới:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Xác nhận tài khoản mới của bạn" body: - other: "Chào mừng bạn đến với {{.SiteName}}!

      \n\nNhấp vào liên kết sau để xác nhận và kích hoạt tài khoản mới của bạn:
      \n{{.RegisterUrl}}

      \n\nNếu liên kết trên không thể nhấp, hãy thử sao chép và dán nó vào thanh địa chỉ của trình duyệt web của bạn.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Email kiểm tra" body: - other: "Đây là một email kiểm tra." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: bình chọn lên @@ -787,7 +787,7 @@ ui: how_to_format: title: Cách định dạng desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: Trước next: Tiếp @@ -904,7 +904,7 @@ ui: msg: empty: Tệp không thể trống. only_image: Chỉ cho phép tệp hình ảnh. - max_size: Kích thước tệp không vượt quá 4 MB. + max_size: File size cannot exceed {{size}} MB. desc: label: Mô tả tab_url: URL hình ảnh @@ -946,6 +946,10 @@ ui: text: Bảng heading: Tiêu đề cell: Ô + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: Tôi đang đóng bài đăng này với lý do... btn_cancel: Hủy @@ -1086,6 +1090,7 @@ ui: search_placeholder: Lọc theo tên thẻ no_desc: Thẻ không có mô tả. more: Thêm + wiki: Wiki ask: title: Thêm Câu hỏi edit_title: Chỉnh sửa Câu hỏi @@ -1522,6 +1527,7 @@ ui: newest: Mới nhất active: Hoạt động hot: Được nhiều quan tâm + frequent: Frequent recommend: Đề xuất score: Điểm unanswered: Chưa được trả lời @@ -1721,6 +1727,8 @@ ui: welcome: Chào mừng bạn đến với Answer Admin! site_statistics: Thống kê trang questions: "Câu hỏi:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "Câu trả lời:" comments: "Bình luận:" votes: "Phiếu bầu:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Thẻ dành riêng text: "Thẻ dành riêng chỉ có thể được thêm vào một bài đăng bởi điều hành viên." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: SEO permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Bạn có chắc chắn muốn hủy bản nháp của mình không? messages: post_deleted: Bài đăng này đã bị xóa. + post_cancel_deleted: This post has been undeleted. post_pin: Bài đăng này đã được ghim. post_unpin: Bài đăng này đã bị bỏ ghim. post_hide_list: Bài đăng này đã được ẩn khỏi danh sách. @@ -2219,3 +2243,15 @@ ui: post_list: Bài đăng này đã được liệt kê. post_unlist: Bài đăng này đã được gỡ bỏ khỏi danh sách. post_pending: Bài đăng của bạn đang chờ xem xét. Đây là bản xem trước, nó sẽ được hiển thị sau khi được phê duyệt. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + diff --git a/i18n/zh_CN.yaml b/i18n/zh_CN.yaml index d0feebb9..07f8d2ea 100644 --- a/i18n/zh_CN.yaml +++ b/i18n/zh_CN.yaml @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] 确认你的新邮箱地址" body: - other: "请点击以下链接确认你在 {{.SiteName}} 上的新邮箱地址:
      \n{{.ChangeEmailUrl}}

      \n\n如果你没有请求此更改,请忽略此邮件。\n" + other: "请点击以下链接确认你在 {{.SiteName}} 上的新邮箱地址:
      \n{{.ChangeEmailUrl}}

      \n\n如果你没有请求此更改,请忽略此邮件。\n\n--
      \n这是系统自动发送的电子邮件,请勿回复,因为您的回复将不会被看到

      " new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} 回答了你的问题" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \n在 {{.SiteName}} 上查看

      \n\n--
      \n取消订阅" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \n在 {{.SiteName}} 上查看

      \n\n--
      \n这是系统自动发送的电子邮件,请勿回复,因为您的回复将不会被看到

      \n\n取消订阅" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} 邀请您回答问题" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      我想你可能知道答案。

      \n在 {{.SiteName}} 上查看

      \n\n--
      \n取消订阅" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      我想你可能知道答案。

      \n在 {{.SiteName}} 上查看

      \n\n--
      \n这是系统自动发送的电子邮件,请勿回复,因为您的回复将不会被看到

      \n\n取消订阅" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} 评论了你的帖子" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \n在 {{.SiteName}} 上查看

      \n\n--
      \n取消订阅" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \n在 {{.SiteName}} 上查看

      \n\n--
      \n这是系统自动发送的电子邮件,请勿回复,因为您的回复将不会被看到

      \n\n取消订阅" new_question: title: other: "[{{.SiteName}}] 新问题: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \n取消订阅" + other: "{{.QuestionTitle}}

      \n{{.Tags}}

      \n\n--
      \n这是系统自动发送的电子邮件,请勿回复,因为您的回复将不会被看到

      \n\n取消订阅" pass_reset: title: other: "[{{.SiteName }}] 重置密码" body: - other: "有人要求在 [{{.SiteName}}] 上重置你的密码。

      \n\n如果这不是你的操作,请安心忽略此电子邮件。

      \n\n请点击以下链接设置一个新密码:
      \n{{.PassResetUrl}}\n" + other: "有人要求在 [{{.SiteName}}] 上重置你的密码。

      \n\n如果这不是你的操作,请安心忽略此电子邮件。

      \n\n请点击以下链接设置一个新密码:
      \n{{.PassResetUrl}}\n\n如果你没有请求此更改,请忽略此邮件。\n" register: title: other: "[{{.SiteName}}] 确认你的新账户" body: - other: "欢迎加入 {{.SiteName}}!

      \n\n请点击以下链接确认并激活你的新账户:
      \n{{.RegisterUrl}}

      \n\n如果上面的链接不能点击,请将其复制并粘贴到你的浏览器地址栏中。\n" + other: "欢迎加入 {{.SiteName}}!

      \n\n请点击以下链接确认并激活你的新账户:
      \n{{.RegisterUrl}}

      \n\n如果上面的链接不能点击,请将其复制并粘贴到你的浏览器地址栏中。\n

      \n\n--
      \n这是系统自动发送的电子邮件,请勿回复,因为您的回复将不会被看到" test: title: other: "[{{.SiteName}}] 测试邮件" body: - other: "这是一封测试邮件。" + other: "这是测试电子邮件。\n

      \n\n-
      \n注意:这是一个自动的系统电子邮件, 请不要回复此消息,因为您的回复将不会被看到。" action_activity_type: upvote: other: 点赞 @@ -787,7 +787,7 @@ ui: how_to_format: title: 如何排版 desc: >- -
      • 引用问题或答案: #10010000000000001

      • 添加链接

        <https://url.com>

        [标题](https://url.com)
      • 段落之间使用空行分隔

      • _斜体_ 或者 **粗体**

      • 使用 4 个空格缩进代码

      • 在行首添加 > 表示引用

      • 反引号进行转义 `像 _这样_`

      • 使用 ``` 创建代码块

        ```
        这是代码块
        ```
      +
      • 引用问题或答案: #post_id

      • 添加链接

        <https://url.com>

        [标题](https://url.com)
      • 段落之间使用空行分隔

      • _斜体_ 或者 **粗体**

      • 使用 个空格缩进代码

      • 在行首添加 > 表示引用

      • 反引号进行转义 `像 _这样_`

      • 使用 ``` 创建代码块

        ```
        这是代码块
        ```
      pagination: prev: 上一页 next: 下一页 @@ -904,7 +904,7 @@ ui: msg: empty: 请选择图片文件。 only_image: 只能上传图片文件。 - max_size: 文件大小不能超过 4 MB。 + max_size: 文件大小不能超过 {{size}} MB。 desc: label: 描述 tab_url: 图片地址 @@ -946,6 +946,10 @@ ui: text: 表格 heading: 表头 cell: 单元格 + file: + text: 附件 + not_supported: "不支持的文件类型。请尝试上传其他类型的文件如: {{file_type}}。" + max_size: "上传文件超过 {{size}} MB。" close_modal: title: 关闭原因是... btn_cancel: 取消 @@ -1523,6 +1527,7 @@ ui: newest: 最新 active: 活跃 hot: 热门 + frequent: 频繁的 recommend: 推荐 score: 评分 unanswered: 未回答 @@ -1557,7 +1562,7 @@ ui: top_questions: 高分问题 stats: 状态 list_empty: 没有找到相关的内容。
      试试看其他选项卡? - content_empty: 没有找到相关的内容。 + content_empty: 未找到帖子。 accepted: 已采纳 answered: 回答于 asked: 提问于 @@ -1723,7 +1728,7 @@ ui: site_statistics: 站点统计 questions: "问题:" resolved: "已解决:" - unanswered: "未回复:" + unanswered: "未回答:" answers: "回答:" comments: "评论:" votes: "投票:" @@ -2011,6 +2016,21 @@ ui: reserved_tags: label: 保留标签 text: "只有版主才能使用保留的标签。" + image_size: + label: 最大图像大小 (MB) + text: "最大图像上传大小." + attachment_size: + label: 最大附件大小 (MB) + text: "最大附件文件上传大小。" + image_megapixels: + label: 最大图像兆像素 + text: "允许图像的最大兆位数。" + image_extensions: + label: 允许的图像后缀 + text: "允许图像显示的文件扩展名的列表,用英文逗号分隔。" + attachment_extensions: + label: 允许的附件后缀 + text: "允许上传的文件扩展名列表与英文逗号分开。警告:允许上传可能会导致安全问题。" seo: page_title: 搜索引擎优化 permalink: @@ -2214,6 +2234,7 @@ ui: discard_confirm: 您确定要丢弃您的草稿吗? messages: post_deleted: 该帖子已被删除。 + post_cancel_deleted: 此帖子已被删除 post_pin: 该帖子已被置顶。 post_unpin: 该帖子已被取消置顶。 post_hide_list: 此帖子已经从列表中隐藏。 @@ -2222,3 +2243,15 @@ ui: post_list: 这个帖子已经被显示 post_unlist: 这个帖子已经被隐藏 post_pending: 您的帖子正在等待审核。它将在它获得批准后可见。 + post_closed: 此帖已关闭。 + answer_deleted: 该回答已被删除. + answer_cancel_deleted: 此答案已取消删除。 + change_user_role: 此用户的角色已被更改。 + user_inactive: 此用户已经处于未激活状态。 + user_normal: 此用户已经是正常的。 + user_suspended: 此用户已被封禁。 + user_deleted: 此用户已被删除 + badge_activated: 此徽章已被激活。 + badge_inactivated: 此徽章已被禁用。 + + diff --git a/i18n/zh_TW.yaml b/i18n/zh_TW.yaml index bec0a0b3..fbe8eb8b 100644 --- a/i18n/zh_TW.yaml +++ b/i18n/zh_TW.yaml @@ -48,15 +48,15 @@ backend: pin: other: 置頂 hide: - other: Unlist + other: 不公開 unpin: - other: Unpin + other: 取消置頂 show: - other: List + other: 清單 invite_someone_to_answer: - other: Edit + other: 編輯 undelete: - other: Undelete + other: 還原 role: name: user: @@ -464,42 +464,42 @@ backend: title: other: "[{{.SiteName}}] Confirm your new email address" body: - other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.\n" + other: "Confirm your new email address for {{.SiteName}} by clicking on the following link:
      \n{{.ChangeEmailUrl}}

      \n\nIf you did not request this change, please ignore this email.

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." new_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} answered your question" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.AnswerSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" invited_you_to_answer: title: other: "[{{.SiteName}}] {{.DisplayName}} invited you to answer" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      I think you may know the answer.

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_comment: title: other: "[{{.SiteName}}] {{.DisplayName}} commented on your post" body: - other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}

      \n\n{{.DisplayName}}:
      \n
      {{.CommentSummary}}

      \nView it on {{.SiteName}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" new_question: title: other: "[{{.SiteName}}] New question: {{.QuestionTitle}}" body: - other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nUnsubscribe" + other: "{{.QuestionTitle}}
      \n{{.Tags}}

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen.

      \n\nUnsubscribe" pass_reset: title: other: "[{{.SiteName }}] Password reset" body: - other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n" + other: "Somebody asked to reset your password on {{.SiteName}}.

      \n\nIf it was not you, you can safely ignore this email.

      \n\nClick the following link to choose a new password:
      \n{{.PassResetUrl}}\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." register: title: other: "[{{.SiteName}}] Confirm your new account" body: - other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n" + other: "Welcome to {{.SiteName}}!

      \n\nClick the following link to confirm and activate your new account:
      \n{{.RegisterUrl}}

      \n\nIf the above link is not clickable, try copying and pasting it into the address bar of your web browser.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." test: title: other: "[{{.SiteName}}] Test Email" body: - other: "This is a test email." + other: "This is a test email.\n

      \n\n--
      \nNote: This is an automatic system email, please do not reply to this message as your response will not be seen." action_activity_type: upvote: other: upvote @@ -787,7 +787,7 @@ ui: how_to_format: title: 如何設定文本格式 desc: >- -
      • link question or answer: #10010000000000001

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      +
      • mention a post: #post_id

      • to make links

        <https://url.com>

        [Title](https://url.com)
      • put returns between paragraphs

      • _italic_ or **bold**

      • indent code by 4 spaces

      • quote by placing > at start of line

      • backtick escapes `like _this_`

      • create code fences with backticks `

        ```
        code here
        ```
      pagination: prev: 上一頁 next: 下一頁 @@ -904,7 +904,7 @@ ui: msg: empty: 文件不能為空。 only_image: 只能上傳圖片文件。 - max_size: 文件大小不能超過4MB + max_size: File size cannot exceed {{size}} MB. desc: label: 圖片描述 tab_url: 圖片地址 @@ -946,6 +946,10 @@ ui: text: 表格 heading: 表頭 cell: 單元格 + file: + text: Attach files + not_supported: "Don’t support that file type. Try again with {{file_type}}." + max_size: "Attach files size cannot exceed {{size}} MB." close_modal: title: 關閉原因是... btn_cancel: 取消 @@ -1086,6 +1090,7 @@ ui: search_placeholder: 通過標籤名過濾 no_desc: 此標籤無描述。 more: 更多 + wiki: Wiki ask: title: 發問 edit_title: 編輯問題 @@ -1522,6 +1527,7 @@ ui: newest: 最新的 active: 活躍的 hot: Hot + frequent: Frequent recommend: Recommend score: 評分 unanswered: 未回答 @@ -1721,6 +1727,8 @@ ui: welcome: Welcome to Admin! site_statistics: Site statistics questions: "問題:" + resolved: "Resolved:" + unanswered: "Unanswered:" answers: "回答:" comments: "評論:" votes: "投票:" @@ -2008,6 +2016,21 @@ ui: reserved_tags: label: Reserved tags text: "Reserved tags can only be used by moderator." + image_size: + label: Max image size (MB) + text: "The maximum image upload size." + attachment_size: + label: Max attachment size (MB) + text: "The maximum attachment files upload size." + image_megapixels: + label: Max image megapixels + text: "Maximum number of megapixels allowed for an image." + image_extensions: + label: Authorized image extensions + text: "A list of file extensions allowed for image display, separate with commas." + attachment_extensions: + label: Authorized attachment extensions + text: "A list of file extensions allowed for upload, separate with commas. WARNING: Allowing uploads may cause security issues." seo: page_title: 搜尋引擎優化 permalink: @@ -2211,6 +2234,7 @@ ui: discard_confirm: Are you sure you want to discard your draft? messages: post_deleted: This post has been deleted. + post_cancel_deleted: This post has been undeleted. post_pin: This post has been pinned. post_unpin: This post has been unpinned. post_hide_list: This post has been hidden from list. @@ -2219,3 +2243,15 @@ ui: post_list: This post has been listed. post_unlist: This post has been unlisted. post_pending: Your post is awaiting review. This is a preview, it will be visible after it has been approved. + post_closed: This post has been closed. + answer_deleted: This answer has been deleted. + answer_cancel_deleted: This answer has been undeleted. + change_user_role: This user's role has been changed. + user_inactive: This user is already inactive. + user_normal: This user is already normal. + user_suspended: This user has been suspended. + user_deleted: This user has been deleted. + badge_activated: This badge has been activated. + badge_inactivated: This badge has been inactivated. + + From f7731bc675930f9cb9fa7a6f6346c102246b2c4d Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 9 Dec 2024 17:31:10 +0800 Subject: [PATCH 333/336] Release/1.4.2 (#1200) --- internal/migrations/migrations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index 00e44198..6160ca88 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -99,7 +99,7 @@ var migrations = []Migration{ NewMigration("v1.3.6", "add hot score to question table", addQuestionHotScore, true), NewMigration("v1.4.0", "add badge/badge_group/badge_award table", addBadges, true), NewMigration("v1.4.1", "add question link", addQuestionLink, true), - NewMigration("v1.4.2", "add the number of question links", addQuestionLinkedCount, false), + NewMigration("v1.4.2", "add the number of question links", addQuestionLinkedCount, true), } func GetMigrations() []Migration { From 0618947350917ecd58a5797365058da17bf8169a Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Tue, 7 Jan 2025 10:37:14 +0800 Subject: [PATCH 334/336] refactor(name): rename incubator-answer --- .goreleaser.yaml | 10 +- .vaunt/config.yaml | 4 +- DISCLAIMER | 2 +- Dockerfile | 2 +- Makefile | 2 +- NOTICE | 4 +- README.md | 6 +- cmd/answer/main.go | 2 +- cmd/command.go | 10 +- cmd/main.go | 12 +- cmd/wire.go | 26 +-- cmd/wire_gen.go | 170 +++++++++--------- docs/release/NOTICE | 4 +- go.mod | 2 +- internal/base/conf/conf.go | 14 +- internal/base/constant/privilege.go | 2 +- internal/base/cron/cron.go | 4 +- internal/base/data/data.go | 4 +- internal/base/handler/handler.go | 6 +- internal/base/handler/lang.go | 2 +- internal/base/handler/response.go | 2 +- internal/base/handler/short_id.go | 2 +- internal/base/middleware/accept_language.go | 4 +- internal/base/middleware/auth.go | 18 +- internal/base/middleware/avatar.go | 6 +- internal/base/middleware/rate_limit.go | 8 +- internal/base/middleware/short_id.go | 4 +- .../middleware/user_center_plugin_auth.go | 6 +- internal/base/middleware/visit_img_auth.go | 2 +- internal/base/server/http.go | 8 +- internal/base/server/http_funcmap.go | 12 +- internal/base/validator/validator.go | 4 +- internal/cli/build.go | 30 ++-- internal/cli/config.go | 6 +- internal/cli/dump.go | 2 +- internal/cli/i18n.go | 6 +- internal/cli/install.go | 8 +- internal/cli/install_check.go | 6 +- internal/controller/activity_controller.go | 12 +- internal/controller/answer_controller.go | 26 +-- internal/controller/badge_controller.go | 12 +- internal/controller/collection_controller.go | 10 +- internal/controller/comment_controller.go | 24 +-- internal/controller/connector_controller.go | 14 +- internal/controller/dashboard_controller.go | 4 +- internal/controller/embed_controller.go | 4 +- internal/controller/follow_controller.go | 10 +- internal/controller/lang_controller.go | 6 +- internal/controller/meta_controller.go | 10 +- .../controller/notification_controller.go | 12 +- internal/controller/permission_controller.go | 8 +- .../controller/plugin_captcha_controller.go | 4 +- .../plugin_user_center_controller.go | 12 +- internal/controller/question_controller.go | 28 +-- internal/controller/rank_controller.go | 8 +- internal/controller/reason_controller.go | 6 +- internal/controller/render_controller.go | 4 +- internal/controller/report_controller.go | 24 +-- internal/controller/review_controller.go | 16 +- internal/controller/revision_controller.go | 22 +-- internal/controller/search_controller.go | 20 +-- internal/controller/siteinfo_controller.go | 8 +- internal/controller/tag_controller.go | 18 +- internal/controller/template_controller.go | 36 ++-- internal/controller/template_render/answer.go | 2 +- .../controller/template_render/comment.go | 4 +- .../controller/template_render/controller.go | 12 +- .../controller/template_render/question.go | 4 +- internal/controller/template_render/tags.go | 4 +- .../controller/template_render/userinfo.go | 2 +- internal/controller/upload_controller.go | 12 +- internal/controller/user_controller.go | 30 ++-- internal/controller/user_plugin_controller.go | 12 +- internal/controller/vote_controller.go | 22 +-- internal/controller_admin/badge_controller.go | 8 +- .../controller_admin/plugin_controller.go | 8 +- internal/controller_admin/role_controller.go | 6 +- .../controller_admin/siteinfo_controller.go | 8 +- internal/controller_admin/theme_controller.go | 4 +- .../user_backyard_controller.go | 14 +- internal/entity/comment_entity.go | 2 +- internal/entity/config_entity.go | 2 +- internal/install/install_controller.go | 18 +- internal/install/install_main.go | 4 +- internal/install/install_req.go | 6 +- internal/install/install_server.go | 6 +- internal/migrations/init.go | 10 +- internal/migrations/init_data.go | 4 +- internal/migrations/migrations.go | 4 +- internal/migrations/v10.go | 6 +- internal/migrations/v11.go | 2 +- internal/migrations/v12.go | 2 +- internal/migrations/v13.go | 8 +- internal/migrations/v15.go | 2 +- internal/migrations/v16.go | 4 +- internal/migrations/v17.go | 4 +- internal/migrations/v18.go | 6 +- internal/migrations/v19.go | 2 +- internal/migrations/v20.go | 2 +- internal/migrations/v22.go | 6 +- internal/migrations/v23.go | 2 +- internal/migrations/v24.go | 6 +- internal/migrations/v3.go | 2 +- internal/migrations/v4.go | 4 +- internal/migrations/v5.go | 2 +- internal/migrations/v6.go | 2 +- internal/migrations/v7.go | 2 +- internal/migrations/v8.go | 4 +- internal/migrations/v9.go | 2 +- internal/repo/activity/activity_repo.go | 12 +- internal/repo/activity/answer_repo.go | 20 +-- internal/repo/activity/follow_repo.go | 14 +- internal/repo/activity/review_repo.go | 18 +- internal/repo/activity/user_active_repo.go | 14 +- internal/repo/activity/vote_repo.go | 24 +-- .../repo/activity_common/activity_repo.go | 16 +- internal/repo/activity_common/follow.go | 12 +- internal/repo/activity_common/vote.go | 10 +- internal/repo/answer/answer_repo.go | 26 +-- internal/repo/auth/auth.go | 10 +- internal/repo/badge/badge_event_rule.go | 12 +- internal/repo/badge/badge_repo.go | 12 +- internal/repo/badge_award/badge_award_repo.go | 12 +- internal/repo/badge_group/badge_group_repo.go | 8 +- internal/repo/captcha/captcha.go | 8 +- .../repo/collection/collection_group_repo.go | 12 +- internal/repo/collection/collection_repo.go | 18 +- internal/repo/comment/comment_repo.go | 14 +- internal/repo/config/config_repo.go | 10 +- internal/repo/export/email_repo.go | 8 +- internal/repo/limit/limit.go | 6 +- internal/repo/meta/meta_repo.go | 8 +- .../repo/notification/notification_repo.go | 14 +- .../repo/plugin_config/plugin_config_repo.go | 8 +- .../plugin_config/plugin_user_config_repo.go | 10 +- internal/repo/provider.go | 64 +++---- internal/repo/question/question_repo.go | 24 +-- internal/repo/rank/user_rank_repo.go | 14 +- internal/repo/reason/reason_repo.go | 8 +- internal/repo/repo_test/auth_test.go | 4 +- internal/repo/repo_test/captcha_test.go | 2 +- internal/repo/repo_test/comment_repo_test.go | 10 +- internal/repo/repo_test/email_repo_test.go | 2 +- internal/repo/repo_test/meta_repo_test.go | 4 +- .../repo/repo_test/notification_repo_test.go | 6 +- internal/repo/repo_test/reason_repo_test.go | 6 +- internal/repo/repo_test/recommend_test.go | 20 +-- internal/repo/repo_test/repo_main_test.go | 4 +- internal/repo/repo_test/revision_repo_test.go | 8 +- internal/repo/repo_test/siteinfo_repo_test.go | 4 +- internal/repo/repo_test/tag_rel_repo_test.go | 6 +- internal/repo/repo_test/tag_repo_test.go | 10 +- .../repo/repo_test/user_backyard_repo_test.go | 6 +- internal/repo/repo_test/user_repo_test.go | 4 +- internal/repo/report/report_repo.go | 14 +- internal/repo/review/review_repo.go | 10 +- internal/repo/revision/revision_repo.go | 18 +- internal/repo/role/power_repo.go | 8 +- internal/repo/role/role_power_rel_repo.go | 6 +- internal/repo/role/role_repo.go | 8 +- internal/repo/role/user_role_rel_repo.go | 8 +- internal/repo/search_common/search_repo.go | 28 +-- internal/repo/search_sync/search_sync.go | 12 +- internal/repo/site_info/siteinfo_repo.go | 10 +- internal/repo/tag/tag_rel_repo.go | 14 +- internal/repo/tag/tag_repo.go | 12 +- internal/repo/tag_common/tag_common_repo.go | 12 +- internal/repo/unique/uniqid_repo.go | 10 +- internal/repo/user/user_backyard_repo.go | 12 +- internal/repo/user/user_repo.go | 14 +- .../user_external_login_repo.go | 12 +- .../user_notification_config_repo.go | 10 +- internal/router/answer_api_router.go | 6 +- internal/router/plugin_api_router.go | 2 +- internal/router/static_router.go | 4 +- internal/router/swagger_router.go | 2 +- internal/router/template_router.go | 8 +- internal/router/ui.go | 10 +- internal/schema/activity.go | 2 +- internal/schema/answer_schema.go | 4 +- internal/schema/backyard_user_schema.go | 10 +- internal/schema/badge_schema.go | 2 +- internal/schema/comment_schema.go | 6 +- internal/schema/email_template.go | 2 +- internal/schema/event_schema.go | 4 +- internal/schema/new_question_queue_schema.go | 4 +- internal/schema/notification_schema.go | 2 +- internal/schema/permission.go | 6 +- internal/schema/plugin_admin_schema.go | 2 +- internal/schema/plugin_user_schema.go | 2 +- internal/schema/question_schema.go | 8 +- internal/schema/reason_schema.go | 2 +- internal/schema/review_schema.go | 4 +- internal/schema/revision_schema.go | 2 +- internal/schema/search_schema.go | 6 +- internal/schema/simple_obj_info_schema.go | 4 +- internal/schema/siteinfo_schema.go | 10 +- internal/schema/tag_schema.go | 4 +- internal/schema/user_notification_schema.go | 4 +- internal/schema/user_schema.go | 14 +- internal/service/action/captcha_service.go | 8 +- internal/service/action/captcha_strategy.go | 4 +- internal/service/activity/activity.go | 30 ++-- .../activity/answer_activity_service.go | 6 +- internal/service/activity/review_active.go | 2 +- internal/service/activity_common/activity.go | 10 +- .../service/activity_queue/activity_queue.go | 2 +- internal/service/answer_common/answer.go | 10 +- internal/service/auth/auth.go | 6 +- internal/service/badge/badge_award_service.go | 20 +-- internal/service/badge/badge_event_handler.go | 8 +- internal/service/badge/badge_group_service.go | 2 +- internal/service/badge/badge_service.go | 16 +- .../collection/collection_group_service.go | 6 +- .../service/collection/collection_service.go | 8 +- .../service/collection_common/collection.go | 2 +- internal/service/comment/comment_service.go | 34 ++-- .../service/comment_common/comment_service.go | 6 +- internal/service/config/config_service.go | 2 +- internal/service/content/answer_service.go | 44 ++--- .../content/question_hottest_service.go | 4 +- internal/service/content/question_service.go | 66 +++---- internal/service/content/revision_service.go | 46 ++--- internal/service/content/search_service.go | 8 +- internal/service/content/user_service.go | 42 ++--- internal/service/content/vote_service.go | 32 ++-- .../service/dashboard/dashboard_service.go | 34 ++-- internal/service/event_queue/event_queue.go | 2 +- internal/service/export/email_service.go | 16 +- internal/service/follow/follow_service.go | 8 +- internal/service/importer/importer_service.go | 20 +-- internal/service/meta/meta_service.go | 24 +-- .../meta_common/meta_common_service.go | 4 +- internal/service/mock/siteinfo_repo_mock.go | 4 +- .../external_notification_queue.go | 2 +- internal/service/notice_queue/notice_queue.go | 2 +- .../notification/external_notification.go | 20 +-- .../invite_answer_notification.go | 4 +- .../notification/new_answer_notification.go | 4 +- .../notification/new_comment_notification.go | 4 +- .../notification/new_question_notification.go | 12 +- .../notification/notification_service.go | 30 ++-- .../notification_common/notification.go | 30 ++-- internal/service/object_info/object_info.go | 18 +- .../service/permission/answer_permission.go | 8 +- .../service/permission/comment_permission.go | 8 +- .../service/permission/question_permission.go | 8 +- internal/service/permission/tag_permission.go | 8 +- .../plugin_common/plugin_common_service.go | 18 +- internal/service/provider.go | 86 ++++----- internal/service/question_common/question.go | 38 ++-- internal/service/rank/rank_service.go | 32 ++-- internal/service/reason/reason_service.go | 4 +- internal/service/reason_common/reason.go | 2 +- internal/service/report/report_service.go | 36 ++-- .../service/report_common/report_common.go | 4 +- .../service/report_handle/report_handle.go | 14 +- internal/service/review/review_service.go | 34 ++-- internal/service/revision/revision.go | 2 +- .../revision_common/revision_service.go | 12 +- internal/service/role/power_service.go | 2 +- internal/service/role/role_service.go | 8 +- .../service/role/user_role_rel_service.go | 2 +- internal/service/search_common/search.go | 4 +- .../service/search_parser/search_parser.go | 10 +- internal/service/siteinfo/siteinfo_service.go | 24 +-- .../siteinfo_common/siteinfo_service.go | 8 +- .../siteinfo_common/siteinfo_service_test.go | 6 +- internal/service/tag/tag_service.go | 26 +-- internal/service/tag_common/tag_common.go | 18 +- internal/service/uploader/upload.go | 16 +- internal/service/user_admin/user_backyard.go | 40 ++--- internal/service/user_common/user.go | 20 +-- .../user_center_login_service.go | 26 +-- .../user_external_login_service.go | 30 ++-- .../user_notification_config_service.go | 8 +- pkg/checker/path_ignore.go | 2 +- pkg/checker/question_link.go | 6 +- pkg/checker/question_link_test.go | 2 +- pkg/checker/reserved_username.go | 6 +- pkg/display/url.go | 6 +- pkg/gravatar/gravatar_test.go | 2 +- pkg/htmltext/htmltext.go | 4 +- pkg/obj/obj.go | 6 +- plugin/plugin.go | 4 +- script/plugin_list | 6 +- ui/public/index.html | 2 +- ui/src/components/PageTags/index.tsx | 2 +- .../components/AnswerLinks/index.tsx | 2 +- .../components/HealthStatus/index.tsx | 6 +- .../pages/Admin/Plugins/Installed/index.tsx | 2 +- .../builtin/ThirdPartyConnector/info.yaml | 2 +- ui/template/header.html | 2 +- 293 files changed, 1620 insertions(+), 1620 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index d2869147..b517defb 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -34,7 +34,7 @@ builds: - id: build main: ./cmd/answer/. binary: answer - ldflags: -s -w -X github.com/apache/incubator-answer/cmd.Version={{.RawVersion}} -X github.com/apache/incubator-answer/cmd.Revision={{.ShortCommit}} -X github.com/apache/incubator-answer/cmd.Time={{.Date}} -X github.com/apache/incubator-answer/cmd.BuildUser=goreleaser + ldflags: -s -w -X github.com/apache/answer/cmd.Version={{.RawVersion}} -X github.com/apache/answer/cmd.Revision={{.ShortCommit}} -X github.com/apache/answer/cmd.Time={{.Date}} -X github.com/apache/answer/cmd.BuildUser=goreleaser flags: -v goos: - linux @@ -45,7 +45,7 @@ builds: - id: build-windows main: ./cmd/answer/. binary: answer - ldflags: -s -w -X github.com/apache/incubator-answer/cmd.Version={{.RawVersion}} -X github.com/apache/incubator-answer/cmd.Revision={{.ShortCommit}} -X github.com/apache/incubator-answer/cmd.Time={{.Date}} -X github.com/apache/incubator-answer/cmd.BuildUser=goreleaser + ldflags: -s -w -X github.com/apache/answer/cmd.Version={{.RawVersion}} -X github.com/apache/answer/cmd.Revision={{.ShortCommit}} -X github.com/apache/answer/cmd.Time={{.Date}} -X github.com/apache/answer/cmd.BuildUser=goreleaser flags: -v goos: - windows @@ -57,7 +57,7 @@ builds: archives: - name_template: >- - apache-answer-{{ .RawVersion }}-incubating-bin-{{ .Os }}-{{ .Arch }} + apache-answer-{{ .RawVersion }}-bin-{{ .Os }}-{{ .Arch }} files: - src: "docs/release/LICENSE" dst: LICENSE @@ -81,8 +81,8 @@ changelog: source: enabled: true - name_template: apache-answer-{{ .RawVersion }}-incubating-src - prefix_template: "apache-answer-{{ .RawVersion }}-incubating-src/" + name_template: apache-answer-{{ .RawVersion }}-src + prefix_template: "apache-answer-{{ .RawVersion }}-src/" # goreleaser release --skip-validate --skip-publish --clean diff --git a/.vaunt/config.yaml b/.vaunt/config.yaml index 87dfb18d..ec419ee8 100644 --- a/.vaunt/config.yaml +++ b/.vaunt/config.yaml @@ -19,7 +19,7 @@ version: 0.0.1 achievements: - achievement: name: Visionary Architect - icon: https://raw.githubusercontent.com/apache/incubator-answer/main/.vaunt/enhancement.png + icon: https://raw.githubusercontent.com/apache/answer/main/.vaunt/enhancement.png description: Awarded for bringing up enhancement, dream big! triggers: - trigger: @@ -28,7 +28,7 @@ achievements: condition: labels in ['enhancement'] & labels in ['LGTM'] - achievement: name: Bug Hunter - icon: https://raw.githubusercontent.com/apache/incubator-answer/main/.vaunt/bug.png + icon: https://raw.githubusercontent.com/apache/answer/main/.vaunt/bug.png description: Awarded for identifying real bugs, well spotted! triggers: - trigger: diff --git a/DISCLAIMER b/DISCLAIMER index 7ae8e4d8..009fd82b 100644 --- a/DISCLAIMER +++ b/DISCLAIMER @@ -1,4 +1,4 @@ -Apache Answer (incubating) is an effort undergoing incubation at the Apache +Apache Answer is an effort undergoing incubation at the Apache Software Foundation (ASF), sponsored by the Apache Incubator PMC. Incubation is required of all newly accepted projects until a further review diff --git a/Dockerfile b/Dockerfile index 6f57aa07..313a91df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ ARG GOPROXY ENV GOPATH /go ENV GOROOT /usr/local/go -ENV PACKAGE github.com/apache/incubator-answer +ENV PACKAGE github.com/apache/answer ENV BUILD_DIR ${GOPATH}/src/${PACKAGE} ENV ANSWER_MODULE ${BUILD_DIR} diff --git a/Makefile b/Makefile index 8b054aab..f653d6e4 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DOCKER_CMD=docker GO_ENV=CGO_ENABLED=0 GO111MODULE=on Revision=$(shell git rev-parse --short HEAD 2>/dev/null || echo "") -GO_FLAGS=-ldflags="-X github.com/apache/incubator-answer/cmd.Version=$(VERSION) -X 'github.com/apache/incubator-answer/cmd.Revision=$(Revision)' -X 'github.com/apache/incubator-answer/cmd.Time=`date +%s`' -extldflags -static" +GO_FLAGS=-ldflags="-X github.com/apache/answer/cmd.Version=$(VERSION) -X 'github.com/apache/answer/cmd.Revision=$(Revision)' -X 'github.com/apache/answer/cmd.Time=`date +%s`' -extldflags -static" GO=$(GO_ENV) "$(shell which go)" build: generate diff --git a/NOTICE b/NOTICE index d81f6d9f..741148fc 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ -Apache Answer (incubating) -Copyright 2023-2024 The Apache Software Foundation +Apache Answer +Copyright 2023-2025 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (https://www.apache.org/). diff --git a/README.md b/README.md index bdf036c7..6bfde762 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ A Q&A platform software for teams at any scales. Whether it’s a community foru To learn more about the project, visit [answer.apache.org](https://answer.apache.org). -[![LICENSE](https://img.shields.io/github/license/apache/incubator-answer)](https://github.com/apache/incubator-answer/blob/main/LICENSE) +[![LICENSE](https://img.shields.io/github/license/apache/answer)](https://github.com/apache/answer/blob/main/LICENSE) [![Language](https://img.shields.io/badge/language-go-blue.svg)](https://golang.org/) [![Language](https://img.shields.io/badge/language-react-blue.svg)](https://reactjs.org/) -[![Go Report Card](https://goreportcard.com/badge/github.com/apache/incubator-answer)](https://goreportcard.com/report/github.com/apache/incubator-answer) +[![Go Report Card](https://goreportcard.com/badge/github.com/apache/answer)](https://goreportcard.com/report/github.com/apache/answer) [![Discord](https://img.shields.io/badge/discord-chat-5865f2?logo=discord&logoColor=f5f5f5)](https://discord.gg/Jm7Y4cbUej) ## Screenshots @@ -65,4 +65,4 @@ See [CONTRIBUTING](https://answer.apache.org/community/contributing) for ways to ## License -[Apache License 2.0](https://github.com/apache/incubator-answer/blob/main/LICENSE) +[Apache License 2.0](https://github.com/apache/answer/blob/main/LICENSE) diff --git a/cmd/answer/main.go b/cmd/answer/main.go index 9ba33b6f..c11da2ad 100644 --- a/cmd/answer/main.go +++ b/cmd/answer/main.go @@ -22,7 +22,7 @@ package main import ( - answercmd "github.com/apache/incubator-answer/cmd" + answercmd "github.com/apache/answer/cmd" ) // main godoc diff --git a/cmd/command.go b/cmd/command.go index 65710e6b..5619fc04 100644 --- a/cmd/command.go +++ b/cmd/command.go @@ -24,11 +24,11 @@ import ( "os" "strings" - "github.com/apache/incubator-answer/internal/base/conf" - "github.com/apache/incubator-answer/internal/cli" - "github.com/apache/incubator-answer/internal/install" - "github.com/apache/incubator-answer/internal/migrations" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/conf" + "github.com/apache/answer/internal/cli" + "github.com/apache/answer/internal/install" + "github.com/apache/answer/internal/migrations" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/log" "github.com/spf13/cobra" ) diff --git a/cmd/main.go b/cmd/main.go index 100c6261..5bc26572 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -25,11 +25,11 @@ import ( "os" "time" - "github.com/apache/incubator-answer/internal/base/conf" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/cron" - "github.com/apache/incubator-answer/internal/cli" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/conf" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/cron" + "github.com/apache/answer/internal/cli" + "github.com/apache/answer/internal/schema" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman" "github.com/segmentfault/pacman/contrib/log/zap" @@ -37,7 +37,7 @@ import ( "github.com/segmentfault/pacman/log" ) -// go build -ldflags "-X github.com/apache/incubator-answer/cmd.Version=x.y.z" +// go build -ldflags "-X github.com/apache/answer/cmd.Version=x.y.z" var ( // Name is the name of the project Name = "answer" diff --git a/cmd/wire.go b/cmd/wire.go index 8d12f5d2..b25026e5 100644 --- a/cmd/wire.go +++ b/cmd/wire.go @@ -25,19 +25,19 @@ package answercmd import ( - "github.com/apache/incubator-answer/internal/base/conf" - "github.com/apache/incubator-answer/internal/base/cron" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/server" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/controller" - "github.com/apache/incubator-answer/internal/controller/template_render" - "github.com/apache/incubator-answer/internal/controller_admin" - "github.com/apache/incubator-answer/internal/repo" - "github.com/apache/incubator-answer/internal/router" - "github.com/apache/incubator-answer/internal/service" - "github.com/apache/incubator-answer/internal/service/service_config" + "github.com/apache/answer/internal/base/conf" + "github.com/apache/answer/internal/base/cron" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/server" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/controller" + "github.com/apache/answer/internal/controller/template_render" + "github.com/apache/answer/internal/controller_admin" + "github.com/apache/answer/internal/repo" + "github.com/apache/answer/internal/router" + "github.com/apache/answer/internal/service" + "github.com/apache/answer/internal/service/service_config" "github.com/google/wire" "github.com/segmentfault/pacman" "github.com/segmentfault/pacman/log" diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 3f267984..6878f337 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -27,91 +27,91 @@ package answercmd import ( - "github.com/apache/incubator-answer/internal/base/conf" - "github.com/apache/incubator-answer/internal/base/cron" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/server" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/controller" - "github.com/apache/incubator-answer/internal/controller/template_render" - "github.com/apache/incubator-answer/internal/controller_admin" - "github.com/apache/incubator-answer/internal/repo/activity" - "github.com/apache/incubator-answer/internal/repo/activity_common" - "github.com/apache/incubator-answer/internal/repo/answer" - "github.com/apache/incubator-answer/internal/repo/auth" - "github.com/apache/incubator-answer/internal/repo/badge" - "github.com/apache/incubator-answer/internal/repo/badge_award" - "github.com/apache/incubator-answer/internal/repo/badge_group" - "github.com/apache/incubator-answer/internal/repo/captcha" - "github.com/apache/incubator-answer/internal/repo/collection" - "github.com/apache/incubator-answer/internal/repo/comment" - "github.com/apache/incubator-answer/internal/repo/config" - "github.com/apache/incubator-answer/internal/repo/export" - "github.com/apache/incubator-answer/internal/repo/limit" - "github.com/apache/incubator-answer/internal/repo/meta" - notification2 "github.com/apache/incubator-answer/internal/repo/notification" - "github.com/apache/incubator-answer/internal/repo/plugin_config" - "github.com/apache/incubator-answer/internal/repo/question" - "github.com/apache/incubator-answer/internal/repo/rank" - "github.com/apache/incubator-answer/internal/repo/reason" - "github.com/apache/incubator-answer/internal/repo/report" - "github.com/apache/incubator-answer/internal/repo/review" - "github.com/apache/incubator-answer/internal/repo/revision" - "github.com/apache/incubator-answer/internal/repo/role" - "github.com/apache/incubator-answer/internal/repo/search_common" - "github.com/apache/incubator-answer/internal/repo/site_info" - "github.com/apache/incubator-answer/internal/repo/tag" - "github.com/apache/incubator-answer/internal/repo/tag_common" - "github.com/apache/incubator-answer/internal/repo/unique" - "github.com/apache/incubator-answer/internal/repo/user" - "github.com/apache/incubator-answer/internal/repo/user_external_login" - "github.com/apache/incubator-answer/internal/repo/user_notification_config" - "github.com/apache/incubator-answer/internal/router" - "github.com/apache/incubator-answer/internal/service/action" - activity2 "github.com/apache/incubator-answer/internal/service/activity" - activity_common2 "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/activity_queue" - "github.com/apache/incubator-answer/internal/service/answer_common" - auth2 "github.com/apache/incubator-answer/internal/service/auth" - badge2 "github.com/apache/incubator-answer/internal/service/badge" - collection2 "github.com/apache/incubator-answer/internal/service/collection" - "github.com/apache/incubator-answer/internal/service/collection_common" - comment2 "github.com/apache/incubator-answer/internal/service/comment" - "github.com/apache/incubator-answer/internal/service/comment_common" - config2 "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/dashboard" - "github.com/apache/incubator-answer/internal/service/event_queue" - export2 "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/follow" - "github.com/apache/incubator-answer/internal/service/importer" - meta2 "github.com/apache/incubator-answer/internal/service/meta" - "github.com/apache/incubator-answer/internal/service/meta_common" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/notification" - "github.com/apache/incubator-answer/internal/service/notification_common" - "github.com/apache/incubator-answer/internal/service/object_info" - "github.com/apache/incubator-answer/internal/service/plugin_common" - "github.com/apache/incubator-answer/internal/service/question_common" - rank2 "github.com/apache/incubator-answer/internal/service/rank" - reason2 "github.com/apache/incubator-answer/internal/service/reason" - report2 "github.com/apache/incubator-answer/internal/service/report" - "github.com/apache/incubator-answer/internal/service/report_handle" - review2 "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/internal/service/revision_common" - role2 "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/search_parser" - "github.com/apache/incubator-answer/internal/service/service_config" - "github.com/apache/incubator-answer/internal/service/siteinfo" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - tag2 "github.com/apache/incubator-answer/internal/service/tag" - tag_common2 "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/internal/service/uploader" - "github.com/apache/incubator-answer/internal/service/user_admin" - "github.com/apache/incubator-answer/internal/service/user_common" - user_external_login2 "github.com/apache/incubator-answer/internal/service/user_external_login" - user_notification_config2 "github.com/apache/incubator-answer/internal/service/user_notification_config" + "github.com/apache/answer/internal/base/conf" + "github.com/apache/answer/internal/base/cron" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/server" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/controller" + "github.com/apache/answer/internal/controller/template_render" + "github.com/apache/answer/internal/controller_admin" + "github.com/apache/answer/internal/repo/activity" + "github.com/apache/answer/internal/repo/activity_common" + "github.com/apache/answer/internal/repo/answer" + "github.com/apache/answer/internal/repo/auth" + "github.com/apache/answer/internal/repo/badge" + "github.com/apache/answer/internal/repo/badge_award" + "github.com/apache/answer/internal/repo/badge_group" + "github.com/apache/answer/internal/repo/captcha" + "github.com/apache/answer/internal/repo/collection" + "github.com/apache/answer/internal/repo/comment" + "github.com/apache/answer/internal/repo/config" + "github.com/apache/answer/internal/repo/export" + "github.com/apache/answer/internal/repo/limit" + "github.com/apache/answer/internal/repo/meta" + notification2 "github.com/apache/answer/internal/repo/notification" + "github.com/apache/answer/internal/repo/plugin_config" + "github.com/apache/answer/internal/repo/question" + "github.com/apache/answer/internal/repo/rank" + "github.com/apache/answer/internal/repo/reason" + "github.com/apache/answer/internal/repo/report" + "github.com/apache/answer/internal/repo/review" + "github.com/apache/answer/internal/repo/revision" + "github.com/apache/answer/internal/repo/role" + "github.com/apache/answer/internal/repo/search_common" + "github.com/apache/answer/internal/repo/site_info" + "github.com/apache/answer/internal/repo/tag" + "github.com/apache/answer/internal/repo/tag_common" + "github.com/apache/answer/internal/repo/unique" + "github.com/apache/answer/internal/repo/user" + "github.com/apache/answer/internal/repo/user_external_login" + "github.com/apache/answer/internal/repo/user_notification_config" + "github.com/apache/answer/internal/router" + "github.com/apache/answer/internal/service/action" + activity2 "github.com/apache/answer/internal/service/activity" + activity_common2 "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_queue" + "github.com/apache/answer/internal/service/answer_common" + auth2 "github.com/apache/answer/internal/service/auth" + badge2 "github.com/apache/answer/internal/service/badge" + collection2 "github.com/apache/answer/internal/service/collection" + "github.com/apache/answer/internal/service/collection_common" + comment2 "github.com/apache/answer/internal/service/comment" + "github.com/apache/answer/internal/service/comment_common" + config2 "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/dashboard" + "github.com/apache/answer/internal/service/event_queue" + export2 "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/follow" + "github.com/apache/answer/internal/service/importer" + meta2 "github.com/apache/answer/internal/service/meta" + "github.com/apache/answer/internal/service/meta_common" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/notification" + "github.com/apache/answer/internal/service/notification_common" + "github.com/apache/answer/internal/service/object_info" + "github.com/apache/answer/internal/service/plugin_common" + "github.com/apache/answer/internal/service/question_common" + rank2 "github.com/apache/answer/internal/service/rank" + reason2 "github.com/apache/answer/internal/service/reason" + report2 "github.com/apache/answer/internal/service/report" + "github.com/apache/answer/internal/service/report_handle" + review2 "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/internal/service/revision_common" + role2 "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/search_parser" + "github.com/apache/answer/internal/service/service_config" + "github.com/apache/answer/internal/service/siteinfo" + "github.com/apache/answer/internal/service/siteinfo_common" + tag2 "github.com/apache/answer/internal/service/tag" + tag_common2 "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/internal/service/uploader" + "github.com/apache/answer/internal/service/user_admin" + "github.com/apache/answer/internal/service/user_common" + user_external_login2 "github.com/apache/answer/internal/service/user_external_login" + user_notification_config2 "github.com/apache/answer/internal/service/user_notification_config" "github.com/segmentfault/pacman" "github.com/segmentfault/pacman/log" ) diff --git a/docs/release/NOTICE b/docs/release/NOTICE index 4eaee775..1978cd38 100644 --- a/docs/release/NOTICE +++ b/docs/release/NOTICE @@ -1,5 +1,5 @@ -Apache Answer (incubating) -Copyright 2024 The Apache Software Foundation +Apache Answer +Copyright 2025 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (https://www.apache.org/). diff --git a/go.mod b/go.mod index 6d8e8891..7e207e6b 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -module github.com/apache/incubator-answer +module github.com/apache/answer go 1.22.0 diff --git a/internal/base/conf/conf.go b/internal/base/conf/conf.go index 4926c16d..4b71b206 100644 --- a/internal/base/conf/conf.go +++ b/internal/base/conf/conf.go @@ -24,13 +24,13 @@ import ( "os" "path/filepath" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/server" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/cli" - "github.com/apache/incubator-answer/internal/router" - "github.com/apache/incubator-answer/internal/service/service_config" - "github.com/apache/incubator-answer/pkg/writer" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/server" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/cli" + "github.com/apache/answer/internal/router" + "github.com/apache/answer/internal/service/service_config" + "github.com/apache/answer/pkg/writer" "github.com/segmentfault/pacman/contrib/conf/viper" "gopkg.in/yaml.v3" ) diff --git a/internal/base/constant/privilege.go b/internal/base/constant/privilege.go index a0fcc674..46fe52d1 100644 --- a/internal/base/constant/privilege.go +++ b/internal/base/constant/privilege.go @@ -19,7 +19,7 @@ package constant -import "github.com/apache/incubator-answer/internal/base/reason" +import "github.com/apache/answer/internal/base/reason" type Privilege struct { Key string `json:"key"` diff --git a/internal/base/cron/cron.go b/internal/base/cron/cron.go index 0d08e50f..2e7a92ab 100644 --- a/internal/base/cron/cron.go +++ b/internal/base/cron/cron.go @@ -23,8 +23,8 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/siteinfo_common" "github.com/robfig/cron/v3" "github.com/segmentfault/pacman/log" ) diff --git a/internal/base/data/data.go b/internal/base/data/data.go index 54e1fbb8..1d24d718 100644 --- a/internal/base/data/data.go +++ b/internal/base/data/data.go @@ -23,8 +23,8 @@ import ( "path/filepath" "time" - "github.com/apache/incubator-answer/pkg/dir" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/pkg/dir" + "github.com/apache/answer/plugin" _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" "github.com/segmentfault/pacman/cache" diff --git a/internal/base/handler/handler.go b/internal/base/handler/handler.go index 2729a832..7670feea 100644 --- a/internal/base/handler/handler.go +++ b/internal/base/handler/handler.go @@ -21,9 +21,9 @@ package handler import ( "errors" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/validator" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/validator" "github.com/gin-gonic/gin" myErrors "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/base/handler/lang.go b/internal/base/handler/lang.go index 69a1d1b8..a676e5bc 100644 --- a/internal/base/handler/lang.go +++ b/internal/base/handler/lang.go @@ -22,7 +22,7 @@ package handler import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/i18n" ) diff --git a/internal/base/handler/response.go b/internal/base/handler/response.go index c02ba7ec..827e0b36 100644 --- a/internal/base/handler/response.go +++ b/internal/base/handler/response.go @@ -20,7 +20,7 @@ package handler import ( - "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/answer/internal/base/translator" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/i18n" ) diff --git a/internal/base/handler/short_id.go b/internal/base/handler/short_id.go index 70a9328c..c763bf94 100644 --- a/internal/base/handler/short_id.go +++ b/internal/base/handler/short_id.go @@ -22,7 +22,7 @@ package handler import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" ) // GetEnableShortID get language from header diff --git a/internal/base/middleware/accept_language.go b/internal/base/middleware/accept_language.go index 6cb7d95d..3f1abd5a 100644 --- a/internal/base/middleware/accept_language.go +++ b/internal/base/middleware/accept_language.go @@ -20,8 +20,8 @@ package middleware import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/i18n" ) diff --git a/internal/base/middleware/auth.go b/internal/base/middleware/auth.go index 44fd20a2..f21837b6 100644 --- a/internal/base/middleware/auth.go +++ b/internal/base/middleware/auth.go @@ -23,17 +23,17 @@ import ( "net/http" "strings" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/ui" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/ui" "github.com/gin-gonic/gin" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/auth" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/auth" + "github.com/apache/answer/pkg/converter" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/base/middleware/avatar.go b/internal/base/middleware/avatar.go index 7bf363a7..1d246417 100644 --- a/internal/base/middleware/avatar.go +++ b/internal/base/middleware/avatar.go @@ -27,9 +27,9 @@ import ( "path/filepath" "strings" - "github.com/apache/incubator-answer/internal/service/service_config" - "github.com/apache/incubator-answer/internal/service/uploader" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/service/service_config" + "github.com/apache/answer/internal/service/uploader" + "github.com/apache/answer/pkg/converter" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/base/middleware/rate_limit.go b/internal/base/middleware/rate_limit.go index 569dc8b0..29b96175 100644 --- a/internal/base/middleware/rate_limit.go +++ b/internal/base/middleware/rate_limit.go @@ -22,10 +22,10 @@ package middleware import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/repo/limit" - "github.com/apache/incubator-answer/pkg/encryption" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/repo/limit" + "github.com/apache/answer/pkg/encryption" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/base/middleware/short_id.go b/internal/base/middleware/short_id.go index 891ebaba..977eddfe 100644 --- a/internal/base/middleware/short_id.go +++ b/internal/base/middleware/short_id.go @@ -20,8 +20,8 @@ package middleware import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/service/siteinfo_common" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/base/middleware/user_center_plugin_auth.go b/internal/base/middleware/user_center_plugin_auth.go index 44589e15..ac9ee78a 100644 --- a/internal/base/middleware/user_center_plugin_auth.go +++ b/internal/base/middleware/user_center_plugin_auth.go @@ -20,9 +20,9 @@ package middleware import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/base/middleware/visit_img_auth.go b/internal/base/middleware/visit_img_auth.go index 25b635fc..eec7edab 100644 --- a/internal/base/middleware/visit_img_auth.go +++ b/internal/base/middleware/visit_img_auth.go @@ -20,7 +20,7 @@ package middleware import ( - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" "github.com/gin-gonic/gin" "net/http" "strings" diff --git a/internal/base/server/http.go b/internal/base/server/http.go index b45991a1..2b455a1f 100644 --- a/internal/base/server/http.go +++ b/internal/base/server/http.go @@ -24,10 +24,10 @@ import ( "io/fs" brotli "github.com/anargu/gin-brotli" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/router" - "github.com/apache/incubator-answer/plugin" - "github.com/apache/incubator-answer/ui" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/router" + "github.com/apache/answer/plugin" + "github.com/apache/answer/ui" "github.com/gin-gonic/gin" ) diff --git a/internal/base/server/http_funcmap.go b/internal/base/server/http_funcmap.go index 0f99dca0..9d8e98f9 100644 --- a/internal/base/server/http_funcmap.go +++ b/internal/base/server/http_funcmap.go @@ -27,12 +27,12 @@ import ( "strings" "time" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/controller" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/day" - "github.com/apache/incubator-answer/pkg/htmltext" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/controller" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/day" + "github.com/apache/answer/pkg/htmltext" "github.com/segmentfault/pacman/i18n" ) diff --git a/internal/base/validator/validator.go b/internal/base/validator/validator.go index bd5da31d..70c7be2e 100644 --- a/internal/base/validator/validator.go +++ b/internal/base/validator/validator.go @@ -26,8 +26,8 @@ import ( "strings" "unicode" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" "github.com/go-playground/locales" german "github.com/go-playground/locales/de" english "github.com/go-playground/locales/en" diff --git a/internal/cli/build.go b/internal/cli/build.go index bba075a9..46df8741 100644 --- a/internal/cli/build.go +++ b/internal/cli/build.go @@ -32,9 +32,9 @@ import ( "text/template" "github.com/Masterminds/semver/v3" - "github.com/apache/incubator-answer/pkg/dir" - "github.com/apache/incubator-answer/pkg/writer" - "github.com/apache/incubator-answer/ui" + "github.com/apache/answer/pkg/dir" + "github.com/apache/answer/pkg/writer" + "github.com/apache/answer/ui" "github.com/segmentfault/pacman/log" "gopkg.in/yaml.v3" ) @@ -43,7 +43,7 @@ const ( mainGoTpl = `package main import ( - answercmd "github.com/apache/incubator-answer/cmd" + answercmd "github.com/apache/answer/cmd" // remote plugins {{- range .remote_plugins}} @@ -86,7 +86,7 @@ type OriginalAnswerInfo struct { } type pluginInfo struct { - // Name of the plugin e.g. github.com/apache/incubator-answer-plugins/github-connector + // Name of the plugin e.g. github.com/apache/answer-plugins/github-connector Name string // Path to the plugin. If path exist, read plugin from local filesystem Path string @@ -136,7 +136,7 @@ func BuildNewAnswer(buildDir, outputPath string, plugins []string, originalAnswe func formatPlugins(plugins []string) (formatted []*pluginInfo) { for _, plugin := range plugins { plugin = strings.TrimSpace(plugin) - // plugin description like this 'github.com/apache/incubator-answer-plugins/github-connector@latest=/local/path' + // plugin description like this 'github.com/apache/answer-plugins/github-connector@latest=/local/path' info := &pluginInfo{} plugin, info.Path, _ = strings.Cut(plugin, "=") info.Name, info.Version, _ = strings.Cut(plugin, "@") @@ -202,7 +202,7 @@ func createMainGoFile(b *buildingMaterial) (err error) { func downloadGoModFile(b *buildingMaterial) (err error) { // If user specify a module replacement, use it. Otherwise, use the latest version. if len(b.answerModuleReplacement) > 0 { - replacement := fmt.Sprintf("%s=%s", "github.com/apache/incubator-answer", b.answerModuleReplacement) + replacement := fmt.Sprintf("%s=%s", "github.com/apache/answer", b.answerModuleReplacement) err = b.newExecCmd("go", "mod", "edit", "-replace", replacement).Run() if err != nil { return err @@ -223,7 +223,7 @@ func downloadGoModFile(b *buildingMaterial) (err error) { // copyUIFiles copy ui files from answer module to tmp dir func copyUIFiles(b *buildingMaterial) (err error) { - goListCmd := b.newExecCmd("go", "list", "-mod=mod", "-m", "-f", "{{.Dir}}", "github.com/apache/incubator-answer") + goListCmd := b.newExecCmd("go", "list", "-mod=mod", "-m", "-f", "{{.Dir}}", "github.com/apache/answer") buf := new(bytes.Buffer) goListCmd.Stdout = buf if err = goListCmd.Run(); err != nil { @@ -232,13 +232,13 @@ func copyUIFiles(b *buildingMaterial) (err error) { answerDir := strings.TrimSpace(buf.String()) goModUIDir := filepath.Join(answerDir, "ui") - localUIBuildDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/incubator-answer/ui/") + localUIBuildDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/answer/ui/") // The node_modules folder generated during development will interfere packaging, so it needs to be ignored. if err = copyDirEntries(os.DirFS(goModUIDir), ".", localUIBuildDir, "node_modules"); err != nil { return fmt.Errorf("failed to copy ui files: %w", err) } - pluginsDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/incubator-answer-plugins/") + pluginsDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/answer-plugins/") localUIPluginDir := filepath.Join(localUIBuildDir, "src/plugins/") // copy plugins dir @@ -283,7 +283,7 @@ func copyUIFiles(b *buildingMaterial) (err error) { // overwriteIndexTs overwrites index.ts file in ui/src/plugins/ dir func overwriteIndexTs(b *buildingMaterial) (err error) { - localUIPluginDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/incubator-answer/ui/src/plugins/") + localUIPluginDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/answer/ui/src/plugins/") folders, err := getFolders(localUIPluginDir) if err != nil { @@ -327,7 +327,7 @@ func generateIndexTsContent(folders []string) string { // buildUI run pnpm install and pnpm build commands to build ui func buildUI(b *buildingMaterial) (err error) { - localUIBuildDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/incubator-answer/ui") + localUIBuildDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/answer/ui") pnpmInstallCmd := b.newExecCmd("pnpm", "pre-install") pnpmInstallCmd.Dir = localUIBuildDir @@ -345,7 +345,7 @@ func buildUI(b *buildingMaterial) (err error) { func replaceNecessaryFile(b *buildingMaterial) (err error) { fmt.Printf("try to replace ui build directory\n") - uiBuildDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/incubator-answer/ui") + uiBuildDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/answer/ui") err = copyDirEntries(ui.Build, ".", uiBuildDir) return err } @@ -401,7 +401,7 @@ func mergeI18nFiles(b *buildingMaterial) (err error) { } } - originalI18nDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/incubator-answer/i18n") + originalI18nDir := filepath.Join(b.tmpDir, "vendor/github.com/apache/answer/i18n") entries, err := os.ReadDir(originalI18nDir) if err != nil { return err @@ -526,7 +526,7 @@ func formatUIPluginsDirName(dirPath string) { // buildBinary build binary file func buildBinary(b *buildingMaterial) (err error) { versionInfo := b.originalAnswerInfo - cmdPkg := "github.com/apache/incubator-answer/cmd" + cmdPkg := "github.com/apache/answer/cmd" ldflags := fmt.Sprintf("-X %s.Version=%s -X %s.Revision=%s -X %s.Time=%s", cmdPkg, versionInfo.Version, cmdPkg, versionInfo.Revision, cmdPkg, versionInfo.Time) err = b.newExecCmd("go", "build", diff --git a/internal/cli/config.go b/internal/cli/config.go index 9ebefa1d..93cb8eab 100644 --- a/internal/cli/config.go +++ b/internal/cli/config.go @@ -23,9 +23,9 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/cli/dump.go b/internal/cli/dump.go index b1a3e56d..e5d52821 100644 --- a/internal/cli/dump.go +++ b/internal/cli/dump.go @@ -24,7 +24,7 @@ import ( "path/filepath" "time" - "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/answer/internal/base/data" "xorm.io/xorm/schemas" ) diff --git a/internal/cli/i18n.go b/internal/cli/i18n.go index ec3cf98f..faef0f28 100644 --- a/internal/cli/i18n.go +++ b/internal/cli/i18n.go @@ -21,9 +21,9 @@ package cli import ( "fmt" - "github.com/apache/incubator-answer/i18n" - "github.com/apache/incubator-answer/pkg/dir" - "github.com/apache/incubator-answer/pkg/writer" + "github.com/apache/answer/i18n" + "github.com/apache/answer/pkg/dir" + "github.com/apache/answer/pkg/writer" "gopkg.in/yaml.v3" "os" "path/filepath" diff --git a/internal/cli/install.go b/internal/cli/install.go index 48b87843..69e673d5 100644 --- a/internal/cli/install.go +++ b/internal/cli/install.go @@ -25,10 +25,10 @@ import ( "path/filepath" "sync" - "github.com/apache/incubator-answer/configs" - "github.com/apache/incubator-answer/i18n" - "github.com/apache/incubator-answer/pkg/dir" - "github.com/apache/incubator-answer/pkg/writer" + "github.com/apache/answer/configs" + "github.com/apache/answer/i18n" + "github.com/apache/answer/pkg/dir" + "github.com/apache/answer/pkg/writer" ) const ( diff --git a/internal/cli/install_check.go b/internal/cli/install_check.go index 5142a0d4..75ed5d3b 100644 --- a/internal/cli/install_check.go +++ b/internal/cli/install_check.go @@ -22,9 +22,9 @@ package cli import ( "fmt" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/pkg/dir" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/pkg/dir" ) func CheckConfigFile(configPath string) bool { diff --git a/internal/controller/activity_controller.go b/internal/controller/activity_controller.go index b4481aea..26cd400c 100644 --- a/internal/controller/activity_controller.go +++ b/internal/controller/activity_controller.go @@ -20,12 +20,12 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/answer_controller.go b/internal/controller/answer_controller.go index 0142c58c..64df858b 100644 --- a/internal/controller/answer_controller.go +++ b/internal/controller/answer_controller.go @@ -23,19 +23,19 @@ import ( "fmt" "net/http" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller/badge_controller.go b/internal/controller/badge_controller.go index 65b59407..8324a13e 100644 --- a/internal/controller/badge_controller.go +++ b/internal/controller/badge_controller.go @@ -20,12 +20,12 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/badge" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/collection_controller.go b/internal/controller/collection_controller.go index a35ee693..78560be0 100644 --- a/internal/controller/collection_controller.go +++ b/internal/controller/collection_controller.go @@ -20,11 +20,11 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/collection" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/collection" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/comment_controller.go b/internal/controller/comment_controller.go index 0b922679..288e8aee 100644 --- a/internal/controller/comment_controller.go +++ b/internal/controller/comment_controller.go @@ -20,18 +20,18 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/comment" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/comment" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" "net/http" diff --git a/internal/controller/connector_controller.go b/internal/controller/connector_controller.go index 96f3ec8e..939a2a09 100644 --- a/internal/controller/connector_controller.go +++ b/internal/controller/connector_controller.go @@ -23,13 +23,13 @@ import ( "fmt" "net/http" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/internal/service/user_external_login" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/user_external_login" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/controller/dashboard_controller.go b/internal/controller/dashboard_controller.go index b7331563..ea5f2aea 100644 --- a/internal/controller/dashboard_controller.go +++ b/internal/controller/dashboard_controller.go @@ -20,8 +20,8 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/service/dashboard" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/service/dashboard" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/embed_controller.go b/internal/controller/embed_controller.go index eb54f1a6..8beb0a61 100644 --- a/internal/controller/embed_controller.go +++ b/internal/controller/embed_controller.go @@ -20,8 +20,8 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/follow_controller.go b/internal/controller/follow_controller.go index 52534da0..aabf2d26 100644 --- a/internal/controller/follow_controller.go +++ b/internal/controller/follow_controller.go @@ -20,11 +20,11 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/follow" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/follow" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" ) diff --git a/internal/controller/lang_controller.go b/internal/controller/lang_controller.go index 1cadc78b..7e5e70fd 100644 --- a/internal/controller/lang_controller.go +++ b/internal/controller/lang_controller.go @@ -22,9 +22,9 @@ package controller import ( "encoding/json" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/service/siteinfo_common" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/i18n" ) diff --git a/internal/controller/meta_controller.go b/internal/controller/meta_controller.go index 1ae3ab91..2a818dfd 100644 --- a/internal/controller/meta_controller.go +++ b/internal/controller/meta_controller.go @@ -20,11 +20,11 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/meta" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/meta" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/notification_controller.go b/internal/controller/notification_controller.go index 952c262e..849c9eff 100644 --- a/internal/controller/notification_controller.go +++ b/internal/controller/notification_controller.go @@ -20,12 +20,12 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/notification" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/notification" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/permission_controller.go b/internal/controller/permission_controller.go index 659e5dc1..73daf559 100644 --- a/internal/controller/permission_controller.go +++ b/internal/controller/permission_controller.go @@ -20,10 +20,10 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/rank" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/rank" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/plugin_captcha_controller.go b/internal/controller/plugin_captcha_controller.go index 7b47e071..c7c98d84 100644 --- a/internal/controller/plugin_captcha_controller.go +++ b/internal/controller/plugin_captcha_controller.go @@ -22,8 +22,8 @@ package controller import ( "encoding/json" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/plugin_user_center_controller.go b/internal/controller/plugin_user_center_controller.go index 84da13af..d426f45d 100644 --- a/internal/controller/plugin_user_center_controller.go +++ b/internal/controller/plugin_user_center_controller.go @@ -23,12 +23,12 @@ import ( "fmt" "net/http" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/internal/service/user_external_login" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/user_external_login" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/controller/question_controller.go b/internal/controller/question_controller.go index 310a8201..fb97187b 100644 --- a/internal/controller/question_controller.go +++ b/internal/controller/question_controller.go @@ -22,20 +22,20 @@ package controller import ( "net/http" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" diff --git a/internal/controller/rank_controller.go b/internal/controller/rank_controller.go index b70e5faf..b330ca3b 100644 --- a/internal/controller/rank_controller.go +++ b/internal/controller/rank_controller.go @@ -20,10 +20,10 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/rank" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/rank" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/reason_controller.go b/internal/controller/reason_controller.go index a6a54843..7ec07cb5 100644 --- a/internal/controller/reason_controller.go +++ b/internal/controller/reason_controller.go @@ -20,9 +20,9 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/reason" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/reason" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/render_controller.go b/internal/controller/render_controller.go index 05e49d0b..63725ae0 100644 --- a/internal/controller/render_controller.go +++ b/internal/controller/render_controller.go @@ -20,8 +20,8 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/report_controller.go b/internal/controller/report_controller.go index 75ceb823..3198d54b 100644 --- a/internal/controller/report_controller.go +++ b/internal/controller/report_controller.go @@ -20,18 +20,18 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/internal/service/report" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/internal/service/report" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller/review_controller.go b/internal/controller/review_controller.go index 435cefa7..3479b2eb 100644 --- a/internal/controller/review_controller.go +++ b/internal/controller/review_controller.go @@ -20,14 +20,14 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller/revision_controller.go b/internal/controller/revision_controller.go index fd2735e0..1ceca87e 100644 --- a/internal/controller/revision_controller.go +++ b/internal/controller/revision_controller.go @@ -20,17 +20,17 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/pkg/obj" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/pkg/obj" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller/search_controller.go b/internal/controller/search_controller.go index b74c0e9e..64acbe25 100644 --- a/internal/controller/search_controller.go +++ b/internal/controller/search_controller.go @@ -20,16 +20,16 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller/siteinfo_controller.go b/internal/controller/siteinfo_controller.go index 51b596f1..5b19ae76 100644 --- a/internal/controller/siteinfo_controller.go +++ b/internal/controller/siteinfo_controller.go @@ -22,10 +22,10 @@ package controller import ( "net/http" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/siteinfo_common" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/controller/tag_controller.go b/internal/controller/tag_controller.go index 1e98b480..9474eede 100644 --- a/internal/controller/tag_controller.go +++ b/internal/controller/tag_controller.go @@ -20,15 +20,15 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/internal/service/tag" - "github.com/apache/incubator-answer/internal/service/tag_common" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/internal/service/tag" + "github.com/apache/answer/internal/service/tag_common" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller/template_controller.go b/internal/controller/template_controller.go index 0b22360f..027926b3 100644 --- a/internal/controller/template_controller.go +++ b/internal/controller/template_controller.go @@ -22,11 +22,11 @@ package controller import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/event_queue" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/event_queue" + "github.com/apache/answer/plugin" "html/template" "net/http" "net/url" @@ -34,19 +34,19 @@ import ( "strings" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - templaterender "github.com/apache/incubator-answer/internal/controller/template_render" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/obj" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/ui" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + templaterender "github.com/apache/answer/internal/controller/template_render" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/obj" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/ui" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/controller/template_render/answer.go b/internal/controller/template_render/answer.go index 72a0925a..f12497e7 100644 --- a/internal/controller/template_render/answer.go +++ b/internal/controller/template_render/answer.go @@ -22,7 +22,7 @@ package templaterender import ( "context" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" ) func (t *TemplateRenderController) AnswerList(ctx context.Context, req *schema.AnswerListReq) ([]*schema.AnswerInfo, int64, error) { diff --git a/internal/controller/template_render/comment.go b/internal/controller/template_render/comment.go index b3908f13..67efd212 100644 --- a/internal/controller/template_render/comment.go +++ b/internal/controller/template_render/comment.go @@ -21,8 +21,8 @@ package templaterender import ( "context" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/schema" ) func (t *TemplateRenderController) CommentList( diff --git a/internal/controller/template_render/controller.go b/internal/controller/template_render/controller.go index 521651b7..5f802fa7 100644 --- a/internal/controller/template_render/controller.go +++ b/internal/controller/template_render/controller.go @@ -22,15 +22,15 @@ package templaterender import ( "math" - "github.com/apache/incubator-answer/internal/service/content" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" + "github.com/apache/answer/internal/service/content" + questioncommon "github.com/apache/answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/comment" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/comment" + "github.com/apache/answer/internal/service/siteinfo_common" "github.com/google/wire" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/tag" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/tag" ) // ProviderSetTemplateRenderController is template render controller providers. diff --git a/internal/controller/template_render/question.go b/internal/controller/template_render/question.go index b9753618..fa1d4837 100644 --- a/internal/controller/template_render/question.go +++ b/internal/controller/template_render/question.go @@ -24,8 +24,8 @@ import ( "math" "net/http" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/schema" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/controller/template_render/tags.go b/internal/controller/template_render/tags.go index bfcc522c..6a6dacc9 100644 --- a/internal/controller/template_render/tags.go +++ b/internal/controller/template_render/tags.go @@ -20,8 +20,8 @@ package templaterender import ( - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/schema" "github.com/jinzhu/copier" "golang.org/x/net/context" ) diff --git a/internal/controller/template_render/userinfo.go b/internal/controller/template_render/userinfo.go index d2c222c1..1734f65c 100644 --- a/internal/controller/template_render/userinfo.go +++ b/internal/controller/template_render/userinfo.go @@ -20,7 +20,7 @@ package templaterender import ( - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" "golang.org/x/net/context" ) diff --git a/internal/controller/upload_controller.go b/internal/controller/upload_controller.go index 753be375..0bd74bf3 100644 --- a/internal/controller/upload_controller.go +++ b/internal/controller/upload_controller.go @@ -20,12 +20,12 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/uploader" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/uploader" + "github.com/apache/answer/pkg/converter" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller/user_controller.go b/internal/controller/user_controller.go index 20fc68ec..dc7d93ce 100644 --- a/internal/controller/user_controller.go +++ b/internal/controller/user_controller.go @@ -22,21 +22,21 @@ package controller import ( "net/url" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/auth" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/internal/service/user_notification_config" - "github.com/apache/incubator-answer/pkg/checker" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/auth" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/user_notification_config" + "github.com/apache/answer/pkg/checker" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/controller/user_plugin_controller.go b/internal/controller/user_plugin_controller.go index f55dc73b..31021525 100644 --- a/internal/controller/user_plugin_controller.go +++ b/internal/controller/user_plugin_controller.go @@ -21,15 +21,15 @@ package controller import ( "encoding/json" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" "github.com/segmentfault/pacman/errors" "net/http" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/plugin_common" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/plugin_common" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" ) diff --git a/internal/controller/vote_controller.go b/internal/controller/vote_controller.go index 09b5fb07..2e0ee612 100644 --- a/internal/controller/vote_controller.go +++ b/internal/controller/vote_controller.go @@ -20,17 +20,17 @@ package controller import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/controller_admin/badge_controller.go b/internal/controller_admin/badge_controller.go index 4a44f176..e399062c 100644 --- a/internal/controller_admin/badge_controller.go +++ b/internal/controller_admin/badge_controller.go @@ -20,10 +20,10 @@ package controller_admin import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/badge" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/badge" "github.com/gin-gonic/gin" ) diff --git a/internal/controller_admin/plugin_controller.go b/internal/controller_admin/plugin_controller.go index bfde841d..78f32728 100644 --- a/internal/controller_admin/plugin_controller.go +++ b/internal/controller_admin/plugin_controller.go @@ -22,10 +22,10 @@ package controller_admin import ( "encoding/json" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/plugin_common" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/plugin_common" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" ) diff --git a/internal/controller_admin/role_controller.go b/internal/controller_admin/role_controller.go index 0e038825..2692371a 100644 --- a/internal/controller_admin/role_controller.go +++ b/internal/controller_admin/role_controller.go @@ -20,9 +20,9 @@ package controller_admin import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" - service "github.com/apache/incubator-answer/internal/service/role" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/schema" + service "github.com/apache/answer/internal/service/role" "github.com/gin-gonic/gin" ) diff --git a/internal/controller_admin/siteinfo_controller.go b/internal/controller_admin/siteinfo_controller.go index 6429d671..cd1b2ab6 100644 --- a/internal/controller_admin/siteinfo_controller.go +++ b/internal/controller_admin/siteinfo_controller.go @@ -23,10 +23,10 @@ import ( "html" "net/http" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/siteinfo" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/siteinfo" "github.com/gin-gonic/gin" ) diff --git a/internal/controller_admin/theme_controller.go b/internal/controller_admin/theme_controller.go index 0c2d56b3..d763f3d9 100644 --- a/internal/controller_admin/theme_controller.go +++ b/internal/controller_admin/theme_controller.go @@ -20,8 +20,8 @@ package controller_admin import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/schema" "github.com/gin-gonic/gin" ) diff --git a/internal/controller_admin/user_backyard_controller.go b/internal/controller_admin/user_backyard_controller.go index a2ab3f2e..ddcad7c9 100644 --- a/internal/controller_admin/user_backyard_controller.go +++ b/internal/controller_admin/user_backyard_controller.go @@ -20,13 +20,13 @@ package controller_admin import ( - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/user_admin" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/user_admin" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/entity/comment_entity.go b/internal/entity/comment_entity.go index 8b79663a..c96f6b3c 100644 --- a/internal/entity/comment_entity.go +++ b/internal/entity/comment_entity.go @@ -24,7 +24,7 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/pkg/converter" ) const ( diff --git a/internal/entity/config_entity.go b/internal/entity/config_entity.go index 68ee9e25..95a02be4 100644 --- a/internal/entity/config_entity.go +++ b/internal/entity/config_entity.go @@ -23,7 +23,7 @@ import ( "encoding/json" "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/pkg/converter" ) // Config config diff --git a/internal/install/install_controller.go b/internal/install/install_controller.go index 0a116569..d43bbb45 100644 --- a/internal/install/install_controller.go +++ b/internal/install/install_controller.go @@ -26,15 +26,15 @@ import ( "path/filepath" "time" - "github.com/apache/incubator-answer/configs" - "github.com/apache/incubator-answer/internal/base/conf" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/cli" - "github.com/apache/incubator-answer/internal/migrations" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/configs" + "github.com/apache/answer/internal/base/conf" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/cli" + "github.com/apache/answer/internal/migrations" + "github.com/apache/answer/internal/schema" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" diff --git a/internal/install/install_main.go b/internal/install/install_main.go index 77d4e298..0d65f33f 100644 --- a/internal/install/install_main.go +++ b/internal/install/install_main.go @@ -23,8 +23,8 @@ import ( "fmt" "os" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/cli" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/cli" ) var ( diff --git a/internal/install/install_req.go b/internal/install/install_req.go index 9863dadd..8b2db0a8 100644 --- a/internal/install/install_req.go +++ b/internal/install/install_req.go @@ -24,9 +24,9 @@ import ( "net/url" "strings" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/pkg/checker" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/pkg/checker" "github.com/segmentfault/pacman/errors" "xorm.io/xorm/schemas" ) diff --git a/internal/install/install_server.go b/internal/install/install_server.go index 76a2fffe..856c699c 100644 --- a/internal/install/install_server.go +++ b/internal/install/install_server.go @@ -25,9 +25,9 @@ import ( "io/fs" "net/http" - "github.com/apache/incubator-answer/configs" - "github.com/apache/incubator-answer/internal/base/conf" - "github.com/apache/incubator-answer/ui" + "github.com/apache/answer/configs" + "github.com/apache/answer/internal/base/conf" + "github.com/apache/answer/ui" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" "gopkg.in/yaml.v3" diff --git a/internal/migrations/init.go b/internal/migrations/init.go index 6b1055a0..a8e4b20e 100644 --- a/internal/migrations/init.go +++ b/internal/migrations/init.go @@ -23,15 +23,15 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" "time" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/repo/unique" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/repo/unique" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "golang.org/x/crypto/bcrypt" "xorm.io/xorm" ) diff --git a/internal/migrations/init_data.go b/internal/migrations/init_data.go index b0143b33..5565809f 100644 --- a/internal/migrations/init_data.go +++ b/internal/migrations/init_data.go @@ -20,8 +20,8 @@ package migrations import ( - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/permission" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/permission" ) const ( diff --git a/internal/migrations/migrations.go b/internal/migrations/migrations.go index 6160ca88..bc2ecda7 100644 --- a/internal/migrations/migrations.go +++ b/internal/migrations/migrations.go @@ -23,8 +23,8 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/migrations/v10.go b/internal/migrations/v10.go index dba8a06f..cb1b7499 100644 --- a/internal/migrations/v10.go +++ b/internal/migrations/v10.go @@ -24,9 +24,9 @@ import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "github.com/tidwall/gjson" "xorm.io/xorm" ) diff --git a/internal/migrations/v11.go b/internal/migrations/v11.go index f5e08ed2..675690af 100644 --- a/internal/migrations/v11.go +++ b/internal/migrations/v11.go @@ -23,7 +23,7 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v12.go b/internal/migrations/v12.go index 172c5471..2dd3ce71 100644 --- a/internal/migrations/v12.go +++ b/internal/migrations/v12.go @@ -24,7 +24,7 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v13.go b/internal/migrations/v13.go index 4fcde381..30bfbb54 100644 --- a/internal/migrations/v13.go +++ b/internal/migrations/v13.go @@ -26,10 +26,10 @@ import ( "time" "xorm.io/builder" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/permission" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/permission" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v15.go b/internal/migrations/v15.go index 43878f5f..5195c105 100644 --- a/internal/migrations/v15.go +++ b/internal/migrations/v15.go @@ -21,7 +21,7 @@ package migrations import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/migrations/v16.go b/internal/migrations/v16.go index efd967b4..11643600 100644 --- a/internal/migrations/v16.go +++ b/internal/migrations/v16.go @@ -21,8 +21,8 @@ package migrations import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v17.go b/internal/migrations/v17.go index 37e5ce36..655e547a 100644 --- a/internal/migrations/v17.go +++ b/internal/migrations/v17.go @@ -22,8 +22,8 @@ package migrations import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/permission" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/permission" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v18.go b/internal/migrations/v18.go index 26dc6da5..89db524f 100644 --- a/internal/migrations/v18.go +++ b/internal/migrations/v18.go @@ -23,9 +23,9 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "xorm.io/xorm" ) diff --git a/internal/migrations/v19.go b/internal/migrations/v19.go index c4478a34..b45d374b 100644 --- a/internal/migrations/v19.go +++ b/internal/migrations/v19.go @@ -21,7 +21,7 @@ package migrations import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/migrations/v20.go b/internal/migrations/v20.go index a2349787..74242aaf 100644 --- a/internal/migrations/v20.go +++ b/internal/migrations/v20.go @@ -23,7 +23,7 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index 1543c6ad..14292a1e 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -22,9 +22,9 @@ package migrations import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/unique" "xorm.io/xorm" ) diff --git a/internal/migrations/v23.go b/internal/migrations/v23.go index 8b8a3370..49a24376 100644 --- a/internal/migrations/v23.go +++ b/internal/migrations/v23.go @@ -22,7 +22,7 @@ package migrations import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/migrations/v24.go b/internal/migrations/v24.go index 907fd1ef..19358af4 100644 --- a/internal/migrations/v24.go +++ b/internal/migrations/v24.go @@ -23,9 +23,9 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "xorm.io/xorm" ) diff --git a/internal/migrations/v3.go b/internal/migrations/v3.go index d7313114..a191d725 100644 --- a/internal/migrations/v3.go +++ b/internal/migrations/v3.go @@ -24,7 +24,7 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/log" "xorm.io/xorm" "xorm.io/xorm/schemas" diff --git a/internal/migrations/v4.go b/internal/migrations/v4.go index 913dc166..d4079a14 100644 --- a/internal/migrations/v4.go +++ b/internal/migrations/v4.go @@ -23,8 +23,8 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/permission" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/permission" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v5.go b/internal/migrations/v5.go index 4924fa99..9d422d74 100644 --- a/internal/migrations/v5.go +++ b/internal/migrations/v5.go @@ -24,7 +24,7 @@ import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/migrations/v6.go b/internal/migrations/v6.go index 367ca446..9171ad47 100644 --- a/internal/migrations/v6.go +++ b/internal/migrations/v6.go @@ -24,7 +24,7 @@ import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/migrations/v7.go b/internal/migrations/v7.go index 376e56c4..f4b64f64 100644 --- a/internal/migrations/v7.go +++ b/internal/migrations/v7.go @@ -23,7 +23,7 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v8.go b/internal/migrations/v8.go index 829beddb..cafb538e 100644 --- a/internal/migrations/v8.go +++ b/internal/migrations/v8.go @@ -24,8 +24,8 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/permission" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/permission" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/migrations/v9.go b/internal/migrations/v9.go index 8c80bd01..5f20b74e 100644 --- a/internal/migrations/v9.go +++ b/internal/migrations/v9.go @@ -23,7 +23,7 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/repo/activity/activity_repo.go b/internal/repo/activity/activity_repo.go index d41f0071..1098a73e 100644 --- a/internal/repo/activity/activity_repo.go +++ b/internal/repo/activity/activity_repo.go @@ -22,12 +22,12 @@ package activity import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_type" - "github.com/apache/incubator-answer/internal/service/config" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_type" + "github.com/apache/answer/internal/service/config" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/activity/answer_repo.go b/internal/repo/activity/answer_repo.go index f3ad1dc0..db6e3bde 100644 --- a/internal/repo/activity/answer_repo.go +++ b/internal/repo/activity/answer_repo.go @@ -26,16 +26,16 @@ import ( "time" "xorm.io/builder" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/pkg/converter" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/activity/follow_repo.go b/internal/repo/activity/follow_repo.go index e1a01593..7af2189a 100644 --- a/internal/repo/activity/follow_repo.go +++ b/internal/repo/activity/follow_repo.go @@ -23,16 +23,16 @@ import ( "context" "time" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/follow" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/follow" + "github.com/apache/answer/pkg/obj" "github.com/segmentfault/pacman/log" "xorm.io/builder" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/activity/review_repo.go b/internal/repo/activity/review_repo.go index 3325a762..c1f04b35 100644 --- a/internal/repo/activity/review_repo.go +++ b/internal/repo/activity/review_repo.go @@ -23,17 +23,17 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/pkg/converter" "xorm.io/builder" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/rank" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/rank" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/activity/user_active_repo.go b/internal/repo/activity/user_active_repo.go index 32da886b..2452bcf8 100644 --- a/internal/repo/activity/user_active_repo.go +++ b/internal/repo/activity/user_active_repo.go @@ -24,13 +24,13 @@ import ( "fmt" "xorm.io/builder" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/rank" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/rank" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/activity/vote_repo.go b/internal/repo/activity/vote_repo.go index 7e8b02e6..3fb40e75 100644 --- a/internal/repo/activity/vote_repo.go +++ b/internal/repo/activity/vote_repo.go @@ -24,24 +24,24 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/service/content" + "github.com/apache/answer/internal/service/content" "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/pkg/converter" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/pkg/obj" "xorm.io/builder" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/activity_common/activity_repo.go b/internal/repo/activity_common/activity_repo.go index 9f0a59e4..b0cece9f 100644 --- a/internal/repo/activity_common/activity_repo.go +++ b/internal/repo/activity_common/activity_repo.go @@ -24,17 +24,17 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/activity_type" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_type" + "github.com/apache/answer/pkg/obj" "xorm.io/builder" "xorm.io/xorm" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/activity_common/follow.go b/internal/repo/activity_common/follow.go index 294214c7..ed364f89 100644 --- a/internal/repo/activity_common/follow.go +++ b/internal/repo/activity_common/follow.go @@ -22,12 +22,12 @@ package activity_common import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/unique" + "github.com/apache/answer/pkg/obj" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/activity_common/vote.go b/internal/repo/activity_common/vote.go index ecdf55a6..cb7d23d0 100644 --- a/internal/repo/activity_common/vote.go +++ b/internal/repo/activity_common/vote.go @@ -21,12 +21,12 @@ package activity_common import ( "context" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/pkg/uid" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/activity_common" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/activity_common" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/answer/answer_repo.go b/internal/repo/answer/answer_repo.go index f59d6006..75f12c27 100644 --- a/internal/repo/answer/answer_repo.go +++ b/internal/repo/answer/answer_repo.go @@ -23,19 +23,19 @@ import ( "context" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/internal/service/unique" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/auth/auth.go b/internal/repo/auth/auth.go index 90a6f415..9553b6ad 100644 --- a/internal/repo/auth/auth.go +++ b/internal/repo/auth/auth.go @@ -22,12 +22,12 @@ package auth import ( "context" "encoding/json" - "github.com/apache/incubator-answer/internal/service/auth" + "github.com/apache/answer/internal/service/auth" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/badge/badge_event_rule.go b/internal/repo/badge/badge_event_rule.go index 11ce38a3..8c4656db 100644 --- a/internal/repo/badge/badge_event_rule.go +++ b/internal/repo/badge/badge_event_rule.go @@ -21,12 +21,12 @@ package badge import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/badge" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/badge" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "strconv" diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index d52fc122..257caef8 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -21,12 +21,12 @@ package badge import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/badge" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index c1ce1e58..6b77a385 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -22,12 +22,12 @@ package badge_award import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/badge" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/badge_group/badge_group_repo.go b/internal/repo/badge_group/badge_group_repo.go index 63f438b9..839ba469 100644 --- a/internal/repo/badge_group/badge_group_repo.go +++ b/internal/repo/badge_group/badge_group_repo.go @@ -21,10 +21,10 @@ package badge_group import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/badge" + "github.com/apache/answer/internal/service/unique" ) type badgeGroupRepo struct { diff --git a/internal/repo/captcha/captcha.go b/internal/repo/captcha/captcha.go index 02a1e57d..f8195c1a 100644 --- a/internal/repo/captcha/captcha.go +++ b/internal/repo/captcha/captcha.go @@ -25,10 +25,10 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/action" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/action" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/collection/collection_group_repo.go b/internal/repo/collection/collection_group_repo.go index 05711f5a..f8dc9c20 100644 --- a/internal/repo/collection/collection_group_repo.go +++ b/internal/repo/collection/collection_group_repo.go @@ -22,14 +22,14 @@ package collection import ( "context" - "github.com/apache/incubator-answer/internal/service/collection" + "github.com/apache/answer/internal/service/collection" "xorm.io/xorm" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/collection/collection_repo.go b/internal/repo/collection/collection_repo.go index c67b7bd2..1aecaf47 100644 --- a/internal/repo/collection/collection_repo.go +++ b/internal/repo/collection/collection_repo.go @@ -21,15 +21,15 @@ package collection import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + collectioncommon "github.com/apache/answer/internal/service/collection_common" + "github.com/apache/answer/internal/service/unique" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/errors" "xorm.io/xorm" ) diff --git a/internal/repo/comment/comment_repo.go b/internal/repo/comment/comment_repo.go index 79f0eaa9..f1794824 100644 --- a/internal/repo/comment/comment_repo.go +++ b/internal/repo/comment/comment_repo.go @@ -24,13 +24,13 @@ import ( "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/comment" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/comment" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/config/config_repo.go b/internal/repo/config/config_repo.go index cbaf7aec..3708aa3e 100644 --- a/internal/repo/config/config_repo.go +++ b/internal/repo/config/config_repo.go @@ -23,11 +23,11 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/config" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/config" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/export/email_repo.go b/internal/repo/export/email_repo.go index 59cba04b..1f8e1ce8 100644 --- a/internal/repo/export/email_repo.go +++ b/internal/repo/export/email_repo.go @@ -21,13 +21,13 @@ package export import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" "github.com/tidwall/gjson" "time" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/service/export" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/service/export" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/limit/limit.go b/internal/repo/limit/limit.go index cf314056..4868accd 100644 --- a/internal/repo/limit/limit.go +++ b/internal/repo/limit/limit.go @@ -22,9 +22,9 @@ package limit import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" "github.com/segmentfault/pacman/errors" "time" ) diff --git a/internal/repo/meta/meta_repo.go b/internal/repo/meta/meta_repo.go index 384fd185..767bd04c 100644 --- a/internal/repo/meta/meta_repo.go +++ b/internal/repo/meta/meta_repo.go @@ -22,10 +22,10 @@ package meta import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/meta_common" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/meta_common" "github.com/segmentfault/pacman/errors" "xorm.io/builder" "xorm.io/xorm" diff --git a/internal/repo/notification/notification_repo.go b/internal/repo/notification/notification_repo.go index 5a2a6cc7..6c72220c 100644 --- a/internal/repo/notification/notification_repo.go +++ b/internal/repo/notification/notification_repo.go @@ -23,13 +23,13 @@ import ( "context" "time" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - notficationcommon "github.com/apache/incubator-answer/internal/service/notification_common" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + notficationcommon "github.com/apache/answer/internal/service/notification_common" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/plugin_config/plugin_config_repo.go b/internal/repo/plugin_config/plugin_config_repo.go index 1ad2e495..8208fb75 100644 --- a/internal/repo/plugin_config/plugin_config_repo.go +++ b/internal/repo/plugin_config/plugin_config_repo.go @@ -22,10 +22,10 @@ package plugin_config import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/plugin_common" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/plugin_common" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/plugin_config/plugin_user_config_repo.go b/internal/repo/plugin_config/plugin_user_config_repo.go index 5b3b54de..72eabec7 100644 --- a/internal/repo/plugin_config/plugin_user_config_repo.go +++ b/internal/repo/plugin_config/plugin_user_config_repo.go @@ -21,13 +21,13 @@ package plugin_config import ( "context" - "github.com/apache/incubator-answer/internal/base/pager" + "github.com/apache/answer/internal/base/pager" "xorm.io/xorm" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/plugin_common" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/plugin_common" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/provider.go b/internal/repo/provider.go index 7f222a42..1b29cc5e 100644 --- a/internal/repo/provider.go +++ b/internal/repo/provider.go @@ -20,38 +20,38 @@ package repo import ( - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/repo/activity" - "github.com/apache/incubator-answer/internal/repo/activity_common" - "github.com/apache/incubator-answer/internal/repo/answer" - "github.com/apache/incubator-answer/internal/repo/auth" - "github.com/apache/incubator-answer/internal/repo/badge" - "github.com/apache/incubator-answer/internal/repo/badge_award" - "github.com/apache/incubator-answer/internal/repo/badge_group" - "github.com/apache/incubator-answer/internal/repo/captcha" - "github.com/apache/incubator-answer/internal/repo/collection" - "github.com/apache/incubator-answer/internal/repo/comment" - "github.com/apache/incubator-answer/internal/repo/config" - "github.com/apache/incubator-answer/internal/repo/export" - "github.com/apache/incubator-answer/internal/repo/limit" - "github.com/apache/incubator-answer/internal/repo/meta" - "github.com/apache/incubator-answer/internal/repo/notification" - "github.com/apache/incubator-answer/internal/repo/plugin_config" - "github.com/apache/incubator-answer/internal/repo/question" - "github.com/apache/incubator-answer/internal/repo/rank" - "github.com/apache/incubator-answer/internal/repo/reason" - "github.com/apache/incubator-answer/internal/repo/report" - "github.com/apache/incubator-answer/internal/repo/review" - "github.com/apache/incubator-answer/internal/repo/revision" - "github.com/apache/incubator-answer/internal/repo/role" - "github.com/apache/incubator-answer/internal/repo/search_common" - "github.com/apache/incubator-answer/internal/repo/site_info" - "github.com/apache/incubator-answer/internal/repo/tag" - "github.com/apache/incubator-answer/internal/repo/tag_common" - "github.com/apache/incubator-answer/internal/repo/unique" - "github.com/apache/incubator-answer/internal/repo/user" - "github.com/apache/incubator-answer/internal/repo/user_external_login" - "github.com/apache/incubator-answer/internal/repo/user_notification_config" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/repo/activity" + "github.com/apache/answer/internal/repo/activity_common" + "github.com/apache/answer/internal/repo/answer" + "github.com/apache/answer/internal/repo/auth" + "github.com/apache/answer/internal/repo/badge" + "github.com/apache/answer/internal/repo/badge_award" + "github.com/apache/answer/internal/repo/badge_group" + "github.com/apache/answer/internal/repo/captcha" + "github.com/apache/answer/internal/repo/collection" + "github.com/apache/answer/internal/repo/comment" + "github.com/apache/answer/internal/repo/config" + "github.com/apache/answer/internal/repo/export" + "github.com/apache/answer/internal/repo/limit" + "github.com/apache/answer/internal/repo/meta" + "github.com/apache/answer/internal/repo/notification" + "github.com/apache/answer/internal/repo/plugin_config" + "github.com/apache/answer/internal/repo/question" + "github.com/apache/answer/internal/repo/rank" + "github.com/apache/answer/internal/repo/reason" + "github.com/apache/answer/internal/repo/report" + "github.com/apache/answer/internal/repo/review" + "github.com/apache/answer/internal/repo/revision" + "github.com/apache/answer/internal/repo/role" + "github.com/apache/answer/internal/repo/search_common" + "github.com/apache/answer/internal/repo/site_info" + "github.com/apache/answer/internal/repo/tag" + "github.com/apache/answer/internal/repo/tag_common" + "github.com/apache/answer/internal/repo/unique" + "github.com/apache/answer/internal/repo/user" + "github.com/apache/answer/internal/repo/user_external_login" + "github.com/apache/answer/internal/repo/user_notification_config" "github.com/google/wire" ) diff --git a/internal/repo/question/question_repo.go b/internal/repo/question/question_repo.go index 9b1d212e..5d889d7a 100644 --- a/internal/repo/question/question_repo.go +++ b/internal/repo/question/question_repo.go @@ -27,18 +27,18 @@ import ( "time" "unicode" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/unique" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "xorm.io/builder" diff --git a/internal/repo/rank/user_rank_repo.go b/internal/repo/rank/user_rank_repo.go index f99b71f9..a44c3e37 100644 --- a/internal/repo/rank/user_rank_repo.go +++ b/internal/repo/rank/user_rank_repo.go @@ -22,13 +22,13 @@ package rank import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/plugin" "github.com/jinzhu/now" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/repo/reason/reason_repo.go b/internal/repo/reason/reason_repo.go index 94df2214..875e3f98 100644 --- a/internal/repo/reason/reason_repo.go +++ b/internal/repo/reason/reason_repo.go @@ -24,10 +24,10 @@ import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/reason_common" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/reason_common" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/repo_test/auth_test.go b/internal/repo/repo_test/auth_test.go index 686d1644..38733239 100644 --- a/internal/repo/repo_test/auth_test.go +++ b/internal/repo/repo_test/auth_test.go @@ -23,8 +23,8 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/auth" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/auth" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/captcha_test.go b/internal/repo/repo_test/captcha_test.go index c9138835..48e9dd80 100644 --- a/internal/repo/repo_test/captcha_test.go +++ b/internal/repo/repo_test/captcha_test.go @@ -23,7 +23,7 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/repo/captcha" + "github.com/apache/answer/internal/repo/captcha" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/comment_repo_test.go b/internal/repo/repo_test/comment_repo_test.go index 642e3d75..3de15481 100644 --- a/internal/repo/repo_test/comment_repo_test.go +++ b/internal/repo/repo_test/comment_repo_test.go @@ -23,11 +23,11 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/comment" - "github.com/apache/incubator-answer/internal/repo/unique" - commentService "github.com/apache/incubator-answer/internal/service/comment" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/comment" + "github.com/apache/answer/internal/repo/unique" + commentService "github.com/apache/answer/internal/service/comment" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/email_repo_test.go b/internal/repo/repo_test/email_repo_test.go index 62d1ccb8..82fc6c57 100644 --- a/internal/repo/repo_test/email_repo_test.go +++ b/internal/repo/repo_test/email_repo_test.go @@ -24,7 +24,7 @@ import ( "testing" "time" - "github.com/apache/incubator-answer/internal/repo/export" + "github.com/apache/answer/internal/repo/export" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/meta_repo_test.go b/internal/repo/repo_test/meta_repo_test.go index fefd8803..e910dab3 100644 --- a/internal/repo/repo_test/meta_repo_test.go +++ b/internal/repo/repo_test/meta_repo_test.go @@ -23,8 +23,8 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/meta" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/meta" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/notification_repo_test.go b/internal/repo/repo_test/notification_repo_test.go index f93daf31..a05913ba 100644 --- a/internal/repo/repo_test/notification_repo_test.go +++ b/internal/repo/repo_test/notification_repo_test.go @@ -23,9 +23,9 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/notification" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/notification" + "github.com/apache/answer/internal/schema" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/reason_repo_test.go b/internal/repo/repo_test/reason_repo_test.go index 7848b2e4..636f8d27 100644 --- a/internal/repo/repo_test/reason_repo_test.go +++ b/internal/repo/repo_test/reason_repo_test.go @@ -23,10 +23,10 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/repo/config" - serviceconfig "github.com/apache/incubator-answer/internal/service/config" + "github.com/apache/answer/internal/repo/config" + serviceconfig "github.com/apache/answer/internal/service/config" - "github.com/apache/incubator-answer/internal/repo/reason" + "github.com/apache/answer/internal/repo/reason" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/recommend_test.go b/internal/repo/repo_test/recommend_test.go index 6c87dfe7..a2169388 100644 --- a/internal/repo/repo_test/recommend_test.go +++ b/internal/repo/repo_test/recommend_test.go @@ -23,16 +23,16 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/activity" - "github.com/apache/incubator-answer/internal/repo/activity_common" - "github.com/apache/incubator-answer/internal/repo/config" - "github.com/apache/incubator-answer/internal/repo/question" - "github.com/apache/incubator-answer/internal/repo/tag" - "github.com/apache/incubator-answer/internal/repo/tag_common" - "github.com/apache/incubator-answer/internal/repo/unique" - "github.com/apache/incubator-answer/internal/repo/user" - config2 "github.com/apache/incubator-answer/internal/service/config" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/activity" + "github.com/apache/answer/internal/repo/activity_common" + "github.com/apache/answer/internal/repo/config" + "github.com/apache/answer/internal/repo/question" + "github.com/apache/answer/internal/repo/tag" + "github.com/apache/answer/internal/repo/tag_common" + "github.com/apache/answer/internal/repo/unique" + "github.com/apache/answer/internal/repo/user" + config2 "github.com/apache/answer/internal/service/config" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/repo_main_test.go b/internal/repo/repo_test/repo_main_test.go index d1c365e4..a59ae626 100644 --- a/internal/repo/repo_test/repo_main_test.go +++ b/internal/repo/repo_test/repo_main_test.go @@ -28,8 +28,8 @@ import ( "testing" "time" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/migrations" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/migrations" "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "github.com/segmentfault/pacman/cache" diff --git a/internal/repo/repo_test/revision_repo_test.go b/internal/repo/repo_test/revision_repo_test.go index 649869c6..01d262d2 100644 --- a/internal/repo/repo_test/revision_repo_test.go +++ b/internal/repo/repo_test/revision_repo_test.go @@ -24,10 +24,10 @@ import ( "encoding/json" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/question" - "github.com/apache/incubator-answer/internal/repo/revision" - "github.com/apache/incubator-answer/internal/repo/unique" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/question" + "github.com/apache/answer/internal/repo/revision" + "github.com/apache/answer/internal/repo/unique" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/siteinfo_repo_test.go b/internal/repo/repo_test/siteinfo_repo_test.go index 27b4bb9c..cb5d8fc0 100644 --- a/internal/repo/repo_test/siteinfo_repo_test.go +++ b/internal/repo/repo_test/siteinfo_repo_test.go @@ -23,8 +23,8 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/site_info" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/site_info" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/tag_rel_repo_test.go b/internal/repo/repo_test/tag_rel_repo_test.go index 1cc96319..e3af67a1 100644 --- a/internal/repo/repo_test/tag_rel_repo_test.go +++ b/internal/repo/repo_test/tag_rel_repo_test.go @@ -25,10 +25,10 @@ import ( "sync" "testing" - "github.com/apache/incubator-answer/internal/repo/unique" + "github.com/apache/answer/internal/repo/unique" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/tag" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/tag" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/tag_repo_test.go b/internal/repo/repo_test/tag_repo_test.go index 0c00782f..b2475a22 100644 --- a/internal/repo/repo_test/tag_repo_test.go +++ b/internal/repo/repo_test/tag_repo_test.go @@ -26,11 +26,11 @@ import ( "sync" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/tag" - "github.com/apache/incubator-answer/internal/repo/tag_common" - "github.com/apache/incubator-answer/internal/repo/unique" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/tag" + "github.com/apache/answer/internal/repo/tag_common" + "github.com/apache/answer/internal/repo/unique" + "github.com/apache/answer/pkg/converter" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/user_backyard_repo_test.go b/internal/repo/repo_test/user_backyard_repo_test.go index cb2c01e4..e1db0d60 100644 --- a/internal/repo/repo_test/user_backyard_repo_test.go +++ b/internal/repo/repo_test/user_backyard_repo_test.go @@ -23,9 +23,9 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/auth" - "github.com/apache/incubator-answer/internal/repo/user" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/auth" + "github.com/apache/answer/internal/repo/user" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/repo_test/user_repo_test.go b/internal/repo/repo_test/user_repo_test.go index 09176b76..7b18833d 100644 --- a/internal/repo/repo_test/user_repo_test.go +++ b/internal/repo/repo_test/user_repo_test.go @@ -23,8 +23,8 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/repo/user" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/repo/user" "github.com/stretchr/testify/assert" ) diff --git a/internal/repo/report/report_repo.go b/internal/repo/report/report_repo.go index 013d036d..e597c9a1 100644 --- a/internal/repo/report/report_repo.go +++ b/internal/repo/report/report_repo.go @@ -22,14 +22,14 @@ package report import ( "context" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/report_common" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/report_common" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/review/review_repo.go b/internal/repo/review/review_repo.go index c87c814c..20cc82aa 100644 --- a/internal/repo/review/review_repo.go +++ b/internal/repo/review/review_repo.go @@ -22,11 +22,11 @@ package review import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/review" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/review" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/revision/revision_repo.go b/internal/repo/revision/revision_repo.go index eba23251..ab00adf9 100644 --- a/internal/repo/revision/revision_repo.go +++ b/internal/repo/revision/revision_repo.go @@ -22,15 +22,15 @@ package revision import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/revision" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/revision" + "github.com/apache/answer/internal/service/unique" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/obj" "github.com/segmentfault/pacman/errors" "xorm.io/builder" "xorm.io/xorm" diff --git a/internal/repo/role/power_repo.go b/internal/repo/role/power_repo.go index 89b33146..8da7c663 100644 --- a/internal/repo/role/power_repo.go +++ b/internal/repo/role/power_repo.go @@ -22,10 +22,10 @@ package role import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/role" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/role" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/role/role_power_rel_repo.go b/internal/repo/role/role_power_rel_repo.go index ccb9e744..76a3c76d 100644 --- a/internal/repo/role/role_power_rel_repo.go +++ b/internal/repo/role/role_power_rel_repo.go @@ -22,9 +22,9 @@ package role import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/service/role" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/service/role" "github.com/segmentfault/pacman/errors" "xorm.io/builder" ) diff --git a/internal/repo/role/role_repo.go b/internal/repo/role/role_repo.go index 1a8bddbc..51dfb232 100644 --- a/internal/repo/role/role_repo.go +++ b/internal/repo/role/role_repo.go @@ -22,10 +22,10 @@ package role import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - service "github.com/apache/incubator-answer/internal/service/role" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + service "github.com/apache/answer/internal/service/role" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/role/user_role_rel_repo.go b/internal/repo/role/user_role_rel_repo.go index 001745fe..7bd14ece 100644 --- a/internal/repo/role/user_role_rel_repo.go +++ b/internal/repo/role/user_role_rel_repo.go @@ -22,10 +22,10 @@ package role import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/role" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/role" "github.com/segmentfault/pacman/errors" "xorm.io/builder" "xorm.io/xorm" diff --git a/internal/repo/search_common/search_repo.go b/internal/repo/search_common/search_repo.go index 1c4f04ab..314c5187 100644 --- a/internal/repo/search_common/search_repo.go +++ b/internal/repo/search_common/search_repo.go @@ -26,22 +26,22 @@ import ( "strings" "time" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/plugin" + tagcommon "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/plugin" - "github.com/apache/incubator-answer/pkg/htmltext" + "github.com/apache/answer/pkg/htmltext" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/search_common" - "github.com/apache/incubator-answer/internal/service/unique" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/obj" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/search_common" + "github.com/apache/answer/internal/service/unique" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/obj" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/errors" "xorm.io/builder" ) diff --git a/internal/repo/search_sync/search_sync.go b/internal/repo/search_sync/search_sync.go index d54c7c2f..5c0adc0f 100644 --- a/internal/repo/search_sync/search_sync.go +++ b/internal/repo/search_sync/search_sync.go @@ -21,12 +21,12 @@ package search_sync import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/site_info/siteinfo_repo.go b/internal/repo/site_info/siteinfo_repo.go index 8d81a3ff..420e483f 100644 --- a/internal/repo/site_info/siteinfo_repo.go +++ b/internal/repo/site_info/siteinfo_repo.go @@ -23,11 +23,11 @@ import ( "context" "encoding/json" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/siteinfo_common" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "xorm.io/builder" diff --git a/internal/repo/tag/tag_rel_repo.go b/internal/repo/tag/tag_rel_repo.go index 3188295c..565c6386 100644 --- a/internal/repo/tag/tag_rel_repo.go +++ b/internal/repo/tag/tag_rel_repo.go @@ -22,13 +22,13 @@ package tag import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + tagcommon "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/internal/service/unique" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/tag/tag_repo.go b/internal/repo/tag/tag_repo.go index c9c2c1fa..bdfe62cf 100644 --- a/internal/repo/tag/tag_repo.go +++ b/internal/repo/tag/tag_repo.go @@ -22,12 +22,12 @@ package tag import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/internal/service/unique" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/internal/service/unique" + "github.com/apache/answer/pkg/converter" "github.com/segmentfault/pacman/errors" "xorm.io/builder" ) diff --git a/internal/repo/tag_common/tag_common_repo.go b/internal/repo/tag_common/tag_common_repo.go index f3a85282..c4762b0c 100644 --- a/internal/repo/tag_common/tag_common_repo.go +++ b/internal/repo/tag_common/tag_common_repo.go @@ -25,12 +25,12 @@ import ( "strconv" "strings" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + tagcommon "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" "xorm.io/builder" ) diff --git a/internal/repo/unique/uniqid_repo.go b/internal/repo/unique/uniqid_repo.go index 27dcea19..8ad3e3be 100644 --- a/internal/repo/unique/uniqid_repo.go +++ b/internal/repo/unique/uniqid_repo.go @@ -23,11 +23,11 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/unique" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/unique" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/user/user_backyard_repo.go b/internal/repo/user/user_backyard_repo.go index 44a05cfb..420b02f2 100644 --- a/internal/repo/user/user_backyard_repo.go +++ b/internal/repo/user/user_backyard_repo.go @@ -26,12 +26,12 @@ import ( "xorm.io/builder" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/auth" - "github.com/apache/incubator-answer/internal/service/user_admin" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/auth" + "github.com/apache/answer/internal/service/user_admin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/repo/user/user_repo.go b/internal/repo/user/user_repo.go index fef1fa71..f56e00b8 100644 --- a/internal/repo/user/user_repo.go +++ b/internal/repo/user/user_repo.go @@ -24,13 +24,13 @@ import ( "strings" "time" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "xorm.io/xorm" diff --git a/internal/repo/user_external_login/user_external_login_repo.go b/internal/repo/user_external_login/user_external_login_repo.go index c2d13108..c797e461 100644 --- a/internal/repo/user_external_login/user_external_login_repo.go +++ b/internal/repo/user_external_login/user_external_login_repo.go @@ -23,12 +23,12 @@ import ( "context" "encoding/json" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/user_external_login" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/user_external_login" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/repo/user_notification_config/user_notification_config_repo.go b/internal/repo/user_notification_config/user_notification_config_repo.go index 6785b679..8ea2b065 100644 --- a/internal/repo/user_notification_config/user_notification_config_repo.go +++ b/internal/repo/user_notification_config/user_notification_config_repo.go @@ -21,11 +21,11 @@ package user_notification_config import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/user_notification_config" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/user_notification_config" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index 2927afef..a855f07d 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -20,9 +20,9 @@ package router import ( - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/controller" - "github.com/apache/incubator-answer/internal/controller_admin" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/controller" + "github.com/apache/answer/internal/controller_admin" "github.com/gin-gonic/gin" ) diff --git a/internal/router/plugin_api_router.go b/internal/router/plugin_api_router.go index e69e0b6b..ce5062ba 100644 --- a/internal/router/plugin_api_router.go +++ b/internal/router/plugin_api_router.go @@ -20,7 +20,7 @@ package router import ( - "github.com/apache/incubator-answer/internal/controller" + "github.com/apache/answer/internal/controller" "github.com/gin-gonic/gin" ) diff --git a/internal/router/static_router.go b/internal/router/static_router.go index 71457f49..807f4c73 100644 --- a/internal/router/static_router.go +++ b/internal/router/static_router.go @@ -20,8 +20,8 @@ package router import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/service/service_config" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/service/service_config" "github.com/gin-gonic/gin" "path/filepath" "strings" diff --git a/internal/router/swagger_router.go b/internal/router/swagger_router.go index 55f2d644..06c13588 100644 --- a/internal/router/swagger_router.go +++ b/internal/router/swagger_router.go @@ -22,7 +22,7 @@ package router import ( "fmt" - "github.com/apache/incubator-answer/docs" + "github.com/apache/answer/docs" "github.com/gin-gonic/gin" swaggerfiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" diff --git a/internal/router/template_router.go b/internal/router/template_router.go index 195030f9..7c42f4ea 100644 --- a/internal/router/template_router.go +++ b/internal/router/template_router.go @@ -20,10 +20,10 @@ package router import ( - "github.com/apache/incubator-answer/internal/base/middleware" - "github.com/apache/incubator-answer/internal/controller" - templaterender "github.com/apache/incubator-answer/internal/controller/template_render" - "github.com/apache/incubator-answer/internal/controller_admin" + "github.com/apache/answer/internal/base/middleware" + "github.com/apache/answer/internal/controller" + templaterender "github.com/apache/answer/internal/controller/template_render" + "github.com/apache/answer/internal/controller_admin" "github.com/gin-gonic/gin" ) diff --git a/internal/router/ui.go b/internal/router/ui.go index b0b8a6d9..0b5ee3f9 100644 --- a/internal/router/ui.go +++ b/internal/router/ui.go @@ -22,16 +22,16 @@ package router import ( "embed" "fmt" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/plugin" "io/fs" "net/http" "os" "strings" - "github.com/apache/incubator-answer/internal/controller" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/ui" + "github.com/apache/answer/internal/controller" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/ui" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/schema/activity.go b/internal/schema/activity.go index 2ec837aa..e62bdd78 100644 --- a/internal/schema/activity.go +++ b/internal/schema/activity.go @@ -19,7 +19,7 @@ package schema -import "github.com/apache/incubator-answer/internal/base/constant" +import "github.com/apache/answer/internal/base/constant" // ActivityMsg activity message type ActivityMsg struct { diff --git a/internal/schema/answer_schema.go b/internal/schema/answer_schema.go index 01bc64a2..72f5a9d0 100644 --- a/internal/schema/answer_schema.go +++ b/internal/schema/answer_schema.go @@ -20,8 +20,8 @@ package schema import ( - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/pkg/converter" ) // RemoveAnswerReq delete answer request diff --git a/internal/schema/backyard_user_schema.go b/internal/schema/backyard_user_schema.go index 7c690aee..a64077de 100644 --- a/internal/schema/backyard_user_schema.go +++ b/internal/schema/backyard_user_schema.go @@ -21,11 +21,11 @@ package schema import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" "github.com/segmentfault/pacman/errors" "strings" ) diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index 8c934ee2..86d13c03 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -19,7 +19,7 @@ package schema -import "github.com/apache/incubator-answer/internal/entity" +import "github.com/apache/answer/internal/entity" const ( BadgeStatusActive BadgeStatus = "active" diff --git a/internal/schema/comment_schema.go b/internal/schema/comment_schema.go index 275e1b9a..a5483322 100644 --- a/internal/schema/comment_schema.go +++ b/internal/schema/comment_schema.go @@ -20,9 +20,9 @@ package schema import ( - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/pkg/converter" "github.com/jinzhu/copier" ) diff --git a/internal/schema/email_template.go b/internal/schema/email_template.go index 56d3ee4e..1fcdfbce 100644 --- a/internal/schema/email_template.go +++ b/internal/schema/email_template.go @@ -21,7 +21,7 @@ package schema import ( "encoding/json" - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" ) const ( diff --git a/internal/schema/event_schema.go b/internal/schema/event_schema.go index abacaed3..fabbabce 100644 --- a/internal/schema/event_schema.go +++ b/internal/schema/event_schema.go @@ -20,8 +20,8 @@ package schema import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/pkg/uid" ) // EventMsg event message diff --git a/internal/schema/new_question_queue_schema.go b/internal/schema/new_question_queue_schema.go index d634d5ad..5faeabb2 100644 --- a/internal/schema/new_question_queue_schema.go +++ b/internal/schema/new_question_queue_schema.go @@ -20,8 +20,8 @@ package schema import ( - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/pkg/uid" ) type ExternalNotificationMsg struct { diff --git a/internal/schema/notification_schema.go b/internal/schema/notification_schema.go index 8d4b694e..a68328ac 100644 --- a/internal/schema/notification_schema.go +++ b/internal/schema/notification_schema.go @@ -21,7 +21,7 @@ package schema import ( "encoding/json" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "sort" ) diff --git a/internal/schema/permission.go b/internal/schema/permission.go index 6ad7b91f..106709d1 100644 --- a/internal/schema/permission.go +++ b/internal/schema/permission.go @@ -22,9 +22,9 @@ package schema import ( "strings" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" "github.com/segmentfault/pacman/i18n" ) diff --git a/internal/schema/plugin_admin_schema.go b/internal/schema/plugin_admin_schema.go index c588c6da..77129ac7 100644 --- a/internal/schema/plugin_admin_schema.go +++ b/internal/schema/plugin_admin_schema.go @@ -20,7 +20,7 @@ package schema import ( - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" ) diff --git a/internal/schema/plugin_user_schema.go b/internal/schema/plugin_user_schema.go index b2734cb1..2e35f58a 100644 --- a/internal/schema/plugin_user_schema.go +++ b/internal/schema/plugin_user_schema.go @@ -20,7 +20,7 @@ package schema import ( - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" ) diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index accc3374..8adc7484 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -23,10 +23,10 @@ import ( "strings" "time" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/uid" ) const ( diff --git a/internal/schema/reason_schema.go b/internal/schema/reason_schema.go index b408ce9b..65b352bc 100644 --- a/internal/schema/reason_schema.go +++ b/internal/schema/reason_schema.go @@ -20,7 +20,7 @@ package schema import ( - "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/answer/internal/base/translator" "github.com/segmentfault/pacman/i18n" ) diff --git a/internal/schema/review_schema.go b/internal/schema/review_schema.go index 6fe9025a..a4006d29 100644 --- a/internal/schema/review_schema.go +++ b/internal/schema/review_schema.go @@ -20,8 +20,8 @@ package schema import ( - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/pkg/uid" ) // UpdateReviewReq update review request diff --git a/internal/schema/revision_schema.go b/internal/schema/revision_schema.go index f1b11688..946d1165 100644 --- a/internal/schema/revision_schema.go +++ b/internal/schema/revision_schema.go @@ -22,7 +22,7 @@ package schema import ( "time" - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" ) // AddRevisionDTO add revision request diff --git a/internal/schema/search_schema.go b/internal/schema/search_schema.go index 50aeaa6f..8667c74a 100644 --- a/internal/schema/search_schema.go +++ b/internal/schema/search_schema.go @@ -23,9 +23,9 @@ import ( "regexp" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/plugin" ) type SearchDTO struct { diff --git a/internal/schema/simple_obj_info_schema.go b/internal/schema/simple_obj_info_schema.go index 3a3f7810..a9bcf3b1 100644 --- a/internal/schema/simple_obj_info_schema.go +++ b/internal/schema/simple_obj_info_schema.go @@ -20,8 +20,8 @@ package schema import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" ) // SimpleObjectInfo simple object info diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go index fee6b8cb..264ddb99 100644 --- a/internal/schema/siteinfo_schema.go +++ b/internal/schema/siteinfo_schema.go @@ -26,11 +26,11 @@ import ( "net/url" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/schema/tag_schema.go b/internal/schema/tag_schema.go index 888c224b..c9c10d9c 100644 --- a/internal/schema/tag_schema.go +++ b/internal/schema/tag_schema.go @@ -22,8 +22,8 @@ package schema import ( "strings" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/pkg/converter" ) // SearchTagLikeReq get tag list all request diff --git a/internal/schema/user_notification_schema.go b/internal/schema/user_notification_schema.go index 4c2cd3f9..eca97e81 100644 --- a/internal/schema/user_notification_schema.go +++ b/internal/schema/user_notification_schema.go @@ -21,8 +21,8 @@ package schema import ( "encoding/json" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" ) type NotificationChannelConfig struct { diff --git a/internal/schema/user_schema.go b/internal/schema/user_schema.go index 95837d96..9d126da8 100644 --- a/internal/schema/user_schema.go +++ b/internal/schema/user_schema.go @@ -22,15 +22,15 @@ package schema import ( "encoding/json" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" "github.com/segmentfault/pacman/errors" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/converter" "github.com/jinzhu/copier" ) diff --git a/internal/service/action/captcha_service.go b/internal/service/action/captcha_service.go index 326ea637..04f8b16a 100644 --- a/internal/service/action/captcha_service.go +++ b/internal/service/action/captcha_service.go @@ -22,10 +22,10 @@ package action import ( "context" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/action/captcha_strategy.go b/internal/service/action/captcha_strategy.go index 1d2dcbc3..3befda82 100644 --- a/internal/service/action/captcha_strategy.go +++ b/internal/service/action/captcha_strategy.go @@ -23,10 +23,10 @@ import ( "context" "time" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" ) // ValidationStrategy diff --git a/internal/service/activity/activity.go b/internal/service/activity/activity.go index 7188fa94..2d384f34 100644 --- a/internal/service/activity/activity.go +++ b/internal/service/activity/activity.go @@ -25,22 +25,22 @@ import ( "fmt" "strings" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/meta_common" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/meta_common" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/object_info" - "github.com/apache/incubator-answer/internal/service/revision_common" - "github.com/apache/incubator-answer/internal/service/tag_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/obj" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/object_info" + "github.com/apache/answer/internal/service/revision_common" + "github.com/apache/answer/internal/service/tag_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/obj" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/activity/answer_activity_service.go b/internal/service/activity/answer_activity_service.go index 221a2040..169e7eb3 100644 --- a/internal/service/activity/answer_activity_service.go +++ b/internal/service/activity/answer_activity_service.go @@ -21,9 +21,9 @@ package activity import ( "context" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_type" - "github.com/apache/incubator-answer/internal/service/config" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_type" + "github.com/apache/answer/internal/service/config" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/activity/review_active.go b/internal/service/activity/review_active.go index 0f0a9c24..48ad5035 100644 --- a/internal/service/activity/review_active.go +++ b/internal/service/activity/review_active.go @@ -22,7 +22,7 @@ package activity import ( "context" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" ) // ReviewActivityRepo interface diff --git a/internal/service/activity_common/activity.go b/internal/service/activity_common/activity.go index 6b3557c0..b01e5603 100644 --- a/internal/service/activity_common/activity.go +++ b/internal/service/activity_common/activity.go @@ -23,11 +23,11 @@ import ( "context" "time" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_queue" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_queue" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/log" "xorm.io/xorm" ) diff --git a/internal/service/activity_queue/activity_queue.go b/internal/service/activity_queue/activity_queue.go index e5019e83..7b8c1e3b 100644 --- a/internal/service/activity_queue/activity_queue.go +++ b/internal/service/activity_queue/activity_queue.go @@ -22,7 +22,7 @@ package activity_queue import ( "context" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/answer_common/answer.go b/internal/service/answer_common/answer.go index 45b11886..d63bf8aa 100644 --- a/internal/service/answer_common/answer.go +++ b/internal/service/answer_common/answer.go @@ -22,11 +22,11 @@ package answercommon import ( "context" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/uid" ) type AnswerRepo interface { diff --git a/internal/service/auth/auth.go b/internal/service/auth/auth.go index afb63391..9ee5f3ee 100644 --- a/internal/service/auth/auth.go +++ b/internal/service/auth/auth.go @@ -22,9 +22,9 @@ package auth import ( "context" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/plugin" ) // AuthRepo auth repository diff --git a/internal/service/badge/badge_award_service.go b/internal/service/badge/badge_award_service.go index feb95a65..3196b9cd 100644 --- a/internal/service/badge/badge_award_service.go +++ b/internal/service/badge/badge_award_service.go @@ -21,16 +21,16 @@ package badge import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/object_info" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/object_info" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" diff --git a/internal/service/badge/badge_event_handler.go b/internal/service/badge/badge_event_handler.go index 8a92f08b..21982294 100644 --- a/internal/service/badge/badge_event_handler.go +++ b/internal/service/badge/badge_event_handler.go @@ -21,10 +21,10 @@ package badge import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/event_queue" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/badge/badge_group_service.go b/internal/service/badge/badge_group_service.go index 16dd74ee..e0dab6e8 100644 --- a/internal/service/badge/badge_group_service.go +++ b/internal/service/badge/badge_group_service.go @@ -21,7 +21,7 @@ package badge import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" ) type BadgeGroupRepo interface { diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 0ab538a3..7bc9ffe2 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -21,14 +21,14 @@ package badge import ( "context" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/collection/collection_group_service.go b/internal/service/collection/collection_group_service.go index 3f6f3db1..244d84ca 100644 --- a/internal/service/collection/collection_group_service.go +++ b/internal/service/collection/collection_group_service.go @@ -22,9 +22,9 @@ package collection import ( "context" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/service/collection/collection_service.go b/internal/service/collection/collection_service.go index 1820ac52..6f02ccf9 100644 --- a/internal/service/collection/collection_service.go +++ b/internal/service/collection/collection_service.go @@ -22,10 +22,10 @@ package collection import ( "context" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + collectioncommon "github.com/apache/answer/internal/service/collection_common" + questioncommon "github.com/apache/answer/internal/service/question_common" ) // CollectionService user service diff --git a/internal/service/collection_common/collection.go b/internal/service/collection_common/collection.go index daf856ec..1d8f05d0 100644 --- a/internal/service/collection_common/collection.go +++ b/internal/service/collection_common/collection.go @@ -22,7 +22,7 @@ package collectioncommon import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" ) // CollectionRepo collection repository diff --git a/internal/service/comment/comment_service.go b/internal/service/comment/comment_service.go index 012149e7..ba9bbe1d 100644 --- a/internal/service/comment/comment_service.go +++ b/internal/service/comment/comment_service.go @@ -21,25 +21,25 @@ package comment import ( "context" - "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/answer/internal/service/event_queue" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/activity_queue" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/object_info" - "github.com/apache/incubator-answer/internal/service/permission" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_queue" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/object_info" + "github.com/apache/answer/internal/service/permission" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/pkg/uid" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/comment_common/comment_service.go b/internal/service/comment_common/comment_service.go index 3554a358..0b6423a4 100644 --- a/internal/service/comment_common/comment_service.go +++ b/internal/service/comment_common/comment_service.go @@ -22,9 +22,9 @@ package comment_common import ( "context" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/service/config/config_service.go b/internal/service/config/config_service.go index cff27f2b..63aea221 100644 --- a/internal/service/config/config_service.go +++ b/internal/service/config/config_service.go @@ -24,7 +24,7 @@ import ( "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" ) // ConfigRepo config repository diff --git a/internal/service/content/answer_service.go b/internal/service/content/answer_service.go index d4983c3c..b9d45b52 100644 --- a/internal/service/content/answer_service.go +++ b/internal/service/content/answer_service.go @@ -24,29 +24,29 @@ import ( "encoding/json" "time" - "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/answer/internal/service/event_queue" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/activity_queue" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/permission" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/internal/service/revision_common" - "github.com/apache/incubator-answer/internal/service/role" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_queue" + answercommon "github.com/apache/answer/internal/service/answer_common" + collectioncommon "github.com/apache/answer/internal/service/collection_common" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/permission" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/internal/service/revision_common" + "github.com/apache/answer/internal/service/role" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/content/question_hottest_service.go b/internal/service/content/question_hottest_service.go index 6a37d3b3..a33b155f 100644 --- a/internal/service/content/question_hottest_service.go +++ b/internal/service/content/question_hottest_service.go @@ -21,8 +21,8 @@ package content import ( "context" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/log" "math" "time" diff --git a/internal/service/content/question_service.go b/internal/service/content/question_service.go index 145f7da1..8ddda597 100644 --- a/internal/service/content/question_service.go +++ b/internal/service/content/question_service.go @@ -25,40 +25,40 @@ import ( "strings" "time" - "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/answer/internal/service/event_queue" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/activity_queue" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/export" - metacommon "github.com/apache/incubator-answer/internal/service/meta_common" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/notification" - "github.com/apache/incubator-answer/internal/service/permission" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/internal/service/revision_common" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/internal/service/tag" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_queue" + answercommon "github.com/apache/answer/internal/service/answer_common" + collectioncommon "github.com/apache/answer/internal/service/collection_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/export" + metacommon "github.com/apache/answer/internal/service/meta_common" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/notification" + "github.com/apache/answer/internal/service/permission" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/internal/service/revision_common" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/tag" + tagcommon "github.com/apache/answer/internal/service/tag_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/pkg/uid" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/content/revision_service.go b/internal/service/content/revision_service.go index b69a0568..effc012b 100644 --- a/internal/service/content/revision_service.go +++ b/internal/service/content/revision_service.go @@ -24,29 +24,29 @@ import ( "encoding/json" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_queue" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/object_info" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/report_common" - "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/internal/service/revision" - "github.com/apache/incubator-answer/internal/service/tag_common" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/obj" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_queue" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/object_info" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/report_common" + "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/internal/service/revision" + "github.com/apache/answer/internal/service/tag_common" + tagcommon "github.com/apache/answer/internal/service/tag_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/obj" + "github.com/apache/answer/pkg/uid" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/content/search_service.go b/internal/service/content/search_service.go index 42d7c521..98add093 100644 --- a/internal/service/content/search_service.go +++ b/internal/service/content/search_service.go @@ -22,10 +22,10 @@ package content import ( "context" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/search_common" - "github.com/apache/incubator-answer/internal/service/search_parser" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/search_common" + "github.com/apache/answer/internal/service/search_parser" + "github.com/apache/answer/plugin" ) type SearchService struct { diff --git a/internal/service/content/user_service.go b/internal/service/content/user_service.go index e4d3f236..b59790c1 100644 --- a/internal/service/content/user_service.go +++ b/internal/service/content/user_service.go @@ -23,30 +23,30 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/service/event_queue" - "github.com/apache/incubator-answer/pkg/token" + "github.com/apache/answer/internal/service/event_queue" + "github.com/apache/answer/pkg/token" "time" - "github.com/apache/incubator-answer/internal/base/constant" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/user_notification_config" + "github.com/apache/answer/internal/base/constant" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/user_notification_config" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/auth" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/internal/service/user_external_login" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/auth" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/siteinfo_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/internal/service/user_external_login" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "golang.org/x/crypto/bcrypt" diff --git a/internal/service/content/vote_service.go b/internal/service/content/vote_service.go index b4b92ddd..ff3ee597 100644 --- a/internal/service/content/vote_service.go +++ b/internal/service/content/vote_service.go @@ -22,27 +22,27 @@ package content import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/answer/internal/service/event_queue" "strings" - "github.com/apache/incubator-answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/activity_type" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/object_info" - "github.com/apache/incubator-answer/pkg/htmltext" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/activity_type" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/object_info" + "github.com/apache/answer/pkg/htmltext" "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/schema" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/schema" + answercommon "github.com/apache/answer/internal/service/answer_common" + questioncommon "github.com/apache/answer/internal/service/question_common" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/service/dashboard/dashboard_service.go b/internal/service/dashboard/dashboard_service.go index ebc9a79d..00c9d7c8 100644 --- a/internal/service/dashboard/dashboard_service.go +++ b/internal/service/dashboard/dashboard_service.go @@ -28,25 +28,25 @@ import ( "net/url" "time" - "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/internal/service/revision" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/internal/service/revision" + "github.com/apache/answer/pkg/converter" "xorm.io/xorm/schemas" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/export" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/report_common" - "github.com/apache/incubator-answer/internal/service/service_config" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/dir" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/export" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/report_common" + "github.com/apache/answer/internal/service/service_config" + "github.com/apache/answer/internal/service/siteinfo_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/dir" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/event_queue/event_queue.go b/internal/service/event_queue/event_queue.go index b89a3ccc..77dc302b 100644 --- a/internal/service/event_queue/event_queue.go +++ b/internal/service/event_queue/event_queue.go @@ -22,7 +22,7 @@ package event_queue import ( "context" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/export/email_service.go b/internal/service/export/email_service.go index 1ed1b784..b00ee093 100644 --- a/internal/service/export/email_service.go +++ b/internal/service/export/email_service.go @@ -23,19 +23,19 @@ import ( "crypto/tls" "encoding/json" "fmt" - "github.com/apache/incubator-answer/pkg/display" + "github.com/apache/answer/pkg/display" "mime" "os" "strings" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/siteinfo_common" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "golang.org/x/net/context" diff --git a/internal/service/follow/follow_service.go b/internal/service/follow/follow_service.go index eecf3555..743b0da6 100644 --- a/internal/service/follow/follow_service.go +++ b/internal/service/follow/follow_service.go @@ -22,10 +22,10 @@ package follow import ( "context" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" + tagcommon "github.com/apache/answer/internal/service/tag_common" ) type FollowRepo interface { diff --git a/internal/service/importer/importer_service.go b/internal/service/importer/importer_service.go index 2b53f7e3..45aabf39 100644 --- a/internal/service/importer/importer_service.go +++ b/internal/service/importer/importer_service.go @@ -23,16 +23,16 @@ import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/rank" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/rank" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/plugin" "github.com/gin-gonic/gin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/meta/meta_service.go b/internal/service/meta/meta_service.go index b85aecf6..9e4f0741 100644 --- a/internal/service/meta/meta_service.go +++ b/internal/service/meta/meta_service.go @@ -23,21 +23,21 @@ import ( "context" "encoding/json" "errors" - "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/answer/internal/service/event_queue" "strconv" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - metacommon "github.com/apache/incubator-answer/internal/service/meta_common" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + answercommon "github.com/apache/answer/internal/service/answer_common" + metacommon "github.com/apache/answer/internal/service/meta_common" + questioncommon "github.com/apache/answer/internal/service/question_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/obj" myErrors "github.com/segmentfault/pacman/errors" ) diff --git a/internal/service/meta_common/meta_common_service.go b/internal/service/meta_common/meta_common_service.go index 08065d54..4da04fb1 100644 --- a/internal/service/meta_common/meta_common_service.go +++ b/internal/service/meta_common/meta_common_service.go @@ -22,8 +22,8 @@ package metacommon import ( "context" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" myErrors "github.com/segmentfault/pacman/errors" ) diff --git a/internal/service/mock/siteinfo_repo_mock.go b/internal/service/mock/siteinfo_repo_mock.go index 42be1067..1b841278 100644 --- a/internal/service/mock/siteinfo_repo_mock.go +++ b/internal/service/mock/siteinfo_repo_mock.go @@ -32,8 +32,8 @@ import ( context "context" reflect "reflect" - entity "github.com/apache/incubator-answer/internal/entity" - schema "github.com/apache/incubator-answer/internal/schema" + entity "github.com/apache/answer/internal/entity" + schema "github.com/apache/answer/internal/schema" gomock "go.uber.org/mock/gomock" ) diff --git a/internal/service/notice_queue/external_notification_queue.go b/internal/service/notice_queue/external_notification_queue.go index 32cabdac..6322a77e 100644 --- a/internal/service/notice_queue/external_notification_queue.go +++ b/internal/service/notice_queue/external_notification_queue.go @@ -22,7 +22,7 @@ package notice_queue import ( "context" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/notice_queue/notice_queue.go b/internal/service/notice_queue/notice_queue.go index c97e56b1..22b733e3 100644 --- a/internal/service/notice_queue/notice_queue.go +++ b/internal/service/notice_queue/notice_queue.go @@ -22,7 +22,7 @@ package notice_queue import ( "context" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/notification/external_notification.go b/internal/service/notification/external_notification.go index 1db83f0b..2a0fdd81 100644 --- a/internal/service/notification/external_notification.go +++ b/internal/service/notification/external_notification.go @@ -22,16 +22,16 @@ package notification import ( "context" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/internal/service/user_external_login" - "github.com/apache/incubator-answer/internal/service/user_notification_config" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/siteinfo_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/internal/service/user_external_login" + "github.com/apache/answer/internal/service/user_notification_config" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/notification/invite_answer_notification.go b/internal/service/notification/invite_answer_notification.go index 503caa51..0a72ae98 100644 --- a/internal/service/notification/invite_answer_notification.go +++ b/internal/service/notification/invite_answer_notification.go @@ -21,8 +21,8 @@ package notification import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/i18n" "github.com/segmentfault/pacman/log" "time" diff --git a/internal/service/notification/new_answer_notification.go b/internal/service/notification/new_answer_notification.go index 1e08b455..8a842bef 100644 --- a/internal/service/notification/new_answer_notification.go +++ b/internal/service/notification/new_answer_notification.go @@ -21,8 +21,8 @@ package notification import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/i18n" "github.com/segmentfault/pacman/log" "time" diff --git a/internal/service/notification/new_comment_notification.go b/internal/service/notification/new_comment_notification.go index 5e2dce7b..c02a008b 100644 --- a/internal/service/notification/new_comment_notification.go +++ b/internal/service/notification/new_comment_notification.go @@ -21,8 +21,8 @@ package notification import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/schema" "github.com/segmentfault/pacman/i18n" "github.com/segmentfault/pacman/log" "time" diff --git a/internal/service/notification/new_question_notification.go b/internal/service/notification/new_question_notification.go index 08a77488..fd98b7f9 100644 --- a/internal/service/notification/new_question_notification.go +++ b/internal/service/notification/new_question_notification.go @@ -24,12 +24,12 @@ import ( "strings" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/pkg/display" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/pkg/display" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/plugin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/i18n" "github.com/segmentfault/pacman/log" diff --git a/internal/service/notification/notification_service.go b/internal/service/notification/notification_service.go index 0860c894..598212aa 100644 --- a/internal/service/notification/notification_service.go +++ b/internal/service/notification/notification_service.go @@ -23,21 +23,21 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/badge" - notficationcommon "github.com/apache/incubator-answer/internal/service/notification_common" - "github.com/apache/incubator-answer/internal/service/report_common" - "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/internal/service/revision_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/badge" + notficationcommon "github.com/apache/answer/internal/service/notification_common" + "github.com/apache/answer/internal/service/report_common" + "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/internal/service/revision_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/uid" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/notification_common/notification.go b/internal/service/notification_common/notification.go index 9d08e258..c2d8fc50 100644 --- a/internal/service/notification_common/notification.go +++ b/internal/service/notification_common/notification.go @@ -24,22 +24,22 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/internal/service/user_external_login" - "github.com/apache/incubator-answer/pkg/display" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/user_external_login" + "github.com/apache/answer/pkg/display" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/object_info" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/object_info" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/plugin" "github.com/goccy/go-json" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" diff --git a/internal/service/object_info/object_info.go b/internal/service/object_info/object_info.go index 9a85f07e..76b1d86d 100644 --- a/internal/service/object_info/object_info.go +++ b/internal/service/object_info/object_info.go @@ -21,15 +21,15 @@ package object_info import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/schema" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/comment_common" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/schema" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/comment_common" + questioncommon "github.com/apache/answer/internal/service/question_common" + tagcommon "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/obj" "github.com/segmentfault/pacman/errors" ) diff --git a/internal/service/permission/answer_permission.go b/internal/service/permission/answer_permission.go index 14af7abc..4eb563a5 100644 --- a/internal/service/permission/answer_permission.go +++ b/internal/service/permission/answer_permission.go @@ -21,11 +21,11 @@ package permission import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" ) // GetAnswerPermission get answer permission diff --git a/internal/service/permission/comment_permission.go b/internal/service/permission/comment_permission.go index aef32792..5a82cf38 100644 --- a/internal/service/permission/comment_permission.go +++ b/internal/service/permission/comment_permission.go @@ -23,10 +23,10 @@ import ( "context" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" ) // GetCommentPermission get comment permission diff --git a/internal/service/permission/question_permission.go b/internal/service/permission/question_permission.go index b93cdfc1..b6750bea 100644 --- a/internal/service/permission/question_permission.go +++ b/internal/service/permission/question_permission.go @@ -21,11 +21,11 @@ package permission import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" ) // GetQuestionPermission get question permission diff --git a/internal/service/permission/tag_permission.go b/internal/service/permission/tag_permission.go index 2b87275d..53161033 100644 --- a/internal/service/permission/tag_permission.go +++ b/internal/service/permission/tag_permission.go @@ -21,11 +21,11 @@ package permission import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/schema" ) // GetTagPermission get tag permission diff --git a/internal/service/plugin_common/plugin_common_service.go b/internal/service/plugin_common/plugin_common_service.go index ea6701bd..185347b7 100644 --- a/internal/service/plugin_common/plugin_common_service.go +++ b/internal/service/plugin_common/plugin_common_service.go @@ -23,19 +23,19 @@ import ( "context" "encoding/json" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/repo/search_sync" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/repo/search_sync" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/importer" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/importer" + "github.com/apache/answer/plugin" ) type PluginConfigRepo interface { diff --git a/internal/service/provider.go b/internal/service/provider.go index 9d523b49..84073235 100644 --- a/internal/service/provider.go +++ b/internal/service/provider.go @@ -20,49 +20,49 @@ package service import ( - "github.com/apache/incubator-answer/internal/service/action" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/activity_queue" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/auth" - "github.com/apache/incubator-answer/internal/service/badge" - "github.com/apache/incubator-answer/internal/service/collection" - collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" - "github.com/apache/incubator-answer/internal/service/comment" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/internal/service/dashboard" - "github.com/apache/incubator-answer/internal/service/event_queue" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/follow" - "github.com/apache/incubator-answer/internal/service/importer" - "github.com/apache/incubator-answer/internal/service/meta" - "github.com/apache/incubator-answer/internal/service/meta_common" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/notification" - notficationcommon "github.com/apache/incubator-answer/internal/service/notification_common" - "github.com/apache/incubator-answer/internal/service/object_info" - "github.com/apache/incubator-answer/internal/service/plugin_common" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/rank" - "github.com/apache/incubator-answer/internal/service/reason" - "github.com/apache/incubator-answer/internal/service/report" - "github.com/apache/incubator-answer/internal/service/report_handle" - "github.com/apache/incubator-answer/internal/service/review" - "github.com/apache/incubator-answer/internal/service/revision_common" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/search_parser" - "github.com/apache/incubator-answer/internal/service/siteinfo" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/internal/service/tag" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/internal/service/uploader" - "github.com/apache/incubator-answer/internal/service/user_admin" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/internal/service/user_external_login" - "github.com/apache/incubator-answer/internal/service/user_notification_config" + "github.com/apache/answer/internal/service/action" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_queue" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/auth" + "github.com/apache/answer/internal/service/badge" + "github.com/apache/answer/internal/service/collection" + collectioncommon "github.com/apache/answer/internal/service/collection_common" + "github.com/apache/answer/internal/service/comment" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/internal/service/dashboard" + "github.com/apache/answer/internal/service/event_queue" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/follow" + "github.com/apache/answer/internal/service/importer" + "github.com/apache/answer/internal/service/meta" + "github.com/apache/answer/internal/service/meta_common" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/notification" + notficationcommon "github.com/apache/answer/internal/service/notification_common" + "github.com/apache/answer/internal/service/object_info" + "github.com/apache/answer/internal/service/plugin_common" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/rank" + "github.com/apache/answer/internal/service/reason" + "github.com/apache/answer/internal/service/report" + "github.com/apache/answer/internal/service/report_handle" + "github.com/apache/answer/internal/service/review" + "github.com/apache/answer/internal/service/revision_common" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/search_parser" + "github.com/apache/answer/internal/service/siteinfo" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/tag" + tagcommon "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/internal/service/uploader" + "github.com/apache/answer/internal/service/user_admin" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/internal/service/user_external_login" + "github.com/apache/answer/internal/service/user_notification_config" "github.com/google/wire" ) diff --git a/internal/service/question_common/question.go b/internal/service/question_common/question.go index fc01159e..3b3595c4 100644 --- a/internal/service/question_common/question.go +++ b/internal/service/question_common/question.go @@ -23,31 +23,31 @@ import ( "context" "encoding/json" "fmt" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" + "github.com/apache/answer/internal/service/siteinfo_common" "math" "strings" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/data" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/activity_queue" - "github.com/apache/incubator-answer/internal/service/config" - metacommon "github.com/apache/incubator-answer/internal/service/meta_common" - "github.com/apache/incubator-answer/internal/service/revision" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/data" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/activity_queue" + "github.com/apache/answer/internal/service/config" + metacommon "github.com/apache/answer/internal/service/meta_common" + "github.com/apache/answer/internal/service/revision" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/errors" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - collectioncommon "github.com/apache/incubator-answer/internal/service/collection_common" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + answercommon "github.com/apache/answer/internal/service/answer_common" + collectioncommon "github.com/apache/answer/internal/service/collection_common" + tagcommon "github.com/apache/answer/internal/service/tag_common" + usercommon "github.com/apache/answer/internal/service/user_common" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/rank/rank_service.go b/internal/service/rank/rank_service.go index 2b4462a6..6651091a 100644 --- a/internal/service/rank/rank_service.go +++ b/internal/service/rank/rank_service.go @@ -22,22 +22,22 @@ package rank import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_type" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/object_info" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/internal/service/role" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_type" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/object_info" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/internal/service/role" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "xorm.io/xorm" diff --git a/internal/service/reason/reason_service.go b/internal/service/reason/reason_service.go index c6c31c4c..35245c34 100644 --- a/internal/service/reason/reason_service.go +++ b/internal/service/reason/reason_service.go @@ -22,8 +22,8 @@ package reason import ( "context" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/reason_common" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/reason_common" ) type ReasonService struct { diff --git a/internal/service/reason_common/reason.go b/internal/service/reason_common/reason.go index ca1bf73d..18d92905 100644 --- a/internal/service/reason_common/reason.go +++ b/internal/service/reason_common/reason.go @@ -22,7 +22,7 @@ package reason_common import ( "context" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/schema" ) type ReasonRepo interface { diff --git a/internal/service/report/report_service.go b/internal/service/report/report_service.go index 2ca44855..7dcc1d68 100644 --- a/internal/service/report/report_service.go +++ b/internal/service/report/report_service.go @@ -21,25 +21,25 @@ package report import ( "encoding/json" - "github.com/apache/incubator-answer/internal/service/event_queue" + "github.com/apache/answer/internal/service/event_queue" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/object_info" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/report_common" - "github.com/apache/incubator-answer/internal/service/report_handle" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/object_info" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/report_common" + "github.com/apache/answer/internal/service/report_handle" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/obj" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/report_common/report_common.go b/internal/service/report_common/report_common.go index 4b504630..64fcb838 100644 --- a/internal/service/report_common/report_common.go +++ b/internal/service/report_common/report_common.go @@ -22,8 +22,8 @@ package report_common import ( "context" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" ) // ReportRepo report repository diff --git a/internal/service/report_handle/report_handle.go b/internal/service/report_handle/report_handle.go index df6cff68..27cffb11 100644 --- a/internal/service/report_handle/report_handle.go +++ b/internal/service/report_handle/report_handle.go @@ -22,13 +22,13 @@ package report_handle import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/comment" - "github.com/apache/incubator-answer/internal/service/content" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/obj" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/comment" + "github.com/apache/answer/internal/service/content" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/obj" ) type ReportHandle struct { diff --git a/internal/service/review/review_service.go b/internal/service/review/review_service.go index dadf58ab..7f934f23 100644 --- a/internal/service/review/review_service.go +++ b/internal/service/review/review_service.go @@ -22,23 +22,23 @@ package review import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/notice_queue" - "github.com/apache/incubator-answer/internal/service/object_info" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/notice_queue" + "github.com/apache/answer/internal/service/object_info" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/siteinfo_common" + tagcommon "github.com/apache/answer/internal/service/tag_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/plugin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/revision/revision.go b/internal/service/revision/revision.go index 6844054b..58427220 100644 --- a/internal/service/revision/revision.go +++ b/internal/service/revision/revision.go @@ -22,7 +22,7 @@ package revision import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" "xorm.io/xorm" ) diff --git a/internal/service/revision_common/revision_service.go b/internal/service/revision_common/revision_service.go index ba73f797..7275916e 100644 --- a/internal/service/revision_common/revision_service.go +++ b/internal/service/revision_common/revision_service.go @@ -22,15 +22,15 @@ package revision_common import ( "context" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/service/revision" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/service/revision" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/uid" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "github.com/jinzhu/copier" ) diff --git a/internal/service/role/power_service.go b/internal/service/role/power_service.go index 86f0e260..f8289963 100644 --- a/internal/service/role/power_service.go +++ b/internal/service/role/power_service.go @@ -22,7 +22,7 @@ package role import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" ) // PowerRepo power repository diff --git a/internal/service/role/role_service.go b/internal/service/role/role_service.go index f0271312..96e8f6d7 100644 --- a/internal/service/role/role_service.go +++ b/internal/service/role/role_service.go @@ -22,10 +22,10 @@ package role import ( "context" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" "github.com/jinzhu/copier" ) diff --git a/internal/service/role/user_role_rel_service.go b/internal/service/role/user_role_rel_service.go index f89f3a4f..d80863f4 100644 --- a/internal/service/role/user_role_rel_service.go +++ b/internal/service/role/user_role_rel_service.go @@ -22,7 +22,7 @@ package role import ( "context" - "github.com/apache/incubator-answer/internal/entity" + "github.com/apache/answer/internal/entity" ) // UserRoleRelRepo userRoleRel repository diff --git a/internal/service/search_common/search.go b/internal/service/search_common/search.go index ba6f6295..d26320c5 100644 --- a/internal/service/search_common/search.go +++ b/internal/service/search_common/search.go @@ -22,8 +22,8 @@ package search_common import ( "context" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/plugin" ) type SearchRepo interface { diff --git a/internal/service/search_parser/search_parser.go b/internal/service/search_parser/search_parser.go index 6485e162..e87efaf6 100644 --- a/internal/service/search_parser/search_parser.go +++ b/internal/service/search_parser/search_parser.go @@ -22,14 +22,14 @@ package search_parser import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" "regexp" "strings" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/tag_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/tag_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/converter" ) type SearchParser struct { diff --git a/internal/service/siteinfo/siteinfo_service.go b/internal/service/siteinfo/siteinfo_service.go index 5b5b1208..5141faee 100644 --- a/internal/service/siteinfo/siteinfo_service.go +++ b/internal/service/siteinfo/siteinfo_service.go @@ -25,18 +25,18 @@ import ( "fmt" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/config" - "github.com/apache/incubator-answer/internal/service/export" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - tagcommon "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/config" + "github.com/apache/answer/internal/service/export" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/internal/service/siteinfo_common" + tagcommon "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/plugin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/siteinfo_common/siteinfo_service.go b/internal/service/siteinfo_common/siteinfo_service.go index 01585876..f715bc9b 100644 --- a/internal/service/siteinfo_common/siteinfo_service.go +++ b/internal/service/siteinfo_common/siteinfo_service.go @@ -24,10 +24,10 @@ import ( "encoding/json" "html" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/pkg/gravatar" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/pkg/gravatar" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/siteinfo_common/siteinfo_service_test.go b/internal/service/siteinfo_common/siteinfo_service_test.go index 387e1e2f..3a567dcb 100644 --- a/internal/service/siteinfo_common/siteinfo_service_test.go +++ b/internal/service/siteinfo_common/siteinfo_service_test.go @@ -23,9 +23,9 @@ import ( "context" "testing" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/service/mock" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/service/mock" "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" ) diff --git a/internal/service/tag/tag_service.go b/internal/service/tag/tag_service.go index e5fcf597..5d626ae2 100644 --- a/internal/service/tag/tag_service.go +++ b/internal/service/tag/tag_service.go @@ -24,21 +24,21 @@ import ( "encoding/json" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/service/activity_queue" - "github.com/apache/incubator-answer/internal/service/revision_common" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - tagcommonser "github.com/apache/incubator-answer/internal/service/tag_common" - "github.com/apache/incubator-answer/pkg/htmltext" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/service/activity_queue" + "github.com/apache/answer/internal/service/revision_common" + "github.com/apache/answer/internal/service/siteinfo_common" + tagcommonser "github.com/apache/answer/internal/service/tag_common" + "github.com/apache/answer/pkg/htmltext" "github.com/jinzhu/copier" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_common" - "github.com/apache/incubator-answer/internal/service/permission" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_common" + "github.com/apache/answer/internal/service/permission" + "github.com/apache/answer/pkg/converter" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index ec11fe45..e5c136c3 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -26,15 +26,15 @@ import ( "sort" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/validator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity_queue" - "github.com/apache/incubator-answer/internal/service/revision_common" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/validator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity_queue" + "github.com/apache/answer/internal/service/revision_common" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/converter" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/uploader/upload.go b/internal/service/uploader/upload.go index 8530d17f..4b018cb4 100644 --- a/internal/service/uploader/upload.go +++ b/internal/service/uploader/upload.go @@ -31,14 +31,14 @@ import ( "path/filepath" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/service/service_config" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/dir" - "github.com/apache/incubator-answer/pkg/uid" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/service/service_config" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/dir" + "github.com/apache/answer/pkg/uid" + "github.com/apache/answer/plugin" "github.com/disintegration/imaging" "github.com/gin-gonic/gin" exifremove "github.com/scottleedavis/go-exif-remove" diff --git a/internal/service/user_admin/user_backyard.go b/internal/service/user_admin/user_backyard.go index ebe1ea74..a414ec4e 100644 --- a/internal/service/user_admin/user_backyard.go +++ b/internal/service/user_admin/user_backyard.go @@ -22,31 +22,31 @@ package user_admin import ( "context" "fmt" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/base/validator" - answercommon "github.com/apache/incubator-answer/internal/service/answer_common" - "github.com/apache/incubator-answer/internal/service/comment_common" - "github.com/apache/incubator-answer/internal/service/export" - questioncommon "github.com/apache/incubator-answer/internal/service/question_common" - "github.com/apache/incubator-answer/pkg/token" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/base/validator" + answercommon "github.com/apache/answer/internal/service/answer_common" + "github.com/apache/answer/internal/service/comment_common" + "github.com/apache/answer/internal/service/export" + questioncommon "github.com/apache/answer/internal/service/question_common" + "github.com/apache/answer/pkg/token" "net/mail" "strings" "time" "unicode" - "github.com/apache/incubator-answer/internal/base/pager" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/auth" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/internal/service/user_external_login" - "github.com/apache/incubator-answer/pkg/checker" + "github.com/apache/answer/internal/base/pager" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/auth" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/siteinfo_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/internal/service/user_external_login" + "github.com/apache/answer/pkg/checker" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/user_common/user.go b/internal/service/user_common/user.go index 7980044e..707f8b9b 100644 --- a/internal/service/user_common/user.go +++ b/internal/service/user_common/user.go @@ -23,17 +23,17 @@ import ( "context" "strings" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/pkg/converter" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/auth" - "github.com/apache/incubator-answer/internal/service/role" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/random" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/auth" + "github.com/apache/answer/internal/service/role" + "github.com/apache/answer/internal/service/siteinfo_common" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/random" "github.com/mozillazg/go-pinyin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" diff --git a/internal/service/user_external_login/user_center_login_service.go b/internal/service/user_external_login/user_center_login_service.go index 5ff47bce..90895ac4 100644 --- a/internal/service/user_external_login/user_center_login_service.go +++ b/internal/service/user_external_login/user_center_login_service.go @@ -24,19 +24,19 @@ import ( "encoding/json" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/converter" - "github.com/apache/incubator-answer/pkg/random" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/siteinfo_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/converter" + "github.com/apache/answer/pkg/random" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/user_external_login/user_external_login_service.go b/internal/service/user_external_login/user_external_login_service.go index 9107fcc0..3f82179b 100644 --- a/internal/service/user_external_login/user_external_login_service.go +++ b/internal/service/user_external_login/user_external_login_service.go @@ -25,21 +25,21 @@ import ( "fmt" "time" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/internal/base/translator" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - "github.com/apache/incubator-answer/internal/service/activity" - "github.com/apache/incubator-answer/internal/service/export" - "github.com/apache/incubator-answer/internal/service/siteinfo_common" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" - "github.com/apache/incubator-answer/internal/service/user_notification_config" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/random" - "github.com/apache/incubator-answer/pkg/token" - "github.com/apache/incubator-answer/plugin" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/internal/base/translator" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + "github.com/apache/answer/internal/service/activity" + "github.com/apache/answer/internal/service/export" + "github.com/apache/answer/internal/service/siteinfo_common" + usercommon "github.com/apache/answer/internal/service/user_common" + "github.com/apache/answer/internal/service/user_notification_config" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/random" + "github.com/apache/answer/pkg/token" + "github.com/apache/answer/plugin" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) diff --git a/internal/service/user_notification_config/user_notification_config_service.go b/internal/service/user_notification_config/user_notification_config_service.go index cc6bc1b1..7c54df0a 100644 --- a/internal/service/user_notification_config/user_notification_config_service.go +++ b/internal/service/user_notification_config/user_notification_config_service.go @@ -21,10 +21,10 @@ package user_notification_config import ( "context" - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/entity" - "github.com/apache/incubator-answer/internal/schema" - usercommon "github.com/apache/incubator-answer/internal/service/user_common" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/entity" + "github.com/apache/answer/internal/schema" + usercommon "github.com/apache/answer/internal/service/user_common" ) type UserNotificationConfigRepo interface { diff --git a/pkg/checker/path_ignore.go b/pkg/checker/path_ignore.go index 5a307ae4..8be757be 100644 --- a/pkg/checker/path_ignore.go +++ b/pkg/checker/path_ignore.go @@ -22,7 +22,7 @@ package checker import ( "sync" - "github.com/apache/incubator-answer/configs" + "github.com/apache/answer/configs" "github.com/segmentfault/pacman/log" "gopkg.in/yaml.v3" ) diff --git a/pkg/checker/question_link.go b/pkg/checker/question_link.go index 36f850d6..41b246c3 100644 --- a/pkg/checker/question_link.go +++ b/pkg/checker/question_link.go @@ -20,9 +20,9 @@ package checker import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/pkg/obj" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/pkg/obj" + "github.com/apache/answer/pkg/uid" ) const ( diff --git a/pkg/checker/question_link_test.go b/pkg/checker/question_link_test.go index bc4eb615..d3ff0625 100644 --- a/pkg/checker/question_link_test.go +++ b/pkg/checker/question_link_test.go @@ -22,7 +22,7 @@ package checker_test import ( "testing" - "github.com/apache/incubator-answer/pkg/checker" + "github.com/apache/answer/pkg/checker" "github.com/stretchr/testify/assert" ) diff --git a/pkg/checker/reserved_username.go b/pkg/checker/reserved_username.go index db0bde93..6dfd3471 100644 --- a/pkg/checker/reserved_username.go +++ b/pkg/checker/reserved_username.go @@ -25,9 +25,9 @@ import ( "path/filepath" "sync" - "github.com/apache/incubator-answer/configs" - "github.com/apache/incubator-answer/internal/cli" - "github.com/apache/incubator-answer/pkg/dir" + "github.com/apache/answer/configs" + "github.com/apache/answer/internal/cli" + "github.com/apache/answer/pkg/dir" ) var ( diff --git a/pkg/display/url.go b/pkg/display/url.go index 8f42f2f5..11574f0a 100644 --- a/pkg/display/url.go +++ b/pkg/display/url.go @@ -20,9 +20,9 @@ package display import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/pkg/htmltext" - "github.com/apache/incubator-answer/pkg/uid" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/pkg/htmltext" + "github.com/apache/answer/pkg/uid" ) // QuestionURL get question url diff --git a/pkg/gravatar/gravatar_test.go b/pkg/gravatar/gravatar_test.go index cedbb1a3..bf504e68 100644 --- a/pkg/gravatar/gravatar_test.go +++ b/pkg/gravatar/gravatar_test.go @@ -20,7 +20,7 @@ package gravatar import ( - "github.com/apache/incubator-answer/internal/base/constant" + "github.com/apache/answer/internal/base/constant" "testing" "github.com/stretchr/testify/assert" diff --git a/pkg/htmltext/htmltext.go b/pkg/htmltext/htmltext.go index 77ca2fba..49049109 100644 --- a/pkg/htmltext/htmltext.go +++ b/pkg/htmltext/htmltext.go @@ -28,8 +28,8 @@ import ( "unicode/utf8" "github.com/Machiel/slugify" - "github.com/apache/incubator-answer/pkg/checker" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/pkg/checker" + "github.com/apache/answer/pkg/converter" strip "github.com/grokify/html-strip-tags-go" "github.com/mozillazg/go-pinyin" ) diff --git a/pkg/obj/obj.go b/pkg/obj/obj.go index 1172b52b..0dc62819 100644 --- a/pkg/obj/obj.go +++ b/pkg/obj/obj.go @@ -20,9 +20,9 @@ package obj import ( - "github.com/apache/incubator-answer/internal/base/constant" - "github.com/apache/incubator-answer/internal/base/reason" - "github.com/apache/incubator-answer/pkg/converter" + "github.com/apache/answer/internal/base/constant" + "github.com/apache/answer/internal/base/reason" + "github.com/apache/answer/pkg/converter" "github.com/segmentfault/pacman/errors" ) diff --git a/plugin/plugin.go b/plugin/plugin.go index 2e4bf749..36087c54 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -25,8 +25,8 @@ import ( "github.com/segmentfault/pacman/i18n" - "github.com/apache/incubator-answer/internal/base/handler" - "github.com/apache/incubator-answer/internal/base/translator" + "github.com/apache/answer/internal/base/handler" + "github.com/apache/answer/internal/base/translator" "github.com/gin-gonic/gin" ) diff --git a/script/plugin_list b/script/plugin_list index 67ba306f..8a767627 100644 --- a/script/plugin_list +++ b/script/plugin_list @@ -1,3 +1,3 @@ -github.com/apache/incubator-answer-plugins/connector-basic@latest -github.com/apache/incubator-answer-plugins/reviewer-basic@latest -github.com/apache/incubator-answer-plugins/captcha-basic@latest \ No newline at end of file +github.com/apache/answer-plugins/connector-basic@latest +github.com/apache/answer-plugins/reviewer-basic@latest +github.com/apache/answer-plugins/captcha-basic@latest \ No newline at end of file diff --git a/ui/public/index.html b/ui/public/index.html index 813deb54..5bca47e4 100644 --- a/ui/public/index.html +++ b/ui/public/index.html @@ -24,7 +24,7 @@ - + diff --git a/ui/src/components/PageTags/index.tsx b/ui/src/components/PageTags/index.tsx index eb8a4e10..ec578a64 100644 --- a/ui/src/components/PageTags/index.tsx +++ b/ui/src/components/PageTags/index.tsx @@ -42,7 +42,7 @@ const Index: FC = () => { if (generatorMetaNode) { generatorMetaNode.setAttribute( 'content', - `Answer ${appVersion} - https://github.com/apache/incubator-answer version ${hashVersion}`, + `Answer ${appVersion} - https://github.com/apache/answer version ${hashVersion}`, ); } }; diff --git a/ui/src/pages/Admin/Dashboard/components/AnswerLinks/index.tsx b/ui/src/pages/Admin/Dashboard/components/AnswerLinks/index.tsx index b7fd6512..666b25e7 100644 --- a/ui/src/pages/Admin/Dashboard/components/AnswerLinks/index.tsx +++ b/ui/src/pages/Admin/Dashboard/components/AnswerLinks/index.tsx @@ -67,7 +67,7 @@ const AnswerLinks = () => {
{t('github')} diff --git a/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx b/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx index c19cddbd..c7f6f6d3 100644 --- a/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx +++ b/ui/src/pages/Admin/Dashboard/components/HealthStatus/index.tsx @@ -53,7 +53,7 @@ const HealthStatus: FC = ({ data }) => { {t('latest')} @@ -62,7 +62,7 @@ const HealthStatus: FC = ({ data }) => { {t('update_to')} {remote_version} @@ -71,7 +71,7 @@ const HealthStatus: FC = ({ data }) => { {t('check_failed')} diff --git a/ui/src/pages/Admin/Plugins/Installed/index.tsx b/ui/src/pages/Admin/Plugins/Installed/index.tsx index 868b827a..f03828d9 100644 --- a/ui/src/pages/Admin/Plugins/Installed/index.tsx +++ b/ui/src/pages/Admin/Plugins/Installed/index.tsx @@ -85,7 +85,7 @@ const Users: FC = () => { Plugins extend and expand the functionality. You may find plugins in the Plugin Repository diff --git a/ui/src/plugins/builtin/ThirdPartyConnector/info.yaml b/ui/src/plugins/builtin/ThirdPartyConnector/info.yaml index 1e9b6fa9..37a42b4f 100644 --- a/ui/src/plugins/builtin/ThirdPartyConnector/info.yaml +++ b/ui/src/plugins/builtin/ThirdPartyConnector/info.yaml @@ -18,6 +18,6 @@ slug_name: third_party_connector type: connector version: 0.0.1 -link: https://github.com/apache/incubator-answer-plugins/tree/main/connector-basic +link: https://github.com/apache/answer-plugins/tree/main/connector-basic author: Answer diff --git a/ui/template/header.html b/ui/template/header.html index 5c4977d9..e3f63509 100644 --- a/ui/template/header.html +++ b/ui/template/header.html @@ -27,7 +27,7 @@ - + {{if .keywords }}{{end}} {{if .noindex }}{{end}} From bbb2e66233730ed7dd9c8e3de138369ba341d8cb Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 13 Jan 2025 11:19:25 +0800 Subject: [PATCH 335/336] docs(disclaimer): remove disclaimer --- DISCLAIMER | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 DISCLAIMER diff --git a/DISCLAIMER b/DISCLAIMER deleted file mode 100644 index 009fd82b..00000000 --- a/DISCLAIMER +++ /dev/null @@ -1,10 +0,0 @@ -Apache Answer is an effort undergoing incubation at the Apache -Software Foundation (ASF), sponsored by the Apache Incubator PMC. - -Incubation is required of all newly accepted projects until a further review -indicates that the infrastructure, communications, and decision making process -have stabilized in a manner consistent with other successful ASF projects. - -While incubation status is not necessarily a reflection of the completeness -or stability of the code, it does indicate that the project has yet to be -fully endorsed by the ASF. \ No newline at end of file From 5886c1ec53087520ac02cbdaf9811a0cfebc829e Mon Sep 17 00:00:00 2001 From: LinkinStars Date: Mon, 13 Jan 2025 11:44:57 +0800 Subject: [PATCH 336/336] build(release): remove DISCLAIMER file from release assets --- .goreleaser.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index b517defb..c0919693 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -65,8 +65,6 @@ archives: dst: NOTICE - src: "docs/release/licenses/*" dst: licenses/ - - src: "DISCLAIMER" - dst: DISCLAIMER wrap_in_directory: true checksum: name_template: 'checksums.txt'