From 8396919a22f2e29f156014d272cda32be3f7d243 Mon Sep 17 00:00:00 2001 From: IQBAL Date: Tue, 6 Oct 2020 09:51:37 +0700 Subject: [PATCH 01/13] Successfully create and finish rest for register API --- .gitignore | 33 ++ .mvn/wrapper/MavenWrapperDownloader.java | 117 +++++++ .mvn/wrapper/maven-wrapper.jar | Bin 0 -> 50710 bytes .mvn/wrapper/maven-wrapper.properties | 2 + README.md | 28 +- mvnw | 310 ++++++++++++++++++ mvnw.cmd | 182 ++++++++++ pom.xml | 92 ++++++ .../api/GlobalLineNetworkApplication.java | 13 + .../id/globallinenetwork/api/user/IUser.java | 7 + .../api/user/RegisterDto.java | 9 + .../api/user/UserController.java | 32 ++ .../api/user/UserService.java | 23 ++ src/main/resources/application.properties | 1 + .../GlobalLineNetworkApplicationTests.java | 21 ++ .../api/controller/UserControllerTest.java | 70 ++++ 16 files changed, 927 insertions(+), 13 deletions(-) create mode 100644 .gitignore create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.jar create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100755 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml create mode 100644 src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java create mode 100644 src/main/java/id/globallinenetwork/api/user/IUser.java create mode 100644 src/main/java/id/globallinenetwork/api/user/RegisterDto.java create mode 100644 src/main/java/id/globallinenetwork/api/user/UserController.java create mode 100644 src/main/java/id/globallinenetwork/api/user/UserService.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java create mode 100644 src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..e76d1f3 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed 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 + * + * https://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 java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 GIT binary patch literal 50710 zcmbTd1CVCTmM+|7+wQV$+qP}n>auOywyU~q+qUhh+uxis_~*a##hm*_WW?9E7Pb7N%LRFiwbEGCJ0XP=%-6oeT$XZcYgtzC2~q zk(K08IQL8oTl}>>+hE5YRgXTB@fZ4TH9>7=79e`%%tw*SQUa9~$xKD5rS!;ZG@ocK zQdcH}JX?W|0_Afv?y`-NgLum62B&WSD$-w;O6G0Sm;SMX65z)l%m1e-g8Q$QTI;(Q z+x$xth4KFvH@Bs6(zn!iF#nenk^Y^ce;XIItAoCsow38eq?Y-Auh!1in#Rt-_D>H^ z=EjbclGGGa6VnaMGmMLj`x3NcwA43Jb(0gzl;RUIRAUDcR1~99l2SAPkVhoRMMtN} zXvC<tOmX83grD8GSo_Lo?%lNfhD#EBgPo z*nf@ppMC#B!T)Ae0RG$mlJWmGl7CkuU~B8-==5i;rS;8i6rJ=PoQxf446XDX9g|c> zU64ePyMlsI^V5Jq5A+BPe#e73+kpc_r1tv#B)~EZ;7^67F0*QiYfrk0uVW;Qb=NsG zN>gsuCwvb?s-KQIppEaeXtEMdc9dy6Dfduz-tMTms+i01{eD9JE&h?Kht*$eOl#&L zJdM_-vXs(V#$Ed;5wyNWJdPNh+Z$+;$|%qR(t`4W@kDhd*{(7-33BOS6L$UPDeE_53j${QfKN-0v-HG z(QfyvFNbwPK%^!eIo4ac1;b>c0vyf9}Xby@YY!lkz-UvNp zwj#Gg|4B~?n?G^{;(W;|{SNoJbHTMpQJ*Wq5b{l9c8(%?Kd^1?H1om1de0Da9M;Q=n zUfn{f87iVb^>Exl*nZ0hs(Yt>&V9$Pg`zX`AI%`+0SWQ4Zc(8lUDcTluS z5a_KerZWe}a-MF9#Cd^fi!y3%@RFmg&~YnYZ6<=L`UJ0v={zr)>$A;x#MCHZy1st7 ztT+N07NR+vOwSV2pvWuN1%lO!K#Pj0Fr>Q~R40{bwdL%u9i`DSM4RdtEH#cW)6}+I-eE< z&tZs+(Ogu(H_;$a$!7w`MH0r%h&@KM+<>gJL@O~2K2?VrSYUBbhCn#yy?P)uF3qWU z0o09mIik+kvzV6w>vEZy@&Mr)SgxPzUiDA&%07m17udz9usD82afQEps3$pe!7fUf z0eiidkJ)m3qhOjVHC_M(RYCBO%CZKZXFb8}s0-+}@CIn&EF(rRWUX2g^yZCvl0bI} zbP;1S)iXnRC&}5-Tl(hASKqdSnO?ASGJ*MIhOXIblmEudj(M|W!+I3eDc}7t`^mtg z)PKlaXe(OH+q-)qcQ8a@!llRrpGI8DsjhoKvw9T;TEH&?s=LH0w$EzI>%u;oD@x83 zJL7+ncjI9nn!TlS_KYu5vn%f*@qa5F;| zEFxY&B?g=IVlaF3XNm_03PA)=3|{n-UCgJoTr;|;1AU9|kPE_if8!Zvb}0q$5okF$ zHaJdmO&gg!9oN|M{!qGE=tb|3pVQ8PbL$}e;NgXz<6ZEggI}wO@aBP**2Wo=yN#ZC z4G$m^yaM9g=|&!^ft8jOLuzc3Psca*;7`;gnHm}tS0%f4{|VGEwu45KptfNmwxlE~ z^=r30gi@?cOm8kAz!EylA4G~7kbEiRlRIzwrb~{_2(x^$-?|#e6Bi_**(vyr_~9Of z!n>Gqf+Qwiu!xhi9f53=PM3`3tNF}pCOiPU|H4;pzjcsqbwg*{{kyrTxk<;mx~(;; z1NMrpaQ`57yn34>Jo3b|HROE(UNcQash!0p2-!Cz;{IRv#Vp5!3o$P8!%SgV~k&Hnqhp`5eLjTcy93cK!3Hm-$`@yGnaE=?;*2uSpiZTs_dDd51U%i z{|Zd9ou-;laGS_x=O}a+ zB||za<795A?_~Q=r=coQ+ZK@@ zId~hWQL<%)fI_WDIX#=(WNl!Dm$a&ROfLTd&B$vatq!M-2Jcs;N2vps$b6P1(N}=oI3<3luMTmC|0*{ zm1w8bt7vgX($!0@V0A}XIK)w!AzUn7vH=pZEp0RU0p?}ch2XC-7r#LK&vyc2=-#Q2 z^L%8)JbbcZ%g0Du;|8=q8B>X=mIQirpE=&Ox{TiuNDnOPd-FLI^KfEF729!!0x#Es z@>3ursjFSpu%C-8WL^Zw!7a0O-#cnf`HjI+AjVCFitK}GXO`ME&on|^=~Zc}^LBp9 zj=-vlN;Uc;IDjtK38l7}5xxQF&sRtfn4^TNtnzXv4M{r&ek*(eNbIu!u$>Ed%` z5x7+&)2P&4>0J`N&ZP8$vcR+@FS0126s6+Jx_{{`3ZrIMwaJo6jdrRwE$>IU_JTZ} z(||hyyQ)4Z1@wSlT94(-QKqkAatMmkT7pCycEB1U8KQbFX&?%|4$yyxCtm3=W`$4fiG0WU3yI@c zx{wfmkZAYE_5M%4{J-ygbpH|(|GD$2f$3o_Vti#&zfSGZMQ5_f3xt6~+{RX=$H8at z?GFG1Tmp}}lmm-R->ve*Iv+XJ@58p|1_jRvfEgz$XozU8#iJS})UM6VNI!3RUU!{5 zXB(+Eqd-E;cHQ>)`h0(HO_zLmzR3Tu-UGp;08YntWwMY-9i^w_u#wR?JxR2bky5j9 z3Sl-dQQU$xrO0xa&>vsiK`QN<$Yd%YXXM7*WOhnRdSFt5$aJux8QceC?lA0_if|s> ze{ad*opH_kb%M&~(~&UcX0nFGq^MqjxW?HJIP462v9XG>j(5Gat_)#SiNfahq2Mz2 zU`4uV8m$S~o9(W>mu*=h%Gs(Wz+%>h;R9Sg)jZ$q8vT1HxX3iQnh6&2rJ1u|j>^Qf`A76K%_ubL`Zu?h4`b=IyL>1!=*%!_K)=XC z6d}4R5L+sI50Q4P3upXQ3Z!~1ZXLlh!^UNcK6#QpYt-YC=^H=EPg3)z*wXo*024Q4b2sBCG4I# zlTFFY=kQ>xvR+LsuDUAk)q%5pEcqr(O_|^spjhtpb1#aC& zghXzGkGDC_XDa%t(X`E+kvKQ4zrQ*uuQoj>7@@ykWvF332)RO?%AA&Fsn&MNzmFa$ zWk&&^=NNjxLjrli_8ESU)}U|N{%j&TQmvY~lk!~Jh}*=^INA~&QB9em!in_X%Rl1&Kd~Z(u z9mra#<@vZQlOY+JYUwCrgoea4C8^(xv4ceCXcejq84TQ#sF~IU2V}LKc~Xlr_P=ry zl&Hh0exdCbVd^NPCqNNlxM3vA13EI8XvZ1H9#bT7y*U8Y{H8nwGpOR!e!!}*g;mJ#}T{ekSb}5zIPmye*If(}}_=PcuAW#yidAa^9-`<8Gr0 z)Fz=NiZ{)HAvw{Pl5uu)?)&i&Us$Cx4gE}cIJ}B4Xz~-q7)R_%owbP!z_V2=Aq%Rj z{V;7#kV1dNT9-6R+H}}(ED*_!F=~uz>&nR3gb^Ce%+0s#u|vWl<~JD3MvS0T9thdF zioIG3c#Sdsv;LdtRv3ml7%o$6LTVL>(H`^@TNg`2KPIk*8-IB}X!MT0`hN9Ddf7yN z?J=GxPL!uJ7lqwowsl?iRrh@#5C$%E&h~Z>XQcvFC*5%0RN-Opq|=IwX(dq(*sjs+ zqy99+v~m|6T#zR*e1AVxZ8djd5>eIeCi(b8sUk)OGjAsKSOg^-ugwl2WSL@d#?mdl zib0v*{u-?cq}dDGyZ%$XRY=UkQwt2oGu`zQneZh$=^! zj;!pCBWQNtvAcwcWIBM2y9!*W|8LmQy$H~5BEx)78J`4Z0(FJO2P^!YyQU{*Al+fs z){!4JvT1iLrJ8aU3k0t|P}{RN)_^v%$$r;+p0DY7N8CXzmS*HB*=?qaaF9D@#_$SN zSz{moAK<*RH->%r7xX~9gVW$l7?b|_SYI)gcjf0VAUJ%FcQP(TpBs; zg$25D!Ry_`8xpS_OJdeo$qh#7U+cepZ??TII7_%AXsT$B z=e)Bx#v%J0j``00Zk5hsvv6%T^*xGNx%KN-=pocSoqE5_R)OK%-Pbu^1MNzfds)mL zxz^F4lDKV9D&lEY;I+A)ui{TznB*CE$=9(wgE{m}`^<--OzV-5V4X2w9j(_!+jpTr zJvD*y6;39&T+==$F&tsRKM_lqa1HC}aGL0o`%c9mO=fts?36@8MGm7Vi{Y z^<7m$(EtdSr#22<(rm_(l_(`j!*Pu~Y>>xc>I9M#DJYDJNHO&4=HM%YLIp?;iR&$m z#_$ZWYLfGLt5FJZhr3jpYb`*%9S!zCG6ivNHYzNHcI%khtgHBliM^Ou}ZVD7ehU9 zS+W@AV=?Ro!=%AJ>Kcy9aU3%VX3|XM_K0A+ZaknKDyIS3S-Hw1C7&BSW5)sqj5Ye_ z4OSW7Yu-;bCyYKHFUk}<*<(@TH?YZPHr~~Iy%9@GR2Yd}J2!N9K&CN7Eq{Ka!jdu; zQNB*Y;i(7)OxZK%IHGt#Rt?z`I|A{q_BmoF!f^G}XVeTbe1Wnzh%1g>j}>DqFf;Rp zz7>xIs12@Ke0gr+4-!pmFP84vCIaTjqFNg{V`5}Rdt~xE^I;Bxp4)|cs8=f)1YwHz zqI`G~s2~qqDV+h02b`PQpUE#^^Aq8l%y2|ByQeXSADg5*qMprEAE3WFg0Q39`O+i1 z!J@iV!`Y~C$wJ!5Z+j5$i<1`+@)tBG$JL=!*uk=2k;T<@{|s1$YL079FvK%mPhyHV zP8^KGZnp`(hVMZ;s=n~3r2y;LTwcJwoBW-(ndU-$03{RD zh+Qn$ja_Z^OuMf3Ub|JTY74s&Am*(n{J3~@#OJNYuEVVJd9*H%)oFoRBkySGm`hx! zT3tG|+aAkXcx-2Apy)h^BkOyFTWQVeZ%e2@;*0DtlG9I3Et=PKaPt&K zw?WI7S;P)TWED7aSH$3hL@Qde?H#tzo^<(o_sv_2ci<7M?F$|oCFWc?7@KBj-;N$P zB;q!8@bW-WJY9do&y|6~mEruZAVe$!?{)N9rZZxD-|oltkhW9~nR8bLBGXw<632!l z*TYQn^NnUy%Ds}$f^=yQ+BM-a5X4^GHF=%PDrRfm_uqC zh{sKwIu|O0&jWb27;wzg4w5uA@TO_j(1X?8E>5Zfma|Ly7Bklq|s z9)H`zoAGY3n-+&JPrT!>u^qg9Evx4y@GI4$n-Uk_5wttU1_t?6><>}cZ-U+&+~JE) zPlDbO_j;MoxdLzMd~Ew|1o^a5q_1R*JZ=#XXMzg?6Zy!^hop}qoLQlJ{(%!KYt`MK z8umEN@Z4w!2=q_oe=;QttPCQy3Nm4F@x>@v4sz_jo{4m*0r%J(w1cSo;D_hQtJs7W z><$QrmG^+<$4{d2bgGo&3-FV}avg9zI|Rr(k{wTyl3!M1q+a zD9W{pCd%il*j&Ft z5H$nENf>>k$;SONGW`qo6`&qKs*T z2^RS)pXk9b@(_Fw1bkb)-oqK|v}r$L!W&aXA>IpcdNZ_vWE#XO8X`#Yp1+?RshVcd zknG%rPd*4ECEI0wD#@d+3NbHKxl}n^Sgkx==Iu%}HvNliOqVBqG?P2va zQ;kRJ$J6j;+wP9cS za#m;#GUT!qAV%+rdWolk+)6kkz4@Yh5LXP+LSvo9_T+MmiaP-eq6_k;)i6_@WSJ zlT@wK$zqHu<83U2V*yJ|XJU4farT#pAA&@qu)(PO^8PxEmPD4;Txpio+2)#!9 z>&=i7*#tc0`?!==vk>s7V+PL#S1;PwSY?NIXN2=Gu89x(cToFm))7L;< z+bhAbVD*bD=}iU`+PU+SBobTQ%S!=VL!>q$rfWsaaV}Smz>lO9JXT#`CcH_mRCSf4%YQAw`$^yY z3Y*^Nzk_g$xn7a_NO(2Eb*I=^;4f!Ra#Oo~LLjlcjke*k*o$~U#0ZXOQ5@HQ&T46l z7504MUgZkz2gNP1QFN8Y?nSEnEai^Rgyvl}xZfMUV6QrJcXp;jKGqB=D*tj{8(_pV zqyB*DK$2lgYGejmJUW)*s_Cv65sFf&pb(Yz8oWgDtQ0~k^0-wdF|tj}MOXaN@ydF8 zNr={U?=;&Z?wr^VC+`)S2xl}QFagy;$mG=TUs7Vi2wws5zEke4hTa2)>O0U?$WYsZ z<8bN2bB_N4AWd%+kncgknZ&}bM~eDtj#C5uRkp21hWW5gxWvc6b*4+dn<{c?w9Rmf zIVZKsPl{W2vQAlYO3yh}-{Os=YBnL8?uN5(RqfQ=-1cOiUnJu>KcLA*tQK3FU`_bM zM^T28w;nAj5EdAXFi&Kk1Nnl2)D!M{@+D-}bIEe+Lc4{s;YJc-{F#``iS2uk;2!Zp zF9#myUmO!wCeJIoi^A+T^e~20c+c2C}XltaR!|U-HfDA=^xF97ev}$l6#oY z&-&T{egB)&aV$3_aVA51XGiU07$s9vubh_kQG?F$FycvS6|IO!6q zq^>9|3U^*!X_C~SxX&pqUkUjz%!j=VlXDo$!2VLH!rKj@61mDpSr~7B2yy{>X~_nc zRI+7g2V&k zd**H++P9dg!-AOs3;GM`(g<+GRV$+&DdMVpUxY9I1@uK28$az=6oaa+PutlO9?6#? zf-OsgT>^@8KK>ggkUQRPPgC7zjKFR5spqQb3ojCHzj^(UH~v+!y*`Smv)VpVoPwa6 zWG18WJaPKMi*F6Zdk*kU^`i~NNTfn3BkJniC`yN98L-Awd)Z&mY? zprBW$!qL-OL7h@O#kvYnLsfff@kDIegt~?{-*5A7JrA;#TmTe?jICJqhub-G@e??D zqiV#g{)M!kW1-4SDel7TO{;@*h2=_76g3NUD@|c*WO#>MfYq6_YVUP+&8e4|%4T`w zXzhmVNziAHazWO2qXcaOu@R1MrPP{t)`N)}-1&~mq=ZH=w=;-E$IOk=y$dOls{6sRR`I5>|X zpq~XYW4sd;J^6OwOf**J>a7u$S>WTFPRkjY;BfVgQst)u4aMLR1|6%)CB^18XCz+r ztkYQ}G43j~Q&1em(_EkMv0|WEiKu;z2zhb(L%$F&xWwzOmk;VLBYAZ8lOCziNoPw1 zv2BOyXA`A8z^WH!nXhKXM`t0;6D*-uGds3TYGrm8SPnJJOQ^fJU#}@aIy@MYWz**H zvkp?7I5PE{$$|~{-ZaFxr6ZolP^nL##mHOErB^AqJqn^hFA=)HWj!m3WDaHW$C)i^ z9@6G$SzB=>jbe>4kqr#sF7#K}W*Cg-5y6kun3u&0L7BpXF9=#7IN8FOjWrWwUBZiU zT_se3ih-GBKx+Uw0N|CwP3D@-C=5(9T#BH@M`F2!Goiqx+Js5xC92|Sy0%WWWp={$(am!#l~f^W_oz78HX<0X#7 zp)p1u~M*o9W@O8P{0Qkg@Wa# z2{Heb&oX^CQSZWSFBXKOfE|tsAm#^U-WkDnU;IowZ`Ok4!mwHwH=s|AqZ^YD4!5!@ zPxJj+Bd-q6w_YG`z_+r;S86zwXb+EO&qogOq8h-Ect5(M2+>(O7n7)^dP*ws_3U6v zVsh)sk^@*c>)3EML|0<-YROho{lz@Nd4;R9gL{9|64xVL`n!m$-Jjrx?-Bacp!=^5 z1^T^eB{_)Y<9)y{-4Rz@9_>;_7h;5D+@QcbF4Wv7hu)s0&==&6u)33 zHRj+&Woq-vDvjwJCYES@$C4{$?f$Ibi4G()UeN11rgjF+^;YE^5nYprYoJNoudNj= zm1pXSeG64dcWHObUetodRn1Fw|1nI$D9z}dVEYT0lQnsf_E1x2vBLql7NrHH!n&Sq z6lc*mvU=WS6=v9Lrl}&zRiu_6u;6g%_DU{9b+R z#YHqX7`m9eydf?KlKu6Sb%j$%_jmydig`B*TN`cZL-g!R)iE?+Q5oOqBFKhx z%MW>BC^(F_JuG(ayE(MT{S3eI{cKiwOtPwLc0XO*{*|(JOx;uQOfq@lp_^cZo=FZj z4#}@e@dJ>Bn%2`2_WPeSN7si^{U#H=7N4o%Dq3NdGybrZgEU$oSm$hC)uNDC_M9xc zGzwh5Sg?mpBIE8lT2XsqTt3j3?We8}3bzLBTQd639vyg^$0#1epq8snlDJP2(BF)K zSx30RM+{f+b$g{9usIL8H!hCO117Xgv}ttPJm9wVRjPk;ePH@zxv%j9k5`TzdXLeT zFgFX`V7cYIcBls5WN0Pf6SMBN+;CrQ(|EsFd*xtwr#$R{Z9FP`OWtyNsq#mCgZ7+P z^Yn$haBJ)r96{ZJd8vlMl?IBxrgh=fdq_NF!1{jARCVz>jNdC)H^wfy?R94#MPdUjcYX>#wEx+LB#P-#4S-%YH>t-j+w zOFTI8gX$ard6fAh&g=u&56%3^-6E2tpk*wx3HSCQ+t7+*iOs zPk5ysqE}i*cQocFvA68xHfL|iX(C4h*67@3|5Qwle(8wT&!&{8*{f%0(5gH+m>$tq zp;AqrP7?XTEooYG1Dzfxc>W%*CyL16q|fQ0_jp%%Bk^k!i#Nbi(N9&T>#M{gez_Ws zYK=l}adalV(nH}I_!hNeb;tQFk3BHX7N}}R8%pek^E`X}%ou=cx8InPU1EE0|Hen- zyw8MoJqB5=)Z%JXlrdTXAE)eqLAdVE-=>wGHrkRet}>3Yu^lt$Kzu%$3#(ioY}@Gu zjk3BZuQH&~7H+C*uX^4}F*|P89JX;Hg2U!pt>rDi(n(Qe-c}tzb0#6_ItoR0->LSt zR~UT<-|@TO%O`M+_e_J4wx7^)5_%%u+J=yF_S#2Xd?C;Ss3N7KY^#-vx+|;bJX&8r zD?|MetfhdC;^2WG`7MCgs>TKKN=^=!x&Q~BzmQio_^l~LboTNT=I zC5pme^P@ER``p$2md9>4!K#vV-Fc1an7pl>_|&>aqP}+zqR?+~Z;f2^`a+-!Te%V? z;H2SbF>jP^GE(R1@%C==XQ@J=G9lKX+Z<@5}PO(EYkJh=GCv#)Nj{DkWJM2}F&oAZ6xu8&g7pn1ps2U5srwQ7CAK zN&*~@t{`31lUf`O;2w^)M3B@o)_mbRu{-`PrfNpF!R^q>yTR&ETS7^-b2*{-tZAZz zw@q5x9B5V8Qd7dZ!Ai$9hk%Q!wqbE1F1c96&zwBBaRW}(^axoPpN^4Aw}&a5dMe+*Gomky_l^54*rzXro$ z>LL)U5Ry>~FJi=*{JDc)_**c)-&faPz`6v`YU3HQa}pLtb5K)u%K+BOqXP0)rj5Au$zB zW1?vr?mDv7Fsxtsr+S6ucp2l#(4dnr9sD*v+@*>g#M4b|U?~s93>Pg{{a5|rm2xfI z`>E}?9S@|IoUX{Q1zjm5YJT|3S>&09D}|2~BiMo=z4YEjXlWh)V&qs;*C{`UMxp$9 zX)QB?G$fPD6z5_pNs>Jeh{^&U^)Wbr?2D6-q?)`*1k@!UvwQgl8eG$r+)NnFoT)L6 zg7lEh+E6J17krfYJCSjWzm67hEth24pomhz71|Qodn#oAILN)*Vwu2qpJirG)4Wnv}9GWOFrQg%Je+gNrPl8mw7ykE8{ z=|B4+uwC&bpp%eFcRU6{mxRV32VeH8XxX>v$du<$(DfinaaWxP<+Y97Z#n#U~V zVEu-GoPD=9$}P;xv+S~Ob#mmi$JQmE;Iz4(){y*9pFyW-jjgdk#oG$fl4o9E8bo|L zWjo4l%n51@Kz-n%zeSCD`uB?T%FVk+KBI}=ve zvlcS#wt`U6wrJo}6I6Rwb=1GzZfwE=I&Ne@p7*pH84XShXYJRgvK)UjQL%R9Zbm(m zxzTQsLTON$WO7vM)*vl%Pc0JH7WhP;$z@j=y#avW4X8iqy6mEYr@-}PW?H)xfP6fQ z&tI$F{NNct4rRMSHhaelo<5kTYq+(?pY)Ieh8*sa83EQfMrFupMM@nfEV@EmdHUv9 z35uzIrIuo4#WnF^_jcpC@uNNaYTQ~uZWOE6P@LFT^1@$o&q+9Qr8YR+ObBkpP9=F+$s5+B!mX2~T zAuQ6RenX?O{IlLMl1%)OK{S7oL}X%;!XUxU~xJN8xk z`xywS*naF(J#?vOpB(K=o~lE;m$zhgPWDB@=p#dQIW>xe_p1OLoWInJRKbEuoncf; zmS1!u-ycc1qWnDg5Nk2D)BY%jmOwCLC+Ny>`f&UxFowIsHnOXfR^S;&F(KXd{ODlm z$6#1ccqt-HIH9)|@fHnrKudu!6B$_R{fbCIkSIb#aUN|3RM>zuO>dpMbROZ`^hvS@ z$FU-;e4W}!ubzKrU@R*dW*($tFZ>}dd*4_mv)#O>X{U@zSzQt*83l9mI zI$8O<5AIDx`wo0}f2fsPC_l>ONx_`E7kdXu{YIZbp1$(^oBAH({T~&oQ&1{X951QW zmhHUxd)t%GQ9#ak5fTjk-cahWC;>^Rg7(`TVlvy0W@Y!Jc%QL3Ozu# zDPIqBCy&T2PWBj+d-JA-pxZlM=9ja2ce|3B(^VCF+a*MMp`(rH>Rt6W1$;r{n1(VK zLs>UtkT43LR2G$AOYHVailiqk7naz2yZGLo*xQs!T9VN5Q>eE(w zw$4&)&6xIV$IO^>1N-jrEUg>O8G4^@y+-hQv6@OmF@gy^nL_n1P1-Rtyy$Bl;|VcV zF=p*&41-qI5gG9UhKmmnjs932!6hceXa#-qfK;3d*a{)BrwNFeKU|ge?N!;zk+kB! zMD_uHJR#%b54c2tr~uGPLTRLg$`fupo}cRJeTwK;~}A>(Acy4k-Xk&Aa1&eWYS1ULWUj@fhBiWY$pdfy+F z@G{OG{*v*mYtH3OdUjwEr6%_ZPZ3P{@rfbNPQG!BZ7lRyC^xlMpWH`@YRar`tr}d> z#wz87t?#2FsH-jM6m{U=gp6WPrZ%*w0bFm(T#7m#v^;f%Z!kCeB5oiF`W33W5Srdt zdU?YeOdPG@98H7NpI{(uN{FJdu14r(URPH^F6tOpXuhU7T9a{3G3_#Ldfx_nT(Hec zo<1dyhsVsTw;ZkVcJ_0-h-T3G1W@q)_Q30LNv)W?FbMH+XJ* zy=$@39Op|kZv`Rt>X`zg&at(?PO^I=X8d9&myFEx#S`dYTg1W+iE?vt#b47QwoHI9 zNP+|3WjtXo{u}VG(lLUaW0&@yD|O?4TS4dfJI`HC-^q;M(b3r2;7|FONXphw-%7~* z&;2!X17|05+kZOpQ3~3!Nb>O94b&ZSs%p)TK)n3m=4eiblVtSx@KNFgBY_xV6ts;NF;GcGxMP8OKV^h6LmSb2E#Qnw ze!6Mnz7>lE9u{AgQ~8u2zM8CYD5US8dMDX-5iMlgpE9m*s+Lh~A#P1er*rF}GHV3h z=`STo?kIXw8I<`W0^*@mB1$}pj60R{aJ7>C2m=oghKyxMbFNq#EVLgP0cH3q7H z%0?L93-z6|+jiN|@v>ix?tRBU(v-4RV`}cQH*fp|)vd3)8i9hJ3hkuh^8dz{F5-~_ zUUr1T3cP%cCaTooM8dj|4*M=e6flH0&8ve32Q)0dyisl))XkZ7Wg~N}6y`+Qi2l+e zUd#F!nJp{#KIjbQdI`%oZ`?h=5G^kZ_uN`<(`3;a!~EMsWV|j-o>c?x#;zR2ktiB! z);5rrHl?GPtr6-o!tYd|uK;Vbsp4P{v_4??=^a>>U4_aUXPWQ$FPLE4PK$T^3Gkf$ zHo&9$U&G`d(Os6xt1r?sg14n)G8HNyWa^q8#nf0lbr4A-Fi;q6t-`pAx1T*$eKM*$ z|CX|gDrk#&1}>5H+`EjV$9Bm)Njw&7-ZR{1!CJTaXuP!$Pcg69`{w5BRHysB$(tWUes@@6aM69kb|Lx$%BRY^-o6bjH#0!7b;5~{6J+jKxU!Kmi# zndh@+?}WKSRY2gZ?Q`{(Uj|kb1%VWmRryOH0T)f3cKtG4oIF=F7RaRnH0Rc_&372={_3lRNsr95%ZO{IX{p@YJ^EI%+gvvKes5cY+PE@unghjdY5#9A!G z70u6}?zmd?v+{`vCu-53_v5@z)X{oPC@P)iA3jK$`r zSA2a7&!^zmUiZ82R2=1cumBQwOJUPz5Ay`RLfY(EiwKkrx%@YN^^XuET;tE zmr-6~I7j!R!KrHu5CWGSChO6deaLWa*9LLJbcAJsFd%Dy>a!>J`N)Z&oiU4OEP-!Ti^_!p}O?7`}i7Lsf$-gBkuY*`Zb z7=!nTT;5z$_5$=J=Ko+Cp|Q0J=%oFr>hBgnL3!tvFoLNhf#D0O=X^h+x08iB;@8pXdRHxX}6R4k@i6%vmsQwu^5z zk1ip`#^N)^#Lg#HOW3sPI33xqFB4#bOPVnY%d6prwxf;Y-w9{ky4{O6&94Ra8VN@K zb-lY;&`HtxW@sF!doT5T$2&lIvJpbKGMuDAFM#!QPXW87>}=Q4J3JeXlwHys?!1^#37q_k?N@+u&Ns20pEoBeZC*np;i;M{2C0Z4_br2gsh6eL z#8`#sn41+$iD?^GL%5?cbRcaa-Nx0vE(D=*WY%rXy3B%gNz0l?#noGJGP728RMY#q z=2&aJf@DcR?QbMmN)ItUe+VM_U!ryqA@1VVt$^*xYt~-qvW!J4Tp<-3>jT=7Zow5M z8mSKp0v4b%a8bxFr>3MwZHSWD73D@+$5?nZAqGM#>H@`)mIeC#->B)P8T$zh-Pxnc z8)~Zx?TWF4(YfKuF3WN_ckpCe5;x4V4AA3(i$pm|78{%!q?|~*eH0f=?j6i)n~Hso zmTo>vqEtB)`%hP55INf7HM@taH)v`Fw40Ayc*R!T?O{ziUpYmP)AH`euTK!zg9*6Z z!>M=$3pd0!&TzU=hc_@@^Yd3eUQpX4-33}b{?~5t5lgW=ldJ@dUAH%`l5US1y_`40 zs(X`Qk}vvMDYYq+@Rm+~IyCX;iD~pMgq^KY)T*aBz@DYEB={PxA>)mI6tM*sx-DmGQHEaHwRrAmNjO!ZLHO4b;;5mf@zzlPhkP($JeZGE7 z?^XN}Gf_feGoG~BjUgVa*)O`>lX=$BSR2)uD<9 z>o^|nb1^oVDhQbfW>>!;8-7<}nL6L^V*4pB=>wwW+RXAeRvKED(n1;R`A6v$6gy0I(;Vf?!4;&sgn7F%LpM}6PQ?0%2Z@b{It<(G1CZ|>913E0nR2r^Pa*Bp z@tFGi*CQ~@Yc-?{cwu1 zsilf=k^+Qs>&WZG(3WDixisHpR>`+ihiRwkL(3T|=xsoNP*@XX3BU8hr57l3k;pni zI``=3Nl4xh4oDj<%>Q1zYXHr%Xg_xrK3Nq?vKX3|^Hb(Bj+lONTz>4yhU-UdXt2>j z<>S4NB&!iE+ao{0Tx^N*^|EZU;0kJkx@zh}S^P{ieQjGl468CbC`SWnwLRYYiStXm zOxt~Rb3D{dz=nHMcY)#r^kF8|q8KZHVb9FCX2m^X*(|L9FZg!5a7((!J8%MjT$#Fs)M1Pb zq6hBGp%O1A+&%2>l0mpaIzbo&jc^!oN^3zxap3V2dNj3x<=TwZ&0eKX5PIso9j1;e zwUg+C&}FJ`k(M|%%}p=6RPUq4sT3-Y;k-<68ciZ~_j|bt>&9ZLHNVrp#+pk}XvM{8 z`?k}o-!if>hVlCP9j%&WI2V`5SW)BCeR5>MQhF)po=p~AYN%cNa_BbV6EEh_kk^@a zD>4&>uCGCUmyA-c)%DIcF4R6!>?6T~Mj_m{Hpq`*(wj>foHL;;%;?(((YOxGt)Bhx zuS+K{{CUsaC++%}S6~CJ=|vr(iIs-je)e9uJEU8ZJAz)w166q)R^2XI?@E2vUQ!R% zn@dxS!JcOimXkWJBz8Y?2JKQr>`~SmE2F2SL38$SyR1^yqj8_mkBp)o$@+3BQ~Mid z9U$XVqxX3P=XCKj0*W>}L0~Em`(vG<>srF8+*kPrw z20{z(=^w+ybdGe~Oo_i|hYJ@kZl*(9sHw#Chi&OIc?w`nBODp?ia$uF%Hs(X>xm?j zqZQ`Ybf@g#wli`!-al~3GWiE$K+LCe=Ndi!#CVjzUZ z!sD2O*;d28zkl))m)YN7HDi^z5IuNo3^w(zy8 zszJG#mp#Cj)Q@E@r-=NP2FVxxEAeOI2e=|KshybNB6HgE^(r>HD{*}S}mO>LuRGJT{*tfTzw_#+er-0${}%YPe@CMJ1Ng#j#)i)SnY@ss3gL;g zg2D~#Kpdfu#G;q1qz_TwSz1VJT(b3zby$Vk&;Y#1(A)|xj`_?i5YQ;TR%jice5E;0 zYHg;`zS5{S*9xI6o^j>rE8Ua*XhIw{_-*&@(R|C(am8__>+Ws&Q^ymy*X4~hR2b5r zm^p3sw}yv=tdyncy_Ui7{BQS732et~Z_@{-IhHDXAV`(Wlay<#hb>%H%WDi+K$862nA@BDtM#UCKMu+kM`!JHyWSi?&)A7_ z3{cyNG%a~nnH_!+;g&JxEMAmh-Z}rC!o7>OVzW&PoMyTA_g{hqXG)SLraA^OP**<7 zjWbr7z!o2n3hnx7A=2O=WL;`@9N{vQIM@&|G-ljrPvIuJHYtss0Er0fT5cMXNUf1B z7FAwBDixt0X7C3S)mPe5g`YtME23wAnbU)+AtV}z+e8G;0BP=bI;?(#|Ep!vVfDbK zvx+|CKF>yt0hWQ3drchU#XBU+HiuG*V^snFAPUp-5<#R&BUAzoB!aZ+e*KIxa26V}s6?nBK(U-7REa573wg-jqCg>H8~>O{ z*C0JL-?X-k_y%hpUFL?I>0WV{oV`Nb)nZbJG01R~AG>flIJf)3O*oB2i8~;!P?Wo_ z0|QEB*fifiL6E6%>tlAYHm2cjTFE@*<);#>689Z6S#BySQ@VTMhf9vYQyLeDg1*F} zjq>i1*x>5|CGKN{l9br3kB0EHY|k4{%^t7-uhjd#NVipUZa=EUuE5kS1_~qYX?>hJ z$}!jc9$O$>J&wnu0SgfYods^z?J4X;X7c77Me0kS-dO_VUQ39T(Kv(Y#s}Qqz-0AH z^?WRL(4RzpkD+T5FG_0NyPq-a-B7A5LHOCqwObRJi&oRi(<;OuIN7SV5PeHU$<@Zh zPozEV`dYmu0Z&Tqd>t>8JVde9#Pt+l95iHe$4Xwfy1AhI zDM4XJ;bBTTvRFtW>E+GzkN)9k!hA5z;xUOL2 zq4}zn-DP{qc^i|Y%rvi|^5k-*8;JZ~9a;>-+q_EOX+p1Wz;>i7c}M6Nv`^NY&{J-> z`(mzDJDM}QPu5i44**2Qbo(XzZ-ZDu%6vm8w@DUarqXj41VqP~ zs&4Y8F^Waik3y1fQo`bVUH;b=!^QrWb)3Gl=QVKr+6sxc=ygauUG|cm?|X=;Q)kQ8 zM(xrICifa2p``I7>g2R~?a{hmw@{!NS5`VhH8+;cV(F>B94M*S;5#O`YzZH1Z%yD? zZ61w(M`#aS-*~Fj;x|J!KM|^o;MI#Xkh0ULJcA?o4u~f%Z^16ViA27FxU5GM*rKq( z7cS~MrZ=f>_OWx8j#-Q3%!aEU2hVuTu(7`TQk-Bi6*!<}0WQi;_FpO;fhpL4`DcWp zGOw9vx0N~6#}lz(r+dxIGZM3ah-8qrqMmeRh%{z@dbUD2w15*_4P?I~UZr^anP}DB zU9CCrNiy9I3~d#&!$DX9e?A});BjBtQ7oGAyoI$8YQrkLBIH@2;lt4E^)|d6Jwj}z z&2_E}Y;H#6I4<10d_&P0{4|EUacwFHauvrjAnAm6yeR#}f}Rk27CN)vhgRqEyPMMS7zvunj2?`f;%?alsJ+-K+IzjJx>h8 zu~m_y$!J5RWAh|C<6+uiCNsOKu)E72M3xKK(a9Okw3e_*O&}7llNV!=P87VM2DkAk zci!YXS2&=P0}Hx|wwSc9JP%m8dMJA*q&VFB0yMI@5vWoAGraygwn){R+Cj6B1a2Px z5)u(K5{+;z2n*_XD!+Auv#LJEM)(~Hx{$Yb^ldQmcYF2zNH1V30*)CN_|1$v2|`LnFUT$%-tO0Eg|c5$BB~yDfzS zcOXJ$wpzVK0MfTjBJ0b$r#_OvAJ3WRt+YOLlJPYMx~qp>^$$$h#bc|`g0pF-Ao43? z>*A+8lx>}L{p(Tni2Vvk)dtzg$hUKjSjXRagj)$h#8=KV>5s)J4vGtRn5kP|AXIz! zPgbbVxW{2o4s-UM;c#We8P&mPN|DW7_uLF!a|^0S=wr6Esx9Z$2|c1?GaupU6$tb| zY_KU`(_29O_%k(;>^|6*pZURH3`@%EuKS;Ns z1lujmf;r{qAN&Q0&m{wJSZ8MeE7RM5+Sq;ul_ z`+ADrd_Um+G37js6tKsArNB}n{p*zTUxQr>3@wA;{EUbjNjlNd6$Mx zg0|MyU)v`sa~tEY5$en7^PkC=S<2@!nEdG6L=h(vT__0F=S8Y&eM=hal#7eM(o^Lu z2?^;05&|CNliYrq6gUv;|i!(W{0N)LWd*@{2q*u)}u*> z7MQgk6t9OqqXMln?zoMAJcc zMKaof_Up})q#DzdF?w^%tTI7STI^@8=Wk#enR*)&%8yje>+tKvUYbW8UAPg55xb70 zEn5&Ba~NmOJlgI#iS8W3-@N%>V!#z-ZRwfPO1)dQdQkaHsiqG|~we2ALqG7Ruup(DqSOft2RFg_X%3w?6VqvV1uzX_@F(diNVp z4{I|}35=11u$;?|JFBEE*gb;T`dy+8gWJ9~pNsecrO`t#V9jW-6mnfO@ff9od}b(3s4>p0i30gbGIv~1@a^F2kl7YO;DxmF3? zWi-RoXhzRJV0&XE@ACc?+@6?)LQ2XNm4KfalMtsc%4!Fn0rl zpHTrHwR>t>7W?t!Yc{*-^xN%9P0cs0kr=`?bQ5T*oOo&VRRu+1chM!qj%2I!@+1XF z4GWJ=7ix9;Wa@xoZ0RP`NCWw0*8247Y4jIZ>GEW7zuoCFXl6xIvz$ezsWgKdVMBH> z{o!A7f;R-@eK9Vj7R40xx)T<2$?F2E<>Jy3F;;=Yt}WE59J!1WN367 zA^6pu_zLoZIf*x031CcwotS{L8bJE(<_F%j_KJ2P_IusaZXwN$&^t716W{M6X2r_~ zaiMwdISX7Y&Qi&Uh0upS3TyEIXNDICQlT5fHXC`aji-c{U(J@qh-mWl-uMN|T&435 z5)a1dvB|oe%b2mefc=Vpm0C%IUYYh7HI*;3UdgNIz}R##(#{(_>82|zB0L*1i4B5j-xi9O4x10rs_J6*gdRBX=@VJ+==sWb&_Qc6tSOowM{BX@(zawtjl zdU!F4OYw2@Tk1L^%~JCwb|e#3CC>srRHQ*(N%!7$Mu_sKh@|*XtR>)BmWw!;8-mq7 zBBnbjwx8Kyv|hd*`5}84flTHR1Y@@uqjG`UG+jN_YK&RYTt7DVwfEDXDW4U+iO{>K zw1hr{_XE*S*K9TzzUlJH2rh^hUm2v7_XjwTuYap|>zeEDY$HOq3X4Tz^X}E9z)x4F zs+T?Ed+Hj<#jY-`Va~fT2C$=qFT-5q$@p9~0{G&eeL~tiIAHXA!f6C(rAlS^)&k<- zXU|ZVs}XQ>s5iONo~t!XXZgtaP$Iau;JT%h)>}v54yut~pykaNye4axEK#5@?TSsQ zE;Jvf9I$GVb|S`7$pG)4vgo9NXsKr?u=F!GnA%VS2z$@Z(!MR9?EPcAqi5ft)Iz6sNl`%kj+_H-X`R<>BFrBW=fSlD|{`D%@Rcbu2?%>t7i34k?Ujb)2@J-`j#4 zLK<69qcUuniIan-$A1+fR=?@+thwDIXtF1Tks@Br-xY zfB+zblrR(ke`U;6U~-;p1Kg8Lh6v~LjW@9l2P6s+?$2!ZRPX`(ZkRGe7~q(4&gEi<$ch`5kQ?*1=GSqkeV z{SA1EaW_A!t{@^UY2D^YO0(H@+kFVzZaAh0_`A`f(}G~EP~?B|%gtxu&g%^x{EYSz zk+T;_c@d;+n@$<>V%P=nk36?L!}?*=vK4>nJSm+1%a}9UlmTJTrfX4{Lb7smNQn@T zw9p2%(Zjl^bWGo1;DuMHN(djsEm)P8mEC2sL@KyPjwD@d%QnZ$ zMJ3cnn!_!iP{MzWk%PI&D?m?C(y2d|2VChluN^yHya(b`h>~GkI1y;}O_E57zOs!{ zt2C@M$^PR2U#(dZmA-sNreB@z-yb0Bf7j*yONhZG=onhx>t4)RB`r6&TP$n zgmN*)eCqvgriBO-abHQ8ECN0bw?z5Bxpx z=jF@?zFdVn?@gD5egM4o$m`}lV(CWrOKKq(sv*`mNcHcvw&Xryfw<{ch{O&qc#WCTXX6=#{MV@q#iHYba!OUY+MGeNTjP%Fj!WgM&`&RlI^=AWTOqy-o zHo9YFt!gQ*p7{Fl86>#-JLZo(b^O`LdFK~OsZBRR@6P?ad^Ujbqm_j^XycM4ZHFyg ziUbIFW#2tj`65~#2V!4z7DM8Z;fG0|APaQ{a2VNYpNotB7eZ5kp+tPDz&Lqs0j%Y4tA*URpcfi z_M(FD=fRGdqf430j}1z`O0I=;tLu81bwJXdYiN7_&a-?ly|-j*+=--XGvCq#32Gh(=|qj5F?kmihk{%M&$}udW5)DHK zF_>}5R8&&API}o0osZJRL3n~>76nUZ&L&iy^s>PMnNcYZ|9*1$v-bzbT3rpWsJ+y{ zPrg>5Zlery96Um?lc6L|)}&{992{_$J&=4%nRp9BAC6!IB=A&=tF>r8S*O-=!G(_( zwXbX_rGZgeiK*&n5E;f=k{ktyA1(;x_kiMEt0*gpp_4&(twlS2e5C?NoD{n>X2AT# zY@Zp?#!b1zNq96MQqeO*M1MMBin5v#RH52&Xd~DO6-BZLnA6xO1$sou(YJ1Dlc{WF zVa%2DyYm`V#81jP@70IJ;DX@y*iUt$MLm)ByAD$eUuji|5{ptFYq(q)mE(5bOpxjM z^Q`AHWq44SG3`_LxC9fwR)XRVIp=B%<(-lOC3jI#bb@dK(*vjom!=t|#<@dZql%>O z15y^{4tQoeW9Lu%G&V$90x6F)xN6y_oIn;!Q zs)8jT$;&;u%Y>=T3hg34A-+Y*na=|glcStr5D;&5*t5*DmD~x;zQAV5{}Ya`?RRGa zT*t9@$a~!co;pD^!J5bo?lDOWFx%)Y=-fJ+PDGc0>;=q=s?P4aHForSB+)v0WY2JH z?*`O;RHum6j%#LG)Vu#ciO#+jRC3!>T(9fr+XE7T2B7Z|0nR5jw@WG)kDDzTJ=o4~ zUpeyt7}_nd`t}j9BKqryOha{34erm)RmST)_9Aw)@ zHbiyg5n&E{_CQR@h<}34d7WM{s{%5wdty1l+KX8*?+-YkNK2Be*6&jc>@{Fd;Ps|| z26LqdI3#9le?;}risDq$K5G3yoqK}C^@-8z^wj%tdgw-6@F#Ju{Sg7+y)L?)U$ez> zoOaP$UFZ?y5BiFycir*pnaAaY+|%1%8&|(@VB)zweR%?IidwJyK5J!STzw&2RFx zZV@qeaCB01Hu#U9|1#=Msc8Pgz5P*4Lrp!Q+~(G!OiNR{qa7|r^H?FC6gVhkk3y7=uW#Sh;&>78bZ}aK*C#NH$9rX@M3f{nckYI+5QG?Aj1DM)@~z_ zw!UAD@gedTlePB*%4+55naJ8ak_;))#S;4ji!LOqY5VRI){GMwHR~}6t4g>5C_#U# ztYC!tjKjrKvRy=GAsJVK++~$|+s!w9z3H4G^mACv=EErXNSmH7qN}%PKcN|8%9=i)qS5+$L zu&ya~HW%RMVJi4T^pv?>mw*Gf<)-7gf#Qj|e#w2|v4#t!%Jk{&xlf;$_?jW*n!Pyx zkG$<18kiLOAUPuFfyu-EfWX%4jYnjBYc~~*9JEz6oa)_R|8wjZA|RNrAp%}14L7fW zi7A5Wym*K+V8pkqqO-X#3ft{0qs?KVt^)?kS>AicmeO&q+~J~ zp0YJ_P~_a8j= zsAs~G=8F=M{4GZL{|B__UorX@MRNQLn?*_gym4aW(~+i13knnk1P=khoC-ViMZk+x zLW(l}oAg1H`dU+Fv**;qw|ANDSRs>cGqL!Yw^`; zv;{E&8CNJcc)GHzTYM}f&NPw<6j{C3gaeelU#y!M)w-utYEHOCCJo|Vgp7K6C_$14 zqIrLUB0bsgz^D%V%fbo2f9#yb#CntTX?55Xy|Kps&Xek*4_r=KDZ z+`TQuv|$l}MWLzA5Ay6Cvsa^7xvwXpy?`w(6vx4XJ zWuf1bVSb#U8{xlY4+wlZ$9jjPk)X_;NFMqdgq>m&W=!KtP+6NL57`AMljW+es zzqjUjgz;V*kktJI?!NOg^s_)ph45>4UDA!Vo0hn>KZ+h-3=?Y3*R=#!fOX zP$Y~+14$f66ix?UWB_6r#fMcC^~X4R-<&OD1CSDNuX~y^YwJ>sW0j`T<2+3F9>cLo z#!j57$ll2K9(%$4>eA7(>FJX5e)pR5&EZK!IMQzOfik#FU*o*LGz~7u(8}XzIQRy- z!U7AlMTIe|DgQFmc%cHy_9^{o`eD%ja_L>ckU6$O4*U**o5uR7`FzqkU8k4gxtI=o z^P^oGFPm5jwZMI{;nH}$?p@uV8FT4r=|#GziKXK07bHJLtK}X%I0TON$uj(iJ`SY^ zc$b2CoxCQ>7LH@nxcdW&_C#fMYBtTxcg46dL{vf%EFCZ~eErMvZq&Z%Lhumnkn^4A zsx$ay(FnN7kYah}tZ@0?-0Niroa~13`?hVi6`ndno`G+E8;$<6^gsE-K3)TxyoJ4M zb6pj5=I8^FD5H@`^V#Qb2^0cx7wUz&cruA5g>6>qR5)O^t1(-qqP&1g=qvY#s&{bx zq8Hc%LsbK1*%n|Y=FfojpE;w~)G0-X4i*K3{o|J7`krhIOd*c*$y{WIKz2n2*EXEH zT{oml3Th5k*vkswuFXdGDlcLj15Nec5pFfZ*0?XHaF_lVuiB%Pv&p7z)%38}%$Gup zVTa~C8=cw%6BKn_|4E?bPNW4PT7}jZQLhDJhvf4z;~L)506IE0 zX!tWXX(QOQPRj-p80QG79t8T2^az4Zp2hOHziQlvT!|H)jv{Ixodabzv6lBj)6WRB z{)Kg@$~~(7$-az?lw$4@L%I&DI0Lo)PEJJziWP33a3azb?jyXt1v0N>2kxwA6b%l> zZqRpAo)Npi&loWbjFWtEV)783BbeIAhqyuc+~>i7aQ8shIXt)bjCWT6$~ro^>99G} z2XfmT0(|l!)XJb^E!#3z4oEGIsL(xd; zYX1`1I(cG|u#4R4T&C|m*9KB1`UzKvho5R@1eYtUL9B72{i(ir&ls8g!pD ztR|25xGaF!4z5M+U@@lQf(12?xGy`!|3E}7pI$k`jOIFjiDr{tqf0va&3pOn6Pu)% z@xtG2zjYuJXrV)DUrIF*y<1O1<$#54kZ#2;=X51J^F#0nZ0(;S$OZDt_U2bx{RZ=Q zMMdd$fH|!s{ zXq#l;{`xfV`gp&C>A`WrQU?d{!Ey5(1u*VLJt>i27aZ-^&2IIk=zP5p+{$q(K?2(b z8?9h)kvj9SF!Dr zoyF}?V|9;6abHxWk2cEvGs$-}Pg}D+ZzgkaN&$Snp%;5m%zh1E#?Wac-}x?BYlGN#U#Mek*}kek#I9XaHt?mz3*fDrRTQ#&#~xyeqJk1QJ~E$7qsw6 z?sV;|?*=-{M<1+hXoj?@-$y+(^BJ1H~wQ9G8C0#^aEAyhDduNX@haoa=PuPp zYsGv8UBfQaRHgBgLjmP^eh>fLMeh{8ic)?xz?#3kX-D#Z{;W#cd_`9OMFIaJg-=t`_3*!YDgtNQ2+QUEAJB9M{~AvT$H`E)IKmCR21H532+ata8_i_MR@ z2Xj<3w<`isF~Ah$W{|9;51ub*f4#9ziKrOR&jM{x7I_7()O@`F*5o$KtZ?fxU~g`t zUovNEVKYn$U~VX8eR)qb`7;D8pn*Pp$(otYTqL)5KH$lUS-jf}PGBjy$weoceAcPp z&5ZYB$r&P$MN{0H0AxCe4Qmd3T%M*5d4i%#!nmBCN-WU-4m4Tjxn-%j3HagwTxCZ9 z)j5vO-C7%s%D!&UfO>bi2oXiCw<-w{vVTK^rVbv#W=WjdADJy8$khnU!`ZWCIU`># zyjc^1W~pcu>@lDZ{zr6gv%)2X4n27~Ve+cQqcND%0?IFSP4sH#yIaXXYAq^z3|cg` z`I3$m%jra>e2W-=DiD@84T!cb%||k)nPmEE09NC%@PS_OLhkrX*U!cgD*;;&gIaA(DyVT4QD+q_xu z>r`tg{hiGY&DvD-)B*h+YEd+Zn)WylQl}<4>(_NlsKXCRV;a)Rcw!wtelM2_rWX`j zTh5A|i6=2BA(iMCnj_fob@*eA;V?oa4Z1kRBGaU07O70fb6-qmA$Hg$ps@^ka1=RO zTbE_2#)1bndC3VuK@e!Sftxq4=Uux}fDxXE#Q5_x=E1h>T5`DPHz zbH<_OjWx$wy7=%0!mo*qH*7N4tySm+R0~(rbus`7;+wGh;C0O%x~fEMkt!eV>U$`i z5>Q(o z=t$gPjgGh0&I7KY#k50V7DJRX<%^X z>6+ebc9efB3@eE2Tr){;?_w`vhgF>`-GDY(YkR{9RH(MiCnyRtd!LxXJ75z+?2 zGi@m^+2hKJ5sB1@Xi@s_@p_Kwbc<*LQ_`mr^Y%j}(sV_$`J(?_FWP)4NW*BIL~sR>t6 zM;qTJZ~GoY36&{h-Pf}L#y2UtR}>ZaI%A6VkU>vG4~}9^i$5WP2Tj?Cc}5oQxe2=q z8BeLa$hwCg_psjZyC2+?yX4*hJ58Wu^w9}}7X*+i5Rjqu5^@GzXiw#SUir1G1`jY% zOL=GE_ENYxhcyUrEt9XlMNP6kx6h&%6^u3@zB8KUCAa18T(R2J`%JjWZ z!{7cXaEW+Qu*iJPu+m>QqW}Lo$4Z+!I)0JNzZ&_M%=|B1yejFRM04bGAvu{=lNPd+ zJRI^DRQ(?FcVUD+bgEcAi@o(msqys9RTCG#)TjI!9~3-dc`>gW;HSJuQvH~d`MQs86R$|SKXHh zqS9Qy)u;T`>>a!$LuaE2keJV%;8g)tr&Nnc;EkvA-RanHXsy)D@XN0a>h}z2j81R; zsUNJf&g&rKpuD0WD@=dDrPHdBoK42WoBU|nMo17o(5^;M|dB4?|FsAGVrSyWcI`+FVw^vTVC`y}f(BwJl zrw3Sp151^9=}B})6@H*i4-dIN_o^br+BkcLa^H56|^2XsT0dESw2 zMX>(KqNl=x2K5=zIKg}2JpGAZu{I_IO}0$EQ5P{4zol**PCt3F4`GX}2@vr8#Y)~J zKb)gJeHcFnR@4SSh%b;c%J`l=W*40UPjF#q{<}ywv-=vHRFmDjv)NtmC zQx9qm)d%0zH&qG7AFa3VAU1S^(n8VFTC~Hb+HjYMjX8r#&_0MzlNR*mnLH5hi}`@{ zK$8qiDDvS_(L9_2vHgzEQ${DYSE;DqB!g*jhJghE&=LTnbgl&Xepo<*uRtV{2wDHN z)l;Kg$TA>Y|K8Lc&LjWGj<+bp4Hiye_@BfU(y#nF{fpR&|Ltbye?e^j0}8JC4#xi% zv29ZR%8%hk=3ZDvO-@1u8KmQ@6p%E|dlHuy#H1&MiC<*$YdLkHmR#F3ae;bKd;@*i z2_VfELG=B}JMLCO-6UQy^>RDE%K4b>c%9ki`f~Z2Qu8hO7C#t%Aeg8E%+}6P7Twtg z-)dj(w}_zFK&86KR@q9MHicUAucLVshUdmz_2@32(V`y3`&Kf8Q2I)+!n0mR=rrDU zXvv^$ho;yh*kNqJ#r1}b0|i|xRUF6;lhx$M*uG3SNLUTC@|htC z-=fsw^F%$qqz4%QdjBrS+ov}Qv!z00E+JWas>p?z@=t!WWU3K*?Z(0meTuTOC7OTx zU|kFLE0bLZ+WGcL$u4E}5dB0g`h|uwv3=H6f+{5z9oLv-=Q45+n~V4WwgO=CabjM% zBAN+RjM65(-}>Q2V#i1Na@a0`08g&y;W#@sBiX6Tpy8r}*+{RnyGUT`?XeHSqo#|J z^ww~c;ou|iyzpErDtlVU=`8N7JSu>4M z_pr9=tX0edVn9B}YFO2y(88j#S{w%E8vVOpAboK*27a7e4Ekjt0)hIX99*1oE;vex z7#%jhY=bPijA=Ce@9rRO(Vl_vnd00!^TAc<+wVvRM9{;hP*rqEL_(RzfK$er_^SN; z)1a8vo8~Dr5?;0X0J62Cusw$A*c^Sx1)dom`-)Pl7hsW4i(r*^Mw`z5K>!2ixB_mu z*Ddqjh}zceRFdmuX1akM1$3>G=#~|y?eYv(e-`Qy?bRHIq=fMaN~fB zUa6I8Rt=)jnplP>yuS+P&PxeWpJ#1$F`iqRl|jF$WL_aZFZl@kLo&d$VJtu&w?Q0O zzuXK>6gmygq(yXJy0C1SL}T8AplK|AGNUOhzlGeK_oo|haD@)5PxF}rV+5`-w{Aag zus45t=FU*{LguJ11Sr-28EZkq;!mJO7AQGih1L4rEyUmp>B!%X0YemsrV3QFvlgt* z5kwlPzaiJ+kZ^PMd-RRbl(Y?F*m`4*UIhIuf#8q>H_M=fM*L_Op-<_r zBZagV=4B|EW+KTja?srADTZXCd3Yv%^Chfpi)cg{ED${SI>InNpRj5!euKv?=Xn92 zsS&FH(*w`qLIy$doc>RE&A5R?u zzkl1sxX|{*fLpXvIW>9d<$ePROttn3oc6R!sN{&Y+>Jr@yeQN$sFR z;w6A<2-0%UA?c8Qf;sX7>>uKRBv3Ni)E9pI{uVzX|6Bb0U)`lhLE3hK58ivfRs1}d zNjlGK0hdq0qjV@q1qI%ZFMLgcpWSY~mB^LK)4GZ^h_@H+3?dAe_a~k*;9P_d7%NEFP6+ zgV(oGr*?W(ql?6SQ~`lUsjLb%MbfC4V$)1E0Y_b|OIYxz4?O|!kRb?BGrgiH5+(>s zoqM}v*;OBfg-D1l`M6T6{K`LG+0dJ1)!??G5g(2*vlNkm%Q(MPABT$r13q?|+kL4- zf)Mi5r$sn;u41aK(K#!m+goyd$c!KPl~-&-({j#D4^7hQkV3W|&>l_b!}!z?4($OA z5IrkfuT#F&S1(`?modY&I40%gtroig{YMvF{K{>5u^I51k8RriGd${z)=5k2tG zM|&Bp5kDTfb#vfuTTd?)a=>bX=lokw^y9+2LS?kwHQIWI~pYgy7 zb?A-RKVm_vM5!9?C%qYdfRAw& zAU7`up~%g=p@}pg#b7E)BFYx3g%(J36Nw(Dij!b>cMl@CSNbrW!DBDbTD4OXk!G4x zi}JBKc8HBYx$J~31PXH+4^x|UxK~(<@I;^3pWN$E=sYma@JP|8YL`L(zI6Y#c%Q{6 z*APf`DU$S4pr#_!60BH$FGViP14iJmbrzSrOkR;f3YZa{#E7Wpd@^4E-zH8EgPc-# zKWFPvh%WbqU_%ZEt`=Q?odKHc7@SUmY{GK`?40VuL~o)bS|is$Hn=<=KGHOsEC5tB zFb|q}gGlL97NUf$G$>^1b^3E18PZ~Pm9kX%*ftnolljiEt@2#F2R5ah$zbXd%V_Ev zyDd{1o_uuoBga$fB@Fw!V5F3jIr=a-ykqrK?WWZ#a(bglI_-8pq74RK*KfQ z0~Dzus7_l;pMJYf>Bk`)`S8gF!To-BdMnVw5M-pyu+aCiC5dwNH|6fgRsIKZcF&)g zr}1|?VOp}I3)IR@m1&HX1~#wsS!4iYqES zK}4J{Ei>;e3>LB#Oly>EZkW14^@YmpbgxCDi#0RgdM${&wxR+LiX}B+iRioOB0(pDKpVEI;ND?wNx>%e|m{RsqR_{(nmQ z3ZS}@t!p4a(BKx_-CYwrcyJ5u1TO9bcXti$8sy>xcLKqKCc#~UOZYD{llKTSFEjJ~ zyNWt>tLU}*>^`TvPxtP%F`ZJQw@W0^>x;!^@?k_)9#bF$j0)S3;mH-IR5y82l|%=F z2lR8zhP?XNP-ucZZ6A+o$xOyF!w;RaLHGh57GZ|TCXhJqY~GCh)aXEV$1O&$c}La1 zjuJxkY9SM4av^Hb;i7efiYaMwI%jGy`3NdY)+mcJhF(3XEiSlU3c|jMBi|;m-c?~T z+x0_@;SxcoY=(6xNgO$bBt~Pj8`-<1S|;Bsjrzw3@zSjt^JC3X3*$HI79i~!$RmTz zsblZsLYs7L$|=1CB$8qS!tXrWs!F@BVuh?kN(PvE5Av-*r^iYu+L^j^m9JG^#=m>@ z=1soa)H*w6KzoR$B8mBCXoU;f5^bVuwQ3~2LKg!yxomG1#XPmn(?YH@E~_ED+W6mxs%x{%Z<$pW`~ON1~2XjP5v(0{C{+6Dm$00tsd3w=f=ZENy zOgb-=f}|Hb*LQ$YdWg<(u7x3`PKF)B7ZfZ6;1FrNM63 z?O6tE%EiU@6%rVuwIQjvGtOofZBGZT1Sh(xLIYt9c4VI8`!=UJd2BfLjdRI#SbVAX ziT(f*RI^T!IL5Ac>ql7uduF#nuCRJ1)2bdvAyMxp-5^Ww5p#X{rb5)(X|fEhDHHW{ zw(Lfc$g;+Q`B0AiPGtmK%*aWfQQ$d!*U<|-@n2HZvCWSiw^I>#vh+LyC;aaVWGbmkENr z&kl*8o^_FW$T?rDYLO1Pyi%>@&kJKQoH2E0F`HjcN}Zlnx1ddoDA>G4Xu_jyp6vuT zPvC}pT&Owx+qB`zUeR|4G;OH(<<^_bzkjln0k40t`PQxc$7h(T8Ya~X+9gDc8Z9{Z z&y0RAU}#_kQGrM;__MK9vwIwK^aoqFhk~dK!ARf1zJqHMxF2?7-8|~yoO@_~Ed;_wvT%Vs{9RK$6uUQ|&@#6vyBsFK9eZW1Ft#D2)VpQRwpR(;x^ zdoTgMqfF9iBl%{`QDv7B0~8{8`8k`C4@cbZAXBu00v#kYl!#_Wug{)2PwD5cNp?K^ z9+|d-4z|gZ!L{57>!Ogfbzchm>J1)Y%?NThxIS8frAw@z>Zb9v%3_3~F@<=LG%r*U zaTov}{{^z~SeX!qgSYow`_5)ij*QtGp4lvF`aIGQ>@3ZTkDmsl#@^5*NGjOuu82}o zzLF~Q9SW+mP=>88%eSA1W4_W7-Q>rdq^?t=m6}^tDPaBRGFLg%ak93W!kOp#EO{6& zP%}Iff5HZQ9VW$~+9r=|Quj#z*=YwcnssS~9|ub2>v|u1JXP47vZ1&L1O%Z1DsOrDfSIMHU{VT>&>H=9}G3i@2rP+rx@eU@uE8rJNec zij~#FmuEBj03F1~ct@C@$>y)zB+tVyjV3*n`mtAhIM0$58vM9jOQC}JJOem|EpwqeMuYPxu3sv}oMS?S#o6GGK@8PN59)m&K4Dc&X% z(;XL_kKeYkafzS3Wn5DD>Yiw{LACy_#jY4op(>9q>>-*9@C0M+=b#bknAWZ37^(Ij zq>H%<@>o4a#6NydoF{_M4i4zB_KG)#PSye9bk0Ou8h%1Dtl7Q_y#7*n%g)?m>xF~( zjqvOwC;*qvN_3(*a+w2|ao0D?@okOvg8JskUw(l7n`0fncglavwKd?~l_ryKJ^Ky! zKCHkIC-o7%fFvPa$)YNh022lakMar^dgL=t#@XLyNHHw!b?%WlM)R@^!)I!smZL@k zBi=6wE5)2v&!UNV(&)oOYW(6Qa!nUjDKKBf-~Da=#^HE4(@mWk)LPvhyN3i4goB$3K8iV7uh zsv+a?#c4&NWeK(3AH;ETrMOIFgu{_@%XRwCZ;L=^8Ts)hix4Pf3yJRQ<8xb^CkdmC z?c_gB)XmRsk`9ch#tx4*hO=#qS7={~Vb4*tTf<5P%*-XMfUUYkI9T1cEF;ObfxxI-yNuA=I$dCtz3ey znVkctYD*`fUuZ(57+^B*R=Q}~{1z#2!ca?)+YsRQb+lt^LmEvZt_`=j^wqig+wz@n@ z`LIMQJT3bxMzuKg8EGBU+Q-6cs5(@5W?N>JpZL{$9VF)veF`L5%DSYTNQEypW%6$u zm_~}T{HeHj1bAlKl8ii92l9~$dm=UM21kLemA&b$;^!wB7#IKWGnF$TVq!!lBlG4 z{?Rjz?P(uvid+|i$VH?`-C&Gcb3{(~Vpg`w+O);Wk1|Mrjxrht0GfRUnZqz2MhrXa zqgVC9nemD5)H$to=~hp)c=l9?#~Z_7i~=U-`FZxb-|TR9@YCxx;Zjo-WpMNOn2)z) zFPGGVl%3N$f`gp$gPnWC+f4(rmts%fidpo^BJx72zAd7|*Xi{2VXmbOm)1`w^tm9% znM=0Fg4bDxH5PxPEm{P3#A(mxqlM7SIARP?|2&+c7qmU8kP&iApzL|F>Dz)Ixp_`O zP%xrP1M6@oYhgo$ZWwrAsYLa4 z|I;DAvJxno9HkQrhLPQk-8}=De{9U3U%)dJ$955?_AOms!9gia%)0E$Mp}$+0er@< zq7J&_SzvShM?e%V?_zUu{niL@gt5UFOjFJUJ}L?$f%eU%jUSoujr{^O=?=^{19`ON zlRIy8Uo_nqcPa6@yyz`CM?pMJ^^SN^Fqtt`GQ8Q#W4kE7`V9^LT}j#pMChl!j#g#J zr-=CCaV%xyFeQ9SK+mG(cTwW*)xa(eK;_Z(jy)woZp~> zA(4}-&VH+TEeLzPTqw&FOoK(ZjD~m{KW05fiGLe@E3Z2`rLukIDahE*`u!ubU)9`o zn^-lyht#E#-dt~S>}4y$-mSbR8{T@}22cn^refuQ08NjLOv?JiEWjyOnzk<^R5%gO zhUH_B{oz~u#IYwVnUg8?3P*#DqD8#X;%q%HY**=I>>-S|!X*-!x1{^l#OnR56O>iD zc;i;KS+t$koh)E3)w0OjWJl_aW2;xF=9D9Kr>)(5}4FqUbk# zI#$N8o0w;IChL49m9CJTzoC!|u{Ljd%ECgBOf$}&jA^$(V#P#~)`&g`H8E{uv52pp zwto`xUL-L&WTAVREEm$0g_gYPL(^vHq(*t1WCH_6alhkeW&GCZ3hL)|{O-jiFOBrF z!EW=Jej|dqQitT6!B-7&io2K)WIm~Q)v@yq%U|VpV+I?{y0@Yd%n8~-NuuM*pM~KA z85YB};IS~M(c<}4Hxx>qRK0cdl&e?t253N%vefkgds>Ubn8X}j6Vpgs>a#nFq$osY z1ZRwLqFv=+BTb=i%D2Wv>_yE0z}+niZ4?rE|*a3d7^kndWGwnFqt+iZ(7+aln<}jzbAQ(#Z2SS}3S$%Bd}^ zc9ghB%O)Z_mTZMRC&H#)I#fiLuIkGa^`4e~9oM5zKPx?zjkC&Xy0~r{;S?FS%c7w< zWbMpzc(xSw?9tGxG~_l}Acq}zjt5ClaB7-!vzqnlrX;}$#+PyQ9oU)_DfePh2E1<7 ztok6g6K^k^DuHR*iJ?jw?bs_whk|bx`dxu^nC6#e{1*m~z1eq7m}Cf$*^Eua(oi_I zAL+3opNhJteu&mWQ@kQWPucmiP)4|nFG`b2tpC;h{-PI@`+h?9v=9mn|0R-n8#t=+Z*FD(c5 zjj79Jxkgck*DV=wpFgRZuwr%}KTm+dx?RT@aUHJdaX-ODh~gByS?WGx&czAkvkg;x zrf92l8$Or_zOwJVwh>5rB`Q5_5}ef6DjS*$x30nZbuO3dijS*wvNEqTY5p1_A0gWr znH<(Qvb!os14|R)n2Ost>jS2;d1zyLHu`Svm|&dZD+PpP{Bh>U&`Md;gRl64q;>{8MJJM$?UNUd`aC>BiLe>*{ zJY15->yW+<3rLgYeTruFDtk1ovU<$(_y7#HgUq>)r0{^}Xbth}V#6?%5jeFYt;SG^ z3qF)=uWRU;Jj)Q}cpY8-H+l_n$2$6{ZR?&*IGr{>ek!69ZH0ZoJ*Ji+ezzlJ^%qL3 zO5a`6gwFw(moEzqxh=yJ9M1FTn!eo&qD#y5AZXErHs%22?A+JmS&GIolml!)rZTnUDM3YgzYfT#;OXn)`PWv3Ta z!-i|-Wojv*k&bC}_JJDjiAK(Ba|YZgUI{f}TdEOFT2+}nPmttytw7j%@bQZDV1vvj z^rp{gRkCDmYJHGrE1~e~AE!-&6B6`7UxVQuvRrfdFkGX8H~SNP_X4EodVd;lXd^>eV1jN+Tt4}Rsn)R0LxBz0c=NXU|pUe!MQQFkGBWbR3&(jLm z%RSLc#p}5_dO{GD=DEFr=Fc% z85CBF>*t!6ugI?soX(*JNxBp+-DdZ4X0LldiK}+WWGvXV(C(Ht|!3$psR=&c*HIM=BmX;pRIpz@Ale{9dhGe(U2|Giv;# zOc|;?p67J=Q(kamB*aus=|XP|m{jN^6@V*Bpm?ye56Njh#vyJqE=DweC;?Rv7faX~ zde03n^I~0B2vUmr;w^X37tVxUK?4}ifsSH5_kpKZIzpYu0;Kv}SBGfI2AKNp+VN#z`nI{UNDRbo-wqa4NEls zICRJpu)??cj^*WcZ^MAv+;bDbh~gpN$1Cor<{Y2oyIDws^JsfW^5AL$azE(T0p&pP z1Mv~6Q44R&RHoH95&OuGx2srIr<@zYJTOMKiVs;Bx3py89I87LOb@%mr`0)#;7_~Z zzcZj8?w=)>%5@HoCHE_&hnu(n_yQ-L(~VjpjjkbT7e)Dk5??fApg(d>vwLRJ-x{um z*Nt?DqTSxh_MIyogY!vf1mU1`Gld-&L)*43f6dilz`Q@HEz;+>MDDYv9u!s;WXeao zUq=TaL$P*IFgJzrGc>j1dDOd zed+=ZBo?w4mr$2)Ya}?vedDopomhW1`#P<%YOJ_j=WwClX0xJH-f@s?^tmzs_j7t!k zK@j^zS0Q|mM4tVP5Ram$VbS6|YDY&y?Q1r1joe9dj08#CM{RSMTU}(RCh`hp_Rkl- zGd|Cv~G@F{DLhCizAm9AN!^{rNs8hu!G@8RpnGx7e`-+K$ffN<0qjR zGq^$dj_Tv!n*?zOSyk5skI7JVKJ)3jysnjIu-@VSzQiP8r6MzudCU=~?v-U8yzo^7 zGf~SUTvEp+S*!X9uX!sq=o}lH;r{pzk~M*VA(uyQ`3C8!{C;)&6)95fv(cK!%Cuz$ z_Zal57H6kPN>25KNiI6z6F)jzEkh#%OqU#-__Xzy)KyH};81#N6OfX$$IXWzOn`Q& z4f$Z1t>)8&8PcYfEwY5UadU1yg+U*(1m2ZlHoC-!2?gB!!fLhmTl))D@dhvkx#+Yj z1O=LV{(T%{^IeCuFK>%QR!VZ4GnO5tK8a+thWE zg4VytZrwcS?7^ zuZfhYnB8dwd%VLO?DK7pV5Wi<(`~DYqOXn8#jUIL^)12*Dbhk4GmL_E2`WX&iT16o zk(t|hok(Y|v-wzn?4x34T)|+SfZP>fiq!><*%vnxGN~ypST-FtC+@TPv*vYv@iU!_ z@2gf|PrgQ?Ktf*9^CnJ(x*CtZVB8!OBfg0%!wL;Z8(tYYre0vcnPGlyCc$V(Ipl*P z_(J!a=o@vp^%Efme!K74(Ke7A>Y}|sxV+JL^aYa{~m%5#$$+R1? zGaQhZTTX!#s#=Xtpegqero$RNt&`4xn3g$)=y*;=N=Qai)}~`xtxI_N*#MMCIq#HFifT zz(-*m;pVH&+4bixL&Bbg)W5FN^bH87pAHp)zPkWNMfTFqS=l~AC$3FX3kQUSh_C?-ZftyClgM)o_D7cX$RGlEYblux0jv5 zTr|i-I3@ZPCGheCl~BGhImF)K4!9@?pC(gi3ozX=a!|r1)LFxy_8c&wY0<^{2cm|P zv6Y`QktY*;I)IUd5y3ne1CqpVanlY45z8hf4&$EUBnucDj16pDa4&GI&TArYhf*xh zdj>*%APH8(h~c>o@l#%T>R$e>rwVx_WUB|~V`p^JHsg*y12lzj&zF}w6W09HwB2yb z%Q~`es&(;7#*DUC_w-Dmt7|$*?TA_m;zB+-u{2;Bg{O}nV7G_@7~<)Bv8fH^G$XG8$(&{A zwXJK5LRK%M34(t$&NI~MHT{UQ9qN-V_yn|%PqC81EIiSzmMM=2zb`mIwiP_b)x+2M z7Gd`83h79j#SItpQ}luuf2uOU`my_rY5T{6P#BNlb%h%<#MZb=m@y5aW;#o1^2Z)SWo+b`y0gV^iRcZtz5!-05vF z7wNo=hc6h4hc&s@uL^jqRvD6thVYtbErDK9k!;+a0xoE0WL7zLixjn5;$fXvT=O3I zT6jI&^A7k6R{&5#lVjz#8%_RiAa2{di{`kx79K+j72$H(!ass|B%@l%KeeKchYLe_ z>!(JC2fxsv>XVen+Y42GeYPxMWqm`6F$(E<6^s|g(slNk!lL*6v^W2>f6hh^mE$s= z3D$)}{V5(Qm&A6bp%2Q}*GZ5Qrf}n7*Hr51?bJOyA-?B4vg6y_EX<*-e20h{=0Mxs zbuQGZ$fLyO5v$nQ&^kuH+mNq9O#MWSfThtH|0q1i!NrWj^S}_P;Q1OkYLW6U^?_7G zx2wg?CULj7))QU(n{$0JE%1t2dWrMi2g-Os{v|8^wK{@qlj%+1b^?NI z$}l2tjp0g>K3O+p%yK<9!XqmQ?E9>z&(|^Pi~aSRwI5x$jaA62GFz9%fmO3t3a>cq zK8Xbv=5Ps~4mKN5+Eqw12(!PEyedFXv~VLxMB~HwT1Vfo51pQ#D8e$e4pFZ{&RC2P z5gTIzl{3!&(tor^BwZfR8j4k{7Rq#`riKXP2O-Bh66#WWK2w=z;iD9GLl+3 zpHIaI4#lQ&S-xBK8PiQ%dwOh?%BO~DCo06pN7<^dnZCN@NzY{_Z1>rrB0U|nC&+!2 z2y!oBcTd2;@lzyk(B=TkyZ)zy0deK05*Q0zk+o$@nun`VI1Er7pjq>8V zNmlW{p7S^Btgb(TA}jL(uR>`0w8gHP^T~Sh5Tkip^spk4SBAhC{TZU}_Z)UJw-}zm zPq{KBm!k)?P{`-(9?LFt&YN4s%SIZ-9lJ!Ws~B%exHOeVFk3~}HewnnH(d)qkLQ_d z6h>O)pEE{vbOVw}E+jdYC^wM+AAhaI(YAibUc@B#_mDss0Ji&BK{WG`4 zOk>vSNq(Bq2IB@s>>Rxm6Wv?h;ZXkpb1l8u|+_qXWdC*jjcPCixq;!%BVPSp#hP zqo`%cNf&YoQXHC$D=D45RiT|5ngPlh?0T~?lUf*O)){K@*Kbh?3RW1j9-T?%lDk@y z4+~?wKI%Y!-=O|_IuKz|=)F;V7ps=5@g)RrE;;tvM$gUhG>jHcw2Hr@fS+k^Zr~>G z^JvPrZc}_&d_kEsqAEMTMJw!!CBw)u&ZVzmq+ZworuaE&TT>$pYsd9|g9O^0orAe8 z221?Va!l1|Y5X1Y?{G7rt1sX#qFA^?RLG^VjoxPf63;AS=_mVDfGJKg73L zsGdnTUD40y(>S##2l|W2Cy!H(@@5KBa(#gs`vlz}Y~$ot5VsqPQ{{YtjYFvIumZzt zA{CcxZLJR|4#{j7k~Tu*jkwz8QA|5G1$Cl895R`Zyp;irp1{KN){kB30O8P1W5;@bG znvX74roeMmQlUi=v9Y%(wl$ZC#9tKNFpvi3!C}f1m6Ct|l2g%psc{TJp)@yu)*e2> z((p0Fg*8gJ!|3WZke9;Z{8}&NRkv7iP=#_y-F}x^y?2m%-D_aj^)f04%mneyjo_;) z6qc_Zu$q37d~X``*eP~Q>I2gg%rrV8v=kDfpp$=%Vj}hF)^dsSWygoN(A$g*E=Do6FX?&(@F#7pbiJ`;c0c@Ul zDqW_90Wm#5f2L<(Lf3)3TeXtI7nhYwRm(F;*r_G6K@OPW4H(Y3O5SjUzBC}u3d|eQ8*8d@?;zUPE+i#QNMn=r(ap?2SH@vo*m z3HJ%XuG_S6;QbWy-l%qU;8x;>z>4pMW7>R}J%QLf%@1BY(4f_1iixd-6GlO7Vp*yU zp{VU^3?s?90i=!#>H`lxT!q8rk>W_$2~kbpz7eV{3wR|8E=8**5?qn8#n`*(bt1xRQrdGxyx2y%B$qmw#>ZV$c7%cO#%JM1lY$Y0q?Yuo> ze9KdJoiM)RH*SB%^;TAdX-zEjA7@%y=!0=Zg%iWK7jVI9b&Dk}0$Af&08KHo+ zOwDhFvA(E|ER%a^cdh@^wLUlmIv6?_3=BvX8jKk92L=Y}7Jf5OGMfh` zBdR1wFCi-i5@`9km{isRb0O%TX+f~)KNaEz{rXQa89`YIF;EN&gN)cigu6mNh>?Cm zAO&Im2flv6D{jwm+y<%WsPe4!89n~KN|7}Cb{Z;XweER73r}Qp2 zz}WP4j}U0&(uD&9yGy6`!+_v-S(yG*iytsTR#x_Rc>=6u^vnRDnf1gP{#2>`ffrAC% zTZ5WQ@hAK;P;>kX{D)mIXe4%a5p=LO1xXH@8T?mz7Q@d)$3pL{{B!2{-v70L*o1AO+|n5beiw~ zk@(>m?T3{2k2c;NWc^`4@P&Z?BjxXJ@;x1qhn)9Mn*IFdt_J-dIqx5#d`NfyfX~m( zIS~5)MfZ2Uy?_4W`47i}u0ZgPh<{D|w_d#;D}Q&U$Q-G}xM1A@1f{#%A$jh6Qp&0hQ<0bPOM z-{1Wm&p%%#eb_?x7i;bol EfAhh=DF6Tf literal 0 HcmV?d00001 diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..642d572 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/README.md b/README.md index c5786a0..7700515 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,26 @@ -

