From d3054a3c7b367caa631acb601b6cb1fd106b5344 Mon Sep 17 00:00:00 2001 From: ojintoad Date: Sun, 8 Feb 2015 23:26:27 -0500 Subject: [PATCH 01/16] Adding blade to moderators list and graphic --- .../moderators.png | Bin 8447 -> 9278 bytes views/static/community-guidelines.jade | 4 ++++ 2 files changed, 4 insertions(+) diff --git a/public/community-guidelines-images/moderators.png b/public/community-guidelines-images/moderators.png index dcbcc1b82b3d6b4acebb6bf52328f073a0141e49..6f59b2cc7359a5b277f9f8197e978f5b60bbcd1f 100644 GIT binary patch delta 6621 zcmZvhc|4Tg`~TA-(mP3#7_twcNR(kj7-Qd}5EVnVgc{4>&XO$I#@L!{jU{{bCd;IR z86+th+Z4t+$Tp0@{8aDH@A3V99^dvf(NORGg+G{(#X_Ro{WDh>|>|LuW}u96?1dJ zI^hygTKexZA}>gWz1#6wDqsItG)G&cHD6SwFg?u6D)z291E85+@|cTX!TvReXykE= z0#3l0|F|}XsQqWoz4H4*S^r)58E*3XONE)py*JCCR@#1TeZ=$^!}IGiHBKGJ2JOAq zub2ym#J0QC^e9L`-NRrx3uN48)bCnv`2JLj=E|Kk(U%lId-feJu~JDTeH#Cwy1GNz zi_u_600z^r&WsYVk2q&9*mLAuuZoR>0g?941V(`Gn?2cMP-Q|;ZLb5qitqk(&WDXp z3UBi$@Y!+4@Gl$NT6J|$n4gLJPL{zqHBg}_w>uk~&J};E#u>XU{t8!nxFBGy)zugg z+M=v~WqiwLG0LNMHS>sKkANeQ7JN-Q5;(4H&(8mF&jf9UFr||TUk1A)SA|2sgp|1C z1H+$Wm}6TuvM9uB=-c7qgVDLQp&fV+OtbQa^e@@6q|ongr=M-(3Nj1_6s+kNJl<5B zhr*ciiZVmfTo#!*m&_X?!4TB9n+O|r#?V)GOKhp^i-F}`hz3H<6RQV)V zMyDh?BU|!#_j;ia!S#E%PLI7cjM?!b1}$W0T>)tkM-S?~ zHw_Iat5&TyD*mMyg}!tbT?rU-+BGqRB7TH4qzJXUG0!nyC=+RY>vL|2J)|y671EMN zc%gyF#|`s(RV4`JkDH{o{yP;3xDoTkt+}}8L%tF<4hh>688v=Cs|vS_y6F=+RS;@82I0 za2nI^zZ|+aE8|yUQtocc3b*`dD|E1^83#n{86`oyj~$CaF| z!M#Yxt-ZgZ%E$oEmoE&IW2=G9pNDfcda%3&-X*F{#^j%ORu0W>wz9o-8prYLiF!ZvFH)Sbf%464W@af zdw!@&IsZe*P>@+D%nih-AUBXIu9v0_6y@jZkimqaq9Pl8R>r$mE2Z2G*OAUUW|s`gu{q%aI?(AhETsy*n zj8*ZH^`qo=JCy1P`s^>>ej~|)zxh;)#HBgCY=2sm;8}utNikN>+Dxc6bdQ_N-fEe4 zYLtqdgocbK9U%ax`qPSMKh7r15sk(QXhfn|4X)M!7Zv;-tNl9<){g>OR(sRn$%OR z3+B&2MvO7z>2)cA%be^*gA0*8a~7e6on{Kj!O}+xvJ-#U z^T`(vxXblb-8$pHJmZZXF{VxrG)t(K4vLfX7&|&zVb#XI@d~mhsB6jMFj>^F3NcUP zZW~8A!IA+&ATb?^Y9QXuvp2@nEnWup<^}N!FAXwB@~$0DgqrYjh$6*+VRIK)xQVdB zYG9QKhLVG~rl>gTKEygBN0j(h8^ka7!Umcg$>4G<_%Z&jY^8Pi^NygQdawCa#VDoq znRsv1nva3WqFW-ht^{It;z2jW3kd95Dh#GkmPSkEVR|mkn4Pw#h)@N0@m?*<7XP)@ zm9`Jr(^vkr2Jm~{$JO?i?K}7RNNsr8StL9D9tZupZUF)bm%BJl4}})9;<>Fq;3dX) zTq6kZ*o`MTl=Y<(S>Fl%0Ai_UsC=Du>AEvjVK7FHwXDHPg2ticIsK|@>gc#&#Q z3qvai%igWYF&wSQvvt4QYO0N_AR^Fv(jSuXvLB|Q1|$C?2vb`*Z))bE>XqVtcw}y^ zJLaOhXeG#&38b$+zIv|GEWhVbT#(!R>?Pl<>bSVLIw<&K&K2<-_Prg0G{OzmqR@$_ zfy7-fLOP04?r9`dqo^AS`lYiZEIjXdQXIdNNE=+@`h_rfPPZ4i={8g^Fv$6)eIQn!G@sD%yHD7oY+Knx0qX}>U#GfKtNc23*(Ck7qt9`0a#WQZ9(b)C zpwJo3Y`bgOs7i{L8 zTs;OeIj8HWh*XNXi#N}xg`F_rL3wpetd6$GZubOfm&V3W?t3_6v?Iu&uLmY<0M8q@ zG#w6;_EsK|)P4_%Ay15t*HU-3;DU;bXTP0z6)Q4^TgShiy@lvdPFFejkYG2@n%%yE z@Sk~@TCFI({o=4`I%5ns@QA6q_-zB{iIg8-;mC*eS^@XqPsW(FUEwP7HzD&GjrUr&sWmv4aHRC0b* zow$B)a^`#8D6^}^b^EYw&I`nrshbq5uI9cCeeL?z^7crnsauy|zP`nChh7aAQ!k%i z9-zjIge*SrbZm+Im!NyO!R+5tD_KWZQL9r!E4LV1rW}fo)(E+sP(Y@)E%MsawyD1= zWBEU!4Vp5dSUq}>^kUdC;9WB7ZSl3WX|y6K=1GK)wy>UD%c6i0IS{?k0?YfRrPrFod*q}jCbWs(1M|z-ZrE7L1^~wqW*jbqx!vB1TH80{sw*)_W+dD0&*SYZq zu%+JG3-~B*vZ)6;reI{m9e~?U1-=LRJoq#zEgf8(n}o zltto)ra4xk4DqPm>fOi-X}HPz)7xN3xUuAPINiKR z4E(|#eF9iYL68)Lr8iWWqePO5WNfRmQZ$J5sxjv}vW~12`m6tOagP=reS^C5(*v_J z*rs&(Ff_m%YN8UG#CWi9c4yiIGt<{$b$@)j-G5t+5{~LzB}_JXPo1WG2L71z{|Dbg zAM@HYykAFRrA2s(-=FNsX8mFgt#mRD)KQlc2_-aWyovkpV|Evt7RRtFo5bc01}#0zKqjm}*3dFgygPe4voR0~zs-=>s~95A$|0P9sP z+`ECL_1k2CeByZBFCXH3cADsPYy!tJ@18tkc5JPXvcGZw zpcls~LBiR5rQ9?gdA+Jvuke47X991FL^G4+@k2~R5qDfd_Fx)L*~_3koYO7}lzvdl zJZS<%^=~UanW)6n&_I-q=cHxx7O|z(_XNlzD}bHKlS1lw@-Uf}uXP}WuUi=;^LEvq ze;j)nN;~wG#Q&A)|3jq*@KF;^I8FbEAhoxhC&Jq5Q;gWPGC}h!hCQ!W*31&umC<8b z>9IPGpkC<%hb7%ow(svpAX8o}cm$r*ADn~ zaLD4&ul)M$1z-kHMMDWJK?HWvpBG%y;7xI8N4}}`a}C?{H+~BzFYPQ`NnGa#DQ|Fx zzP+KY#d34r?C#&2?|yG!ElFHNoqr&4m5gPa;$6j850-l@uDV|SFP)Ph>7UY_eHmW= zsd3UN=JD=qymIV_w`4Q}sErEGTVwa{tt-l*?Yrut0ShR?$a>+@aKU8t#TJ2H5J zGGN>;Oj;WIB%U&vpai^`9Xu-)GuHOHr4mljaz<@!CD^idai7#mG{O4NLv}FgmCF#9 z;%e`3M?%0w>wizS`~E%IzD~WtULbc6*JHj|fA;)=`%Xb+Mf&+7dh;p4LZw))4wbK4 zR<+#@bLU?k6PwOki?_=tbTB4gKuBLC_&IK}|Fdi(8dy4eTE*3u7glYDIL=tmrQe z>sG8bbSLCWc)&to^-J0}Z=8t9wMsY<^g(||rTzCAIq{a`v@fDkSekf2jQ!aq`)Ah` zoJfGerl)O9n*J|uR3)O_1;pfgAS^{ zimD7bM537%8h#CVDZ1zC@vUo8;5U^ytAc-tetYJ!~EPY$@8}ISM zdjF;l(Of_NFo-w%_5uT%JQ0zzV(&3$kDv#KR#p>0{o3S^u`jG2nt}JOEmSq$PmPoW z*El(BSeM(%KrUYF_s)v4D@5LxQ|muvHvFKpe}57L=t)H7qzQ3^`t^)lutRwgRg%@EHRW=ILm|?>8}Evy zw(54?l*^K6z0GqBMjYe&hEdYY!)E~v2lVQ_GXk5d{X$bB&12>fSThWzYHwQwMy0-q z^eT8KEbQZaShgRZt7vMIvNEgWYTKI}n4zH$bz7594&l1{ftmu$uWEhahoJKTO}wcy z%cTc_b?Bcy(0^&=pWiIVhwU#J;=g^4)cmmJVe<3m{Ku{%0~Yj#ob2*dEL992wnHr%#Z4nLjlJEod!8N)lInw8aN)P$-ggq-UTJ{-86AhqSCXd`?wCyVeQAkt}LX}CzE-qJ1^ z-Zh`ji(td`_`gW)ytf@3eL{`2#IbdIeV~W0(m_%oOgvE2uzpyo11&&$&&BN@ z%M(EjlDe6oE1?!>hZ|9ApS@6Z*Xg-@vwLXGQuou*K zBT0jIT1G29pLwcE7QlM~J14%6{}JZn`~QPzz<6AKBu^I8y@@(=@DHq64UVyexiy0c zpC_tL=`^{zq?y(#>6POqcN^+TQ=9K>I+28r;mJ-{ZA~*kQ_J?Iqhj!DQx!u6@(ps$ zK)2F^#?7UjZ9jxa>HY(sF~Kg0qIuf;^^F7M4CaxOJEVOEGh>@yORkr8d%bH~1QT%G z3D919yI1m+duDKBetqgh9b`*iYJnfS$H>f+V%XF5rj8&I%VbWt&CYCqLYwK5*P?>f zv=}>CcGfZwWVQYbxMq-6mgox;!BBt=O=djZ9=n*rvAC@wFr>nbnwIY}cBWEiSxzmH zjA`sKc212qd7VpRoqvGk|4>2)?SCcfMf&m^Q17fGARV0wXv+4QFnRwaWowBKFXYL# zthGlc4kd89ZfD9JM6@L*cAk1B|I$vDxf77wCXQ>U8AEm`s zN3Z-aStf9AQ$|X>1gmEx$%|D=l5C1Z+OU?2V^vTc9XiryQ*RglG)T%A9a=7nZd9G9 z@+&g2&B&{PD?QxZ^hNp9_ znkE9I8iwns-=y!j!Q!8g@+))FVcsNWvK>%gnAqr~9A$=nHC$dF{<<-<+LeC~(GaTr z@~vt4<)4I4Y{Ww;4QFqOmIxJW{?p8qfw(NIBZ}^yf*%vFLA7Bktqc3fli!J+5fT z-PizC_%dDq-2mAOnE(P?Z&4oYb-|ctNy?0!g2Z{M-h-WJF1vXV=EW7X5D1$tG0H%H z_|8W4Zy?c-?YMrXeI~*WP>-25Lqs&Ave&j2IwGSUJ zQ~paX{c4;H^{|5r|MGdeO&gW?7T^bX;vd;QuIaRLd{mXS`u4iEWE+34c)u`TG_gpQ z)CJDlBVmA$;otxKO+$2kjB}LmZxbYzlyu$N8y&}A!TUFPfzQ}$<4?-sFHevBgVXk z1gn{;vF(WyCyS5YJ>}RAFSU5Ot zp-!u5Y2~Vb2UIhL-+JB5%6TUF0bkp%Q|cJw?4IixT8rwo${Geo$W^|UGwQ#VY9MN!F4$sC4f0)a=? zY$t`|IjjuhISe&fE*PE>ei?s8I3CU^@_!36V#db{dr#rV8(S7*&nf(Hyx)P~U+msd zFA!X>u^JlWr0(;H$sc;9hG4Q&=FFdP7@GdTnH`%aKGq1)c9Y5_kc-P)%$^41^pAy$KhO$H-*OYC}N#0-lUt3DdxuU1@RRibU=1yN_vPMazBEv;aoKWNZ0x)1R!jYM0+VxN5Wzgq zra*?EP*2X=Iq4BM9g^kAsx#(rK@8o1pfsa|*9%!e%6iT|^L?z`UzOdZ!ZA>phKV61 zdHeCpb*S_9Byaf~#idQbzV6ifi_UQhg3GD|on%4;3g-b9ge)L@thj3@C4ZUf8I|=0 zU6j5I=mQLib_w-DkWTd&2sL>V#wl^Gp*qa=$KM#FsF;1oB*T zZupf0|BXf^9$3KLu zA}8M55`+azHaAXs#&Np7mw=RVe*M!#ej`Ojj}dLQr6Ta{aY0Dez5NlNUSx}KtM-%) z=&?_jbku@#+O&13Pk(6=x5Adi95loOSbi5(s@!&!?n$2ClzDhlz2cS z7~i)=G0xOsP!ej&ag2G!_@yv=Zl6fm*8i@VIdOIR5^mZK^n#kLl0Pzb!t=M{8<_t4 z%QE@yr%zW;Np~$ZIM$>B^0+rPH+e1gJ7tU-!*BC}#3{|E7lS~5y?1iiu>DX=DHB-D zo7c44&)G@s>RAcP2GBOSAP1-AK(ERzt7|BEU0n!a4AUv_r)LLZXgEx!r3SEVyJHp6|WM&taZ z8U0&pBTuh*L695oO5R;#QjK8{CHmls*gI;Uh|8jmY!vQ* zLS;rC97HKfH;oM))yj3DW2!TKQqEV^h_B|*?rBJA7cFC1ghRmk7lbc3gqy~5UEu+| z9w!<*&Ir#qG}`y#gj=sjbzGR`{PlhAyM)7C$5Jk?%YL5|I-ILMxdgg@4LI9c884C2 zWR&&TX#F@%BaT@7B1Y{mZu?=Zo|D`bM2Xs={g&N5l|xx0;9Mh?Y9m7vzX;;2FN_uE!+k^EA)DoB$9Vd-=tr>nPjIp*Pap=D8~ zTJ6jQYg;;fPXsGhvu_WRl&}yqq>aC-YF+ER1lw(xXUBihU0RshczJw2mo>IR#i52RXZ$Cc0^VWx${L^9FHt1u zkLyAjx-}v?c9#0)z+)dj+9G?e8gOB!EhhtI!PU1zZ`?>gQ%vFeMOPt{PV1)=qsM+O zg{Ox6XkKyxhmv_=o;*)x-alB4URR1+xx;(qHsvpN+yzksqUVZ%?+A#_+Z&6dKLGaG_cnF&BtPq1YKa67fmPuDB^Yb7^-IAnb%=`-c_ zMw*@c+Hg-%P)DU>ah)r2cn9kj3cq#SOnjT3AE}0b*v{WJ z<8}lt zAN)~wiQ8sKChPe=&j1V?(gPo zIXO8*&wQo|0Q%idk^LccW{jq^w;Dp+OkC&$HWdq`=wC@(UmH1z#+p2WfCc=Fw)Bg; z_2XnyzXBJr%IyL=5#uc7{^TnT{x%+?J}F7Zs9Iw+?`Tw|%;DU*-hcFd;J&>@DU7f@>p`%o@W7gu0>#z>c67tAl?MF|#J#+V59C{&rIg$|E z?Hc{s5lQrKpcj<@+TjYmf()arQ86D%0-NELWJu17y#n;eyIa&QjYQesec69|dCjaj zOHNmZ1mEPC!?9Vdown9qusTyBTa)R!^d?Q+$$PdSAb*_;RS{JCRlkf&5;+lo36Ezq zN3_BAUaSMQRPc2XS=C(qTLcfu{IY;*FPUqBz>wV=Y5J~ox|O?G{Z?%U&H1&;ac}hf z{n}562+*@O2wfX6CFrx3X@Qz!oW)){J*H>sZsXMPUq0HGHWk#xIp=JdR=|3b8Nw*3yH@d~S&NF2_jD_a{83Z^ zXuD3N#dYL|4#qgX_*tJ2Vmvt(k(8dalPmA?kXi{BKOUIc)qYP?fvhe;e0ZkN(F|G% zT0dv-8i4_-^NJkG5~;OjP*XVoj3AJ=JF*qWOURIsB<3t$PS^ah3LJ=SKq1BHAQPQ& z@pD^g==j5ZpXp^3{>wH8i3`0uIaUuv`GTU>Jw7mNlxmHuw|r}ttg~%@#sE92QPmt~ z8^h6kKJySp&gqh@z1zCWaYDE%Cv7W2fR4zcq!L=H4Rx7ns~7cyfe5JIuR_ZI6s1}S z&GnPT@dDb{@yv+yXsTuZOO0>m%;6bZpIsEYIFL^ty&bv!Y`aslKGMEFt(HA)+6FoO zq2memwdt3ck>=?XL0d)Tid@9?4`Bn$B&+fZje5fB4urIeBoL3_h#^7WG83yJn4DQz zD=z-G2EQph?7F;dXdhs+e;LNFJ^y|&;a^&dA4_9>Ui(A3z@;ZM<*`)BQ0Bt+H76@^ z&2f`zyEj&N1v$Cxu_6yzLV+Lb=8?D*uT-{umbqYS)${0{J8!1m`XZM(7ptFpnjAv# z*P!o>io`S-8N_ZvAAnW4Iyo4uGKBK4C1WBR0nBWXj)oM@qezx%?7E4GY}CpfuMXB_ z>WE{Vt@7wA@R-r9r*}bNb2^k7wK3z~94+YGiS^zmm(+vtqA?Wx*Wm^%{y3F_R_=x) zm%iW)Z=+jUpdyp;FOBI*b=x48++L!P^f~L?HodvJpUSW}{YkX|1m)zlMu#%j@1@K< zfZ6`bv#`*DspE;WtvwI!{*0XQqTjWDLGFA;&1jA7m)-on*^~K5IccL6QH!8|D+|T9 zvi41)i#Bg3dOYxy*HK5=8qM%GA}Bj~M4wepejSWkwJH1$F&AfqN&Sy8gJQ;PjHU~L zA8h76k}U|JbT5koP?SwB!!50gIa|tgB-!_1rk=LPBhTo?IeXj5iu058 zea!dPPQK%Foh_-X7q%uI&ZT;pm@FFnqgdW9ndK-Sx^# zT5Q<4mF+9lWqSRtLY-rccE^={G^L3Ip+OSDUG!?K3*PL)@{DD%2DVN`;K>#&javr?s`|d1-#Ql5V0TKS<6#U?rSl#;lfy4oSR6NH3X;MVFY?~mENWA?S!=`2Z6XSW zsQa#Ssr=esQ(<=m1Qe8s_NkpJNVW44PoCV*oB*hP_#3I3c11q^%lViB`G19e!QVvP z;9D;CCNwzs)VPU4qha%eb!bJoCTYX*oDS*iIfgkB5I^ZJ)o~ylRfpC5A034ATJh zyIplRCtcMeIl$bSUC@9t|CCy-SpWLga)!}hGgj035YpAYyCdrH7>)EIL3Qe$^uR;`TT%pxRiISgn|Nazw z^{dZJm2vKt!~Y;2&E86H6K8`f^1s-@oI>WoV2na~%G)&Q9wdYYOTxq)Ms5hS2{`~v zLa!FBX%I9vCNUm?2Vz8T&Z8T`Yi!U)-zzA6O4(9Tv*}fM=pn*XMuWA{Y$Y{;rsz9F zWsO+d5JzNxdGt{X=i!||ssQ_}$4T!P-AG9Bx!M&d!LoK(ad*9%d8)9CY+-AiAfr?( zv)(!U$}rV0w^R${o|~|BSOngp%Qu)1JYXUb*t|L`f_^j*c!O}C2U6_UA%@G*+^?Gi zQL_*tmW6NAw=j-_*9mI!pP~8@X&8R;gXn(Uy#r6g$?^pE0K2nHpdGupg8pGtDq~_i zb13r8Ob3fm1j~`CQ2g_$GswAPD%DUQyOqf|LYCM#(H1?kCYv7Nzs?<*Qw__`5?Fnh zkyb?R-36X%j3$vfPNADW|7Bgu9bQswSzmJ`1d~)qBSo)WPSgKhQW4;s+i^JWo2|+r zh4X8qdHVse_J}t3{_3eNHBwlH(p59>Nj_fR(X@qOE>jvJIV^Puvt{`8BGEHi949Q* z5y60W@-PFAfePIIv&iWof$y!0#gzG`0nKY-fH-m?LCloKe%@MMZfrT@kh!OWuLaBt z%^ti82w=c;e$(V^>^U1-6@H&jV*%%W^Fi0R-($?K1N{C$(ZGviB&7^-dPKf>4`0b6 zm8uD{fMjU!#Bvfa6-P6H%TFn8FOc(Z13ZqPOG~b}cF6IdF+;kR7Y`h0;g+Fs^AcP)W46Jw_S5@HHx$inod1nZ2U!WIFY}}= Date: Sun, 8 Feb 2015 23:33:15 -0500 Subject: [PATCH 02/16] removed space --- views/static/community-guidelines.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/static/community-guidelines.jade b/views/static/community-guidelines.jade index a6f185770a..7cffc25ffa 100644 --- a/views/static/community-guidelines.jade +++ b/views/static/community-guidelines.jade @@ -92,7 +92,7 @@ block content =env.t('commGuidePara011c') |) li - strong Blade (crooked neighbor  + strong Blade (crookedneighbor  =env.t('commGuidePara011d') |) li From 2b0f667368309b908d7344eee96ebb43c69917bb Mon Sep 17 00:00:00 2001 From: ojintoad Date: Mon, 9 Feb 2015 00:08:36 -0500 Subject: [PATCH 03/16] Adds language to Address PMs, explicitly forbid spamming, list sexism in the public spaces inappropriate behaviors, define duplicate accounts as severe infractions. --- views/static/community-guidelines.jade | 3 +++ 1 file changed, 3 insertions(+) diff --git a/views/static/community-guidelines.jade b/views/static/community-guidelines.jade index 7cffc25ffa..7831cbf161 100644 --- a/views/static/community-guidelines.jade +++ b/views/static/community-guidelines.jade @@ -121,7 +121,9 @@ block content li!=env.t('commGuideList02F') li!=env.t('commGuideList02G') li!=env.t('commGuideList02H') + li!=env.t('commGuideList02I') p!=env.t('commGuidePara019') + p=env.t('commGuidePara020') p=env.t('commGuidePara021') h3=env.t('commGuideHeadingTavern') @@ -239,6 +241,7 @@ block content li=env.t('commGuideList06B') li=env.t('commGuideList06C') li=env.t('commGuideList06D') + li=env.t('commGuideList06E') h4=env.t('commGuideHeadingMinorInfractions') p=env.t('commGuidePara056') p=env.t('commGuidePara057') From 4ba7f9f7c87cfb40c5eab3d1e931959969a00b34 Mon Sep 17 00:00:00 2001 From: ojintoad Date: Mon, 9 Feb 2015 00:14:05 -0500 Subject: [PATCH 04/16] moves dupes to the severe infractions list --- views/static/community-guidelines.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/static/community-guidelines.jade b/views/static/community-guidelines.jade index 7831cbf161..7d32398dbd 100644 --- a/views/static/community-guidelines.jade +++ b/views/static/community-guidelines.jade @@ -233,6 +233,7 @@ block content li=env.t('commGuideList05C') li=env.t('commGuideList05D') li=env.t('commGuideList05E') + li=env.t('commGuideList05F') h4=env.t('commGuideHeadingModerateInfractions') p=env.t('commGuidePara054') p=env.t('commGuidePara055') @@ -241,7 +242,6 @@ block content li=env.t('commGuideList06B') li=env.t('commGuideList06C') li=env.t('commGuideList06D') - li=env.t('commGuideList06E') h4=env.t('commGuideHeadingMinorInfractions') p=env.t('commGuidePara056') p=env.t('commGuidePara057') From 24a6b2f4ccf155972443109154476dc5a19c5e03 Mon Sep 17 00:00:00 2001 From: Lisa Marie Date: Mon, 9 Feb 2015 19:39:05 -0700 Subject: [PATCH 05/16] migration(plans): sample code for plans which didn't get applied --- migrations/freeMonth.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/migrations/freeMonth.js b/migrations/freeMonth.js index 36f320746c..dba8d256ee 100644 --- a/migrations/freeMonth.js +++ b/migrations/freeMonth.js @@ -8,4 +8,25 @@ db.users.update( 'purchased.plan.planId':'basic_earned', 'purchased.plan.dateTerminated': moment().add('month',1).toDate() }} -) \ No newline at end of file +) + +// db.users.update( +// {_id:''}, +// {$set:{'purchased.plan':{ +// planId: 'basic_3mo', +// paymentMethod: 'Paypal', +// customerId: 'Gift', +// dateCreated: new Date(), +// dateTerminated: moment().add('month',3).toDate() +// dateUpdated: new Date(), +// extraMonths: 0, +// gemsBought: 0, +// mysteryItems: [], +// consecutive: { +// count: 0, +// offset: 3, +// gemCapExtra: 15, +// trinkets: 1 +// } +// }}} +// ) \ No newline at end of file From 1c3873647b04b7350e830c212d7b5a99ac82865f Mon Sep 17 00:00:00 2001 From: ojintoad Date: Mon, 9 Feb 2015 21:45:09 -0500 Subject: [PATCH 06/16] Spacing out paragraphs --- views/static/community-guidelines.jade | 1 + 1 file changed, 1 insertion(+) diff --git a/views/static/community-guidelines.jade b/views/static/community-guidelines.jade index 7d32398dbd..0845e6ce76 100644 --- a/views/static/community-guidelines.jade +++ b/views/static/community-guidelines.jade @@ -124,6 +124,7 @@ block content li!=env.t('commGuideList02I') p!=env.t('commGuidePara019') p=env.t('commGuidePara020') + p   p=env.t('commGuidePara021') h3=env.t('commGuideHeadingTavern') From 5489c37a1e8cc407bcb7962be4cfe27b1bd42c6c Mon Sep 17 00:00:00 2001 From: ojintoad Date: Mon, 9 Feb 2015 21:50:46 -0500 Subject: [PATCH 07/16] Updating blacksmiths list --- views/static/community-guidelines.jade | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/views/static/community-guidelines.jade b/views/static/community-guidelines.jade index 0845e6ce76..0e7cc1352a 100644 --- a/views/static/community-guidelines.jade +++ b/views/static/community-guidelines.jade @@ -177,8 +177,7 @@ block content li Alys li benmanley (Pixel) li colegleason (Cole) - li deilann (Ryan) - li djuretic + li deilann (Ryan v) li Fandekasp li Lemoness li litenull @@ -187,8 +186,14 @@ block content li Sinza- li snicker li thepeopleseason - li wc8 li zakkain + li crookedneighbor (Blade) + li @huaruiwu + li negue + li ruddfawcett + li wogsland + li MagicMicky + li viirus h3=env.t('commGuideHeadingWiki') div(class='clearfix') From 7f29503ff2a560658e0dcb3d9617ceeee839fe60 Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 9 Feb 2015 22:29:36 -0600 Subject: [PATCH 08/16] Corrected names --- views/static/community-guidelines.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/static/community-guidelines.jade b/views/static/community-guidelines.jade index 0e7cc1352a..dc0353edaf 100644 --- a/views/static/community-guidelines.jade +++ b/views/static/community-guidelines.jade @@ -177,7 +177,7 @@ block content li Alys li benmanley (Pixel) li colegleason (Cole) - li deilann (Ryan v) + li deilann (Ryan v*) li Fandekasp li Lemoness li litenull @@ -188,7 +188,7 @@ block content li thepeopleseason li zakkain li crookedneighbor (Blade) - li @huaruiwu + li huaruiwu li negue li ruddfawcett li wogsland From b1d535874d8ec630a6576748c62a9c003de084ed Mon Sep 17 00:00:00 2001 From: Blade Barringer Date: Mon, 9 Feb 2015 22:38:06 -0600 Subject: [PATCH 09/16] Updated last revised date --- views/static/community-guidelines.jade | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/static/community-guidelines.jade b/views/static/community-guidelines.jade index dc0353edaf..4af0c13a60 100644 --- a/views/static/community-guidelines.jade +++ b/views/static/community-guidelines.jade @@ -27,8 +27,8 @@ block content h1=env.t('communityGuidelines') p.pagemeta |Last updated  - =env.t('October') - | 27, 2014 + =env.t('February') + | 9, 2015 h2=env.t('commGuideHeadingWelcome') div(class='clearfix') img(class='pull-left', src='/community-guidelines-images/intro.png', alt='') From 291b5eb1e70f31dae15c5c2f7bedcff563b72bd2 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 5 Feb 2015 17:56:31 +0100 Subject: [PATCH 10/16] partial --- src/controllers/groups.js | 193 ++++++++++++++++++++++++++------------ src/controllers/user.js | 40 -------- src/routes/apiv2.coffee | 11 +-- 3 files changed, 132 insertions(+), 112 deletions(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 7d874e0d50..1acad39fdb 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -508,80 +508,149 @@ api.leave = function(req, res, next) { }) } -api.invite = function(req, res, next) { - var group = res.locals.group; - var uuid = req.query.uuid; +var inviteByUUID = function(uuids, group, req, res, next){ + uuids = Array.isArray(uuids) ? uuids : [uuids]; - User.findById(uuid, function(err,invite){ - if (err) return next(err); - if (!invite) - return res.json(400,{err:'User with id "' + uuid + '" not found'}); - if (group.type == 'guild') { - if (_.contains(group.members,uuid)) - return res.json(400,{err: "User already in that group"}); - if (invite.invitations && invite.invitations.guilds && _.find(invite.invitations.guilds, {id:group._id})) - return res.json(400, {err:"User already invited to that group"}); - sendInvite(); - } else if (group.type == 'party') { - if (invite.invitations && !_.isEmpty(invite.invitations.party)) - return res.json(400,{err:"User already pending invitation."}); - Group.find({type:'party', members:{$in:[uuid]}}, function(err, groups){ - if (err) return next(err); - if (!_.isEmpty(groups)) - return res.json(400,{err:"User already in a party."}) + async.each(uuids, function(uuid, cb){ + User.findById(uuid, function(err,invite){ + if (err) return cb(err); + if (!invite) + return cb({code:400,err:'User with id "' + uuid + '" not found'}); + if (group.type == 'guild') { + if (_.contains(group.members,uuid)) + return cb({code:400,err: "User already in that group"}); + if (invite.invitations && invite.invitations.guilds && _.find(invite.invitations.guilds, {id:group._id})) + return cb({code:400,err:"User already invited to that group"}); sendInvite(); - }); - } - - function sendInvite (){ - if(group.type === 'guild'){ - invite.invitations.guilds.push({id: group._id, name: group.name, inviter:res.locals.user._id}); - }else{ - //req.body.type in 'guild', 'party' - invite.invitations.party = {id: group._id, name: group.name, inviter:res.locals.user._id}; + } else if (group.type == 'party') { + if (invite.invitations && !_.isEmpty(invite.invitations.party)) + return cb({code:400,err:"User already pending invitation."}); + Group.find({type:'party', members:{$in:[uuid]}}, function(err, groups){ + if (err) return cb(err); + if (!_.isEmpty(groups)) + return cb({code:400,err:"User already in a party."}) + sendInvite(); + }); } - group.invites.push(invite._id); - - async.series([ - function(cb){ - invite.save(cb); - }, - function(cb){ - group.save(cb); - }, - function(cb){ - populateQuery(group.type, Group.findById(group._id)).exec(cb); + function sendInvite (){ + if(group.type === 'guild'){ + invite.invitations.guilds.push({id: group._id, name: group.name, inviter:res.locals.user._id}); + }else{ + //req.body.type in 'guild', 'party' + invite.invitations.party = {id: group._id, name: group.name, inviter:res.locals.user._id}; } - ], function(err, results){ - if (err) return next(err); - if(invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false){ - var emailVars = [ - {name: 'INVITER', content: utils.getUserInfo(res.locals.user, ['name']).name} - ]; + group.invites.push(invite._id); - if(group.type == 'guild'){ - emailVars.push( - {name: 'GUILD_NAME', content: group.name}, - {name: 'GUILD_URL', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'} - ); - }else{ - emailVars.push( - {name: 'PARTY_NAME', content: group.name}, - {name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'} - ) + async.series([ + function(cb){ + invite.save(cb); + }, + function(cb){ + group.save(cb); + } + ], function(err, results){ + if (err) return cb(err); + + if(invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false){ + var emailVars = [ + {name: 'INVITER', content: utils.getUserInfo(res.locals.user, ['name']).name} + ]; + + if(group.type == 'guild'){ + emailVars.push( + {name: 'GUILD_NAME', content: group.name}, + {name: 'GUILD_URL', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'} + ); + }else{ + emailVars.push( + {name: 'PARTY_NAME', content: group.name}, + {name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'} + ) + } + + utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); } - utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); - } + cb(); + }); + } + }); + }, function(err){ + if(err){ + return err.code ? res.json(err.code, {err: err.err}) : next(err); + } - // Have to return whole group and its members for angular to show the invited user - res.json(results[2]); - group = uuid = null; - }); + populateQuery(group.type, Group.findById(group._id)).exec(function(err, populatedGroup){ + if(err) return next(err); + + res.json(populatedGroup); + }); + }); + +}; + +var inviteByEmail = function(invites, group, req, res, next){ + var usersAlreadyRegistered = []; + + async.each(invites, function(invite, cb){ + if (invite.email) { + User.findOne({$or: [ + {'auth.local.email': invite.email}, + {'auth.facebook.emails.value': invite.email} + ]}).select({_id: true, 'preferences.emailNotifications': true}) + .exec(function(err, userToContact){ + if(err) return next(err); + + if(userToContact){ + usersAlreadyRegistered.push(userToContact._id); + return cb(); + } + + var link = nconf.get('BASE_URL')+'?groupInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); + + var variables = [ + {name: 'LINK', content: link}, + {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} + ]; + + // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo + if(!userToContact || + (invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false && + userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ + // TODO implement "users can only be invited once" + invite.canSend = true; + utils.txnEmail(invite, 'invite-friend', variables); + } + + cb(); + }); + }else{ + cb('Email address is required.'); + } + }, function(err){ + if(err) return next(err); + + if(usersAlreadyRegistered.length > 0){ + inviteByUUID(usersAlreadyRegistered, group, req, res, next); + }else{ + res.send(200); } }); +}; + +api.invite = function(req, res, next){ + var group = res.locals.group; + var invitationType = req.query.invitationType; + + if(invitationType == 'uuid'){ + inviteByUUID(req.query.uuid, group, req, res, next); + }else if(invitationType == 'email'){ + inviteByEmail(req.body.emails, group, req, res, next) + }else{ + return res.json(400,{err: "Can invite only by email or uuid"}); + } } api.removeMember = function(req, res, next){ diff --git a/src/controllers/user.js b/src/controllers/user.js index ae2987fb8c..09c27ddd89 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -409,46 +409,6 @@ api.cast = function(req, res, next) { } } -/** - * POST /user/invite-friends - */ -api.inviteFriends = function(req, res, next) { - Group.findOne({type:'party', members:{'$in': [res.locals.user._id]}}).select('_id name').exec(function(err,party){ - if (err) return next(err); - - _.each(req.body.emails, function(invite){ - if (invite.email) { - - User.findOne({$or: [ - {'auth.local.email': invite.email}, - {'auth.facebook.emails.value': invite.email} - ]}).select({_id: true, 'preferences.emailNotifications': true}) - .exec(function(err, userToContact){ - if(err) return next(err); - - var link = nconf.get('BASE_URL')+'?partyInvite='+ utils.encrypt(JSON.stringify({id:party._id, inviter:res.locals.user._id, name:party.name})); - - var variables = [ - {name: 'LINK', content: link}, - {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} - ]; - - invite.canSend = true; - - // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo - if(!userToContact || (userToContact.preferences.emailNotifications.invitedParty !== false && - userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ - // TODO implement "users can only be invited once" - utils.txnEmail(invite, 'invite-friend', variables); - } - }); - - } - }); - res.send(200); - }) -} - api.sessionPartyInvite = function(req,res,next){ if (!req.session.partyInvite) return next(); var inv = res.locals.user.invitations; diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 39d4523a75..2c8703734b 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -365,15 +365,6 @@ module.exports = (swagger, v2) -> ] action: user.deleteTag - "/user/social/invite-friends": - spec: - method: 'POST' - description: 'Invite friends via email' - parameters: [ - body 'invites','Array of [{name:"Friend\'s Name", email:"friends@email.com"}] to invite to play in your party','object' - ] - action: user.inviteFriends - # Webhooks "/user/webhooks": spec: @@ -469,7 +460,7 @@ module.exports = (swagger, v2) -> description: "Invite a user to a group" parameters: [ path 'gid','Group id','string' - query 'uuid','User id to invite','string' + query 'invitationType','The type of invitation to send (uuid or email)','string' ] middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action:groups.invite From b069529fe8797bcaf278c6dd3471e3300830cb81 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 9 Feb 2015 20:16:00 +0100 Subject: [PATCH 11/16] add todos --- src/controllers/groups.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 1acad39fdb..24472b5b30 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -573,15 +573,15 @@ var inviteByUUID = function(uuids, group, req, res, next){ utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); } + // TODO what does this cb calls? anything? cb(); }); } }); }, function(err){ - if(err){ - return err.code ? res.json(err.code, {err: err.err}) : next(err); - } + if(err) return err.code ? res.json(err.code, {err: err.err}) : next(err); + // TODO pass group from save above don't find it again, or you have to find it again in order to run populate? populateQuery(group.type, Group.findById(group._id)).exec(function(err, populatedGroup){ if(err) return next(err); @@ -616,6 +616,7 @@ var inviteByEmail = function(invites, group, req, res, next){ ]; // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo + // Todo now this should be only for non registered users so no need to check preferences if(!userToContact || (invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false && userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ @@ -635,6 +636,7 @@ var inviteByEmail = function(invites, group, req, res, next){ if(usersAlreadyRegistered.length > 0){ inviteByUUID(usersAlreadyRegistered, group, req, res, next); }else{ + // todo send back group here as we do when inviting by uuid? res.send(200); } }); From fdf0c1d3ec7d145503c7f570ff6d358c1edc55ca Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 9 Feb 2015 20:35:41 +0100 Subject: [PATCH 12/16] bring client side changes and cleanup --- public/js/controllers/groupsCtrl.js | 45 +++++++++++++++---------- public/js/controllers/rootCtrl.js | 1 + views/options/social/group.jade | 10 +----- views/shared/modals/invite-friends.jade | 6 ++-- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index c911b1e2f2..1b4fb9b42c 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -65,15 +65,12 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } } - // ------ Invites ------ - - $scope.invite = function(group){ - Groups.Group.invite({gid: group._id, uuid: group.invitee}, undefined, function(){ - group.invitee = ''; - }, function(){ - group.invitee = ''; - }); - } + $scope.openInviteModal = function(group){ + $rootScope.openModal('invite-friends', {controller:'InviteToGroupCtrl', resolve: + {injectedGroup: function(){ + return group; + }}}); + }; //var serializeQs = function(obj, prefix){ // var str = []; @@ -91,14 +88,6 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' //$scope.inviteLink = function(obj){ // return window.env.BASE_URL + '?' + serializeQs({partyInvite: obj}); //} - $scope.emails = [{name:"",email:""},{name:"",email:""}]; - $scope.inviter = User.user.profile.name; - $scope.inviteEmails = function(inviter, emails){ - $http.post('/api/v2/user/social/invite-friends', {inviter:inviter, emails:emails}).success(function(){ - Notification.text("Invitations sent!"); - $scope.emails = [{name:'',email:''},{name:'',email:''}]; - }); - } $scope.quickReply = function(uid) { Members.selectMember(uid, function(){ @@ -108,6 +97,28 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } ]) + .controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', function($scope, User, Groups, injectedGroup, $http){ $scope.group = injectedGroup; + + $scope.inviter = User.user.profile.name; + $scope.emails = [{name:"",email:""},{name:"",email:""}]; + + // todo use Groups.Group.invite for everything not raw $http + $scope.inviteEmails = function(){ + $http.post('/api/v2/user/social/invite-friends/' + $scope.group._id, {inviter:$scope.inviter, emails:$scope.emails}).success(function(){ + Notification.text("Invitations sent!"); + $scope.emails = [{name:'',email:''},{name:'',email:''}]; + }); + }; + + $scope.invite = function(){ + Groups.Group.invite({gid: $scope.group._id, uuid: $scope.invitee}, undefined, function(){ + $scope.invitee = ''; + }, function(){ + $scope.invitee = ''; + }); + }; + }]) + .controller("MemberModalCtrl", ['$scope', '$rootScope', 'Members', 'Shared', '$http', 'Notification', 'Groups', function($scope, $rootScope, Members, Shared, $http, Notification, Groups) { $scope.timestamp = function(timestamp){ diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js index 65e1188e77..bad8734e37 100644 --- a/public/js/controllers/rootCtrl.js +++ b/public/js/controllers/rootCtrl.js @@ -114,6 +114,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ templateUrl: 'modals/' + template + '.html', controller: options.controller, // optional scope: options.scope, // optional + resolve: options.resolve, // optional keyboard: (options.keyboard === undefined ? true : options.keyboard), // optional backdrop: (options.backdrop === undefined ? true : options.backdrop), // optional size: options.size, // optional, 'sm' or 'lg' diff --git a/views/options/social/group.jade b/views/options/social/group.jade index 5d50ec3596..0e59b631de 100644 --- a/views/options/social/group.jade +++ b/views/options/social/group.jade @@ -55,7 +55,7 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter .panel-heading h3.panel-title =env.t('members') - button.pull-right.btn.btn-primary(ng-click="openModal('invite-friends', {controller:'GroupsCtrl'})", ng-if='::group.type=="party"') Invite Friends + button.pull-right.btn.btn-primary(ng-click="openInviteModal(group)") Invite Friends .panel-body.modal-fixed-height div.form-group(ng-if='::group.type=="party"') p=env.t('partyList') @@ -99,14 +99,6 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter a.media-body span(ng-click='clickMember(invite._id, true)') | {{invite.profile.name}} - .panel-footer(ng-if='::group.type!="party"') - form.form-inline(ng-submit='invite(group)') - //.alert.alert-danger(ng-show='_groupError') {{_groupError}} - .input-group - input.form-control(type='text', placeholder=env.t('userId'), ng-model='group.invitee') - span.input-group-btn - input.btn.btn-default(type='submit', value=env.t('invite')) - a.btn.btn-danger(data-id='{{group.id}}', ng-click='clickLeave(group, $event)')=env.t('leave') diff --git a/views/shared/modals/invite-friends.jade b/views/shared/modals/invite-friends.jade index 02e4ce0c8d..13f954167f 100644 --- a/views/shared/modals/invite-friends.jade +++ b/views/shared/modals/invite-friends.jade @@ -4,10 +4,10 @@ script(type='text/ng-template', id='modals/invite-friends.html') .modal-body p.alert.alert-info Invite friends by User ID here. - form.form-inline(ng-submit='invite(party)') + form.form-inline(ng-submit='invite()') //-.alert.alert-danger(ng-show='_groupError') {{_groupError}} .form-group - input.form-control(type='text', placeholder=env.t('userId'), ng-model='party.invitee') + input.form-control(type='text', placeholder=env.t('userId'), ng-model='invitee') |  button.btn.btn-primary(type='submit') Invite Existing User @@ -15,7 +15,7 @@ script(type='text/ng-template', id='modals/invite-friends.html') p.alert.alert-info Invite friends by email. If they join via your email, they'll automatically be invited to your party. - form.form-horizontal(ng-submit='inviteEmails(inviter, emails)') + form.form-horizontal(ng-submit='inviteEmails()') table.table.table-striped thead tr From 06561bf70f2dda5edee8ea1e1ee66e2cad5a897d Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 19:40:15 +0100 Subject: [PATCH 13/16] finash invites reworking --- public/js/controllers/groupsCtrl.js | 13 +++++---- src/controllers/groups.js | 41 ++++++++++++----------------- src/controllers/user.js | 10 ++++++- src/middleware.js | 3 ++- src/routes/apiv2.coffee | 2 +- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index 1b4fb9b42c..3f27ecd82e 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -97,21 +97,24 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } ]) - .controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', function($scope, User, Groups, injectedGroup, $http){ $scope.group = injectedGroup; + .controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', 'Notification', function($scope, User, Groups, injectedGroup, $http, Notification){ + $scope.group = injectedGroup; $scope.inviter = User.user.profile.name; $scope.emails = [{name:"",email:""},{name:"",email:""}]; - // todo use Groups.Group.invite for everything not raw $http $scope.inviteEmails = function(){ - $http.post('/api/v2/user/social/invite-friends/' + $scope.group._id, {inviter:$scope.inviter, emails:$scope.emails}).success(function(){ - Notification.text("Invitations sent!"); + Groups.Group.invite({gid: $scope.group._id}, {inviter: $scope.inviter, emails: $scope.emails}, function(){ + Notification.text("Invitation(s) sent!"); + $scope.emails = [{name:'',email:''},{name:'',email:''}]; + }, function(){ $scope.emails = [{name:'',email:''},{name:'',email:''}]; }); }; $scope.invite = function(){ - Groups.Group.invite({gid: $scope.group._id, uuid: $scope.invitee}, undefined, function(){ + Groups.Group.invite({gid: $scope.group._id}, {uuids: [$scope.invitee]}, function(){ + Notification.text("Invitation(s) sent!"); $scope.invitee = ''; }, function(){ $scope.invitee = ''; diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 24472b5b30..9003799722 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -508,9 +508,7 @@ api.leave = function(req, res, next) { }) } -var inviteByUUID = function(uuids, group, req, res, next){ - uuids = Array.isArray(uuids) ? uuids : [uuids]; - +var inviteByUUIDs = function(uuids, group, req, res, next){ async.each(uuids, function(uuid, cb){ User.findById(uuid, function(err,invite){ if (err) return cb(err); @@ -573,7 +571,6 @@ var inviteByUUID = function(uuids, group, req, res, next){ utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); } - // TODO what does this cb calls? anything? cb(); }); } @@ -591,7 +588,7 @@ var inviteByUUID = function(uuids, group, req, res, next){ }; -var inviteByEmail = function(invites, group, req, res, next){ +var inviteByEmails = function(invites, group, req, res, next){ var usersAlreadyRegistered = []; async.each(invites, function(invite, cb){ @@ -608,35 +605,32 @@ var inviteByEmail = function(invites, group, req, res, next){ return cb(); } - var link = nconf.get('BASE_URL')+'?groupInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); + // yeah, it supports guild too but for backward compatibility we'll use partyInvite as query + var link = nconf.get('BASE_URL')+'?partyInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); var variables = [ {name: 'LINK', content: link}, {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} ]; - // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo - // Todo now this should be only for non registered users so no need to check preferences - if(!userToContact || - (invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false && - userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ - // TODO implement "users can only be invited once" - invite.canSend = true; - utils.txnEmail(invite, 'invite-friend', variables); - } + // TODO implement "users can only be invited once" + invite.canSend = true; // Requested by utils.txnEmail + utils.txnEmail(invite, ('invite-friend' + (group.type == 'guild' ? '-guild' : '')), variables); cb(); }); }else{ - cb('Email address is required.'); + cb({code: 400, err: 'Email address is required.'}); } }, function(err){ - if(err) return next(err); + if(err) return err.code ? res.json(err.code, {err: err.err}) : next(err); if(usersAlreadyRegistered.length > 0){ - inviteByUUID(usersAlreadyRegistered, group, req, res, next); + inviteByUUIDs(usersAlreadyRegistered, group, req, res, next); }else{ - // todo send back group here as we do when inviting by uuid? + + // Send only status code down the line because it doesn't need + // info on invited users since they are not yet registered res.send(200); } }); @@ -644,12 +638,11 @@ var inviteByEmail = function(invites, group, req, res, next){ api.invite = function(req, res, next){ var group = res.locals.group; - var invitationType = req.query.invitationType; - if(invitationType == 'uuid'){ - inviteByUUID(req.query.uuid, group, req, res, next); - }else if(invitationType == 'email'){ - inviteByEmail(req.body.emails, group, req, res, next) + if(req.body.uuids){ + inviteByUUIDs(req.body.uuids, group, req, res, next); + }else if(req.body.emails){ + inviteByEmails(req.body.emails, group, req, res, next) }else{ return res.json(400,{err: "Can invite only by email or uuid"}); } diff --git a/src/controllers/user.js b/src/controllers/user.js index 09c27ddd89..d3fd377e63 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -409,13 +409,14 @@ api.cast = function(req, res, next) { } } +// It supports guild too now but we'll stick to partyInvite for backward compatibility api.sessionPartyInvite = function(req,res,next){ if (!req.session.partyInvite) return next(); var inv = res.locals.user.invitations; if (inv.party && inv.party.id) return next(); // already invited to a party async.waterfall([ function(cb){ - Group.findOne({_id:req.session.partyInvite.id, type:'party', members:{$in:[req.session.partyInvite.inviter]}}) + Group.findOne({_id:req.session.partyInvite.id, members:{$in:[req.session.partyInvite.inviter]}}) .select('invites members').exec(cb); }, function(group, cb){ @@ -424,6 +425,13 @@ api.sessionPartyInvite = function(req,res,next){ delete req.session.partyInvite; return cb(); } + + if(group.type === 'guild'){ + inv.guilds.push(req.session.partyInvite); + }else{ + //req.body.type in 'guild', 'party' + inv.party = req.session.partyInvite; + } inv.party = req.session.partyInvite; delete req.session.partyInvite; if (!~group.invites.indexOf(res.locals.user._id)) diff --git a/src/middleware.js b/src/middleware.js index 0c6c70d5d8..a3b3f092ba 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -201,7 +201,8 @@ module.exports.locals = function(req, res, next) { worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {} }); - // Put query-string party invitations into session to be handled later + // Put query-string party (& guild but use partyInvite for backward compatibility) + // invitations into session to be handled later try{ req.session.partyInvite = JSON.parse(utils.decrypt(req.query.partyInvite)) } catch(e){} diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 2c8703734b..acfa448f53 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -460,7 +460,7 @@ module.exports = (swagger, v2) -> description: "Invite a user to a group" parameters: [ path 'gid','Group id','string' - query 'invitationType','The type of invitation to send (uuid or email)','string' + body '','a payload of invites either under body.uuids or body.emails, only one of them!','object' ] middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action:groups.invite From 0d23ef94da2d595c18fb49e18553c9f86e22e4c8 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 21:42:43 +0100 Subject: [PATCH 14/16] fix when second email not defined --- src/controllers/groups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 9003799722..52389f1234 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -620,7 +620,7 @@ var inviteByEmails = function(invites, group, req, res, next){ cb(); }); }else{ - cb({code: 400, err: 'Email address is required.'}); + cb(); } }, function(err){ if(err) return err.code ? res.json(err.code, {err: err.err}) : next(err); From be276461437838b6ca96456d914facceff8967ef Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 21:53:26 +0100 Subject: [PATCH 15/16] correctly fetch group.type --- src/controllers/user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/user.js b/src/controllers/user.js index d3fd377e63..e7125c51c0 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -417,7 +417,7 @@ api.sessionPartyInvite = function(req,res,next){ async.waterfall([ function(cb){ Group.findOne({_id:req.session.partyInvite.id, members:{$in:[req.session.partyInvite.inviter]}}) - .select('invites members').exec(cb); + .select('invites members type').exec(cb); }, function(group, cb){ if (!group){ @@ -426,7 +426,7 @@ api.sessionPartyInvite = function(req,res,next){ return cb(); } - if(group.type === 'guild'){ + if(group.type == 'guild'){ inv.guilds.push(req.session.partyInvite); }else{ //req.body.type in 'guild', 'party' From 9c6fc78a2fe6791d26796f58d02237cc67e9bd12 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 22:07:36 +0100 Subject: [PATCH 16/16] invite friend to guild: pass guild name --- src/controllers/groups.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 52389f1234..a98fb8e1bc 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -613,6 +613,10 @@ var inviteByEmails = function(invites, group, req, res, next){ {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} ]; + if(group.type == 'guild'){ + variables.push({name: 'GUILD_NAME', content: group.name}); + } + // TODO implement "users can only be invited once" invite.canSend = true; // Requested by utils.txnEmail utils.txnEmail(invite, ('invite-friend' + (group.type == 'guild' ? '-guild' : '')), variables);