diff --git a/resources/builtin/repo/code.png b/resources/builtin/repo/code.png new file mode 100644 index 0000000000000000000000000000000000000000..f7e56be76276860087e987694d3397d22689ef74 GIT binary patch literal 4346 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 literal 0 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�PO1$Z+PHOSL5rA=27g-ZnGt@td_GH;YI-+n|g5ZQlA0fM{-tM?(T z3+`y_*OoxRM;z+KIjJuu5uxqh{mvfHT5Q7m33`hhR6!GwN|M4o=bqszi8v_vZpGm6ZQMQODM=`B~@tl$}j0e@BcWPQbrJ>i}2h@F0L3XRD&p!B;LPMptht4xE znx{E3Msub6i_g3+RuHsNc6&9{o_5g7@bP?P`d;-*M-KD!jFw-XHTm!BVisS~$|vgL zz~3!}mvXQGhR-t|g?$4}cwq#!0C(VujN{|W*2j;+xLjoRe#x+Swn3j$JcJAGlW%m_ z53_`nvy$=W*maF%C$SA&<`qI|aow{L1vP#{-q+MfNYV|1^nLJC{?r1o!cSq4GD?oF zSk4a=Cx(`mUP{bldee%RZUsD7Y>g~y7;dZVQ)Qnf&Bc6PM*^@^U#DoZJg`rk=@JF!G;1QH)BM6nv z#VYO@^?+=24x{DEA~S2!WGZ`dlF(#Se75CCQ)sU+dK#vb^PofAdebU(_Ac&DrcujS zgCWIBLx|)x|GW7%|6_$&-AqPXgWJSRVH&!QmlAjv$%7^2A77{OnIo!vpUPoWuKwk_ z)$o&2_xSj>`!+v3&z4-T#Z2yyPy266%gv2NGt7pPTVV2pS1+i3?)jCg#G9T z6;RJ-DM>R{flp9$o-c0&N~3V;uFKy~M&ZQijSI?QKWKG%^4bi-xM<&FYE%eE(qHui zGbY&=l|KSI?V2+~zMh(yb0vv;ac|53id8G*2O$!TxAT`&F%CV4J{S{uZ*4h;Rtvsy zWsmUz{6&(KrQ#z>TQpw-%Dm-3eFls4lAot~nI`88_kG+5`+d6mkrM4NR}D1p39NI| zQ6J25G~1s|X<+=D)H18qWzYmj?yn$e%H;2 zS`tezWxEw(@z=FKtLBt3;QHW-5KVbPpz15@R8Xs6R&V2s68WwnPlzj!n_b*Hibf9Fd!IiY z80*VQg8YIR*ksL9r|!G{bPB7O^RoX-lg}o(>?-`$w_yI{N%;=Hc`uyj$q~PNF^FT` z8g-3=S893Bjg04>PDniY@Xvz}5|ST3N&Qt+YHR;FJLUboyT^~r%+9p8Q}z}*bwV&M z=I9|7?YHl=qJKrz)^v816otIhaox(L+5h4@yI=i^y>-3{db*B`%P0Jsb^G(zwHqEk zQSG{RklWvjIn?Lor2zTrFSnR-SFS3JUw?y%rNftjfqA{Bi(^Oy$WT z<@e!`+16^#00Rv(idL@e_kWc;ZBCfQF*m+gWdni34kDooB4-&G8ynyKANBI;$=j82 zxfAL{)IY>2_NnaM5W&@KF|VpQ-j@i_xQHyiT%( zLCj0nS-kk_xbnX6=7R!D+>$rWYPjaov&{IyEcas(+yc=zqIAR0Y`o?jyoPs0uJ1;z zI~$XN*T`MOJe@EfLF)^$S?H?6F8>sYt}^@&n;bd zwMZ@5HD>;zSV7K+&uoNE`(?aFEckk!a_z}x_OH7RX>cqE-Yy<|d)r$6t+}_$l5cPO zJg>6t|DDcnaj%(TcQ*)#zr3Z|vcu>4I)x*ayUIir*InHDnxn9J-CdWCX!jR4x}rG* zqkWEx9T#|FCcC@Wp#0sXwbkDRUohUS>Ie{)ySVbWzrdT9#=E}!VO6U5*~PcFs@LP* zg@xNYUdZ09>_1_5VP?O_!R6;mQogG%d2(85*T(mnL0`X0$Nu;x%5=Z}&!4Yv%z1zR z&G~*_{=VX;=TGj}|G)gLd(H9#zy2y^{=aN&q@J**D_DU~ep_IIbj^uH4rVnGevL9e z3MMc;f9RAa$7=TcQ1koqngtK7ZEoypVA{X=p<^ARDAz+rK~=p&jXRG{(b&oR+eJp(e3S!|uQjxVrm6NuyK>gTe~DWM4fy$||& literal 0 Hc$@LsGH(K{h}3DF{= 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 literal 0 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 literal 0 Hc$@JsXVyRxGMXL)ff^N2IRqaIyYRRRRXmN>H8cK=1&v;mCwP@hAS@(PvG_*qi3X04wu50G>m_ zq7o-gN}rMvI}GAGsHkG(7@F5Gw8Gt*YAcR)GrOvEM(Bw8E%&TZRw>e4>yqsQLf>P1 z9o`F`&zSj$dnsRc3m=|+N*v7AzxZ}wp;DgHVqGxJ?i37|T{^vg$1Cysc(DGzkGsDZf(kto6t`BpsaCgpV4C8j$M$hl*lcWxr0OkzDT_jyw;CFQjkHd?fgASB9Nq)am8iU7%X zEN<#)Kbg&pT|G&*cwsCqBc4%sQT}`Zhouh8TG4S|5%q$Ju;Q+wo4h0?R=V5D!i0vA{3H@Y&{AzVjc#rw`X!VblJ7x z(KG>pq0o<#lz2h^c@X1WlE=a^v?PA#jLKzAHJWaN$8-1n@MyGGRm-kXC3a49EbbGy zBsa70P1Z^#w=r+vIOHXKs@)6r^0C*MkU5AkxZka{q(lCs!|B4V67Ffs3Dws4Ea8&f zK%SBWvyJevlRf?JgpuYWB2YI=wed76WizDR!-lAJo)hM>c6>MxGbvFTQnLVyxEA)ah;Tev}iR(EQPOj!&V> z^e%@$smJI2>bWn1_NprJ;i5k&Nk$<58x_BqfY_V(zaxc(XO)L$OrH0kqjlP`8kV8X zt;s!+s8!Y|qxfB->mp;jdlXbeG77U(^=Lba4D;$99Nqp5p>JoDT<*Bb0yCIikC_KHg#%y&9y4Dc6*3=N#_l|*KsB};rg|qTw z9q1KyWD5A20&R=v_I&Z=nF!UKFLgSL*kFfkCuG31#U^|vpKMwEmDN#Crl_-_q+sMg zac~Kdh*=uY^1W!}D@S8?+h{-XF7hQ)LeYe?WQsuydYi~?%n?OIWaZ;?*`v3R0Vs$8 z^$P>@{qm;wGT?S4zwcu;?NL#49J*Gxgq;ZRmZ8m zFJ2Y*xbj>yPz>r4m3r(41OFGg!sP_HYLPQ-OrUzXP3+z=<3z|OYqd&>R6?eOT8nck zBqKj-tLso^*EwnSd`gp&g2_B<=POgtmYFlM3YUJeh&Gxe=xgqD6diq^Kc@I5_f>J^ zcmJ1#gDOBc=@-QsbKAVFyZ7f*En!>aBMWa^_$kw2iX9xQ-t2Wf5TzEM+0ZeD%!~QgQ&OhfE01f|3P(3 zax#DYW&oXU2vd25KWk-|Z_m6-;-oy_f#rm-t8bSs7Ofvf4 zTZ6^?I6#WjguN7B8n+xr?rLVbbEjHsV22eFa0!=GR;CT**2Wy@ z3i5y!BX+Q;VHj48KtKh(m9=k+)0?gzRHC@EA~I2gkt2xG2yp5I!qZlX>&PjV9TkCt zZ_d0%$a6|{1Gc`Txz_Oa{gLKEI*OsB-35opSue?WtYKSgNFHfcq)F>fLK7oNbM09E zaa^idi9JtaRUYyMx;GDe!Kb+XJ1M3o+Xn6UeL3phJIJx!RhzAKk$(!sxu0l-(v=o> R+*=|5#s=p4<+?7>e+8Q_l{^3d literal 0 Hc$@OiU_5^_rAbyX-viluE)ioRlB$IL8%^SOKqZ6oq@+bcn(kG+0_Fr%~(Uaf> zI&_9y*)ujVIoy`zX&(0c6CDX_U%U3@yZfkL8@`zO+r2&eoyU3q!a!CM%&J_~{q=%@ zlNws8#r(H|=?C?%ausj8%&jVsTkUOpI^y>;w}HbeIkdmB4jmC~jdvmoPQM9CHI5L19C`2Gbg>M9IA3co3D^@~Hjim3OsOHHeSPr83rNMtE zg%T{p_b<2i6JutM+rmkGEe0sFcGq|nOxEhi=i!UfD8D~}sS)PRsHMNu&`k>ut_w4@u+W=h0fzVYLWx2HHKuxHeCG93~!7n1vHcqHt6Dlb!9q3CyyVmk^ z)wAs%G$vDhXQ~W$a`@G9}9z?WYevW6C*8|XfhAFf;I|ji7 zD(YumE~hP}?z-NWC(nALi9zHm#emXd#)6@2&VyMM z#%?2@B`%(t@m{H0)?AGBcYk;|Z~Ip!wsuUuUxMAzr3Z*bhokJm|tL;FN$ zf6S3k4NA+(u?fj3s`NaGah%G-MHUqpeJBmghIxk0aHBpgxWT)DD%-}iwy~!5Od-o@ zBKPUY$Ia5M1hDXjcOSwzK(IoPFM{~S2rTRH$-)RO|Dh;Ew$b7=&L2UPMuW+|qC0g@ z=yZA&AxcLyuQF#gN&KNBz(wX;UCgAl9@l{ku1`e3kSQME)>qr{>n9mbYZ*J7joS%U ziF{1qvW9NZV0t#6bz&>sp2}PMA4e58EZG+iC1mnhE{U8Go2!M9FByIvxb155o~pf^ zVFUcZ7@Bi^IuIxcPt_?tCO`QGBWOg1Wo1`QW)PkSw2ptQuh{?A5}+Gc_t&&&yF2Y6M)~wSo9m@%?qI38 z` zQ^>GQb3-na-1~D=?$L1nK5tfLQ4$Sq@DK)nZ|K$a4gZXl*E#LT>1;1Ixi1SLqXLuH zQLxBauCriba7yo+dhv_4i<91be1MwBkrPxHh`F{cja-aa65{ID-3%^({y@{3A_UF9 SE2XpccZbIkoEx3Kz405lOn!j? literal 0 Hc$@Pj`PY7{W}U$zuyO_Gn$;W&=QoA~ zi9C8BG;_Mm=TFuPUYb-@@b2EpEmMg1NKF!W;>r6|J2utGM zr=A$jRbyK=+erBF(eEeT8v2<>T{fF2zg&@lfn|!Pi(^Oy7F_?_ z%`L_sc*pbq(j#0R1t_eKbdCabfiy zyPTHuuM4{;{$O^@2{3pdzL=v``NoC}9hEi#{{{yoO|}VM%}!RzZ#G$8IPtVK>LGi_ zA03X3@%tU0o{xX{l|SVl_gdKtoZKs81#Ss@{bpAvsZik`J%*~o_*rlvM#^nbT03ftnx!o<&Ma;oL25w+HzXBqq6n1amUqGZ_Xo9 zhgi>KMTe|O%jWXcNvQ6+%6C%4DOXqQ!iy6jR=m1myKHBAtzUiAX{&zl%kZrc2OO3e zU6}nf?}pUL?QUxqioL#EkyQV4Qms*&Tf2GLi`lytDsV77P};Hl+{5pF5;2|1mS`sWh9`ueWO*DrEEN1A3! zbJlgIy;VB6FYQ{QFsIq^Ns-Gv47FyOc8WZn6qyXutTXf&*Dj~~o=Q_qnX7bkMGDMs zx#FDX)}~!k6^iLj+ZtW6Juh_gt-pe?w$s+;g-MHj?h|ufJ@M;$ggL*mx65tU=}a=< zsZU;>dwUxYS#HafHn)2BIQXk_Z*2C{oh{|cKXdcy5(^6x>pYWQMn>^{j*Ps!J-<{p zvDVTdDf8xs#@4f!g-)-0)x4qb*_tCoIFO+yEMOyIr9u_*i##(Te zP``)H)cIJks{6|D$}@DEL}3iV%Nfz zZ5Cdq7ffqnOX_TIOFt46!gKVApm#9KoT_~uIzI!>Hp(P*wgwv>nKYUEX^QZ9?q0{! zlX$=GnWH?f(Bey1h0&#j3$7n|BFJbhxc0~tE>TrA!OOe2bM|y9EoS{rdGm;h)60*>+wzg#lqa9|J%AK6LWrq3_&B+;0YiyQpZYYDsZ% z^D4Ktv^!-wu3XadKw!nXPt2N%2jtl{{G2HA;5DNA%Q%esBMxpmsNfVHc+ zd!GE5zAAW&x?kvA3%ehPlzj!n_b*HibeurlFq0D z#`ltvAirP+UXA$eA3yC))#m54-16T+Zq7<&wM%#PC2u`Fd_jmYuaQaWt$J+E#rqQS z|D65=6x7XKb>!a5qtj>fZ~Xc7wfFB=zCjOJ+0F|aJQFo~C#H4w#bYiLM{64%D>rAo zAKyhxW!h#=4b%;L^!H1laoUGq*(0?pHymvFOmOtNTmF<*BDGwb#D0tPJ(J^!NHA|4AyIK$I1=z3%Wa->EsDr>(vHY00g9 z$>}SKW|x~jP1{=SzoM%8`_q)I{~cD;vGYGoD*fTnv2gM4;tjXzbdFs7C_FQIu8nBY z%P%w6Y&Up}?x<8cfT{Cst zU3cf?^;t8&S^bI4Kh?eUYf;9V$cqvAr@KpE$m&FFNI2NU$}I+EXsfN6{N7&0ic_06 z`}Ohby|RBv8v+`}{Xt+F-SN zSM{sccR$L7@!Wrqh-^NT@#?kwj=1{|)_n&mZtLUezhb^8QzT64+Vj2(H+t7^_`}tV zq~%&U2auh7-D#0FQ28-+HFD(eyR?^3$WUG-a>7X}@&MG~8@W?|Sd(&ozk=f-D$n zMcJ<%im48rbvwl1+M!25{-Lj;;xxrxzt|O3DrFy`6ISi7J9ED^s%KW0fMUaP!Vi9_ zoXFJ?CmWB{U-)o#YuDGE%70#mUDpcxB>3MmAI&psKY?r{XqX z3ZA@m?dpo$_sz#-%2)kL%Rm3Ux+(a7V!5vcqB>4jB3 zKA#w(rrHZPhd8YETAbwD5~jZDh|Kv_3qyU^&RCqs^JSOPvm5+pUv2Nu?3(Vpy<7XJ zfcb*EkJt>I-w1r^RzJdGJ;|f}O7_W`{7D{@w@a&To?F}grSkv7#VPBKEmQSa{p8BC zJrSoJv(p#cnYt+Fy`S#9?dNh=&xo*P`+xA^>bK>7EVC-&rj*XP@aWthLsN;X=R`U; z`OWY>{Ic(-ME6Dr+T~{$b|Yfr;=8*gv}4vp@NPIJ6yEbRht+12gtkSPKi7SmSG-+E zBltgFo~83YqUUP!eXHMpk_@jo|H-VMR<3jGR@eTwFTa9RBwXKn+Ey&tw=MX8?slL` zHuLH-t7OA#*Nzrk-FaHBdt*}j!$jZr_cuythcSn5o64X3^KSSzAmy3EShIGfg1tc) ze-qCa!)dv_kCW@gl7DX5l(|X5J4O1?%lk(onmJbQ*Lt;4O?l71+kt(dD*Ou;z1(Kg zm80V+(=@4Z6_d-A3k5=5o7U^QnZ(+%q$+bexB!9RCrPE8xgqSym!*LPFN3G6pUXO@ GgeCxPgOW7> literal 0 Hc$@`f`C!a0fdIiZT_uQN6 z!r}4r)};lj*k5+eb`um?e9`X4dcHmTHnaUPw4J!{Y+rrv1UB zCn*KCMjTNR+t}f%lO)&;WQI*#8MU^mSL$l^HKj1Mt*@`FUB3TH{)G*K8!u(vaq*mG zraUeFbCuV{MX7R0TeI#i%RRU?JD;ia#R?;<(sQ+I^t9MweP`r-O<8&0_W8!D6%t#_ z601%v3_q9rHOw$0x#`Qq;P@mNjIauPQTpHcw`gLq~i)nk!+`vIX3DzKQ-)$ zn5OsXg`>{tg32C+X{k$W+yqZwa+h1&nJQ@<=J$A&z-hBMKVhDYIl|T_7ye%ob3AKx zQo!MsnL6#7YS%X|^SaFCchz^sOWV|$7d4)5OglHrcKL&6=ZqVl>2HWqt>C|x{!nRY z#2kYopQN|C{Eyt#6C6=>I(*HWCH8BgV$*vR!_=~`t;@bsarb~*%#y?4FcI6RB@YRm zX`OAGw%0kUT;qm>=F|hnGBm31n!7IAz3KW1mqmi?-0Q4S!}F-=@^jC!uA1>jxv%Nj zmUDO6{+#%|%@LVz?<`gMTPA!u|9sq1i4FSv8>RTyZrl0b)*JIiKA&Jo_V2Sjrrq2% z%Rrd_)TULDDzod?`c80ee_GHYX+3>$k(HZHJ6lnflTP&M%%WBGb0VgRevgKVnKggvWlLwB+i8|_)A{c${L&<& zH!J4&t|dtYH(PcZ`A+i_E|$wKo1PfV_3o9a@QYoib`?(EKD9PaHl(X+JMYFltL_C( zVmr>e@zRdnKjYm0rY2urJm-+nt@1^;{{Fst?#$B@r+&^uNl}lKOC05Lx{ffX=09HL zks|^LIDzS%%*uv=H;peo*mYR52SvxK9ev*`Eix_~e%;$S_2S~A)nBLQ_OBP#UOV^i zl$5VgNk6~VE)wy#ey(_JvvBi#@jFvisa@!vuJ!n8w(v=#+tR{mceNw$txG+2F7=nJ z<(s5q=brAIvrhQ*!sTQwzo4i z@tEEL>z!Zg{dMkVY=62)aoXBtbHWUgpMOZ4BVz{)s9zz9`!gSG&bi$8+~(SE{k5yb z?_3vGyI>fZ_j%i<^V>7MHh$c#IPH4>e6ON!(-p&{mImvuyA=QHy6nzl0@}@goo`?H zacS8t{=PL2p}w8U5AnBlqSC~GZ(d%?fl9ctEFVdQ&MBb@ E05<|fzyJUM literal 0 Hc$@ 'applications/diffusion/management/DiffusionRepositoryManagementPanel.php', 'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php', 'DiffusionRepositoryPoliciesManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php', + 'DiffusionRepositoryProfilePictureController' => 'applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php', 'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php', 'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php', 'DiffusionRepositorySearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositorySearchConduitAPIMethod.php', @@ -5820,6 +5821,7 @@ 'DiffusionRepositoryManagementPanel' => 'Phobject', 'DiffusionRepositoryPath' => 'Phobject', 'DiffusionRepositoryPoliciesManagementPanel' => 'DiffusionRepositoryManagementPanel', + 'DiffusionRepositoryProfilePictureController' => 'DiffusionController', 'DiffusionRepositoryRef' => 'Phobject', 'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositorySearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php --- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php +++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php @@ -140,6 +140,8 @@ $this->getEditRoutePattern('edit/') => 'DiffusionCommitEditController', ), + 'picture/(?P[0-9]\d*)/' + => 'DiffusionRepositoryProfilePictureController', ), ); } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -274,7 +274,9 @@ ->setHeader($repository->getName()) ->setUser($viewer) ->setPolicyObject($repository) - ->setHeaderIcon('fa-code'); + ->setProfileHeader(true) + ->setImage($repository->getProfileImageURI()) + ->setImageEditURL('/diffusion/picture/'.$repository->getID().'/'); if (!$repository->isTracked()) { $header->setStatus('fa-ban', 'dark', pht('Inactive')); diff --git a/src/applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php b/src/applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php new file mode 100644 --- /dev/null +++ b/src/applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php @@ -0,0 +1,244 @@ +getViewer(); + $id = $request->getURIData('id'); + + $repository = id(new PhabricatorRepositoryQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needProfileImage(true) + ->needURIs(true) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + + if (!$repository) { + return new Aphront404Response(); + } + + $supported_formats = PhabricatorFile::getTransformableImageFormats(); + $e_file = true; + $errors = array(); + $done_uri = $repository->getURI(); + + if ($request->isFormPost()) { + $phid = $request->getStr('phid'); + $is_default = false; + if ($phid == PhabricatorPHIDConstants::PHID_VOID) { + $phid = null; + $is_default = true; + } else if ($phid) { + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($phid)) + ->executeOne(); + } else { + if ($request->getFileExists('picture')) { + $file = PhabricatorFile::newFromPHPUpload( + $_FILES['picture'], + array( + 'authorPHID' => $viewer->getPHID(), + 'canCDN' => true, + )); + } else { + $e_file = pht('Required'); + $errors[] = pht( + 'You must choose a file when uploading a new profile picture.'); + } + } + + if (!$errors && !$is_default) { + if (!$file->isTransformableImage()) { + $e_file = pht('Not Supported'); + $errors[] = pht( + 'This server only supports these image formats: %s.', + implode(', ', $supported_formats)); + } else { + $xform = PhabricatorFileTransform::getTransformByKey( + PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE); + $xformed = $xform->executeTransform($file); + } + } + + if (!$errors) { + if ($is_default) { + $repository->setProfileImagePHID(null); + } else { + $repository->setProfileImagePHID($xformed->getPHID()); + $xformed->attachToObject($repository->getPHID()); + } + $repository->save(); + return id(new AphrontRedirectResponse())->setURI($done_uri); + } + } + + $title = pht('Edit Picture'); + + $form = id(new PHUIFormLayoutView()) + ->setUser($viewer); + + $default_image = PhabricatorFile::loadBuiltin( + $viewer, 'repo/code.png'); + + $images = array(); + + $current = $repository->getProfileImagePHID(); + $has_current = false; + if ($current) { + $files = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($current)) + ->execute(); + if ($files) { + $file = head($files); + if ($file->isTransformableImage()) { + $has_current = true; + $images[$current] = array( + 'uri' => $file->getBestURI(), + 'tip' => pht('Current Picture'), + ); + } + } + } + + $builtins = array( + 'repo/commit.png', + 'repo/database.png', + 'repo/desktop.png', + 'repo/gears.png', + 'repo/globe.png', + 'repo/locked.png', + 'repo/microchip.png', + 'repo/mobile.png', + 'repo/repo.png', + 'repo/servers.png', + ); + foreach ($builtins as $builtin) { + $file = PhabricatorFile::loadBuiltin($viewer, $builtin); + $images[$file->getPHID()] = array( + 'uri' => $file->getBestURI(), + 'tip' => pht('Builtin Image'), + ); + } + + $images[PhabricatorPHIDConstants::PHID_VOID] = array( + 'uri' => $default_image->getBestURI(), + 'tip' => pht('Default Picture'), + ); + + require_celerity_resource('people-profile-css'); + Javelin::initBehavior('phabricator-tooltips', array()); + + $buttons = array(); + foreach ($images as $phid => $spec) { + $style = null; + if (isset($spec['style'])) { + $style = $spec['style']; + } + $button = javelin_tag( + 'button', + array( + 'class' => 'button-grey profile-image-button', + 'sigil' => 'has-tooltip', + 'meta' => array( + 'tip' => $spec['tip'], + 'size' => 300, + ), + ), + phutil_tag( + 'img', + array( + 'height' => 50, + 'width' => 50, + 'src' => $spec['uri'], + ))); + + $button = array( + phutil_tag( + 'input', + array( + 'type' => 'hidden', + 'name' => 'phid', + 'value' => $phid, + )), + $button, + ); + + $button = phabricator_form( + $viewer, + array( + 'class' => 'profile-image-form', + 'method' => 'POST', + ), + $button); + + $buttons[] = $button; + } + + if ($has_current) { + $form->appendChild( + id(new AphrontFormMarkupControl()) + ->setLabel(pht('Current Picture')) + ->setValue(array_shift($buttons))); + } + + $form->appendChild( + id(new AphrontFormMarkupControl()) + ->setLabel(pht('Use Picture')) + ->setValue($buttons)); + + $form_box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->setFormErrors($errors) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setForm($form); + + $upload_form = id(new AphrontFormView()) + ->setUser($viewer) + ->setEncType('multipart/form-data') + ->appendChild( + id(new AphrontFormFileControl()) + ->setName('picture') + ->setLabel(pht('Upload Picture')) + ->setError($e_file) + ->setCaption( + pht('Supported formats: %s', implode(', ', $supported_formats)))) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($done_uri) + ->setValue(pht('Upload Picture'))); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Edit Repository Picture')) + ->setHeaderIcon('fa-camera-retro'); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb($repository->getName(), $repository->getURI()); + $crumbs->addTextCrumb(pht('Edit Picture')); + $crumbs->setBorder(true); + + $upload_box = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Upload New Picture')) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setForm($upload_form); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $form_box, + $upload_box, + )); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); + } +} diff --git a/src/applications/diffusion/request/DiffusionRequest.php b/src/applications/diffusion/request/DiffusionRequest.php --- a/src/applications/diffusion/request/DiffusionRequest.php +++ b/src/applications/diffusion/request/DiffusionRequest.php @@ -143,6 +143,7 @@ $query = id(new PhabricatorRepositoryQuery()) ->setViewer($viewer) ->withIdentifiers(array($identifier)) + ->needProfileImage(true) ->needURIs(true); if ($need_edit) { diff --git a/src/applications/repository/query/PhabricatorRepositoryQuery.php b/src/applications/repository/query/PhabricatorRepositoryQuery.php --- a/src/applications/repository/query/PhabricatorRepositoryQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryQuery.php @@ -36,6 +36,7 @@ private $needCommitCounts; private $needProjectPHIDs; private $needURIs; + private $needProfileImage; public function withIDs(array $ids) { $this->ids = $ids; @@ -160,6 +161,11 @@ return $this; } + public function needProfileImage($need) { + $this->needProfileImage = $need; + return $this; + } + public function getBuiltinOrders() { return array( 'committed' => array( @@ -374,6 +380,36 @@ } } + if ($this->needProfileImage) { + $default = null; + + $file_phids = mpull($repositories, 'getProfileImagePHID'); + $file_phids = array_filter($file_phids); + if ($file_phids) { + $files = id(new PhabricatorFileQuery()) + ->setParentQuery($this) + ->setViewer($this->getViewer()) + ->withPHIDs($file_phids) + ->execute(); + $files = mpull($files, null, 'getPHID'); + } else { + $files = array(); + } + + foreach ($repositories as $repository) { + $file = idx($files, $repository->getProfileImagePHID()); + if (!$file) { + if (!$default) { + $default = PhabricatorFile::loadBuiltin( + $this->getViewer(), + 'repo/code.png'); + } + $file = $default; + } + $repository->attachProfileImageFile($file); + } + } + return $repositories; } diff --git a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php --- a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php +++ b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php @@ -15,7 +15,8 @@ return id(new PhabricatorRepositoryQuery()) ->needProjectPHIDs(true) ->needCommitCounts(true) - ->needMostRecentCommits(true); + ->needMostRecentCommits(true) + ->needProfileImage(true); } protected function buildCustomSearchFields() { @@ -165,7 +166,8 @@ ->setObject($repository) ->setHeader($repository->getName()) ->setObjectName($repository->getMonogram()) - ->setHref($repository->getURI()); + ->setHref($repository->getURI()) + ->setImageURI($repository->getProfileImageURI()); $commit = $repository->getMostRecentCommit(); if ($commit) { diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -57,6 +57,7 @@ protected $viewPolicy; protected $editPolicy; protected $pushPolicy; + protected $profileImagePHID; protected $versionControlSystem; protected $details = array(); @@ -69,6 +70,7 @@ private $mostRecentCommit = self::ATTACHABLE; private $projectPHIDs = self::ATTACHABLE; private $uris = self::ATTACHABLE; + private $profileImageFile = self::ATTACHABLE; public static function initializeNewRepository(PhabricatorUser $actor) { @@ -110,6 +112,7 @@ 'credentialPHID' => 'phid?', 'almanacServicePHID' => 'phid?', 'localPath' => 'text128?', + 'profileImagePHID' => 'phid?', ), self::CONFIG_KEY_SCHEMA => array( 'callsign' => array( @@ -478,6 +481,20 @@ } } + public function getProfileImageURI() { + return $this->getProfileImageFile()->getBestURI(); + } + + public function attachProfileImageFile(PhabricatorFile $file) { + $this->profileImageFile = $file; + return $this; + } + + public function getProfileImageFile() { + return $this->assertAttached($this->profileImageFile); + } + + /* -( Remote Command Execution )------------------------------------------- */