- Thanks for taking the time to do our front-end / full-stack practical coding challenge. The objective of this challenge is to evaluate your domain knowledge in front-end / full-stack development: code organization, style and best practices. # Overview: -The main challenge will be to build a simple user management tool that will perform basic CRUD operations on a user. Please use mockups as a reference -about look of the application. There are no business rules & guidelines other than to show us what you’re truly made of. It can be as simple or as complex as you want it to be. + +# This is the Backend from Me Muhamad Nizar Iqbal + +## List of API + +- Register /api/register ### Prerequisites + There are none :) Our main solutions stack include but not limited to Kotlin, Java, AngularJS, Flutter, Spring... Feel free to use any languages and technologies you are comfortable with. ## Mockups +

@@ -24,26 +28,24 @@ Feel free to use any languages and technologies you are comfortable with.

### Front-end: + - For API please use https://reqres.in/. ### Back-end: + - The API should be similar to https://reqres.in/, performing basic operations for user. _We'll be happy if you cover application with tests._ ### Submission Guidelines + - Please fork the repo and then submit a Pull Request when you are done. - Instructions must be provided to run the application, install any dependencies, and any other information needed. - Please use version control and make sure we can see the history of how you went about it, rather than just uploading the complete project to GitHub. -## Questions? ### -Please feel free to reach out and ask any questions while you are working on a solution. -Send your questions to [tech@chimaera.my](mailto:tech@chimaera.my). - - -Good luck! - - +## Questions? +Please feel free to reach out and ask any questions while you are working on a solution. +Send your questions to [tech@chimaera.my](mailto:tech@chimaera.my). - +Good luck! diff --git a/mvnw b/mvnw new file mode 100755 index 0000000..a16b543 --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# 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 +# +# https://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..c8d4337 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..351396c --- /dev/null +++ b/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.4.RELEASE + + + id. + global-line-network + 0.0.1-SNAPSHOT + global-line-network + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.springframework.security + spring-security-test + test + + + junit + junit + 4.12 + test + + + org.mockito + mockito-core + 3.5.13 + test + + + com.google.code.gson + gson + 2.8.6 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java b/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java new file mode 100644 index 0000000..fe7a853 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java @@ -0,0 +1,13 @@ +package id.globallinenetwork.api; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GlobalLineNetworkApplication { + + public static void main(String[] args) { + SpringApplication.run(GlobalLineNetworkApplication.class, args); + } + +} diff --git a/src/main/java/id/globallinenetwork/api/user/IUser.java b/src/main/java/id/globallinenetwork/api/user/IUser.java new file mode 100644 index 0000000..7a7119e --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/IUser.java @@ -0,0 +1,7 @@ +package id.globallinenetwork.api.user; + +import java.util.Map; + +public interface IUser { + Map registration(RegisterDto registerDto); +} diff --git a/src/main/java/id/globallinenetwork/api/user/RegisterDto.java b/src/main/java/id/globallinenetwork/api/user/RegisterDto.java new file mode 100644 index 0000000..7c67864 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/RegisterDto.java @@ -0,0 +1,9 @@ +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class RegisterDto { + private String email; + private String password; +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java new file mode 100644 index 0000000..909f499 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -0,0 +1,32 @@ +package id.globallinenetwork.api.user; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api") +public class UserController { + + private final UserService userService; + + public UserController(UserService userService) { + this.userService = userService; + } + + @PostMapping("/register") + public ResponseEntity register(@RequestBody RegisterDto registerDto){ + Map data = userService.registration(registerDto); + if (!data.containsKey("id")){ + return ResponseEntity.ok().body(data); + } + + return ResponseEntity.badRequest().body(data); + } +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserService.java b/src/main/java/id/globallinenetwork/api/user/UserService.java new file mode 100644 index 0000000..1b4ae0f --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/UserService.java @@ -0,0 +1,23 @@ +package id.globallinenetwork.api.user; + +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class UserService implements IUser { + @Override + public Map registration(RegisterDto registerDto) { + Map data = new HashMap<>(); + if (registerDto.getPassword().equals("") || registerDto.getPassword() == null){ + data.put("error", "Missing password"); + return data; + } + + data.put("id", 4); + data.put("token", "QpwL5tke4Pnpja7X4"); + + return data; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java b/src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java new file mode 100644 index 0000000..1a299b5 --- /dev/null +++ b/src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java @@ -0,0 +1,21 @@ +package id.globallinenetwork.api; + +import id.globallinenetwork.api.user.UserController; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +class GlobalLineNetworkApplicationTests { + + @Autowired + private UserController userController; + + @Test + void contextLoads() { + assertThat(userController).isNotNull(); + } + +} diff --git a/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java new file mode 100644 index 0000000..b11a469 --- /dev/null +++ b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java @@ -0,0 +1,70 @@ +package id.globallinenetwork.api.controller; + +import com.google.gson.Gson; +import id.globallinenetwork.api.user.RegisterDto; +import id.globallinenetwork.api.user.UserController; +import id.globallinenetwork.api.user.UserService; +import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.assertj.core.api.Assertions.assertThat; + + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Tag("UserController") +public class UserControllerTest { + + private MockMvc mockMvc; + + @MockBean + private UserService userService; + + @Autowired + private TestRestTemplate restTemplate; + + @BeforeEach + public void test(){ + mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userService)).build(); + } + + @Test + @DisplayName("Registration of new user it will return error if failed") + public void register() throws Exception { + RegisterDto registerDto = new RegisterDto(); + registerDto.setEmail("muhamad.iqbal1987@gmail.com"); + registerDto.setPassword("123Abcdefgh_!#"); + + Gson gson = new Gson(); + String gsonRegister = gson.toJson(registerDto); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/register", registerDto, ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + + Map data = new HashMap<>(); + data.put("id", 4); + data.put("token", "QpwL5tke4Pnpja7X4"); + assertThat(Objects.equals(result.getBody(), data)); + } +} From cb58dea200af46faf8841fb9d2c53b8e8cc47c67 Mon Sep 17 00:00:00 2001 From: IQBAL Date: Tue, 6 Oct 2020 13:37:58 +0700 Subject: [PATCH 02/13] Add message list of API Add LoginDTO for login API add CreateUserDto as request body add ResponseCreateUser as response when /api/users is call Add method to process login and create user in UserService and interface IUser --- README.md | 2 + .../api/GlobalLineNetworkApplication.java | 1 - .../api/user/CreateUserDto.java | 9 +++++ .../id/globallinenetwork/api/user/IUser.java | 4 ++ .../globallinenetwork/api/user/LoginDto.java | 7 ++++ .../api/user/ResponseCreateUser.java | 11 ++++++ .../api/user/UserController.java | 37 ++++++++++++++++++- .../api/user/UserService.java | 32 ++++++++++++++++ .../api/controller/UserControllerTest.java | 4 +- 9 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/user/CreateUserDto.java create mode 100644 src/main/java/id/globallinenetwork/api/user/LoginDto.java create mode 100644 src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java diff --git a/README.md b/README.md index 7700515..96104f2 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ The objective of this challenge is to evaluate your domain knowledge in front-en ## List of API - Register /api/register +- Login /api/login +- Create /api/users ### Prerequisites diff --git a/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java b/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java index fe7a853..da5e821 100644 --- a/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java +++ b/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java @@ -9,5 +9,4 @@ public class GlobalLineNetworkApplication { public static void main(String[] args) { SpringApplication.run(GlobalLineNetworkApplication.class, args); } - } diff --git a/src/main/java/id/globallinenetwork/api/user/CreateUserDto.java b/src/main/java/id/globallinenetwork/api/user/CreateUserDto.java new file mode 100644 index 0000000..257cce9 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/CreateUserDto.java @@ -0,0 +1,9 @@ +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class CreateUserDto{ + private String name; + private String job; +} \ No newline at end of file diff --git a/src/main/java/id/globallinenetwork/api/user/IUser.java b/src/main/java/id/globallinenetwork/api/user/IUser.java index 7a7119e..4fad963 100644 --- a/src/main/java/id/globallinenetwork/api/user/IUser.java +++ b/src/main/java/id/globallinenetwork/api/user/IUser.java @@ -1,7 +1,11 @@ package id.globallinenetwork.api.user; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.util.Map; public interface IUser { Map registration(RegisterDto registerDto); + Map login(LoginDto loginDto); + ResponseCreateUser createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException; } diff --git a/src/main/java/id/globallinenetwork/api/user/LoginDto.java b/src/main/java/id/globallinenetwork/api/user/LoginDto.java new file mode 100644 index 0000000..d10034b --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/LoginDto.java @@ -0,0 +1,7 @@ +package id.globallinenetwork.api.user; + +@Data +public class LoginDto{ + private String email; + private String password; +} \ No newline at end of file diff --git a/src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java b/src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java new file mode 100644 index 0000000..c8570cf --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java @@ -0,0 +1,11 @@ +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class ResponseCreateUser { + private String name; + private String job; + private String id; + private String createdAt; +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 909f499..4943759 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -1,12 +1,15 @@ package id.globallinenetwork.api.user; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.util.HashMap; import java.util.Map; @@ -23,10 +26,42 @@ public UserController(UserService userService) { @PostMapping("/register") public ResponseEntity register(@RequestBody RegisterDto registerDto){ Map data = userService.registration(registerDto); - if (!data.containsKey("id")){ + if (data.containsKey("id")){ return ResponseEntity.ok().body(data); } return ResponseEntity.badRequest().body(data); } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody LoginDto loginDto){ + Map data = userService.login(loginDto); + if (data.containsKey("token")){ + return ResponseEntity.ok().body(data); + } + + return ResponseEntity.badRequest().body(data); + } + + @PostMapping("/users") + public ResponseEntity createUser(@RequestBody CreateUserDto createUserDto){ + Map data = new HashMap<>(); + if (createUserDto.getName().equals("") || createUserDto.getName() == null){ + data.put("error:", "Missing name"); + return ResponseEntity.badRequest().body(data); + } + + if (createUserDto.getJob().equals("") || createUserDto.getJob() == null){ + data.put("error:", "Missing Job"); + return ResponseEntity.badRequest().body(data); + } + + try { + return ResponseEntity.ok().body(userService.createUser(createUserDto)); + } catch (NoSuchProviderException | NoSuchAlgorithmException e) { + data.put("error", e); + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(data); + } + } } diff --git a/src/main/java/id/globallinenetwork/api/user/UserService.java b/src/main/java/id/globallinenetwork/api/user/UserService.java index 1b4ae0f..78bcabc 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserService.java +++ b/src/main/java/id/globallinenetwork/api/user/UserService.java @@ -2,6 +2,10 @@ import org.springframework.stereotype.Service; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.time.Instant; import java.util.HashMap; import java.util.Map; @@ -20,4 +24,32 @@ public Map registration(RegisterDto registerDto) { return data; } + + @Override + public Map login(LoginDto loginDto){ + Map data = new HashMap<>(); + if (loginDto.getPassword().equals("") || loginDto.getPassword() == null){ + data.put("error", "Missing password"); + return data; + } + + data.put("token", "QpwL5tke4Pnpja7X4"); + return data; + } + + @Override + public ResponseCreateUser createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException { + ResponseCreateUser createUser = new ResponseCreateUser(); + createUser.setName(createUserDto.getName()); + createUser.setJob(createUserDto.getJob()); + + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN"); + int id = secureRandom.nextInt(1000); + createUser.setId(String.valueOf(id)); + createUser.setCreatedAt(Instant.now().toString()); + + return createUser; + } + + } diff --git a/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java index b11a469..4c433f0 100644 --- a/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java +++ b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java @@ -50,8 +50,8 @@ public void test(){ @DisplayName("Registration of new user it will return error if failed") public void register() throws Exception { RegisterDto registerDto = new RegisterDto(); - registerDto.setEmail("muhamad.iqbal1987@gmail.com"); - registerDto.setPassword("123Abcdefgh_!#"); + registerDto.setEmail("eve.holt@reqres.in"); + registerDto.setPassword("cityslicka"); Gson gson = new Gson(); String gsonRegister = gson.toJson(registerDto); From f77ae2ba224192149d41961b129af9e9d8863d6c Mon Sep 17 00:00:00 2001 From: IQBAL Date: Tue, 6 Oct 2020 20:35:34 +0700 Subject: [PATCH 03/13] Add update with patch method Add service to process update data user --- .../id/globallinenetwork/api/user/IUser.java | 1 + .../api/user/ResponseUpdateUser.java | 10 ++++++++++ .../api/user/UserController.java | 16 ++++++++++++---- .../globallinenetwork/api/user/UserService.java | 12 +++++++++++- 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java diff --git a/src/main/java/id/globallinenetwork/api/user/IUser.java b/src/main/java/id/globallinenetwork/api/user/IUser.java index 4fad963..4b34a92 100644 --- a/src/main/java/id/globallinenetwork/api/user/IUser.java +++ b/src/main/java/id/globallinenetwork/api/user/IUser.java @@ -8,4 +8,5 @@ public interface IUser { Map registration(RegisterDto registerDto); Map login(LoginDto loginDto); ResponseCreateUser createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException; + ResponseUpdateUser updateUser(Integer id, CreateUserDto createUserDto); } diff --git a/src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java b/src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java new file mode 100644 index 0000000..818bca6 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java @@ -0,0 +1,10 @@ +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class ResponseUpdateUser { + private String name; + private String job; + private String updatedAt; +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 4943759..440cc8c 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -3,10 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; @@ -64,4 +61,15 @@ public ResponseEntity createUser(@RequestBody CreateUserDto createUserDto){ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(data); } } + + @PatchMapping("/users/{id}") + public ResponseEntity updateUser(@PathVariable("id") Integer id, @RequestBody CreateUserDto createUserDto){ + ResponseUpdateUser result = userService.updateUser(id, createUserDto); + Map data = new HashMap<>(); + if (result == null) { + data.put("error:","Missing id"); + return ResponseEntity.badRequest().body(data); + } + return ResponseEntity.ok().body(result); + } } diff --git a/src/main/java/id/globallinenetwork/api/user/UserService.java b/src/main/java/id/globallinenetwork/api/user/UserService.java index 78bcabc..1af28b5 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserService.java +++ b/src/main/java/id/globallinenetwork/api/user/UserService.java @@ -51,5 +51,15 @@ public ResponseCreateUser createUser(CreateUserDto createUserDto) throws NoSuchP return createUser; } - + @Override + public ResponseUpdateUser updateUser(Integer id, CreateUserDto createUserDto){ + if (id != null){ + ResponseUpdateUser updateUser = new ResponseUpdateUser(); + updateUser.setName(createUserDto.getName()); + updateUser.setJob(createUserDto.getJob()); + updateUser.setUpdatedAt(Instant.now().toString()); + return updateUser; + } + return null; + } } From 2c3e3a2c9814d57ee9ef3ef10f8b7a838a0164e8 Mon Sep 17 00:00:00 2001 From: IQBAL Date: Tue, 6 Oct 2020 20:58:39 +0700 Subject: [PATCH 04/13] Add request method PUT so the controller use Multiple HTTP Request Methods to the Same Controller Method --- .../java/id/globallinenetwork/api/user/UserController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 440cc8c..8e61b61 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -1,6 +1,5 @@ package id.globallinenetwork.api.user; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -62,7 +61,7 @@ public ResponseEntity createUser(@RequestBody CreateUserDto createUserDto){ } } - @PatchMapping("/users/{id}") + @RequestMapping(value = "/users/{id}", method = {RequestMethod.PATCH, RequestMethod.PUT}) public ResponseEntity updateUser(@PathVariable("id") Integer id, @RequestBody CreateUserDto createUserDto){ ResponseUpdateUser result = userService.updateUser(id, createUserDto); Map data = new HashMap<>(); From 816f96f0c30f348ce47f52ff4f6599832f84c9e3 Mon Sep 17 00:00:00 2001 From: IQBAL Date: Wed, 7 Oct 2020 07:05:28 +0700 Subject: [PATCH 05/13] Create Model for user Refactored method for update Add new method for delete --- .../id/globallinenetwork/api/user/IUser.java | 5 +- .../id/globallinenetwork/api/user/User.java | 14 +++++ .../api/user/UserController.java | 10 +++- .../api/user/UserService.java | 60 +++++++++++++------ 4 files changed, 69 insertions(+), 20 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/user/User.java diff --git a/src/main/java/id/globallinenetwork/api/user/IUser.java b/src/main/java/id/globallinenetwork/api/user/IUser.java index 4b34a92..a517fc4 100644 --- a/src/main/java/id/globallinenetwork/api/user/IUser.java +++ b/src/main/java/id/globallinenetwork/api/user/IUser.java @@ -7,6 +7,7 @@ public interface IUser { Map registration(RegisterDto registerDto); Map login(LoginDto loginDto); - ResponseCreateUser createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException; - ResponseUpdateUser updateUser(Integer id, CreateUserDto createUserDto); + User createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException; + User updateUser(Integer id, CreateUserDto createUserDto); + boolean deleteUser(Integer id); } diff --git a/src/main/java/id/globallinenetwork/api/user/User.java b/src/main/java/id/globallinenetwork/api/user/User.java new file mode 100644 index 0000000..aac47ab --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/User.java @@ -0,0 +1,14 @@ +package id.globallinenetwork.api.user; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class User { + private Integer id; + private String name; + private String job; + private String createdAt; + private String updateAt; +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 8e61b61..336e4ca 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -63,7 +63,7 @@ public ResponseEntity createUser(@RequestBody CreateUserDto createUserDto){ @RequestMapping(value = "/users/{id}", method = {RequestMethod.PATCH, RequestMethod.PUT}) public ResponseEntity updateUser(@PathVariable("id") Integer id, @RequestBody CreateUserDto createUserDto){ - ResponseUpdateUser result = userService.updateUser(id, createUserDto); + User result = userService.updateUser(id, createUserDto); Map data = new HashMap<>(); if (result == null) { data.put("error:","Missing id"); @@ -71,4 +71,12 @@ public ResponseEntity updateUser(@PathVariable("id") Integer id, @RequestBody } return ResponseEntity.ok().body(result); } + + @DeleteMapping(value = "/users/{id}") + public ResponseEntity deleteUser(@PathVariable("id") Integer id){ + if (userService.deleteUser(id)) { + return new ResponseEntity<>(HttpStatus.OK); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } } diff --git a/src/main/java/id/globallinenetwork/api/user/UserService.java b/src/main/java/id/globallinenetwork/api/user/UserService.java index 1af28b5..37bc538 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserService.java +++ b/src/main/java/id/globallinenetwork/api/user/UserService.java @@ -1,16 +1,40 @@ package id.globallinenetwork.api.user; +import lombok.val; import org.springframework.stereotype.Service; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.time.Instant; -import java.util.HashMap; -import java.util.Map; +import java.util.*; @Service public class UserService implements IUser { + + private List users = new ArrayList<>(); + private SecureRandom secureRandom = null; + + public UserService(){ + int id = 0; + + try { + secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN"); + id = secureRandom.nextInt(1000); + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { + e.printStackTrace(); + } + User user1 = new User(1, "Muhammad", "CEO", Instant.now().toString(), Instant.now().toString()); + User user2 = new User(2, "Abu Bakar", "CTO", Instant.now().toString(), Instant.now().toString()); + User user3 = new User(3, "Umar", "Software Engineer", Instant.now().toString(), Instant.now().toString()); + User user4 = new User(4, "Usman", "FrontEnd Engineer", Instant.now().toString(), Instant.now().toString()); + User user5 = new User(5, "Ali", "Security Engineer", Instant.now().toString(), Instant.now().toString()); + } + + public List getUsers(){ + return users; + } + @Override public Map registration(RegisterDto registerDto) { Map data = new HashMap<>(); @@ -38,28 +62,30 @@ public Map login(LoginDto loginDto){ } @Override - public ResponseCreateUser createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException { - ResponseCreateUser createUser = new ResponseCreateUser(); - createUser.setName(createUserDto.getName()); - createUser.setJob(createUserDto.getJob()); - - SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN"); + public User createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException { int id = secureRandom.nextInt(1000); - createUser.setId(String.valueOf(id)); - createUser.setCreatedAt(Instant.now().toString()); + User createUser = new User(id, createUserDto.getName(), createUserDto.getJob(),Instant.now().toString(), Instant.now().toString()); + users.add(createUser); - return createUser; + return users.get(users.size()-1); } @Override - public ResponseUpdateUser updateUser(Integer id, CreateUserDto createUserDto){ + public User updateUser(Integer id, CreateUserDto createUserDto){ + if (id != null){ - ResponseUpdateUser updateUser = new ResponseUpdateUser(); - updateUser.setName(createUserDto.getName()); - updateUser.setJob(createUserDto.getJob()); - updateUser.setUpdatedAt(Instant.now().toString()); - return updateUser; + Optional optionalUser = users.stream().filter(user -> user.getId().equals(id)).findFirst(); + if (optionalUser.isPresent()) { + User currentUser = optionalUser.get(); + currentUser.setUpdateAt(Instant.now().toString()); + return currentUser; + } } return null; } + + @Override + public boolean deleteUser(Integer id) { + return users.removeIf(user -> user.getId().equals(id)); + } } From 5ffb15cfd1a2958c7f6fda5eee2399c23c7ce920 Mon Sep 17 00:00:00 2001 From: "IDX2-03-NB\\Muhamad Nizar Iqbal" Date: Wed, 7 Oct 2020 09:28:09 +0700 Subject: [PATCH 06/13] Revise method login in UserService Revise method createuser in UserService Add new properties in User model --- .../id/globallinenetwork/api/user/User.java | 2 + .../api/user/UserController.java | 4 +- .../api/user/UserService.java | 51 +++++++++++-------- .../api/utility/PasswordGenerator.java | 20 ++++++++ 4 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java diff --git a/src/main/java/id/globallinenetwork/api/user/User.java b/src/main/java/id/globallinenetwork/api/user/User.java index aac47ab..f52f96b 100644 --- a/src/main/java/id/globallinenetwork/api/user/User.java +++ b/src/main/java/id/globallinenetwork/api/user/User.java @@ -9,6 +9,8 @@ public class User { private Integer id; private String name; private String job; + private String email; + private String password; private String createdAt; private String updateAt; } diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 336e4ca..ac7e2af 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -32,7 +32,9 @@ public ResponseEntity register(@RequestBody RegisterDto registerDto){ @PostMapping("/login") public ResponseEntity login(@RequestBody LoginDto loginDto){ Map data = userService.login(loginDto); - if (data.containsKey("token")){ + if (data == null) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + }else if (data.containsKey("token")){ return ResponseEntity.ok().body(data); } diff --git a/src/main/java/id/globallinenetwork/api/user/UserService.java b/src/main/java/id/globallinenetwork/api/user/UserService.java index 37bc538..816c051 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserService.java +++ b/src/main/java/id/globallinenetwork/api/user/UserService.java @@ -1,6 +1,6 @@ package id.globallinenetwork.api.user; -import lombok.val; +import id.globallinenetwork.api.utility.PasswordGenerator; import org.springframework.stereotype.Service; import java.security.NoSuchAlgorithmException; @@ -12,10 +12,11 @@ @Service public class UserService implements IUser { - private List users = new ArrayList<>(); + private static final String EMAIL_DOMAIN = "@globallinenetwork.com"; + private final List users = new ArrayList<>(); private SecureRandom secureRandom = null; - public UserService(){ + public UserService() { int id = 0; try { @@ -24,21 +25,22 @@ public UserService(){ } catch (NoSuchAlgorithmException | NoSuchProviderException e) { e.printStackTrace(); } - User user1 = new User(1, "Muhammad", "CEO", Instant.now().toString(), Instant.now().toString()); - User user2 = new User(2, "Abu Bakar", "CTO", Instant.now().toString(), Instant.now().toString()); - User user3 = new User(3, "Umar", "Software Engineer", Instant.now().toString(), Instant.now().toString()); - User user4 = new User(4, "Usman", "FrontEnd Engineer", Instant.now().toString(), Instant.now().toString()); - User user5 = new User(5, "Ali", "Security Engineer", Instant.now().toString(), Instant.now().toString()); + User user1 = new User(1, "Muhammad", "CEO", "muhammad@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); + User user2 = new User(2, "Abu Bakar", "CTO", "abu.bakar@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); + User user3 = new User(3, "Umar", "Software Engineer", "umar@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); + User user4 = new User(4, "Usman", "FrontEnd Engineer", "usman@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); + User user5 = new User(5, "Ali", "Security Engineer", "ali@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); + User user6 = new User(6, "Eve Holt", "Security Engineer", "eve.holt@reqres.in", "pistol", Instant.now().toString(), Instant.now().toString()); } - public List getUsers(){ + public List getUsers() { return users; } @Override public Map registration(RegisterDto registerDto) { Map data = new HashMap<>(); - if (registerDto.getPassword().equals("") || registerDto.getPassword() == null){ + if (registerDto.getPassword().equals("") || registerDto.getPassword() == null) { data.put("error", "Missing password"); return data; } @@ -50,35 +52,42 @@ public Map registration(RegisterDto registerDto) { } @Override - public Map login(LoginDto loginDto){ + public Map login(LoginDto loginDto) { Map data = new HashMap<>(); - if (loginDto.getPassword().equals("") || loginDto.getPassword() == null){ + if (loginDto.getPassword().equals("") || loginDto.getPassword() == null) { data.put("error", "Missing password"); return data; + } else { + Optional optionalUser = users.stream().filter(user -> user.getEmail().equals(loginDto.getEmail()) && + user.getPassword().equals(loginDto.getPassword())).findFirst(); + if (optionalUser.isPresent()) { + data.put("token", "QpwL5tke4Pnpja7X4"); + return data; + } } - - data.put("token", "QpwL5tke4Pnpja7X4"); - return data; + return null; } @Override public User createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException { int id = secureRandom.nextInt(1000); - User createUser = new User(id, createUserDto.getName(), createUserDto.getJob(),Instant.now().toString(), Instant.now().toString()); + String email = createUserDto.getName() + EMAIL_DOMAIN; + User createUser = new User(id, createUserDto.getName(), createUserDto.getJob(), email, + PasswordGenerator.generateRandomPassword(), Instant.now().toString(), Instant.now().toString()); users.add(createUser); - return users.get(users.size()-1); + return users.get(users.size() - 1); } @Override - public User updateUser(Integer id, CreateUserDto createUserDto){ + public User updateUser(Integer id, CreateUserDto createUserDto) { - if (id != null){ + if (id != null) { Optional optionalUser = users.stream().filter(user -> user.getId().equals(id)).findFirst(); if (optionalUser.isPresent()) { - User currentUser = optionalUser.get(); + User currentUser = optionalUser.get(); currentUser.setUpdateAt(Instant.now().toString()); - return currentUser; + return currentUser; } } return null; diff --git a/src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java b/src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java new file mode 100644 index 0000000..5c93832 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java @@ -0,0 +1,20 @@ +package id.globallinenetwork.api.utility; + +import java.security.SecureRandom; + +public class PasswordGenerator { + public static String generateRandomPassword(){ + // ASCII range - alphanumeric (0-9, a-z, A-Z) + final String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + SecureRandom random = new SecureRandom(); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < 10; i++) { + int randomIndex = random.nextInt(chars.length()); + sb.append(chars.charAt(randomIndex)); + } + + return sb.toString(); + } +} From bf920e269def3a94a2507d946f3105eaefab559f Mon Sep 17 00:00:00 2001 From: "IDX2-03-NB\\Muhamad Nizar Iqbal" Date: Wed, 7 Oct 2020 15:32:03 +0700 Subject: [PATCH 07/13] Add method in controller to get all user data with paging Add method in controller to get all user data with paging and delayed Add method in controller and service toget single user and all user --- .../api/company/Company.java | 13 ++ .../id/globallinenetwork/api/user/IUser.java | 12 ++ .../api/user/ListAllUserDto.java | 17 ++ .../api/user/ResponseCreateUser.java | 11 -- .../api/user/ResponseSingleUser.java | 12 ++ .../id/globallinenetwork/api/user/User.java | 1 + .../api/user/UserController.java | 39 ++++- .../api/user/UserService.java | 150 +++++++++++++++++- 8 files changed, 234 insertions(+), 21 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/company/Company.java create mode 100644 src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java delete mode 100644 src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java create mode 100644 src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java diff --git a/src/main/java/id/globallinenetwork/api/company/Company.java b/src/main/java/id/globallinenetwork/api/company/Company.java new file mode 100644 index 0000000..3ea08dc --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/company/Company.java @@ -0,0 +1,13 @@ +package id.globallinenetwork.api.company; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Company { + private Integer id; + private String companyName; + private String url; + private String text; +} diff --git a/src/main/java/id/globallinenetwork/api/user/IUser.java b/src/main/java/id/globallinenetwork/api/user/IUser.java index a517fc4..19796b9 100644 --- a/src/main/java/id/globallinenetwork/api/user/IUser.java +++ b/src/main/java/id/globallinenetwork/api/user/IUser.java @@ -2,12 +2,24 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; public interface IUser { Map registration(RegisterDto registerDto); + Map login(LoginDto loginDto); + User createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException; + User updateUser(Integer id, CreateUserDto createUserDto); + boolean deleteUser(Integer id); + + Map getSingleUser(Integer id); + + ListAllUserDto getListUser(int page); + + CompletableFuture getAsyncAllUser(int delay, int page) throws InterruptedException; } diff --git a/src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java b/src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java new file mode 100644 index 0000000..4713f6f --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java @@ -0,0 +1,17 @@ +package id.globallinenetwork.api.user; + +import id.globallinenetwork.api.company.Company; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ListAllUserDto { + private int page; + private int perPage; + private int totalData; + private int totalPage; + private Map> data; + private Map companyMap; +} diff --git a/src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java b/src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java deleted file mode 100644 index c8570cf..0000000 --- a/src/main/java/id/globallinenetwork/api/user/ResponseCreateUser.java +++ /dev/null @@ -1,11 +0,0 @@ -package id.globallinenetwork.api.user; - -import lombok.Data; - -@Data -public class ResponseCreateUser { - private String name; - private String job; - private String id; - private String createdAt; -} diff --git a/src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java b/src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java new file mode 100644 index 0000000..b05e80f --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java @@ -0,0 +1,12 @@ +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class ResponseSingleUser { + private Integer id; + private String email; + private String firstName; + private String lastName; + private String avatar; +} diff --git a/src/main/java/id/globallinenetwork/api/user/User.java b/src/main/java/id/globallinenetwork/api/user/User.java index f52f96b..e53e2bb 100644 --- a/src/main/java/id/globallinenetwork/api/user/User.java +++ b/src/main/java/id/globallinenetwork/api/user/User.java @@ -11,6 +11,7 @@ public class User { private String job; private String email; private String password; + private String avatar; private String createdAt; private String updateAt; } diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index ac7e2af..30c556b 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -5,9 +5,9 @@ import org.springframework.web.bind.annotation.*; import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CompletableFuture; @RestController @RequestMapping("/api") @@ -56,7 +56,7 @@ public ResponseEntity createUser(@RequestBody CreateUserDto createUserDto){ try { return ResponseEntity.ok().body(userService.createUser(createUserDto)); - } catch (NoSuchProviderException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { data.put("error", e); e.printStackTrace(); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(data); @@ -81,4 +81,39 @@ public ResponseEntity deleteUser(@PathVariable("id") Integer id){ } return new ResponseEntity<>(HttpStatus.NO_CONTENT); } + + @GetMapping(value = "/users/{id}") + public ResponseEntity singleUser(@PathVariable("id") Integer id){ + Map data = userService.getSingleUser(id); + if (data == null) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + }else if(data.containsKey("error")){ + return new ResponseEntity<>(data, HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(data, HttpStatus.OK); + } + + @GetMapping(value = "/users/") + public ResponseEntity getAllUser(@RequestParam("page") Integer page){ + final int perPage = 6; + int start = (perPage-1)*page; + int totalData = userService.getUsers().size(); + + if (start > totalData) { + return new ResponseEntity<>(null, HttpStatus.FORBIDDEN); + }else if (totalData <= 0){ + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + } + + ListAllUserDto listUser = userService.getListUser(page); + return new ResponseEntity<>(listUser, HttpStatus.OK); + } + + @GetMapping(value = "/users/") + public CompletableFuture getDelayedUser(@RequestParam("delay") Integer delay, + @RequestParam("page") Integer page) throws InterruptedException{ + CompletableFuture listAllUserDtoCompletableFuture = + userService.getAsyncAllUser(delay, page); + return listAllUserDtoCompletableFuture; + } } diff --git a/src/main/java/id/globallinenetwork/api/user/UserService.java b/src/main/java/id/globallinenetwork/api/user/UserService.java index 816c051..a99c94c 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserService.java +++ b/src/main/java/id/globallinenetwork/api/user/UserService.java @@ -1,6 +1,8 @@ package id.globallinenetwork.api.user; +import id.globallinenetwork.api.company.Company; import id.globallinenetwork.api.utility.PasswordGenerator; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.security.NoSuchAlgorithmException; @@ -8,6 +10,7 @@ import java.security.SecureRandom; import java.time.Instant; import java.util.*; +import java.util.concurrent.CompletableFuture; @Service public class UserService implements IUser { @@ -15,6 +18,7 @@ public class UserService implements IUser { private static final String EMAIL_DOMAIN = "@globallinenetwork.com"; private final List users = new ArrayList<>(); private SecureRandom secureRandom = null; + private Company company; public UserService() { int id = 0; @@ -22,15 +26,61 @@ public UserService() { try { secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN"); id = secureRandom.nextInt(1000); + User user1 = new User(1, "Muhammad Thobroni", "CEO", "muhammad" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user2 = new User(2, "Abu Bakar", "CTO", "abu.bakar@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user3 = new User(3, "Muhamamd Umar", "Software Engineer", "umar" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user4 = new User(4, "Muhammad Usman", "FrontEnd Engineer", "usman" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user5 = new User(5, "Muhammad Ali", "Security Engineer", "ali" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user6 = new User(6, "Eve Holt", "Security Engineer", "eve.holt@reqres.in", "pistol" + , "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user7 = new User(7, "Janet Weaver", "QA", "janet.weaver@reqres.in", "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user8 = new User(8, "Michael Lawson", "Scrum Master", "michael.lawson@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user9 = new User(7, "Lindsay Ferguson", "Software Engineer", "lindsay" + + ".ferguson@reqres" + + ".in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user10 = new User(7, "Tobias Funke", "Senior Software Engineer", "tobias.funke@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user11 = new User(7, "Byron Fields", "Senior Software Engineer", "byron.fields@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + User user12 = new User(7, "George Edwards", "Senior Software Engineer", "george.edwards@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + company = new Company(secureRandom.nextInt(1000), "StatusCode " + + "Weekly", "http://statuscode.org/", + "A weekly newsletter focusing on software development, " + + "infrastructure, the server, performance, and the stack end of things."); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { e.printStackTrace(); } - User user1 = new User(1, "Muhammad", "CEO", "muhammad@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); - User user2 = new User(2, "Abu Bakar", "CTO", "abu.bakar@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); - User user3 = new User(3, "Umar", "Software Engineer", "umar@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); - User user4 = new User(4, "Usman", "FrontEnd Engineer", "usman@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); - User user5 = new User(5, "Ali", "Security Engineer", "ali@globallinenetwork.com", "fur7jf89", Instant.now().toString(), Instant.now().toString()); - User user6 = new User(6, "Eve Holt", "Security Engineer", "eve.holt@reqres.in", "pistol", Instant.now().toString(), Instant.now().toString()); } public List getUsers() { @@ -69,11 +119,12 @@ public Map login(LoginDto loginDto) { } @Override - public User createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException { + public User createUser(CreateUserDto createUserDto) throws NoSuchAlgorithmException { int id = secureRandom.nextInt(1000); String email = createUserDto.getName() + EMAIL_DOMAIN; User createUser = new User(id, createUserDto.getName(), createUserDto.getJob(), email, - PasswordGenerator.generateRandomPassword(), Instant.now().toString(), Instant.now().toString()); + PasswordGenerator.generateRandomPassword(),"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg", Instant.now().toString(), Instant.now().toString()); users.add(createUser); return users.get(users.size() - 1); @@ -97,4 +148,87 @@ public User updateUser(Integer id, CreateUserDto createUserDto) { public boolean deleteUser(Integer id) { return users.removeIf(user -> user.getId().equals(id)); } + + @Override + public Map getSingleUser(Integer id) { + Map data = new HashMap<>(); + if (id == null) { + data.put("error", "Missing id"); + return data; + } + + Optional optionalUser = users.stream().filter(user -> user.getId().equals(id)).findFirst(); + if (optionalUser.isPresent()) { + User currentUser = optionalUser.get(); + ResponseSingleUser singleUser = populateUser(currentUser); + + data.put("data", singleUser); + data.put("ad", company); + return data; + } + + return null; + } + + @Override + public ListAllUserDto getListUser(int page) { + + return populateListAllUserDto(page); + } + + private ListAllUserDto populateListAllUserDto(int page){ + Map> data = new HashMap<>(); + Map companyMap = new HashMap<>(); + ListAllUserDto allUserDto = new ListAllUserDto(); + final int perPage = 6; + + allUserDto.setPage(page); + allUserDto.setPerPage(perPage); + allUserDto.setTotalData(users.size()); + allUserDto.setTotalPage(users.size()/perPage); + + List userList = new ArrayList<>(); + for (int i = (perPage-1)*page; i < perPage*page; i++) { + User user = users.get(i); + ResponseSingleUser responseSingleUser = populateUser(user); + userList.add(responseSingleUser); + } + data.put("data", userList); + allUserDto.setData(data); + companyMap.put("ad", company); + allUserDto.setCompanyMap(companyMap); + + return allUserDto; + } + + @Override + @Async("asyncExecutor") + public CompletableFuture getAsyncAllUser(int delay, int page) throws InterruptedException { + long sleepDelay = Long.parseLong(delay+"000"); + Thread.sleep(sleepDelay); + return + + CompletableFuture.completedFuture(populateListAllUserDto(page)); + } + + private ResponseSingleUser populateUser(User currentUser){ + String firstName = ""; + String lastName = ""; + String[] arrayName = currentUser.getName().split(" "); + + if (arrayName.length>1) { + firstName = arrayName[0]; + lastName = arrayName[1]; + } + + firstName = arrayName[0]; + lastName = arrayName[0]; + ResponseSingleUser singleUser = new ResponseSingleUser(); + singleUser.setId(currentUser.getId()); + singleUser.setFirstName(firstName); + singleUser.setLastName(lastName); + singleUser.setEmail(currentUser.getEmail()); + singleUser.setAvatar(currentUser.getAvatar()); + return singleUser; + } } From 38dc475d53b81b01c1a4da0499832b8faca1eba3 Mon Sep 17 00:00:00 2001 From: "IDX2-03-NB\\Muhamad Nizar Iqbal" Date: Thu, 8 Oct 2020 08:52:31 +0700 Subject: [PATCH 08/13] Add Interface IResource Add Dto to get list all Resouce ListAllResourceDto Add model Resource Add ResourceController Add ResourceService Add method to get all user with delayed --- .../api/resource/IResource.java | 9 +++ .../api/resource/ListAllResourceDto.java | 17 ++++ .../api/resource/Resource.java | 14 ++++ .../api/resource/ResourceController.java | 32 ++++++++ .../api/resource/ResourcesService.java | 79 +++++++++++++++++++ .../api/user/UserController.java | 4 +- 6 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/resource/IResource.java create mode 100644 src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java create mode 100644 src/main/java/id/globallinenetwork/api/resource/Resource.java create mode 100644 src/main/java/id/globallinenetwork/api/resource/ResourceController.java create mode 100644 src/main/java/id/globallinenetwork/api/resource/ResourcesService.java diff --git a/src/main/java/id/globallinenetwork/api/resource/IResource.java b/src/main/java/id/globallinenetwork/api/resource/IResource.java new file mode 100644 index 0000000..fce19d0 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/resource/IResource.java @@ -0,0 +1,9 @@ +package id.globallinenetwork.api.resource; + +import java.util.List; +import java.util.Map; + +public interface IResource { + ListAllResourceDto getAllResources(int page); + Map getSingleResource(Integer id); +} diff --git a/src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java b/src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java new file mode 100644 index 0000000..7a2b109 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java @@ -0,0 +1,17 @@ +package id.globallinenetwork.api.resource; + +import id.globallinenetwork.api.company.Company; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ListAllResourceDto { + private int page; + private int perPage; + private int totalData; + private int totalPage; + private Map> data; + private Map companyMap; +} diff --git a/src/main/java/id/globallinenetwork/api/resource/Resource.java b/src/main/java/id/globallinenetwork/api/resource/Resource.java new file mode 100644 index 0000000..224b7c6 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/resource/Resource.java @@ -0,0 +1,14 @@ +package id.globallinenetwork.api.resource; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Resource { + private Integer id; + private String name; + private Integer year; + private String color; + private String pantoneValue; +} diff --git a/src/main/java/id/globallinenetwork/api/resource/ResourceController.java b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java new file mode 100644 index 0000000..fb11f71 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java @@ -0,0 +1,32 @@ +package id.globallinenetwork.api.resource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/api") +public class ResourceController { + + private final ResourcesService resourcesService; + + public ResourceController(ResourcesService resourcesService) { + this.resourcesService = resourcesService; + } + + @GetMapping(value = "/unknown/{page}") + public ResponseEntity getAllResources(@PathVariable Integer page){ + ListAllResourceDto allResourceDto = resourcesService.getAllResources(page); + List resources = resourcesService.getResources(); + if (resources.isEmpty()) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(allResourceDto, HttpStatus.OK); + } +} diff --git a/src/main/java/id/globallinenetwork/api/resource/ResourcesService.java b/src/main/java/id/globallinenetwork/api/resource/ResourcesService.java new file mode 100644 index 0000000..840d074 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/resource/ResourcesService.java @@ -0,0 +1,79 @@ +package id.globallinenetwork.api.resource; + +import id.globallinenetwork.api.company.Company; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class ResourcesService implements IResource { + private List resources = null; + private Company company = null; + + public ResourcesService(){ + resources = new ArrayList<>(); + int id = 0; + int year = 2000; + + resources.add(new Resource(++id, "cerulean", 2000, "#98B2D1", "15-4020")); + resources.add(new Resource(++id, "fuchsia rose", ++year, "#C74375", "17-2031")); + resources.add(new Resource(++id, "true read", ++year, "#BF1932", "19-1664")); + resources.add(new Resource(++id, "aqua sky", ++year, "#7BC4C4", "17-2031")); + resources.add(new Resource(++id, "tigerlily", ++year, "#E2583E", "17-1456")); + resources.add(new Resource(++id, "blue turquoise", ++year, "#53B0AE", "15-5217")); + + company = new Company(1, "StatusCode " + + "Weekly", "http://statuscode.org/", + "A weekly newsletter focusing on software development, " + + "infrastructure, the server, performance, and the stack end of things."); + } + + public List getResources(){ + return resources; + } + + @Override + public ListAllResourceDto getAllResources(int page) { + Map> data = new HashMap<>(); + Map companyMap = new HashMap<>(); + ListAllResourceDto allResourceDto = new ListAllResourceDto(); + + final int perPage = 6; + allResourceDto.setPage(page); + allResourceDto.setPerPage(perPage); + allResourceDto.setTotalData(resources.size()); + allResourceDto.setTotalPage(resources.size()/perPage); + + List resourceList = new ArrayList<>(); + for (int i = (perPage-1)*page; i < perPage*page; i++) { + Resource resource = resources.get(i); + resourceList.add(resource); + } + data.put("data", resourceList); + allResourceDto.setData(data); + companyMap.put("ad", company); + allResourceDto.setCompanyMap(companyMap); + + return allResourceDto; + } + + @Override + public Map getSingleResource(Integer id) { + Map data = new HashMap<>(); + if (id == null) { + data.put("error", "Missing id"); + return data; + } + + Optional optionalResource = + resources.stream().filter(user -> user.getId().equals(id)).findFirst(); + if (optionalResource.isPresent()) { + Resource currentResource = optionalResource.get(); + data.put("data", currentResource); + data.put("ad", company); + return data; + } + + return null; + } +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 30c556b..7b6996d 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -112,8 +112,6 @@ public ResponseEntity getAllUser(@RequestParam("page") Integer page){ @GetMapping(value = "/users/") public CompletableFuture getDelayedUser(@RequestParam("delay") Integer delay, @RequestParam("page") Integer page) throws InterruptedException{ - CompletableFuture listAllUserDtoCompletableFuture = - userService.getAsyncAllUser(delay, page); - return listAllUserDtoCompletableFuture; + return userService.getAsyncAllUser(delay, page); } } From 15c7734abbdb4a94363e4c5f3e515eede3726326 Mon Sep 17 00:00:00 2001 From: "IDX2-03-NB\\Muhamad Nizar Iqbal" Date: Thu, 8 Oct 2020 09:07:35 +0700 Subject: [PATCH 09/13] Change return method getSingleResource Separate return type of single user with class GetSingleData and static method to return response entity --- .../api/resource/IResource.java | 1 - .../api/resource/ResourceController.java | 13 +++++++++++-- .../api/user/UserController.java | 8 ++------ .../api/utility/GetSingleData.java | 17 +++++++++++++++++ 4 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/utility/GetSingleData.java diff --git a/src/main/java/id/globallinenetwork/api/resource/IResource.java b/src/main/java/id/globallinenetwork/api/resource/IResource.java index fce19d0..bb65d6c 100644 --- a/src/main/java/id/globallinenetwork/api/resource/IResource.java +++ b/src/main/java/id/globallinenetwork/api/resource/IResource.java @@ -1,6 +1,5 @@ package id.globallinenetwork.api.resource; -import java.util.List; import java.util.Map; public interface IResource { diff --git a/src/main/java/id/globallinenetwork/api/resource/ResourceController.java b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java index fb11f71..a0f1c10 100644 --- a/src/main/java/id/globallinenetwork/api/resource/ResourceController.java +++ b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java @@ -1,6 +1,6 @@ package id.globallinenetwork.api.resource; -import org.springframework.beans.factory.annotation.Autowired; +import id.globallinenetwork.api.utility.GetSingleData; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.Map; @RestController @RequestMapping("/api") @@ -21,7 +22,7 @@ public ResourceController(ResourcesService resourcesService) { } @GetMapping(value = "/unknown/{page}") - public ResponseEntity getAllResources(@PathVariable Integer page){ + public ResponseEntity getAllResources(@PathVariable Integer page) { ListAllResourceDto allResourceDto = resourcesService.getAllResources(page); List resources = resourcesService.getResources(); if (resources.isEmpty()) { @@ -29,4 +30,12 @@ public ResponseEntity getAllResources(@PathVariable Integer } return new ResponseEntity<>(allResourceDto, HttpStatus.OK); } + + @GetMapping(value = "/unknown/{id}") + public ResponseEntity getSingleResource(@PathVariable Integer id) { + Map resource = resourcesService.getSingleResource(id); + return GetSingleData.getResponseEntity(resource); + } + + } diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 7b6996d..4322333 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -1,5 +1,6 @@ package id.globallinenetwork.api.user; +import id.globallinenetwork.api.utility.GetSingleData; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -85,12 +86,7 @@ public ResponseEntity deleteUser(@PathVariable("id") Integer id){ @GetMapping(value = "/users/{id}") public ResponseEntity singleUser(@PathVariable("id") Integer id){ Map data = userService.getSingleUser(id); - if (data == null) { - return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); - }else if(data.containsKey("error")){ - return new ResponseEntity<>(data, HttpStatus.BAD_REQUEST); - } - return new ResponseEntity<>(data, HttpStatus.OK); + return GetSingleData.getResponseEntity(data); } @GetMapping(value = "/users/") diff --git a/src/main/java/id/globallinenetwork/api/utility/GetSingleData.java b/src/main/java/id/globallinenetwork/api/utility/GetSingleData.java new file mode 100644 index 0000000..435dbf4 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/utility/GetSingleData.java @@ -0,0 +1,17 @@ +package id.globallinenetwork.api.utility; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.util.Map; + +public class GetSingleData { + public static ResponseEntity getResponseEntity(Map data) { + if (data == null) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + } else if (data.containsKey("error")) { + return new ResponseEntity<>(data, HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(data, HttpStatus.OK); + } +} From e977f1eab804e1c4278d90a0b3ba3b81241ba503 Mon Sep 17 00:00:00 2001 From: IQBAL Date: Fri, 9 Oct 2020 11:11:40 +0700 Subject: [PATCH 10/13] All Service and Controller already tested on postman For the Spring boot test it reach until rest of update user --- .gitignore | 66 +- .mvn/wrapper/MavenWrapperDownloader.java | 234 +++---- .mvn/wrapper/maven-wrapper.properties | 4 +- README.md | 106 +-- mvnw | 620 +++++++++--------- mvnw.cmd | 364 +++++----- pom.xml | 184 +++--- .../api/GlobalLineNetworkApplication.java | 24 +- .../api/company/Company.java | 26 +- .../api/component/DataComponent.java | 30 + .../api/resource/IResource.java | 16 +- .../api/resource/ListAllResourceDto.java | 34 +- .../api/resource/Resource.java | 28 +- .../api/resource/ResourceController.java | 82 +-- .../api/resource/ResourcesService.java | 158 ++--- .../api/user/CreateUserDto.java | 16 +- .../id/globallinenetwork/api/user/IUser.java | 50 +- .../api/user/ListAllUserDto.java | 34 +- .../globallinenetwork/api/user/LoginDto.java | 14 +- .../api/user/RegisterDto.java | 18 +- .../api/user/ResponseSingleUser.java | 24 +- .../api/user/ResponseUpdateUser.java | 20 +- .../id/globallinenetwork/api/user/User.java | 34 +- .../api/user/UserController.java | 231 +++---- .../api/user/UserService.java | 529 ++++++++------- .../api/utility/GetSingleData.java | 34 +- .../api/utility/PasswordGenerator.java | 40 +- src/main/resources/application.properties | 2 +- .../GlobalLineNetworkApplicationTests.java | 45 +- .../api/controller/UserControllerTest.java | 303 +++++++-- 30 files changed, 1817 insertions(+), 1553 deletions(-) create mode 100644 src/main/java/id/globallinenetwork/api/component/DataComponent.java diff --git a/.gitignore b/.gitignore index 549e00a..7bc4bf7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,33 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java index e76d1f3..ecf77ce 100644 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -1,117 +1,117 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed 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 - * - * https://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 java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} +/* + * Copyright 2007-present the original author or authors. + * + * Licensed 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 + * + * https://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 java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 642d572..5dd3024 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,2 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/README.md b/README.md index 96104f2..d883c3c 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,53 @@ -

- -

- -Thanks for taking the time to do our front-end / full-stack practical coding challenge. - -The objective of this challenge is to evaluate your domain knowledge in front-end / full-stack development: code organization, style and best practices. - -# Overview: - -# This is the Backend from Me Muhamad Nizar Iqbal - -## List of API - -- Register /api/register -- Login /api/login -- Create /api/users - -### Prerequisites - -There are none :) Our main solutions stack include but not limited to Kotlin, Java, AngularJS, Flutter, Spring... -Feel free to use any languages and technologies you are comfortable with. - -## Mockups - -

- - - -

- -### Front-end: - -- For API please use https://reqres.in/. - -### Back-end: - -- The API should be similar to https://reqres.in/, performing basic operations for user. - -_We'll be happy if you cover application with tests._ - -### Submission Guidelines - -- Please fork the repo and then submit a Pull Request when you are done. -- Instructions must be provided to run the application, install any dependencies, and any other information needed. -- Please use version control and make sure we can see the history of how you went about it, rather than just uploading the complete project to GitHub. - -## Questions? - -Please feel free to reach out and ask any questions while you are working on a solution. -Send your questions to [tech@chimaera.my](mailto:tech@chimaera.my). - -Good luck! +

+ +

+ +Thanks for taking the time to do our front-end / full-stack practical coding challenge. + +The objective of this challenge is to evaluate your domain knowledge in front-end / full-stack development: code organization, style and best practices. + +# Overview: + +# This is the Backend from Me Muhamad Nizar Iqbal + +## List of API + +- Register /api/register +- Login /api/login +- Create /api/users + +### Prerequisites + +There are none :) Our main solutions stack include but not limited to Kotlin, Java, AngularJS, Flutter, Spring... +Feel free to use any languages and technologies you are comfortable with. + +## Mockups + +

+ + + +

+ +### Front-end: + +- For API please use https://reqres.in/. + +### Back-end: + +- The API should be similar to https://reqres.in/, performing basic operations for user. + +_We'll be happy if you cover application with tests._ + +### Submission Guidelines + +- Please fork the repo and then submit a Pull Request when you are done. +- Instructions must be provided to run the application, install any dependencies, and any other information needed. +- Please use version control and make sure we can see the history of how you went about it, rather than just uploading the complete project to GitHub. + +## Questions? + +Please feel free to reach out and ask any questions while you are working on a solution. +Send your questions to [tech@chimaera.my](mailto:tech@chimaera.my). + +Good luck! diff --git a/mvnw b/mvnw index a16b543..4c1c427 100755 --- a/mvnw +++ b/mvnw @@ -1,310 +1,310 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# 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 -# -# https://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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +#!/bin/sh +# ---------------------------------------------------------------------------- +# 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 +# +# https://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index c8d4337..66db70c 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,182 +1,182 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 351396c..47009d1 100644 --- a/pom.xml +++ b/pom.xml @@ -1,92 +1,92 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.3.4.RELEASE - - - id. - global-line-network - 0.0.1-SNAPSHOT - global-line-network - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-devtools - runtime - true - - - org.postgresql - postgresql - runtime - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.security - spring-security-test - test - - - junit - junit - 4.12 - test - - - org.mockito - mockito-core - 3.5.13 - test - - - com.google.code.gson - gson - 2.8.6 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.4.RELEASE + + + id. + global-line-network + 0.0.1-SNAPSHOT + global-line-network + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.springframework.security + spring-security-test + test + + + junit + junit + 4.12 + test + + + org.mockito + mockito-core + 3.5.13 + test + + + com.google.code.gson + gson + 2.8.6 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java b/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java index da5e821..31abbc7 100644 --- a/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java +++ b/src/main/java/id/globallinenetwork/api/GlobalLineNetworkApplication.java @@ -1,12 +1,12 @@ -package id.globallinenetwork.api; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class GlobalLineNetworkApplication { - - public static void main(String[] args) { - SpringApplication.run(GlobalLineNetworkApplication.class, args); - } -} +package id.globallinenetwork.api; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class GlobalLineNetworkApplication { + + public static void main(String[] args) { + SpringApplication.run(GlobalLineNetworkApplication.class, args); + } +} diff --git a/src/main/java/id/globallinenetwork/api/company/Company.java b/src/main/java/id/globallinenetwork/api/company/Company.java index 3ea08dc..1021326 100644 --- a/src/main/java/id/globallinenetwork/api/company/Company.java +++ b/src/main/java/id/globallinenetwork/api/company/Company.java @@ -1,13 +1,13 @@ -package id.globallinenetwork.api.company; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class Company { - private Integer id; - private String companyName; - private String url; - private String text; -} +package id.globallinenetwork.api.company; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Company { + private Integer id; + private String companyName; + private String url; + private String text; +} diff --git a/src/main/java/id/globallinenetwork/api/component/DataComponent.java b/src/main/java/id/globallinenetwork/api/component/DataComponent.java new file mode 100644 index 0000000..11d4204 --- /dev/null +++ b/src/main/java/id/globallinenetwork/api/component/DataComponent.java @@ -0,0 +1,30 @@ +package id.globallinenetwork.api.component; + +import id.globallinenetwork.api.resource.ResourcesService; +import id.globallinenetwork.api.user.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class DataComponent { + + private final UserService userService; + private final ResourcesService resourcesService; + + public DataComponent(UserService userService, ResourcesService resourcesService) { + this.userService = userService; + this.resourcesService = resourcesService; + } + + @PostConstruct + public void initDataUserService(){ + userService.initializeData(); + } + + @PostConstruct + void initDataResourceService(){ + resourcesService.initializeData(); + } +} diff --git a/src/main/java/id/globallinenetwork/api/resource/IResource.java b/src/main/java/id/globallinenetwork/api/resource/IResource.java index bb65d6c..b6ccb91 100644 --- a/src/main/java/id/globallinenetwork/api/resource/IResource.java +++ b/src/main/java/id/globallinenetwork/api/resource/IResource.java @@ -1,8 +1,8 @@ -package id.globallinenetwork.api.resource; - -import java.util.Map; - -public interface IResource { - ListAllResourceDto getAllResources(int page); - Map getSingleResource(Integer id); -} +package id.globallinenetwork.api.resource; + +import java.util.Map; + +public interface IResource { + ListAllResourceDto getAllResources(int page); + Map getSingleResource(Integer id); +} diff --git a/src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java b/src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java index 7a2b109..4fdf044 100644 --- a/src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java +++ b/src/main/java/id/globallinenetwork/api/resource/ListAllResourceDto.java @@ -1,17 +1,17 @@ -package id.globallinenetwork.api.resource; - -import id.globallinenetwork.api.company.Company; -import lombok.Data; - -import java.util.List; -import java.util.Map; - -@Data -public class ListAllResourceDto { - private int page; - private int perPage; - private int totalData; - private int totalPage; - private Map> data; - private Map companyMap; -} +package id.globallinenetwork.api.resource; + +import id.globallinenetwork.api.company.Company; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ListAllResourceDto { + private int page; + private int perPage; + private int totalData; + private int totalPage; + private Map> data; + private Map companyMap; +} diff --git a/src/main/java/id/globallinenetwork/api/resource/Resource.java b/src/main/java/id/globallinenetwork/api/resource/Resource.java index 224b7c6..1acfba7 100644 --- a/src/main/java/id/globallinenetwork/api/resource/Resource.java +++ b/src/main/java/id/globallinenetwork/api/resource/Resource.java @@ -1,14 +1,14 @@ -package id.globallinenetwork.api.resource; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class Resource { - private Integer id; - private String name; - private Integer year; - private String color; - private String pantoneValue; -} +package id.globallinenetwork.api.resource; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Resource { + private Integer id; + private String name; + private Integer year; + private String color; + private String pantoneValue; +} diff --git a/src/main/java/id/globallinenetwork/api/resource/ResourceController.java b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java index a0f1c10..ce4112b 100644 --- a/src/main/java/id/globallinenetwork/api/resource/ResourceController.java +++ b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java @@ -1,41 +1,41 @@ -package id.globallinenetwork.api.resource; - -import id.globallinenetwork.api.utility.GetSingleData; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; -import java.util.Map; - -@RestController -@RequestMapping("/api") -public class ResourceController { - - private final ResourcesService resourcesService; - - public ResourceController(ResourcesService resourcesService) { - this.resourcesService = resourcesService; - } - - @GetMapping(value = "/unknown/{page}") - public ResponseEntity getAllResources(@PathVariable Integer page) { - ListAllResourceDto allResourceDto = resourcesService.getAllResources(page); - List resources = resourcesService.getResources(); - if (resources.isEmpty()) { - return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); - } - return new ResponseEntity<>(allResourceDto, HttpStatus.OK); - } - - @GetMapping(value = "/unknown/{id}") - public ResponseEntity getSingleResource(@PathVariable Integer id) { - Map resource = resourcesService.getSingleResource(id); - return GetSingleData.getResponseEntity(resource); - } - - -} +package id.globallinenetwork.api.resource; + +import id.globallinenetwork.api.utility.GetSingleData; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/api") +public class ResourceController { + + private final ResourcesService resourcesService; + + public ResourceController(ResourcesService resourcesService) { + this.resourcesService = resourcesService; + } + + @GetMapping(value = "/unknown/{page}") + public ResponseEntity getAllResources(@PathVariable Integer page) { + ListAllResourceDto allResourceDto = resourcesService.getAllResources(page); + List resources = resourcesService.getResources(); + if (resources.isEmpty()) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(allResourceDto, HttpStatus.OK); + } + + @GetMapping(value = "/unknown/{id}") + public ResponseEntity getSingleResource(@PathVariable Integer id) { + Map resource = resourcesService.getSingleResource(id); + return GetSingleData.getResponseEntity(resource); + } + + +} diff --git a/src/main/java/id/globallinenetwork/api/resource/ResourcesService.java b/src/main/java/id/globallinenetwork/api/resource/ResourcesService.java index 840d074..a157fd3 100644 --- a/src/main/java/id/globallinenetwork/api/resource/ResourcesService.java +++ b/src/main/java/id/globallinenetwork/api/resource/ResourcesService.java @@ -1,79 +1,79 @@ -package id.globallinenetwork.api.resource; - -import id.globallinenetwork.api.company.Company; -import org.springframework.stereotype.Service; - -import java.util.*; - -@Service -public class ResourcesService implements IResource { - private List resources = null; - private Company company = null; - - public ResourcesService(){ - resources = new ArrayList<>(); - int id = 0; - int year = 2000; - - resources.add(new Resource(++id, "cerulean", 2000, "#98B2D1", "15-4020")); - resources.add(new Resource(++id, "fuchsia rose", ++year, "#C74375", "17-2031")); - resources.add(new Resource(++id, "true read", ++year, "#BF1932", "19-1664")); - resources.add(new Resource(++id, "aqua sky", ++year, "#7BC4C4", "17-2031")); - resources.add(new Resource(++id, "tigerlily", ++year, "#E2583E", "17-1456")); - resources.add(new Resource(++id, "blue turquoise", ++year, "#53B0AE", "15-5217")); - - company = new Company(1, "StatusCode " + - "Weekly", "http://statuscode.org/", - "A weekly newsletter focusing on software development, " + - "infrastructure, the server, performance, and the stack end of things."); - } - - public List getResources(){ - return resources; - } - - @Override - public ListAllResourceDto getAllResources(int page) { - Map> data = new HashMap<>(); - Map companyMap = new HashMap<>(); - ListAllResourceDto allResourceDto = new ListAllResourceDto(); - - final int perPage = 6; - allResourceDto.setPage(page); - allResourceDto.setPerPage(perPage); - allResourceDto.setTotalData(resources.size()); - allResourceDto.setTotalPage(resources.size()/perPage); - - List resourceList = new ArrayList<>(); - for (int i = (perPage-1)*page; i < perPage*page; i++) { - Resource resource = resources.get(i); - resourceList.add(resource); - } - data.put("data", resourceList); - allResourceDto.setData(data); - companyMap.put("ad", company); - allResourceDto.setCompanyMap(companyMap); - - return allResourceDto; - } - - @Override - public Map getSingleResource(Integer id) { - Map data = new HashMap<>(); - if (id == null) { - data.put("error", "Missing id"); - return data; - } - - Optional optionalResource = - resources.stream().filter(user -> user.getId().equals(id)).findFirst(); - if (optionalResource.isPresent()) { - Resource currentResource = optionalResource.get(); - data.put("data", currentResource); - data.put("ad", company); - return data; - } - - return null; - } -} +package id.globallinenetwork.api.resource; + +import id.globallinenetwork.api.company.Company; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class ResourcesService implements IResource { + private List resources = null; + private Company company = null; + + public void initializeData(){ + resources = new ArrayList<>(); + int id = 0; + int year = 2000; + + resources.add(new Resource(++id, "cerulean", 2000, "#98B2D1", "15-4020")); + resources.add(new Resource(++id, "fuchsia rose", ++year, "#C74375", "17-2031")); + resources.add(new Resource(++id, "true read", ++year, "#BF1932", "19-1664")); + resources.add(new Resource(++id, "aqua sky", ++year, "#7BC4C4", "17-2031")); + resources.add(new Resource(++id, "tigerlily", ++year, "#E2583E", "17-1456")); + resources.add(new Resource(++id, "blue turquoise", ++year, "#53B0AE", "15-5217")); + + company = new Company(1, "StatusCode " + + "Weekly", "http://statuscode.org/", + "A weekly newsletter focusing on software development, " + + "infrastructure, the server, performance, and the stack end of things."); + } + + public List getResources(){ + return resources; + } + + @Override + public ListAllResourceDto getAllResources(int page) { + Map> data = new HashMap<>(); + Map companyMap = new HashMap<>(); + ListAllResourceDto allResourceDto = new ListAllResourceDto(); + + final int perPage = 6; + allResourceDto.setPage(page); + allResourceDto.setPerPage(perPage); + allResourceDto.setTotalData(resources.size()); + allResourceDto.setTotalPage(resources.size()/perPage); + + List resourceList = new ArrayList<>(); + for (int i = (perPage-1)*page; i < perPage*page; i++) { + Resource resource = resources.get(i); + resourceList.add(resource); + } + data.put("data", resourceList); + allResourceDto.setData(data); + companyMap.put("ad", company); + allResourceDto.setCompanyMap(companyMap); + + return allResourceDto; + } + + @Override + public Map getSingleResource(Integer id) { + Map data = new HashMap<>(); + if (id == null) { + data.put("error", "Missing id"); + return data; + } + + Optional optionalResource = + resources.stream().filter(user -> user.getId().equals(id)).findFirst(); + if (optionalResource.isPresent()) { + Resource currentResource = optionalResource.get(); + data.put("data", currentResource); + data.put("ad", company); + return data; + } + + return null; + } +} diff --git a/src/main/java/id/globallinenetwork/api/user/CreateUserDto.java b/src/main/java/id/globallinenetwork/api/user/CreateUserDto.java index 257cce9..ee8e32c 100644 --- a/src/main/java/id/globallinenetwork/api/user/CreateUserDto.java +++ b/src/main/java/id/globallinenetwork/api/user/CreateUserDto.java @@ -1,9 +1,9 @@ -package id.globallinenetwork.api.user; - -import lombok.Data; - -@Data -public class CreateUserDto{ - private String name; - private String job; +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class CreateUserDto{ + private String name; + private String job; } \ No newline at end of file diff --git a/src/main/java/id/globallinenetwork/api/user/IUser.java b/src/main/java/id/globallinenetwork/api/user/IUser.java index 19796b9..8b4a2b3 100644 --- a/src/main/java/id/globallinenetwork/api/user/IUser.java +++ b/src/main/java/id/globallinenetwork/api/user/IUser.java @@ -1,25 +1,25 @@ -package id.globallinenetwork.api.user; - -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -public interface IUser { - Map registration(RegisterDto registerDto); - - Map login(LoginDto loginDto); - - User createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException; - - User updateUser(Integer id, CreateUserDto createUserDto); - - boolean deleteUser(Integer id); - - Map getSingleUser(Integer id); - - ListAllUserDto getListUser(int page); - - CompletableFuture getAsyncAllUser(int delay, int page) throws InterruptedException; -} +package id.globallinenetwork.api.user; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +public interface IUser { + Map registration(RegisterDto registerDto); + + Map login(LoginDto loginDto); + + User createUser(CreateUserDto createUserDto) throws NoSuchProviderException, NoSuchAlgorithmException; + + User updateUser(Integer id, CreateUserDto createUserDto); + + boolean deleteUser(Integer id); + + Map getSingleUser(Integer id); + + ListAllUserDto getListUser(int page); + + CompletableFuture getAsyncAllUser(int delay, int page) throws InterruptedException; +} diff --git a/src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java b/src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java index 4713f6f..eb7907b 100644 --- a/src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java +++ b/src/main/java/id/globallinenetwork/api/user/ListAllUserDto.java @@ -1,17 +1,17 @@ -package id.globallinenetwork.api.user; - -import id.globallinenetwork.api.company.Company; -import lombok.Data; - -import java.util.List; -import java.util.Map; - -@Data -public class ListAllUserDto { - private int page; - private int perPage; - private int totalData; - private int totalPage; - private Map> data; - private Map companyMap; -} +package id.globallinenetwork.api.user; + +import id.globallinenetwork.api.company.Company; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ListAllUserDto { + private int page; + private int perPage; + private int totalData; + private int totalPage; + private Map> data; + private Map companyMap; +} diff --git a/src/main/java/id/globallinenetwork/api/user/LoginDto.java b/src/main/java/id/globallinenetwork/api/user/LoginDto.java index d10034b..9f3cf7e 100644 --- a/src/main/java/id/globallinenetwork/api/user/LoginDto.java +++ b/src/main/java/id/globallinenetwork/api/user/LoginDto.java @@ -1,7 +1,9 @@ -package id.globallinenetwork.api.user; - -@Data -public class LoginDto{ - private String email; - private String password; +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class LoginDto{ + private String email; + private String password; } \ No newline at end of file diff --git a/src/main/java/id/globallinenetwork/api/user/RegisterDto.java b/src/main/java/id/globallinenetwork/api/user/RegisterDto.java index 7c67864..e87f7b7 100644 --- a/src/main/java/id/globallinenetwork/api/user/RegisterDto.java +++ b/src/main/java/id/globallinenetwork/api/user/RegisterDto.java @@ -1,9 +1,9 @@ -package id.globallinenetwork.api.user; - -import lombok.Data; - -@Data -public class RegisterDto { - private String email; - private String password; -} +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class RegisterDto { + private String email; + private String password; +} diff --git a/src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java b/src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java index b05e80f..df1840e 100644 --- a/src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java +++ b/src/main/java/id/globallinenetwork/api/user/ResponseSingleUser.java @@ -1,12 +1,12 @@ -package id.globallinenetwork.api.user; - -import lombok.Data; - -@Data -public class ResponseSingleUser { - private Integer id; - private String email; - private String firstName; - private String lastName; - private String avatar; -} +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class ResponseSingleUser { + private Integer id; + private String email; + private String firstName; + private String lastName; + private String avatar; +} diff --git a/src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java b/src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java index 818bca6..5f4670d 100644 --- a/src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java +++ b/src/main/java/id/globallinenetwork/api/user/ResponseUpdateUser.java @@ -1,10 +1,10 @@ -package id.globallinenetwork.api.user; - -import lombok.Data; - -@Data -public class ResponseUpdateUser { - private String name; - private String job; - private String updatedAt; -} +package id.globallinenetwork.api.user; + +import lombok.Data; + +@Data +public class ResponseUpdateUser { + private String name; + private String job; + private String updatedAt; +} diff --git a/src/main/java/id/globallinenetwork/api/user/User.java b/src/main/java/id/globallinenetwork/api/user/User.java index e53e2bb..6875e62 100644 --- a/src/main/java/id/globallinenetwork/api/user/User.java +++ b/src/main/java/id/globallinenetwork/api/user/User.java @@ -1,17 +1,17 @@ -package id.globallinenetwork.api.user; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class User { - private Integer id; - private String name; - private String job; - private String email; - private String password; - private String avatar; - private String createdAt; - private String updateAt; -} +package id.globallinenetwork.api.user; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class User { + private Integer id; + private String name; + private String job; + private String email; + private String password; + private String avatar; + private String createdAt; + private String updateAt; +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserController.java b/src/main/java/id/globallinenetwork/api/user/UserController.java index 4322333..312ddc5 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserController.java +++ b/src/main/java/id/globallinenetwork/api/user/UserController.java @@ -1,113 +1,118 @@ -package id.globallinenetwork.api.user; - -import id.globallinenetwork.api.utility.GetSingleData; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -@RestController -@RequestMapping("/api") -public class UserController { - - private final UserService userService; - - public UserController(UserService userService) { - this.userService = userService; - } - - @PostMapping("/register") - public ResponseEntity register(@RequestBody RegisterDto registerDto){ - Map data = userService.registration(registerDto); - if (data.containsKey("id")){ - return ResponseEntity.ok().body(data); - } - - return ResponseEntity.badRequest().body(data); - } - - @PostMapping("/login") - public ResponseEntity login(@RequestBody LoginDto loginDto){ - Map data = userService.login(loginDto); - if (data == null) { - return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); - }else if (data.containsKey("token")){ - return ResponseEntity.ok().body(data); - } - - return ResponseEntity.badRequest().body(data); - } - - @PostMapping("/users") - public ResponseEntity createUser(@RequestBody CreateUserDto createUserDto){ - Map data = new HashMap<>(); - if (createUserDto.getName().equals("") || createUserDto.getName() == null){ - data.put("error:", "Missing name"); - return ResponseEntity.badRequest().body(data); - } - - if (createUserDto.getJob().equals("") || createUserDto.getJob() == null){ - data.put("error:", "Missing Job"); - return ResponseEntity.badRequest().body(data); - } - - try { - return ResponseEntity.ok().body(userService.createUser(createUserDto)); - } catch (NoSuchAlgorithmException e) { - data.put("error", e); - e.printStackTrace(); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(data); - } - } - - @RequestMapping(value = "/users/{id}", method = {RequestMethod.PATCH, RequestMethod.PUT}) - public ResponseEntity updateUser(@PathVariable("id") Integer id, @RequestBody CreateUserDto createUserDto){ - User result = userService.updateUser(id, createUserDto); - Map data = new HashMap<>(); - if (result == null) { - data.put("error:","Missing id"); - return ResponseEntity.badRequest().body(data); - } - return ResponseEntity.ok().body(result); - } - - @DeleteMapping(value = "/users/{id}") - public ResponseEntity deleteUser(@PathVariable("id") Integer id){ - if (userService.deleteUser(id)) { - return new ResponseEntity<>(HttpStatus.OK); - } - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - @GetMapping(value = "/users/{id}") - public ResponseEntity singleUser(@PathVariable("id") Integer id){ - Map data = userService.getSingleUser(id); - return GetSingleData.getResponseEntity(data); - } - - @GetMapping(value = "/users/") - public ResponseEntity getAllUser(@RequestParam("page") Integer page){ - final int perPage = 6; - int start = (perPage-1)*page; - int totalData = userService.getUsers().size(); - - if (start > totalData) { - return new ResponseEntity<>(null, HttpStatus.FORBIDDEN); - }else if (totalData <= 0){ - return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); - } - - ListAllUserDto listUser = userService.getListUser(page); - return new ResponseEntity<>(listUser, HttpStatus.OK); - } - - @GetMapping(value = "/users/") - public CompletableFuture getDelayedUser(@RequestParam("delay") Integer delay, - @RequestParam("page") Integer page) throws InterruptedException{ - return userService.getAsyncAllUser(delay, page); - } -} +package id.globallinenetwork.api.user; + +import id.globallinenetwork.api.utility.GetSingleData; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/api") +public class UserController { + + private final UserService userService; + + public UserController(UserService userService) { + this.userService = userService; + } + + @PostMapping("/register") + public ResponseEntity register(@RequestBody RegisterDto registerDto){ + Map data = userService.registration(registerDto); + if (data.containsKey("id")){ + return ResponseEntity.ok().body(data); + } + + return ResponseEntity.badRequest().body(data); + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody LoginDto loginDto){ + Map data = userService.login(loginDto); + if (data == null) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + }else if (data.containsKey("token")){ + return ResponseEntity.ok().body(data); + } + + return ResponseEntity.badRequest().body(data); + } + + @PostMapping("/users") + public ResponseEntity createUser(@RequestBody CreateUserDto createUserDto){ + Map data = new HashMap<>(); + if (createUserDto.getName().equals("") || createUserDto.getName() == null){ + data.put("error:", "Missing name"); + return ResponseEntity.badRequest().body(data); + } + + if (createUserDto.getJob().equals("") || createUserDto.getJob() == null){ + data.put("error:", "Missing Job"); + return ResponseEntity.badRequest().body(data); + } + + try { + return ResponseEntity.ok().body(userService.createUser(createUserDto)); + } catch (NoSuchAlgorithmException e) { + data.put("error", e); + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(data); + } + } + + @RequestMapping(value = "/users/{id}", method = {RequestMethod.PATCH, RequestMethod.PUT}) + public ResponseEntity updateUser(@PathVariable("id") Integer id, @RequestBody CreateUserDto createUserDto){ + User result = userService.updateUser(id, createUserDto); + Map data = new HashMap<>(); + if (result == null) { + data.put("error:","Missing id"); + return ResponseEntity.badRequest().body(data); + } + return ResponseEntity.ok().body(result); + } + + @DeleteMapping(value = "/users/{id}") + public ResponseEntity deleteUser(@PathVariable("id") Integer id){ + if (userService.deleteUser(id)) { + return new ResponseEntity<>(HttpStatus.OK); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @GetMapping(value = "/users/{id}") + public ResponseEntity singleUser(@PathVariable("id") Integer id){ + Map data = userService.getSingleUser(id); + return GetSingleData.getResponseEntity(data); + } + + @GetMapping(value = "/users") + public ResponseEntity getAllUser(@RequestParam("page") Optional page, + @RequestParam("delay") Optional delay) throws InterruptedException, ExecutionException { + if (delay.isPresent()){ + return new ResponseEntity<>(userService.getAsyncAllUser(delay.get(), 1).get(), + HttpStatus.OK); + }else { + ListAllUserDto listUser = null; + if (page.isPresent()){ + final int perPage = 6; + int start = (perPage - 1) * page.get(); + int totalData = userService.getUsers().size(); + + if (start > totalData) { + return new ResponseEntity<>(null, HttpStatus.FORBIDDEN); + } else if (totalData <= 0) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + } + listUser = userService.getListUser(page.get()); + } + + return new ResponseEntity<>(listUser, HttpStatus.OK); + } + } +} diff --git a/src/main/java/id/globallinenetwork/api/user/UserService.java b/src/main/java/id/globallinenetwork/api/user/UserService.java index a99c94c..1bfa733 100644 --- a/src/main/java/id/globallinenetwork/api/user/UserService.java +++ b/src/main/java/id/globallinenetwork/api/user/UserService.java @@ -1,234 +1,295 @@ -package id.globallinenetwork.api.user; - -import id.globallinenetwork.api.company.Company; -import id.globallinenetwork.api.utility.PasswordGenerator; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; - -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SecureRandom; -import java.time.Instant; -import java.util.*; -import java.util.concurrent.CompletableFuture; - -@Service -public class UserService implements IUser { - - private static final String EMAIL_DOMAIN = "@globallinenetwork.com"; - private final List users = new ArrayList<>(); - private SecureRandom secureRandom = null; - private Company company; - - public UserService() { - int id = 0; - - try { - secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN"); - id = secureRandom.nextInt(1000); - User user1 = new User(1, "Muhammad Thobroni", "CEO", "muhammad" + - "@globallinenetwork.com", "fur7jf89", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user2 = new User(2, "Abu Bakar", "CTO", "abu.bakar@globallinenetwork.com", "fur7jf89", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user3 = new User(3, "Muhamamd Umar", "Software Engineer", "umar" + - "@globallinenetwork.com", "fur7jf89", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user4 = new User(4, "Muhammad Usman", "FrontEnd Engineer", "usman" + - "@globallinenetwork.com", "fur7jf89", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user5 = new User(5, "Muhammad Ali", "Security Engineer", "ali" + - "@globallinenetwork.com", "fur7jf89", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user6 = new User(6, "Eve Holt", "Security Engineer", "eve.holt@reqres.in", "pistol" - , "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user7 = new User(7, "Janet Weaver", "QA", "janet.weaver@reqres.in", "pistol", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user8 = new User(8, "Michael Lawson", "Scrum Master", "michael.lawson@reqres.in", - "pistol", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user9 = new User(7, "Lindsay Ferguson", "Software Engineer", "lindsay" + - ".ferguson@reqres" + - ".in", - "pistol", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user10 = new User(7, "Tobias Funke", "Senior Software Engineer", "tobias.funke@reqres.in", - "pistol", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user11 = new User(7, "Byron Fields", "Senior Software Engineer", "byron.fields@reqres.in", - "pistol", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - User user12 = new User(7, "George Edwards", "Senior Software Engineer", "george.edwards@reqres.in", - "pistol", - "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg",Instant.now().toString(), Instant.now().toString()); - - company = new Company(secureRandom.nextInt(1000), "StatusCode " + - "Weekly", "http://statuscode.org/", - "A weekly newsletter focusing on software development, " + - "infrastructure, the server, performance, and the stack end of things."); - } catch (NoSuchAlgorithmException | NoSuchProviderException e) { - e.printStackTrace(); - } - } - - public List getUsers() { - return users; - } - - @Override - public Map registration(RegisterDto registerDto) { - Map data = new HashMap<>(); - if (registerDto.getPassword().equals("") || registerDto.getPassword() == null) { - data.put("error", "Missing password"); - return data; - } - - data.put("id", 4); - data.put("token", "QpwL5tke4Pnpja7X4"); - - return data; - } - - @Override - public Map login(LoginDto loginDto) { - Map data = new HashMap<>(); - if (loginDto.getPassword().equals("") || loginDto.getPassword() == null) { - data.put("error", "Missing password"); - return data; - } else { - Optional optionalUser = users.stream().filter(user -> user.getEmail().equals(loginDto.getEmail()) && - user.getPassword().equals(loginDto.getPassword())).findFirst(); - if (optionalUser.isPresent()) { - data.put("token", "QpwL5tke4Pnpja7X4"); - return data; - } - } - return null; - } - - @Override - public User createUser(CreateUserDto createUserDto) throws NoSuchAlgorithmException { - int id = secureRandom.nextInt(1000); - String email = createUserDto.getName() + EMAIL_DOMAIN; - User createUser = new User(id, createUserDto.getName(), createUserDto.getJob(), email, - PasswordGenerator.generateRandomPassword(),"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + - ".jpg", Instant.now().toString(), Instant.now().toString()); - users.add(createUser); - - return users.get(users.size() - 1); - } - - @Override - public User updateUser(Integer id, CreateUserDto createUserDto) { - - if (id != null) { - Optional optionalUser = users.stream().filter(user -> user.getId().equals(id)).findFirst(); - if (optionalUser.isPresent()) { - User currentUser = optionalUser.get(); - currentUser.setUpdateAt(Instant.now().toString()); - return currentUser; - } - } - return null; - } - - @Override - public boolean deleteUser(Integer id) { - return users.removeIf(user -> user.getId().equals(id)); - } - - @Override - public Map getSingleUser(Integer id) { - Map data = new HashMap<>(); - if (id == null) { - data.put("error", "Missing id"); - return data; - } - - Optional optionalUser = users.stream().filter(user -> user.getId().equals(id)).findFirst(); - if (optionalUser.isPresent()) { - User currentUser = optionalUser.get(); - ResponseSingleUser singleUser = populateUser(currentUser); - - data.put("data", singleUser); - data.put("ad", company); - return data; - } - - return null; - } - - @Override - public ListAllUserDto getListUser(int page) { - - return populateListAllUserDto(page); - } - - private ListAllUserDto populateListAllUserDto(int page){ - Map> data = new HashMap<>(); - Map companyMap = new HashMap<>(); - ListAllUserDto allUserDto = new ListAllUserDto(); - final int perPage = 6; - - allUserDto.setPage(page); - allUserDto.setPerPage(perPage); - allUserDto.setTotalData(users.size()); - allUserDto.setTotalPage(users.size()/perPage); - - List userList = new ArrayList<>(); - for (int i = (perPage-1)*page; i < perPage*page; i++) { - User user = users.get(i); - ResponseSingleUser responseSingleUser = populateUser(user); - userList.add(responseSingleUser); - } - data.put("data", userList); - allUserDto.setData(data); - companyMap.put("ad", company); - allUserDto.setCompanyMap(companyMap); - - return allUserDto; - } - - @Override - @Async("asyncExecutor") - public CompletableFuture getAsyncAllUser(int delay, int page) throws InterruptedException { - long sleepDelay = Long.parseLong(delay+"000"); - Thread.sleep(sleepDelay); - return - - CompletableFuture.completedFuture(populateListAllUserDto(page)); - } - - private ResponseSingleUser populateUser(User currentUser){ - String firstName = ""; - String lastName = ""; - String[] arrayName = currentUser.getName().split(" "); - - if (arrayName.length>1) { - firstName = arrayName[0]; - lastName = arrayName[1]; - } - - firstName = arrayName[0]; - lastName = arrayName[0]; - ResponseSingleUser singleUser = new ResponseSingleUser(); - singleUser.setId(currentUser.getId()); - singleUser.setFirstName(firstName); - singleUser.setLastName(lastName); - singleUser.setEmail(currentUser.getEmail()); - singleUser.setAvatar(currentUser.getAvatar()); - return singleUser; - } -} +package id.globallinenetwork.api.user; + +import id.globallinenetwork.api.company.Company; +import id.globallinenetwork.api.utility.PasswordGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@Service +public class UserService implements IUser { + + private static final String EMAIL_DOMAIN = "@globallinenetwork.com"; + private static final Logger LOG = LoggerFactory.getLogger(Logger.class); + private final List users = new ArrayList<>(); + private SecureRandom secureRandom = null; + private Company company; + + public void initializeData() { + int companyId = 0; + int userId = 0; + + try { + secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN"); + companyId = secureRandom.nextInt(1000); + + ++userId; + User user1 = new User(1, "Muhammad Thobroni", "CEO", "muhammad" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + ++userId; + User user2 = new User(2, "Abu Bakar", "CTO", "abu.bakar@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user3 = new User(3, "Muhammad Umar", "Software Engineer", "umar" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user4 = new User(4, "Muhammad Usman", "FrontEnd Engineer", "usman" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user5 = new User(5, "Muhammad Ali", "Security Engineer", "ali" + + "@globallinenetwork.com", "fur7jf89", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user6 = new User(6, "Eve Holt", "Security Engineer", "eve.holt@reqres.in", "pistol" + , "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user7 = new User(7, "Janet Weaver", "QA", "janet.weaver@reqres.in", "cityslicka", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + ++userId; + User user8 = new User(8, "Michael Lawson", "Scrum Master", "michael.lawson@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user9 = new User(9, "Lindsay Ferguson", "Software Engineer", "lindsay" + + ".ferguson@reqres" + + ".in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user10 = new User(10, "Tobias Funke", "Senior Software Engineer", + "tobias.funke@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user11 = new User(11, "Byron Fields", "Senior Software Engineer", + "byron.fields@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + ++userId; + User user12 = new User(12, "George Edwards", "Senior Software Engineer", + "george.edwards@reqres.in", + "pistol", + "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg",Instant.now().toString(), Instant.now().toString()); + + users.add(user1); + users.add(user2); + users.add(user3); + users.add(user4); + users.add(user5); + users.add(user6); + users.add(user7); + users.add(user8); + users.add(user9); + users.add(user10); + users.add(user11); + users.add(user12); + + company = new Company(companyId, "StatusCode " + + "Weekly", "http://statuscode.org/", + "A weekly newsletter focusing on software development, " + + "infrastructure, the server, performance, and the stack end of things."); + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { + e.printStackTrace(); + } + } + + public List getUsers() { + return users; + } + + @Override + public Map registration(RegisterDto registerDto) { + Map data = new HashMap<>(); + if (registerDto.getPassword() == null || registerDto.getPassword().equals("")) { + data.put("error", "Missing password"); + return data; + } + + List listUser = users + .stream() + .filter(user -> + user.getEmail().equals(registerDto.getEmail()) && user.getPassword().equals(registerDto.getPassword())) + .collect(Collectors.toList()); + + if (!listUser.isEmpty()){ + data.put("id", listUser.get(0).getId()); + data.put("token", "QpwL5tke4Pnpja7X4"); + }else{ + return null; + } + + return data; + } + + @Override + public Map login(LoginDto loginDto) { + Map data = new HashMap<>(); + if (loginDto.getPassword() == null || loginDto.getPassword().equals("")) { + data.put("error", "Missing password"); + return data; + } else { + LOG.info("Email: "+loginDto.getEmail()); + LOG.info("Password: "+loginDto.getPassword()); + + List optionalUser = users + .stream() + .filter(user -> + user.getEmail().equals(loginDto.getEmail()) && user.getPassword().equals(loginDto.getPassword())) + .collect(Collectors.toList()); + + LOG.info("Optional size => "+optionalUser.size()); + if (optionalUser.size() > 0) { + data.put("token", "QpwL5tke4Pnpja7X4"); + return data; + } + } + return null; + } + + @Override + public User createUser(CreateUserDto createUserDto) throws NoSuchAlgorithmException { + int id = secureRandom.nextInt(1000); + String email = createUserDto.getName() + EMAIL_DOMAIN; + User createUser = new User(id, createUserDto.getName(), createUserDto.getJob(), email, + PasswordGenerator.generateRandomPassword(),"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128" + + ".jpg", Instant.now().toString(), Instant.now().toString()); + users.add(createUser); + + return users.get(users.size() - 1); + } + + @Override + public User updateUser(Integer id, CreateUserDto createUserDto) { + + if (id != null) { + Optional optionalUser = users.stream().filter(user -> user.getId().equals(id)).findFirst(); + if (optionalUser.isPresent()) { + User currentUser = optionalUser.get(); + currentUser.setUpdateAt(Instant.now().toString()); + return currentUser; + } + } + return null; + } + + @Override + public boolean deleteUser(Integer id) { + return users.removeIf(user -> user.getId().equals(id)); + } + + @Override + public Map getSingleUser(Integer id) { + Map data = new HashMap<>(); + if (id == null) { + data.put("error", "Missing id"); + return data; + } + + Optional optionalUser = users.stream().filter(user -> user.getId().equals(id)).findFirst(); + if (optionalUser.isPresent()) { + User currentUser = optionalUser.get(); + ResponseSingleUser singleUser = populateUser(currentUser); + + data.put("data", singleUser); + data.put("ad", company); + return data; + } + + return null; + } + + @Override + public ListAllUserDto getListUser(int page) { + + return populateListAllUserDto(page); + } + + private ListAllUserDto populateListAllUserDto(int page){ + Map> data = new HashMap<>(); + Map companyMap = new HashMap<>(); + ListAllUserDto allUserDto = new ListAllUserDto(); + final int perPage = 6; + + allUserDto.setPage(page); + allUserDto.setPerPage(perPage); + allUserDto.setTotalData(users.size()); + allUserDto.setTotalPage(users.size()/perPage); + + List userList = new ArrayList<>(); + for (int i = (page-1)*perPage; i < perPage*page; i++) { + User user = users.get(i); + ResponseSingleUser responseSingleUser = populateUser(user); + userList.add(responseSingleUser); + } + data.put("data", userList); + allUserDto.setData(data); + companyMap.put("ad", company); + allUserDto.setCompanyMap(companyMap); + + return allUserDto; + } + + @Override + @Async("asyncExecutor") + public CompletableFuture getAsyncAllUser(int delay, int page) throws InterruptedException { + long sleepDelay = Long.parseLong(delay+"000"); + Thread.sleep(sleepDelay); + return + + CompletableFuture.completedFuture(populateListAllUserDto(page)); + } + + private ResponseSingleUser populateUser(User currentUser){ + String firstName = ""; + String lastName = ""; + String[] arrayName = currentUser.getName().split(" "); + + if (arrayName.length>1) { + firstName = arrayName[0]; + lastName = arrayName[1]; + } + + firstName = arrayName[0]; + lastName = arrayName[0]; + ResponseSingleUser singleUser = new ResponseSingleUser(); + singleUser.setId(currentUser.getId()); + singleUser.setFirstName(firstName); + singleUser.setLastName(lastName); + singleUser.setEmail(currentUser.getEmail()); + singleUser.setAvatar(currentUser.getAvatar()); + return singleUser; + } +} diff --git a/src/main/java/id/globallinenetwork/api/utility/GetSingleData.java b/src/main/java/id/globallinenetwork/api/utility/GetSingleData.java index 435dbf4..bf792d7 100644 --- a/src/main/java/id/globallinenetwork/api/utility/GetSingleData.java +++ b/src/main/java/id/globallinenetwork/api/utility/GetSingleData.java @@ -1,17 +1,17 @@ -package id.globallinenetwork.api.utility; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -import java.util.Map; - -public class GetSingleData { - public static ResponseEntity getResponseEntity(Map data) { - if (data == null) { - return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); - } else if (data.containsKey("error")) { - return new ResponseEntity<>(data, HttpStatus.BAD_REQUEST); - } - return new ResponseEntity<>(data, HttpStatus.OK); - } -} +package id.globallinenetwork.api.utility; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.util.Map; + +public class GetSingleData { + public static ResponseEntity getResponseEntity(Map data) { + if (data == null) { + return new ResponseEntity<>(null, HttpStatus.NOT_FOUND); + } else if (data.containsKey("error")) { + return new ResponseEntity<>(data, HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(data, HttpStatus.OK); + } +} diff --git a/src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java b/src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java index 5c93832..94cbee0 100644 --- a/src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java +++ b/src/main/java/id/globallinenetwork/api/utility/PasswordGenerator.java @@ -1,20 +1,20 @@ -package id.globallinenetwork.api.utility; - -import java.security.SecureRandom; - -public class PasswordGenerator { - public static String generateRandomPassword(){ - // ASCII range - alphanumeric (0-9, a-z, A-Z) - final String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - - SecureRandom random = new SecureRandom(); - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < 10; i++) { - int randomIndex = random.nextInt(chars.length()); - sb.append(chars.charAt(randomIndex)); - } - - return sb.toString(); - } -} +package id.globallinenetwork.api.utility; + +import java.security.SecureRandom; + +public class PasswordGenerator { + public static String generateRandomPassword(){ + // ASCII range - alphanumeric (0-9, a-z, A-Z) + final String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + SecureRandom random = new SecureRandom(); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < 10; i++) { + int randomIndex = random.nextInt(chars.length()); + sb.append(chars.charAt(randomIndex)); + } + + return sb.toString(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..d3f5a12 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1 @@ - + diff --git a/src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java b/src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java index 1a299b5..c4e327d 100644 --- a/src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java +++ b/src/test/java/id/globallinenetwork/api/GlobalLineNetworkApplicationTests.java @@ -1,21 +1,24 @@ -package id.globallinenetwork.api; - -import id.globallinenetwork.api.user.UserController; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -class GlobalLineNetworkApplicationTests { - - @Autowired - private UserController userController; - - @Test - void contextLoads() { - assertThat(userController).isNotNull(); - } - -} +package id.globallinenetwork.api; + +import id.globallinenetwork.api.user.UserController; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest +class GlobalLineNetworkApplicationTests { + + @Autowired + private UserController userController; + + @Test + void contextLoads() { + assertThat(userController).isNotNull(); + } + +} diff --git a/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java index 4c433f0..2b10b48 100644 --- a/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java +++ b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java @@ -1,70 +1,233 @@ -package id.globallinenetwork.api.controller; - -import com.google.gson.Gson; -import id.globallinenetwork.api.user.RegisterDto; -import id.globallinenetwork.api.user.UserController; -import id.globallinenetwork.api.user.UserService; -import org.junit.Test; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; - -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import static org.assertj.core.api.Assertions.assertThat; - - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Tag("UserController") -public class UserControllerTest { - - private MockMvc mockMvc; - - @MockBean - private UserService userService; - - @Autowired - private TestRestTemplate restTemplate; - - @BeforeEach - public void test(){ - mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userService)).build(); - } - - @Test - @DisplayName("Registration of new user it will return error if failed") - public void register() throws Exception { - RegisterDto registerDto = new RegisterDto(); - registerDto.setEmail("eve.holt@reqres.in"); - registerDto.setPassword("cityslicka"); - - Gson gson = new Gson(); - String gsonRegister = gson.toJson(registerDto); - - //when - ResponseEntity result = restTemplate.postForEntity("/api/register", registerDto, ResponseEntity.class); - - //Then - assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - - Map data = new HashMap<>(); - data.put("id", 4); - data.put("token", "QpwL5tke4Pnpja7X4"); - assertThat(Objects.equals(result.getBody(), data)); - } -} +package id.globallinenetwork.api.controller; + +import com.google.gson.Gson; +import id.globallinenetwork.api.user.*; +import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.*; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.assertj.core.api.Assertions.assertThat; + + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Tag("UserController") +public class UserControllerTest { + + private MockMvc mockMvc; + + @MockBean + private UserService userService; + + @Autowired + private TestRestTemplate restTemplate; + + @BeforeEach + public void test(){ + mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userService)).build(); + } + + @Test + @DisplayName("Registration of new user is success") + public void successfullyRegister() throws Exception { + RegisterDto registerDto = new RegisterDto(); + registerDto.setEmail("eve.holt@reqres.in"); + registerDto.setPassword("cityslicka"); + + Gson gson = new Gson(); + String gsonRegister = gson.toJson(registerDto); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/register", registerDto, ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + + Map data = new HashMap<>(); + data.put("id", 4); + data.put("token", "QpwL5tke4Pnpja7X4"); + assertThat(Objects.equals(result.getBody(), data)); + } + + @Test + @DisplayName("Registration of new user unsuccessful") + public void unSuccessfullyRegister() throws Exception { + RegisterDto registerDto = new RegisterDto(); + registerDto.setEmail("eve.holt@reqres.in"); + + Gson gson = new Gson(); + String gsonRegister = gson.toJson(registerDto); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/register", registerDto, ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + + Map data = new HashMap<>(); + data.put("error", "Missing password"); + assertThat(Objects.equals(result.getBody(), data)); + } + + @Test + @DisplayName("Login Successful") + public void loginSuccessful() throws Exception { + LoginDto loginDto = new LoginDto(); + loginDto.setEmail("janet.weaver@reqres.in"); + loginDto.setPassword("cityslicka"); + + Gson gson = new Gson(); + String gsonLogin = gson.toJson(loginDto); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/login", loginDto, + ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + + Map data = new HashMap<>(); + data.put("token", "QpwL5tke4Pnpja7X4"); + assertThat(Objects.equals(result.getBody(), data)); + } + + @Test + @DisplayName("UnSuccessful Login") + public void loginUnSuccessful() throws Exception { + LoginDto loginDto = new LoginDto(); + loginDto.setEmail("janet.weaver@reqres.in"); + + Gson gson = new Gson(); + String gsonLogin = gson.toJson(loginDto); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/login", loginDto, + ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + + Map data = new HashMap<>(); + data.put("error", "Missing password"); + assertThat(Objects.equals(result.getBody(), data)); + } + + @Test + @DisplayName("Create New User") + public void createUser() throws Exception { + CreateUserDto createUserDto = new CreateUserDto(); + createUserDto.setName("Muhammad Umar"); + createUserDto.setJob("Software Engineer"); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/users", createUserDto, + ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(!Objects.equals(result.getBody(), null)); + } + + @Test + @DisplayName("Failed Create New User") + public void failedCreateUserMissingName() throws Exception { + CreateUserDto createUserDto = new CreateUserDto(); + createUserDto.setName("Muhammad Umar"); + createUserDto.setJob("Software Engineer"); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/users", createUserDto, + ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + Map data = new HashMap<>(); + data.put("error", "Missing name"); + assertThat(Objects.equals(result.getBody(), data)); + } + + @Test + @DisplayName("Failed Create New User") + public void failedCreateUserMissingJob() throws Exception { + CreateUserDto createUserDto = new CreateUserDto(); + createUserDto.setName("Muhammad Umar"); + createUserDto.setJob("Software Engineer"); + + //when + ResponseEntity result = restTemplate.postForEntity("/api/users", createUserDto, + ResponseEntity.class); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + Map data = new HashMap<>(); + data.put("error", "Missing Job"); + assertThat(Objects.equals(result.getBody(), data)); + } + + @Test + @DisplayName("Successfully Update New User") + public void successUpdateUser() throws Exception { + CreateUserDto createUserDto = new CreateUserDto(); + createUserDto.setName("Muhammad Umar"); + createUserDto.setJob("Software Engineer"); + + // create headers + HttpHeaders headers = new HttpHeaders(); + // set `content-type` header + headers.setContentType(MediaType.APPLICATION_JSON); + // set `accept` header + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + + // build the request + HttpEntity entity = new HttpEntity<>(createUserDto, headers); + + //when + ResponseEntity result = restTemplate.exchange("/api/users/{id}", HttpMethod.PUT, entity, ResponseEntity.class, 6); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(!Objects.equals(result.getBody(), null)); + } + + @Test + @DisplayName("Failed Update User") + public void failedUpdateUser() throws Exception { + CreateUserDto createUserDto = new CreateUserDto(); + createUserDto.setName("Muhammad Umar"); + createUserDto.setJob("Software Engineer"); + + // create headers + HttpHeaders headers = new HttpHeaders(); + // set `content-type` header + headers.setContentType(MediaType.APPLICATION_JSON); + // set `accept` header + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + + // build the request + HttpEntity entity = new HttpEntity<>(createUserDto, headers); + + //when + ResponseEntity result = restTemplate.exchange("/api/users/{id}", HttpMethod.PUT, entity, ResponseEntity.class, 6); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(!Objects.equals(result.getBody(), null)); + } +} From 099d5fb53adfa8677ed224bb0d4426c00ea895ff Mon Sep 17 00:00:00 2001 From: IQBAL Date: Fri, 9 Oct 2020 15:39:33 +0700 Subject: [PATCH 11/13] Add method to test get single user, success and failed --- .../api/controller/UserControllerTest.java | 63 +++++++++++-------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java index 2b10b48..da5f3b4 100644 --- a/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java +++ b/src/test/java/id/globallinenetwork/api/controller/UserControllerTest.java @@ -3,20 +3,14 @@ import com.google.gson.Gson; import id.globallinenetwork.api.user.*; import org.junit.Test; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.*; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; - -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import java.util.Collections; import java.util.HashMap; @@ -31,19 +25,9 @@ @Tag("UserController") public class UserControllerTest { - private MockMvc mockMvc; - - @MockBean - private UserService userService; - @Autowired private TestRestTemplate restTemplate; - @BeforeEach - public void test(){ - mockMvc = MockMvcBuilders.standaloneSetup(new UserController(userService)).build(); - } - @Test @DisplayName("Registration of new user is success") public void successfullyRegister() throws Exception { @@ -51,9 +35,6 @@ public void successfullyRegister() throws Exception { registerDto.setEmail("eve.holt@reqres.in"); registerDto.setPassword("cityslicka"); - Gson gson = new Gson(); - String gsonRegister = gson.toJson(registerDto); - //when ResponseEntity result = restTemplate.postForEntity("/api/register", registerDto, ResponseEntity.class); @@ -72,9 +53,6 @@ public void unSuccessfullyRegister() throws Exception { RegisterDto registerDto = new RegisterDto(); registerDto.setEmail("eve.holt@reqres.in"); - Gson gson = new Gson(); - String gsonRegister = gson.toJson(registerDto); - //when ResponseEntity result = restTemplate.postForEntity("/api/register", registerDto, ResponseEntity.class); @@ -93,9 +71,6 @@ public void loginSuccessful() throws Exception { loginDto.setEmail("janet.weaver@reqres.in"); loginDto.setPassword("cityslicka"); - Gson gson = new Gson(); - String gsonLogin = gson.toJson(loginDto); - //when ResponseEntity result = restTemplate.postForEntity("/api/login", loginDto, ResponseEntity.class); @@ -230,4 +205,42 @@ public void failedUpdateUser() throws Exception { assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(!Objects.equals(result.getBody(), null)); } + + @Test + @DisplayName("Bad Request Get Single User") + public void badRequestGetSingleUser() throws Exception{ + Map data = new HashMap<>(); + //When + ResponseEntity result = restTemplate.getForEntity("/api/users/{id}", ResponseEntity.class, 6); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); + data.put("error", "Missing id"); + assertThat(Objects.equals(result.getBody(), data)); + } + + @Test + @DisplayName("Not Found/Null Get Single User") + public void notFoundGetSingleUser() throws Exception{ + //When + ResponseEntity result = restTemplate.getForEntity("/api/users/{id}", ResponseEntity.class, 6); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + assertThat(Objects.equals(result.getBody(), null)); + } + + @Test + @DisplayName("Success Get Single User") + public void successGetSingleUser() throws Exception{ + //When + ResponseEntity result = restTemplate.getForEntity("/api/users/{id}", ResponseEntity.class, 6); + + //Then + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + Map data = new HashMap<>(); + data.put("data",null); + data.put("ad", null); + assertThat(!Objects.equals(result.getBody(), data)); + } } From 467ac81972d39e8c56a7a2177352dd73e0580eb7 Mon Sep 17 00:00:00 2001 From: IQBAL Date: Sat, 10 Oct 2020 12:03:14 +0700 Subject: [PATCH 12/13] Add list of API in Readme --- README.md | 47 ++++--------------- .../api/resource/ResourceController.java | 2 - 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index d883c3c..ba1a20f 100644 --- a/README.md +++ b/README.md @@ -8,46 +8,17 @@ The objective of this challenge is to evaluate your domain knowledge in front-en # Overview: -# This is the Backend from Me Muhamad Nizar Iqbal +# This is Backend - Coding Challenge -## List of API +## List of User API - Register /api/register - Login /api/login -- Create /api/users +- Create New User /api/users +- Update New User /api/users/{id} +- Delete User /api/users/{id} +- Get Single User /api/users/{id} +- Get All User /api/users/ +- Get Single Resource /api/unknown/{id} +- Get All Resources /api/unknown/{page} -### Prerequisites - -There are none :) Our main solutions stack include but not limited to Kotlin, Java, AngularJS, Flutter, Spring... -Feel free to use any languages and technologies you are comfortable with. - -## Mockups - -

- - - -

- -### Front-end: - -- For API please use https://reqres.in/. - -### Back-end: - -- The API should be similar to https://reqres.in/, performing basic operations for user. - -_We'll be happy if you cover application with tests._ - -### Submission Guidelines - -- Please fork the repo and then submit a Pull Request when you are done. -- Instructions must be provided to run the application, install any dependencies, and any other information needed. -- Please use version control and make sure we can see the history of how you went about it, rather than just uploading the complete project to GitHub. - -## Questions? - -Please feel free to reach out and ask any questions while you are working on a solution. -Send your questions to [tech@chimaera.my](mailto:tech@chimaera.my). - -Good luck! diff --git a/src/main/java/id/globallinenetwork/api/resource/ResourceController.java b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java index ce4112b..b4c46b6 100644 --- a/src/main/java/id/globallinenetwork/api/resource/ResourceController.java +++ b/src/main/java/id/globallinenetwork/api/resource/ResourceController.java @@ -36,6 +36,4 @@ public ResponseEntity getSingleResource(@PathVariable Integer id) { Map resource = resourcesService.getSingleResource(id); return GetSingleData.getResponseEntity(resource); } - - } From 613423b2808e177b8140ad8d3c7ae615d5f26a27 Mon Sep 17 00:00:00 2001 From: i4ba1 Date: Sat, 10 Oct 2020 12:08:47 +0700 Subject: [PATCH 13/13] Update README.md --- README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/README.md b/README.md index ba1a20f..54c8748 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,3 @@ -

- -

- -Thanks for taking the time to do our front-end / full-stack practical coding challenge. - -The objective of this challenge is to evaluate your domain knowledge in front-end / full-stack development: code organization, style and best practices. - # Overview: # This is Backend - Coding Challenge