From 884b2aaad637531320da2169d7d7024579ddaee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=AF=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=B2?= Date: Sun, 12 May 2024 01:51:51 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D1=87=D1=82=D0=B8=20=D0=B2=D1=81?= =?UTF-8?q?=D1=8F=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82,=20=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=D0=BE=D1=81=D1=8C=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7?= =?UTF-8?q?=D1=8B=20=D0=B8=20=D0=B8=D0=B3=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 8 ++ data.mv.db | Bin 45056 -> 65536 bytes .../com/example/demo/DemoApplication.java | 83 ++++++------ .../demo/core/api/GlobalController.java | 28 ++++ .../demo/core/api/PageAttributesMapper.java | 18 +++ .../com/example/demo/core/api/PageDto.java | 97 ------------- .../example/demo/core/api/PageDtoMapper.java | 25 ---- .../demo/core/configuration/Constants.java | 13 +- .../configuration/MapperConfiguration.java | 12 +- .../core/configuration/WebConfiguration.java | 8 +- .../demo/core/error/AdviceController.java | 53 ++++++++ .../core/security/SecurityConfiguration.java | 63 +++++++++ .../demo/core/security/UserPrincipal.java | 64 +++++++++ .../demo/core/session/SessionCart.java | 14 ++ .../demo/core/session/SessionHelper.java | 16 +++ .../demo/games/api/GameController.java | 53 +++++--- .../com/example/demo/games/api/GameDto.java | 27 ++-- .../demo/games/service/GameService.java | 40 ++++-- .../demo/genres/api/GenreController.java | 93 +++++++++---- .../demo/orders/api/OrderController.java | 83 ------------ .../com/example/demo/orders/api/OrderDto.java | 25 +--- .../demo/orders/model/OrderEntity.java | 43 +++--- .../orders/repository/OrderRepository.java | 7 +- .../demo/orders/service/OrderService.java | 35 +++-- .../demo/types/api/TypeController.java | 91 +++++++++---- .../com/example/demo/types/api/TypeDto.java | 15 +- .../demo/users/api/UserCartController.java | 128 ++++++++++++++++++ .../example/demo/users/api/UserCartDto.java | 53 ++++++++ .../demo/users/api/UserController.java | 110 +++++++++++---- .../com/example/demo/users/api/UserDto.java | 31 ++--- .../demo/users/api/UserProfileController.java | 82 +++++++++++ .../demo/users/api/UserSignupController.java | 63 +++++++++ .../example/demo/users/api/UserSignupDto.java | 51 +++++++ .../example/demo/users/model/UserEntity.java | 12 +- .../example/demo/users/model/UserRole.java | 15 ++ .../demo/users/service/UserService.java | 60 ++++++-- src/main/resources/application.properties | 1 + src/main/resources/public/css/style.css | 67 +++++++++ src/main/resources/public/favicon.svg | 5 + src/main/resources/templates/cart.html | 68 ++++++++++ src/main/resources/templates/default.html | 75 ++++++++++ src/main/resources/templates/error.html | 37 +++++ src/main/resources/templates/game.html | 55 ++++++++ src/main/resources/templates/genre-edit.html | 28 ++++ src/main/resources/templates/genre.html | 51 +++++++ src/main/resources/templates/login.html | 42 ++++++ src/main/resources/templates/orders.html | 62 +++++++++ src/main/resources/templates/pagination.html | 51 +++++++ src/main/resources/templates/profile.html | 25 ++++ src/main/resources/templates/signup.html | 40 ++++++ src/main/resources/templates/type-edit.html | 28 ++++ src/main/resources/templates/type.html | 50 +++++++ src/main/resources/templates/user-edit.html | 34 +++++ src/main/resources/templates/user.html | 58 ++++++++ .../com/example/demo/OrderServiceTest.java | 69 +++++----- 55 files changed, 1963 insertions(+), 502 deletions(-) create mode 100644 src/main/java/com/example/demo/core/api/GlobalController.java create mode 100644 src/main/java/com/example/demo/core/api/PageAttributesMapper.java delete mode 100644 src/main/java/com/example/demo/core/api/PageDto.java delete mode 100644 src/main/java/com/example/demo/core/api/PageDtoMapper.java create mode 100644 src/main/java/com/example/demo/core/error/AdviceController.java create mode 100644 src/main/java/com/example/demo/core/security/SecurityConfiguration.java create mode 100644 src/main/java/com/example/demo/core/security/UserPrincipal.java create mode 100644 src/main/java/com/example/demo/core/session/SessionCart.java create mode 100644 src/main/java/com/example/demo/core/session/SessionHelper.java delete mode 100644 src/main/java/com/example/demo/orders/api/OrderController.java create mode 100644 src/main/java/com/example/demo/users/api/UserCartController.java create mode 100644 src/main/java/com/example/demo/users/api/UserCartDto.java create mode 100644 src/main/java/com/example/demo/users/api/UserProfileController.java create mode 100644 src/main/java/com/example/demo/users/api/UserSignupController.java create mode 100644 src/main/java/com/example/demo/users/api/UserSignupDto.java create mode 100644 src/main/java/com/example/demo/users/model/UserRole.java create mode 100644 src/main/resources/public/css/style.css create mode 100644 src/main/resources/public/favicon.svg create mode 100644 src/main/resources/templates/cart.html create mode 100644 src/main/resources/templates/default.html create mode 100644 src/main/resources/templates/error.html create mode 100644 src/main/resources/templates/game.html create mode 100644 src/main/resources/templates/genre-edit.html create mode 100644 src/main/resources/templates/genre.html create mode 100644 src/main/resources/templates/login.html create mode 100644 src/main/resources/templates/orders.html create mode 100644 src/main/resources/templates/pagination.html create mode 100644 src/main/resources/templates/profile.html create mode 100644 src/main/resources/templates/signup.html create mode 100644 src/main/resources/templates/type-edit.html create mode 100644 src/main/resources/templates/type.html create mode 100644 src/main/resources/templates/user-edit.html create mode 100644 src/main/resources/templates/user.html diff --git a/build.gradle b/build.gradle index 2f776a6..233f023 100644 --- a/build.gradle +++ b/build.gradle @@ -36,6 +36,14 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'com.h2database:h2:2.2.224' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.3.0' + runtimeOnly 'org.webjars.npm:bootstrap:5.3.3' + runtimeOnly 'org.webjars.npm:bootstrap-icons:1.11.3' + + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' + testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/data.mv.db b/data.mv.db index 8989e4e971892ed649282e978fc22c1029f39181..75e080085b9d8d155574dbbca4b31c79404abce7 100644 GIT binary patch literal 65536 zcmeHwdu$v@dS4AWLpG_^^LDjwX_hOkq!W+scUSYg7gFRkz|^lSr4`;gAC^31BA(f*?SGAb&Z? zSFfI$nI3YuqHZ5*5;Ij_cU9L{U)OYhRrP(pZ+y_~50+NLH)T4%_;x&K=(^q?Uf)=G zbI^^<{%|cO>v1$_;Kaq25e1RkpRBGell4KX|8~4~YjJgj6-<`m_3(PUHfTE}jzZh+ zMfqPYfm{N)1ab-F638WxOCXm(E`eMExdd_vvPi2^$zh7+2W8ITaJGdwyqG5u=!)xGBgBlDFD7c0{vm2%(g#WRx= zBYgvX;}d5pbJLV}c@p@l4$oD~mnW*@WurV-QAo==Rxa=Tf$Z4G@W^;&v|JrNGpSzl z?C?}&zVBo&y-9tua}y(#zVg`Q%y9LjW1V7Bn7%kU+0V~UjP{k!Oq`vVt~Q>jUY)I6 zYkhjOGCwjmFFE}v!+0P<@1%R zN+aUvH8|R`V{o5NorHdDJbFL$zOur{$v%4NrjFF}bP7i0y6D4JgYw$h$}|jUIX3BC zxmKC3PE@aMG0=FOtOC8KJ_!vkZPRdFldZ>dtHJ5$wQ<~g>NMP~#YY>PUgOvl4EAvj z)REZ_cl50mca+y^YiL4?a%i$Pns28vj`-!Y+bgb=h*|Jk~^b9~ZZtp@j;8C@+ zk?Hlp3udtJmmR;drvr6ssQdHpUh%A{h1J!lyg-)YiL>x!bbtOA_m(t!G9b!P6KWnP ze4+Cn(3+NJ1Bnh7zF7Q+dphY$2zid@mNb`L{|lvm1f@z{$eDR?^dWkH9}GVD^uv7* zyB|0YUVnfe?sumiyaGpm^kF9)-~X`V!Dk-Q>*2yw*RRr=Evj{8S3@rq4tD=0)axuF z>+FLA^xqz%-*C+r3YPX;aIVM>bc)lowQubETRp!GX9^vt0~vE9T3%ckS|*E21L5lO z1S9wU=rNNVGxTHO%);8afLPY}8@H;L?&66{3m1$T?B59Q%$TdAmnPTFe0F8@{Ko91 zrAhPLxvACjx968T3g+C#t$1x{L0)y7lIcYavhJS0d&&OnTW?k;FFE7O^Bd99hB3WF zre-fJ1WR|{_^iLNc<#bjWn%WMJ2f{wcVq1=Fy6mU@BPP=@dlnd8d{^Be14y?=XYpX z-k}c00X=bO|G#_cpU`{fbhw@LwxLh#|BJo9OOJRRUS~;zBgKb%KD`gUfO?n;HQah*0JhY&;mc6t&G6cXR`%q7H1|YaS4) zY#~n>^{}rnYU>4KuMzMe=7&LOrIc<4I;HrGrk;Y^Y}@HMBQio=p`1D@P)o*s$m;PP zKntuMr!26lrdJUZ#>zDlPrYUmE0n1_Hc4AIEeo3p6)RUUZCkBp`?k^^ZMD|A4ZT(< zqU#71h7da4$x}MDitnMq{ZUj%;LtU!uRQM$p5!*p~3>B{}(>j5i0yY znhv3k(m6;sQHS+;NbjMJ&upT?B0?RbaDEZaPe5Dn*D-x~VExX3_<_gKC9<>;SMT18 zkByOVeRb{btE+1Z1J})g<=eM_j0d7%V0vR|iIp2A>x7o=Zz%JTx?tn{JAJ;v!!Wg` zk8SM5hGXy2L|VB_??4})?X*@6$Ij!iOIJr{$If3qH$G>$6~~&Z;BnuueV8fE%vC1N zPSZJvI+K~Jj8*37FkwGr$C$MQ-tXmn2nB{hcVE1_~$zd1(?#mH-w5OFR`?A z`N84CC0KeGfWcS%!$aRL77imuo9x?S-%d9z;rKFj1?`Cxi_{k>5osXOP^6JaW0592 zCAvuA)lJ(Wrbv0~F5|&t-<{_{xkJV&&SYR{%eL->079|S$Q#dCBAd$ za0#AX?Ab7IZ7=0xK#tow%2z4VtfR0>S^87TRUA$TR`#$nTpDQ}dcvMb1C7rlUR6Ak zcoUp3^g7C^qXaX&q-m(A$%hEBv8VD)Ps*-px?9vOy3HBcJME{P*-iL7RYH?2=9O`re$A} z8g3W}4cBEFt|=xxFtJD{Jr>h&O;edmfEp>L6TaQgl-zV3-DJ}VC&1}Cx|?{h8#U{= z&~&O4K%VNjMnGIe$<^^UQa(e$CuV$Ff=@%8o$)!3nZOK7>f(}1mvb3NP26G=2<+M5 z@Rv@_94Am_5N7CQF&!#Qhm2{{g~?KFrbed_Fp03Ze$I4a+enyx&SfJta*ONBpi3KY zCx<{sE%4O5!qURO_z$2(fbMYgK2Jf1pfu@q* zfuGAe8M+^=#qAmbw(SxQ>Hu zkqX@k3*8C}-3klc3Jcu|3*8C}-3klc3Jcu|3*8C}-O3lbl`nKFU+7l8Xx|s@*K|A9 zgU6(EsrpN^#$+`=-sSslYmG@%R9|;tVq1|J1Zs=T`anjD^?HwdNH@JFx2-APJgsV~ z8k1yp8;xn(HU+oM`oOj|1-C6Fq-soA+-7J@ZMK=AF^QVnNhm{O%4k!LAXV=%TS_Qv z2&pwQG^Ui>n#NQwAue01Sp!aM)^z90n%)*;NRMF6ifU<@HCx|LMPJXVX*X-YHEy?T z)3&zYHk~8LHtXkD&5dq92}`xeZM0Iks2T~qqV}qfYV&`?@FLrFEM?-pOW9u8e*MZF z*JV=erMCTVwOR$O@ttrT!eK9cSn1p)PRnJ!|3Aw2|KGc}_5S~B`Tl>t|DW&wXB#%; z`~T%uh6nln{}a9c-#Om#ZU@pbR|?WKgDB0xtY(YVgWpSM<=d|wh)KD+dLSp|J6t-T z+j=dwPa|bgp1qQge1umLYT}N>B8XYHSfg%7a&a4R#xAN5x1Fwmu=NL6si8Ze!s1a` z^q}Ha_JLdNR!4l{29rox1M!lN&aV2l`>0$sWUDq}ou;;zNY^F`_p5>CN5o9*#L@i3 zflUX8XashrgNP&=@oZCv4O)%hK#zmK(}+)qXT=yYF?PXXQj=@=T43slXC@(Jti&;6 z0+}dGObd=UvE!Q9(t;qui4po*5R=Ftp{|8?;D@1OYoQzax=nm7#HQ}SSuKQfQDDW8 z!LZirMw*-p&*Ct=3zi$? zzYbf`1Cy&O3-T6x?Dwvp!0q~7?{ee(Tb)Oz`~UEaifsRJ&i~=vrrQ6*;tjQnqDDrr z^<8KG&vpbdY>HCG;ZnlBOV|zV)&c;X{||PJq4#N?+4WkX&OEbA@5nIE?EWvE@6$Z9 z`)kGbW1e}S`wvUMM%VaJi7oR#(|x|{*Xg2u2l7fiC5@2>%uimf|?JND;{a>nW zyOe%#;LCN}E~Wo<@GI)JOX=^U?nCIswkHkg^Z_;*vqPwB!0-O zS$WAo*slsoSkDTou62MGR@w`N^(-$L!X5>)UPY&i%z731o6LF@y-w3jghuG`dk9^4 z2dq~?tGEWo7lsfDX}XCJSgca3R|J;)Kk*$>5pVQ~_|Hok^p3nbx zeKPz6UQpWq%lWrDjZWwPVT`>fdMx(;a{YljbJgq`>GYr3GP3zUm@f+d|CV-(DdS+H zC`=utsp2jz0MPmW@vbwdqX5nVzjqJz|KDI~$B+Mw)2B2{aA>*-SjzR3_YW32P9x1Q zuxT3>(G0M;!hYy!hVSW)>*$aP{KVHS%>Zk5FY8)TH6C<^+bF*x1yZFwtGliZp2gra4LA!Af|jxq1}G zNgQb|*f>WCv;_t2B=Jqi#GVH$3*kuwdyOyMZ1Uv8!PZEJdv_&_LL* z=`_wsvpI<@4zB+0o*Edx}-DL^XPZ+POWAS7ciSXYQ`Y!)t5g?oRd#+G*`E zbe8VQwAa;k82n+Dc?`k;*M0u?!|caLv8^4+zMT%{7kqSYS%jYYpPk?7=s1N^l}W>3 z(@d>rS%whtRI5rc{k3&uRF?RWeuY>a7dro3m5o9np zsyMLU?n4fnpcv%)|I(8=pZ{muE9CqC9PQ#sbcTNd=l^+^p9GYL{4VEr`C|!Rk`L^U z&A>Jr>>0tH6rd930d@y4y}*m@*cm_-03?BUEnW%ZV~+)S=Tq(QFa!P!*dQjwBfz8Co5~h0731buMSY?ym7jDjCvRhhSw0 zR!ZSN(V+s^D4)5{)3bn?La|Z)bQV&80~z`*v*Hrh5msE1`VjPK%VGZ<;G<=r24O({ z!GH^d0T&1ZdJqO&ARiEfe2NW3QH3aqkPXLe6-fxYa0J80hY#QmVL%kZP!c;7NeDw- z413F+fAzxC-C(ON)rBC1dJR*k*U*q>Lo>|*u1Tg^(YXJvZlkCB|FGX1+UDc5{|`f^ zBq(@6%m9F51aSj^^o82e&b7vQ$PECvharXi*&PD_ZvX!V`U$YTejo76U4w;pXiWjn ze4^{+4i-rOAaW4=EGSe?;X5>v0NmxjU5g}8`0t&0B!N7VKpsgTGekm;B#=U;g7CG;Z@gW|`wjzKXqH(HrX!(OzG zK|v$cWCyw^9@tSh2HX&1LNdURdW#2J2MQ4dTVn?+g8>@ZSvUsVS3I*SogF z46M|NIh93L+gk=|8S5)P1M-)#by@(X2vFxQpvy2l|9K)yP3$GyQhqy;A7_diluF@+*C>9y|WpiIb;3dAc7J zUxu!~y$fAeB3^M0n#Yy$wh)22M*E6KKos&B#D8TwkMA|w7~xCGLJSvG7R95`;UC|P z4#RIrJ{EX8ZS~mhE0%ZmU}$xt*@NK~=uL}oWjh+V06(zfM+4lwK4|`nEnaRPXyAe3 zt03f6@e^x|5I1&y*c>x1jE%XYBiNXqI%ABCH^Q`srWDDLJ!ZFmCXdZZ5Ttx)MgC1r^aY*~fUJderMWgV^m~PF|oEe>) zojo@T`>xwsWW@^g0iZ5Qge5KY_-J_~enhlZP>O@N8@qPDEMcR_VMv>NYk|o!c zm#XzOTdr{F#^@MD8t!kQdZMXzb$anO;=v({p9C2`*iwdKRy(K5=g9g6$aAsB!t+l{x#YQSs)-&()f$`+3*RYECvyiRvXv zqZ)qiQ6<`v!v={m&Xk#9mS9_6tJd30!HS0@8 za`pR&6L|2`+E3D&JB$-};K=uTeo6(RIr49Me;Te+4@7h1|Ll2}9t3Qf8W7EqUwG`UZ)#WSx#dB}tsoC3W)jKmwm!h}M zzqL3$fBXFO&8mOn(v9_CVfyWJ18u2YDQ(=J+8J9Q1>WO7(;1{_ArP2WD5JQt?1gGOk1&<<(Jj zk*;hJK#JG1Egmz9Qw}FUjMPasjb{bcsA>MA8r$k|SgFW(SH&N^`pxH6lh;f`*VHxz zV)kU(rf}O*X}l^;Oh0@kuQgn>?X5?p$*W>LDotF3$!luq!VSw>nvOD@ZO4%Yu&P;` z8nG+WlGICTL5jDxB;`D-mZU9N-rA0|O_npwN^3!i!#2!HIm@b5X-k&3wkd6s#hh{>tTjbblN66{EGcf2C@4c`xNDN~>ZmBB$Zp~sK)F$5H$gcb!+?`i zq}FrmT6bM$ktj++L`H=(H?{%U?Z@tcog*N)5tuv!vKxyD_xexpl-f5^yGJnOqA3`1 zK{>E@{Ezn_-9)9o9EJ2AD*f+op+W%mj|Dg$456+PO*c{39;g=FLtO`kP$7i#&(ajm zzx-#A!ud&<`i5}+GL(zp{NIH05uAr>79u#GY(fg>0rjmA!}*mVMC~oR*6#BZVzN;h zVzNPskhcC^mgZl%1ab-F638WxOCXoPlOzFY|1a(DRV(_`{yzfvf9G+S|CiJFf80sX z7V&}!^RcrcUuf-006?a$XP_?E7>`x_e+$6$cE|jm#s53rbrv!FzxOsd{vV_n_Byt&)X!zjo9&%vMC94fp1 z5YI38=s>u+409R6(g4LVlfiP^dFo*M^QyDzDzkd3pO?};WsO|$6V~{9$dW{uTTAf@4 z+~)ppEhg*nB_8YwylaE{0%mgotTfc@r5!dmEkob(io&C?>AIq#2zbYwRw1~q>+5l> zw&=I2m=M!3A)vr*vNR||^wxPy>pQQ>c{Q4)lrrn5KFE^Ux;CAix5@7yM0aSsGZ~Vt z@2B9lrG!M}z&g>Y+?p->*;=-|O|yBJv?-wsFYSze$`Qo56>YYZP}UGqYeFc97P6%^ zA;@Begm{})^ZktYcn4qW79&B_^qShN)ub^WTesPKKWjC&Y}0POpS7A>wrN{iaNE@8 zarQv?5c^nvaze{}tl_m_INbePK4MhL6z<>roau6pZ%)}N;qRxndtg0YzB#!XOp%-Q z(EnMH0DQpl_aOoR0rY!4&KyTcvjc^mbZ6Jri1jWbsaD z$N`0E>Ia-8x>fT8j^Xs?t8?G;jl_WbK_vo!z8C6G%Xmq0FoTmrcSatY)T$R&_V zAeTTcf!&vY^#7Os_o^Fx>i=&N001D50{}q!|3?O!#T&x^-(%BXh;YfH|JB_8Z61%+ z(bFivo*vk~62}v+v=ZNeDLqVuA@-<;{ateZXa4`sb;an{04%wucMmG{n5AB`vJGh)!_!QysrS&%&8bILwfXi{d0Y)P2A6OZ1v% zugNZk4tIa2_+?hU(}S{5lHT~|y8m18Bf}m@uZ22CrxBLX(HoE z6AAW5WPEEP<69FM-27`1hhyk-b)`hH^xVK-(;!ALK3t93CvhB=O*<7QtT+ZstKpl2Tg3PdnLJf6MpFTHVNdHsa><|XYKU*R>ppa* zNt)1dde`Z?Cp_$Nzm0zhB9$5A4|AcLYr7Lp-^UZ?3MLL=}J zPwpXf;T}e;vv#!udad z^NVo)k2d+;`qmJ?TYm!Q>D~Hs_|U%xzg)l8|517@?&Nn2;uzw)5;V18_W}M2_p5>C zN5o9*#L@i3iLmPsjp)7`L?qFOXPY`~cW49$dK?6vMtnj%E5?wCu^R=pCT$(Gz|<4Z zOhU+5iDSkDGEtbA794S6$2GB~1wn)pBlNW(CXqoxT?_5N4@1Y+LO0I+|8xI;uC&DO s&yPL#|9^jS%N=M{2U;=zPv_q?mCEQ(=l_w9y(n?)-I__)uG9Pf0Uk`-F8}}l literal 45056 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 diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java index 766cd00..c306c0d 100644 --- a/src/main/java/com/example/demo/DemoApplication.java +++ b/src/main/java/com/example/demo/DemoApplication.java @@ -10,6 +10,7 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import com.example.demo.core.configuration.Constants; import com.example.demo.games.model.GameEntity; import com.example.demo.games.service.GameService; import com.example.demo.genres.model.GenreEntity; @@ -19,57 +20,61 @@ import com.example.demo.orders.service.OrderService; import com.example.demo.types.model.TypeEntity; import com.example.demo.types.service.TypeService; import com.example.demo.users.model.UserEntity; +import com.example.demo.users.model.UserRole; import com.example.demo.users.service.UserService; - @SpringBootApplication public class DemoApplication implements CommandLineRunner { - private final Logger log = LoggerFactory.getLogger(DemoApplication.class); + private final Logger log = LoggerFactory.getLogger(DemoApplication.class); - private final TypeService typeService; - private final GenreService genreService; - private final GameService gameService; - private final OrderService orderService; - private final UserService userService; + private final TypeService typeService; + private final GenreService genreService; + private final GameService gameService; + private final OrderService orderService; + private final UserService userService; - public DemoApplication(TypeService typeService, GenreService genreService, GameService gameService, OrderService orderService, UserService userService){ - this.typeService = typeService; - this.gameService = gameService; - this.genreService = genreService; - this.orderService = orderService; - this.userService = userService; - } + public DemoApplication(TypeService typeService, GenreService genreService, GameService gameService, + OrderService orderService, UserService userService) { + this.typeService = typeService; + this.gameService = gameService; + this.genreService = genreService; + this.orderService = orderService; + this.userService = userService; + } - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } - @Override - public void run(String... args) throws Exception{ - log.info("start"); - // final var type1 = typeService.create(new TypeEntity("ААА")); - // final var type2 = typeService.create(new TypeEntity("АА")); + @Override + public void run(String... args) throws Exception { + log.info("start"); - // final var genre1 = genreService.create(new GenreEntity("Приключения")); - // final var genre2 = genreService.create(new GenreEntity("Симулятор")); + log.info("Create default user values"); + final var admin = new UserEntity("admin", "admin@mail.com", "admin"); + admin.setRole(UserRole.ADMIN); + userService.create(admin); + final var user1 = userService.create(new UserEntity("user", "user@gmail.com", Constants.DEFAULT_PASSWORD)); - // final List genres1 = new ArrayList(); - // genres1.add(genre1); - // genres1.add(genre2); + final var type1 = typeService.create(new TypeEntity("ААА")); + final var type2 = typeService.create(new TypeEntity("АА")); - // final List genres2 = new ArrayList(); - // genres2.add(genre2); + final var genre1 = genreService.create(new GenreEntity("Приключения")); + final var genre2 = genreService.create(new GenreEntity("Симулятор")); - // final var game1 = gameService.create(new GameEntity(type1,"Game1",2100.0,"good game", genres1)); - // final var game2 = gameService.create(new GameEntity( type2, "Game2", 1200.0,"bad game", genres2)); - // final List games = new ArrayList(); - // games.add(game1); - // games.add(game2); + final List genres1 = new ArrayList(); + genres1.add(genre1); + genres1.add(genre2); - // var user1 = userService.create(new UserEntity( "login1", "email@mail.com", "qwerty123")); - // var user2 = userService.create(new UserEntity( "login2", "email@gmail.com", "qwerty1234")); + final List genres2 = new ArrayList(); + genres2.add(genre2); - // orderService.create(7, new OrderEntity(user1,games)); - // orderService.create(8, new OrderEntity(user2,games)); - } + final var game1 = gameService.create(new GameEntity(type1, "Game1", 2100.0, "good game", genres1)); + final var game2 = gameService.create(new GameEntity(type2, "Game2", 1200.0, "bad game", genres2)); + final List games = new ArrayList(); + games.add(game1); + games.add(game2); + + orderService.create(user1.getId(), new OrderEntity(games)); + } } diff --git a/src/main/java/com/example/demo/core/api/GlobalController.java b/src/main/java/com/example/demo/core/api/GlobalController.java new file mode 100644 index 0000000..bc3f2ca --- /dev/null +++ b/src/main/java/com/example/demo/core/api/GlobalController.java @@ -0,0 +1,28 @@ +package com.example.demo.core.api; + +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ModelAttribute; + +import com.example.demo.core.session.SessionCart; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; + +@ControllerAdvice +public class GlobalController { + private final SessionCart cart; + + public GlobalController(SessionCart cart) { + this.cart = cart; + } + + @ModelAttribute("servletPath") + String getRequestServletPath(HttpServletRequest request) { + return request.getServletPath(); + } + + @ModelAttribute("totalCart") + double getTotalCart(HttpSession session) { + return cart.getSum(); + } +} diff --git a/src/main/java/com/example/demo/core/api/PageAttributesMapper.java b/src/main/java/com/example/demo/core/api/PageAttributesMapper.java new file mode 100644 index 0000000..74ee38d --- /dev/null +++ b/src/main/java/com/example/demo/core/api/PageAttributesMapper.java @@ -0,0 +1,18 @@ +package com.example.demo.core.api; + +import java.util.Map; +import java.util.function.Function; + +import org.springframework.data.domain.Page; + +public class PageAttributesMapper { + private PageAttributesMapper() { + } + + public static Map toAttributes(Page page, Function mapper) { + return Map.of( + "items", page.getContent().stream().map(mapper::apply).toList(), + "currentPage", page.getNumber(), + "totalPages", page.getTotalPages()); + } +} diff --git a/src/main/java/com/example/demo/core/api/PageDto.java b/src/main/java/com/example/demo/core/api/PageDto.java deleted file mode 100644 index 4cae429..0000000 --- a/src/main/java/com/example/demo/core/api/PageDto.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.example.demo.core.api; - -import java.util.ArrayList; -import java.util.List; - -public class PageDto { - private List items = new ArrayList<>(); - private int itemsCount; - private int currentPage; - private int currentSize; - private int totalPages; - private long totalItems; - private boolean isFirst; - private boolean isLast; - private boolean hasNext; - private boolean hasPrevious; - - public List getItems() { - return items; - } - - public void setItems(List items) { - this.items = items; - } - - public int getItemsCount() { - return itemsCount; - } - - public void setItemsCount(int itemsCount) { - this.itemsCount = itemsCount; - } - - public int getCurrentPage() { - return currentPage; - } - - public void setCurrentPage(int currentPage) { - this.currentPage = currentPage; - } - - public int getCurrentSize() { - return currentSize; - } - - public void setCurrentSize(int currentSize) { - this.currentSize = currentSize; - } - - public int getTotalPages() { - return totalPages; - } - - public void setTotalPages(int totalPages) { - this.totalPages = totalPages; - } - - public long getTotalItems() { - return totalItems; - } - - public void setTotalItems(long totalItems) { - this.totalItems = totalItems; - } - - public boolean isFirst() { - return isFirst; - } - - public void setFirst(boolean isFirst) { - this.isFirst = isFirst; - } - - public boolean isLast() { - return isLast; - } - - public void setLast(boolean isLast) { - this.isLast = isLast; - } - - public boolean isHasNext() { - return hasNext; - } - - public void setHasNext(boolean hasNext) { - this.hasNext = hasNext; - } - - public boolean isHasPrevious() { - return hasPrevious; - } - - public void setHasPrevious(boolean hasPrevious) { - this.hasPrevious = hasPrevious; - } -} diff --git a/src/main/java/com/example/demo/core/api/PageDtoMapper.java b/src/main/java/com/example/demo/core/api/PageDtoMapper.java deleted file mode 100644 index e8d3dd0..0000000 --- a/src/main/java/com/example/demo/core/api/PageDtoMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.example.demo.core.api; - -import java.util.function.Function; - -import org.springframework.data.domain.Page; - -public class PageDtoMapper { - private PageDtoMapper() { - } - - public static PageDto toDto(Page page, Function mapper) { - final PageDto dto = new PageDto<>(); - dto.setItems(page.getContent().stream().map(mapper::apply).toList()); - dto.setItemsCount(page.getNumberOfElements()); - dto.setCurrentPage(page.getNumber()); - dto.setCurrentSize(page.getSize()); - dto.setTotalPages(page.getTotalPages()); - dto.setTotalItems(page.getTotalElements()); - dto.setFirst(page.isFirst()); - dto.setLast(page.isLast()); - dto.setHasNext(page.hasNext()); - dto.setHasPrevious(page.hasPrevious()); - return dto; - } -} diff --git a/src/main/java/com/example/demo/core/configuration/Constants.java b/src/main/java/com/example/demo/core/configuration/Constants.java index 42de69f..a6e6497 100644 --- a/src/main/java/com/example/demo/core/configuration/Constants.java +++ b/src/main/java/com/example/demo/core/configuration/Constants.java @@ -2,8 +2,17 @@ package com.example.demo.core.configuration; public class Constants { public static final String SEQUENCE_NAME = "hibernate_sequence"; - public static final String API_URL = "/api/1.0"; - public static final String DEFAULT_PAGE_SIZE = "5"; + + public static final int DEFAULT_PAGE_SIZE = 5; + + public static final String REDIRECT_VIEW = "redirect:"; + + public static final String ADMIN_PREFIX = "/admin"; + + public static final String LOGIN_URL = "/login"; + public static final String LOGOUT_URL = "/logout"; + + public static final String DEFAULT_PASSWORD = "123456"; private Constants() { } diff --git a/src/main/java/com/example/demo/core/configuration/MapperConfiguration.java b/src/main/java/com/example/demo/core/configuration/MapperConfiguration.java index a5ad6f3..44defae 100644 --- a/src/main/java/com/example/demo/core/configuration/MapperConfiguration.java +++ b/src/main/java/com/example/demo/core/configuration/MapperConfiguration.java @@ -1,13 +1,23 @@ package com.example.demo.core.configuration; import org.modelmapper.ModelMapper; +import org.modelmapper.PropertyMap; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import com.example.demo.core.model.BaseEntity; + @Configuration public class MapperConfiguration { @Bean ModelMapper modelMapper() { - return new ModelMapper(); + final ModelMapper mapper = new ModelMapper(); + mapper.addMappings(new PropertyMap() { + @Override + protected void configure() { + skip(destination.getId()); + } + }); + return mapper; } } diff --git a/src/main/java/com/example/demo/core/configuration/WebConfiguration.java b/src/main/java/com/example/demo/core/configuration/WebConfiguration.java index 762e85a..6316aa8 100644 --- a/src/main/java/com/example/demo/core/configuration/WebConfiguration.java +++ b/src/main/java/com/example/demo/core/configuration/WebConfiguration.java @@ -1,15 +1,13 @@ package com.example.demo.core.configuration; import org.springframework.context.annotation.Configuration; -import org.springframework.lang.NonNull; -import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfiguration implements WebMvcConfigurer { @Override - public void addCorsMappings(@NonNull CorsRegistry registry) { - registry.addMapping("/**") - .allowedMethods("GET", "POST", "PUT", "DELETE"); + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/login").setViewName("login"); } } diff --git a/src/main/java/com/example/demo/core/error/AdviceController.java b/src/main/java/com/example/demo/core/error/AdviceController.java new file mode 100644 index 0000000..72c9937 --- /dev/null +++ b/src/main/java/com/example/demo/core/error/AdviceController.java @@ -0,0 +1,53 @@ +package com.example.demo.core.error; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.servlet.ModelAndView; + +import jakarta.servlet.http.HttpServletRequest; + +@ControllerAdvice +public class AdviceController { +private final Logger log = LoggerFactory.getLogger(AdviceController.class); + + private static Throwable getRootCause(Throwable throwable) { + Throwable rootCause = throwable; + while (rootCause.getCause() != null && rootCause.getCause() != rootCause) { + rootCause = rootCause.getCause(); + } + return rootCause; + } + + private static Map getAttributes(HttpServletRequest request, Throwable throwable) { + final Throwable rootCause = getRootCause(throwable); + final StackTraceElement firstError = rootCause.getStackTrace()[0]; + return Map.of( + "message", rootCause.getMessage(), + "url", request.getRequestURL(), + "exception", rootCause.getClass().getName(), + "file", firstError.getFileName(), + "method", firstError.getMethodName(), + "line", firstError.getLineNumber()); + } + + @ExceptionHandler(value = Exception.class) + public ModelAndView defaultErrorHandler(HttpServletRequest request, Throwable throwable) throws Throwable { + if (AnnotationUtils.findAnnotation(throwable.getClass(), + ResponseStatus.class) != null) { + throw throwable; + } + + log.error("{}", throwable.getMessage()); + throwable.printStackTrace(); + final ModelAndView model = new ModelAndView(); + model.addAllObjects(getAttributes(request, throwable)); + model.setViewName("error"); + return model; + } +} diff --git a/src/main/java/com/example/demo/core/security/SecurityConfiguration.java b/src/main/java/com/example/demo/core/security/SecurityConfiguration.java new file mode 100644 index 0000000..0b194f0 --- /dev/null +++ b/src/main/java/com/example/demo/core/security/SecurityConfiguration.java @@ -0,0 +1,63 @@ +package com.example.demo.core.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + +import com.example.demo.core.configuration.Constants; +import com.example.demo.users.api.UserSignupController; +import com.example.demo.users.model.UserRole; + +@Configuration +@EnableWebSecurity +public class SecurityConfiguration { +@Bean + SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity.headers(headers -> headers.frameOptions(FrameOptionsConfig::sameOrigin)); + httpSecurity.csrf(AbstractHttpConfigurer::disable); + httpSecurity.cors(Customizer.withDefaults()); + + httpSecurity.authorizeHttpRequests(requests -> requests + .requestMatchers("/css/**", "/webjars/**", "/*.svg") + .permitAll()); + + httpSecurity.authorizeHttpRequests(requests -> requests + .requestMatchers(Constants.ADMIN_PREFIX + "/**").hasRole(UserRole.ADMIN.name()) + .requestMatchers("/h2-console/**").hasRole(UserRole.ADMIN.name()) + .requestMatchers(UserSignupController.URL).anonymous() + .requestMatchers(Constants.LOGIN_URL).anonymous() + .anyRequest().authenticated()); + + httpSecurity.formLogin(formLogin -> formLogin + .loginPage(Constants.LOGIN_URL)); + + httpSecurity.rememberMe(rememberMe -> rememberMe.key("uniqueAndSecret")); + + httpSecurity.logout(logout -> logout + .deleteCookies("JSESSIONID")); + + return httpSecurity.build(); + } + + @Bean + DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService) { + final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); + authProvider.setUserDetailsService(userDetailsService); + authProvider.setPasswordEncoder(passwordEncoder()); + return authProvider; + } + + @Bean + PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/example/demo/core/security/UserPrincipal.java b/src/main/java/com/example/demo/core/security/UserPrincipal.java new file mode 100644 index 0000000..ba72b74 --- /dev/null +++ b/src/main/java/com/example/demo/core/security/UserPrincipal.java @@ -0,0 +1,64 @@ +package com.example.demo.core.security; + +import java.util.Collection; +import java.util.Set; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.example.demo.users.model.UserEntity; + +public class UserPrincipal implements UserDetails{ +private final long id; + private final String username; + private final String password; + private final Set roles; + private final boolean active; + + public UserPrincipal(UserEntity user) { + this.id = user.getId(); + this.username = user.getLogin(); + this.password = user.getPassword(); + this.roles = Set.of(user.getRole()); + this.active = true; + } + + public Long getId() { + return id; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public Collection getAuthorities() { + return roles; + } + + @Override + public boolean isEnabled() { + return active; + } + + @Override + public boolean isAccountNonExpired() { + return isEnabled(); + } + + @Override + public boolean isAccountNonLocked() { + return isEnabled(); + } + + @Override + public boolean isCredentialsNonExpired() { + return isEnabled(); + } +} diff --git a/src/main/java/com/example/demo/core/session/SessionCart.java b/src/main/java/com/example/demo/core/session/SessionCart.java new file mode 100644 index 0000000..d4696a6 --- /dev/null +++ b/src/main/java/com/example/demo/core/session/SessionCart.java @@ -0,0 +1,14 @@ +package com.example.demo.core.session; + +import java.util.HashMap; + +import com.example.demo.users.api.UserCartDto; + +public class SessionCart extends HashMap { + public double getSum() { + return this.values().stream() + .map(item -> item.getPrice()) + .mapToDouble(Double::doubleValue) + .sum(); + } +} diff --git a/src/main/java/com/example/demo/core/session/SessionHelper.java b/src/main/java/com/example/demo/core/session/SessionHelper.java new file mode 100644 index 0000000..6ee3d8c --- /dev/null +++ b/src/main/java/com/example/demo/core/session/SessionHelper.java @@ -0,0 +1,16 @@ +package com.example.demo.core.session; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.web.context.WebApplicationContext; + +@Configuration +public class SessionHelper { + @Bean + @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) + SessionCart todos() { + return new SessionCart(); + } +} diff --git a/src/main/java/com/example/demo/games/api/GameController.java b/src/main/java/com/example/demo/games/api/GameController.java index 7b8f82f..e72cc73 100644 --- a/src/main/java/com/example/demo/games/api/GameController.java +++ b/src/main/java/com/example/demo/games/api/GameController.java @@ -1,8 +1,11 @@ package com.example.demo.games.api; import java.util.List; +import java.util.Map; import org.modelmapper.ModelMapper; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -11,10 +14,8 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import com.example.demo.core.api.PageDto; -import com.example.demo.core.api.PageDtoMapper; +import com.example.demo.core.api.PageAttributesMapper; import com.example.demo.core.configuration.Constants; import com.example.demo.games.model.GameEntity; import com.example.demo.games.service.GameService; @@ -24,23 +25,31 @@ import com.example.demo.types.service.TypeService; import jakarta.validation.Valid; -@RestController -@RequestMapping(Constants.API_URL + "/game") +@Controller +@RequestMapping(GameController.URL) public class GameController { + + public static final String URL = Constants.ADMIN_PREFIX + "/game"; + private static final String GAME_VIEW = "game"; + private static final String GAME_EDIT_VIEW = "game-edit"; + private static final String PAGE_ATTRIBUTE = "page"; + private static final String GAME_ATTRIBUTE = "game"; + private final GameService gameService; private final TypeService typeService; private final GenreService genreService; private final ModelMapper modelMapper; - public GameController(GameService gameService, TypeService typeService, GenreService genreService, ModelMapper modelMapper){ + public GameController(GameService gameService, TypeService typeService, GenreService genreService, + ModelMapper modelMapper) { this.gameService = gameService; this.genreService = genreService; this.modelMapper = modelMapper; this.typeService = typeService; } - private GameDto toDto(GameEntity entity){ - //return modelMapper.map(entity, GameDto.class); + private GameDto toDto(GameEntity entity) { + // return modelMapper.map(entity, GameDto.class); var dto = new GameDto(); dto.setId(entity.getId()); dto.setGenres(entity.getGenres().stream().map(GenreEntity::getId).toList()); @@ -51,44 +60,46 @@ public class GameController { return dto; } - private GameEntity toEntity(GameDto dto){ + private GameEntity toEntity(GameDto dto) { + // return modelMapper.map(dto, GameEntity.class); final GameEntity entity = modelMapper.map(dto, GameEntity.class); entity.setType(typeService.get(dto.getTypeId())); var genres = dto.getGenres(); List genresList = genreService.getAllById(genres); - for(var genre : genresList){ + for (var genre : genresList) { entity.setGenres(genre); } return entity; } @GetMapping - public PageDto getAll( - @RequestParam(name = "typeId", defaultValue = "0") long typeId, - //@RequestParam(name = "genres", defaultValue = "") List genres, - @RequestParam(name = "genreId", defaultValue = "0") long genre, - @RequestParam(name = "page", defaultValue = "0") int page, - @RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size){ - return PageDtoMapper.toDto(gameService.getAll(typeId, genre, page, size), this::toDto); + public String getAll( + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + Model model) { + final Map attributes = PageAttributesMapper.toAttributes( + gameService.getAll(0, 0, page, Constants.DEFAULT_PAGE_SIZE), this::toDto); + model.addAllAttributes(attributes); + model.addAttribute(PAGE_ATTRIBUTE, page); + return GAME_VIEW; } @GetMapping("/{id}") - public GameDto get(@PathVariable(name = "id") Long id){ + public GameDto get(@PathVariable(name = "id") Long id) { return toDto(gameService.get(id)); } @PostMapping - public GameDto create(@RequestBody @Valid GameDto dto){ + public GameDto create(@RequestBody @Valid GameDto dto) { return toDto(gameService.create(toEntity(dto))); } @PutMapping("/{id}") - public GameDto update(@PathVariable(name = "id") Long id, @RequestBody GameDto dto){ + public GameDto update(@PathVariable(name = "id") Long id, @RequestBody GameDto dto) { return toDto(gameService.update(id, toEntity(dto))); } @DeleteMapping("/{id}") - public GameDto delete(@PathVariable(name = "id") Long id){ + public GameDto delete(@PathVariable(name = "id") Long id) { return toDto(gameService.delete(id)); } } diff --git a/src/main/java/com/example/demo/games/api/GameDto.java b/src/main/java/com/example/demo/games/api/GameDto.java index c7ef495..1a6e39f 100644 --- a/src/main/java/com/example/demo/games/api/GameDto.java +++ b/src/main/java/com/example/demo/games/api/GameDto.java @@ -3,14 +3,11 @@ package com.example.demo.games.api; import java.util.ArrayList; import java.util.List; -import com.fasterxml.jackson.annotation.JsonProperty; - import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; public class GameDto { - @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; @NotNull @Min(1) @@ -25,52 +22,52 @@ public class GameDto { @NotBlank private String description; - public Long getId(){ + public Long getId() { return id; } - public void setId(Long id){ + public void setId(Long id) { this.id = id; } - public Long getTypeId(){ + public Long getTypeId() { return typeId; } - public void setTypeId(Long typeId){ + public void setTypeId(Long typeId) { this.typeId = typeId; } - public List getGenres(){ + public List getGenres() { return genres; } - public void setGenres(List genres){ + public void setGenres(List genres) { this.genres.clear(); this.genres.addAll(genres); } - public Double getPrice(){ + public Double getPrice() { return price; } - public void setPrice(Double price){ + public void setPrice(Double price) { this.price = price; } - public String getName(){ + public String getName() { return name; } - public void setName(String name){ + public void setName(String name) { this.name = name; } - public String getDescription(){ + public String getDescription() { return description; } - public void setDescription(String description){ + public void setDescription(String description) { this.description = description; } diff --git a/src/main/java/com/example/demo/games/service/GameService.java b/src/main/java/com/example/demo/games/service/GameService.java index cd9279a..3bafb07 100644 --- a/src/main/java/com/example/demo/games/service/GameService.java +++ b/src/main/java/com/example/demo/games/service/GameService.java @@ -1,8 +1,11 @@ package com.example.demo.games.service; +import java.util.Collection; import java.util.List; //import java.util.List; import java.util.Objects; +import java.util.stream.StreamSupport; + import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; @@ -18,48 +21,57 @@ import com.example.demo.genres.service.GenreService; public class GameService { private final GameRepository repository; - public GameService(GameRepository repository, GenreService genreService){ + public GameService(GameRepository repository, GenreService genreService) { this.repository = repository; } @Transactional(readOnly = true) - public List getAll(long typeId, long genre){ + public List getAll(long typeId, long genre) { - if(!Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)){ + if (!Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)) { return repository.findByTypeIdAndGenres(typeId, genre); } - if(Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)){ + if (Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)) { return repository.findByGenres(genre); } - if(!Objects.equals(typeId, 0L) && Objects.equals(genre, 0L)){ + if (!Objects.equals(typeId, 0L) && Objects.equals(genre, 0L)) { return repository.findByTypeId(typeId); } return repository.findAll(); } @Transactional(readOnly = true) - public Page getAll(long typeId, long genre, int page, int size){ + public Page getAll(long typeId, long genre, int page, int size) { final Pageable pageRequest = PageRequest.of(page, size); - if(!Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)){ + if (!Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)) { return repository.findByTypeIdAndGenres(typeId, genre, pageRequest); } - if(Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)){ + if (Objects.equals(typeId, 0L) && !Objects.equals(genre, 0L)) { return repository.findByGenres(genre, pageRequest); } - if(!Objects.equals(typeId, 0L) && Objects.equals(genre, 0L)){ + if (!Objects.equals(typeId, 0L) && Objects.equals(genre, 0L)) { return repository.findByTypeId(typeId, pageRequest); } return repository.findAll(pageRequest); } @Transactional(readOnly = true) - public GameEntity get(Long id){ + public GameEntity get(Long id) { return repository.findOneById(id).orElseThrow(() -> new NotFoundException(GameEntity.class, id)); } + @Transactional(readOnly = true) + public List getByIds(Collection ids) { + final List games = StreamSupport.stream(repository.findAllById(ids).spliterator(), false).toList(); + if (games.size() < ids.size()) { + throw new IllegalArgumentException("Invalid type"); + } + return games; + } + @Transactional - public GameEntity create(GameEntity entity){ + public GameEntity create(GameEntity entity) { if (entity == null) { throw new IllegalArgumentException("Entity is null"); } @@ -67,21 +79,21 @@ public class GameService { } @Transactional - public GameEntity update(Long id, GameEntity entity){ + public GameEntity update(Long id, GameEntity entity) { final GameEntity existEntity = get(id); existEntity.setName(entity.getName()); existEntity.setPrice(entity.getPrice()); existEntity.setDescription(entity.getDescription()); existEntity.setType(entity.getType()); var genres = entity.getGenres(); - for(var genre : genres){ + for (var genre : genres) { existEntity.setGenres(genre); } return repository.save(existEntity); } @Transactional - public GameEntity delete(Long id){ + public GameEntity delete(Long id) { final GameEntity existEntity = get(id); repository.delete(existEntity); return existEntity; diff --git a/src/main/java/com/example/demo/genres/api/GenreController.java b/src/main/java/com/example/demo/genres/api/GenreController.java index 852f406..e6c6b12 100644 --- a/src/main/java/com/example/demo/genres/api/GenreController.java +++ b/src/main/java/com/example/demo/genres/api/GenreController.java @@ -1,16 +1,14 @@ package com.example.demo.genres.api; -import java.util.List; - import org.modelmapper.ModelMapper; -import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; import com.example.demo.core.configuration.Constants; import com.example.demo.genres.model.GenreEntity; @@ -18,47 +16,90 @@ import com.example.demo.genres.service.GenreService; import jakarta.validation.Valid; -@RestController -@RequestMapping(Constants.API_URL + "/genre") +@Controller +@RequestMapping(GenreController.URL) public class GenreController { + + public static final String URL = Constants.ADMIN_PREFIX + "/genre"; + private static final String GENRE_VIEW = "genre"; + private static final String GENRE_EDIT_VIEW = "genre-edit"; + private static final String GENRE_ATTRIBUTE = "genre"; + private final GenreService genreService; private final ModelMapper modelMapper; - public GenreController(GenreService genreService, ModelMapper modelMapper){ + public GenreController(GenreService genreService, ModelMapper modelMapper) { this.genreService = genreService; this.modelMapper = modelMapper; } - private GenreDto toDto(GenreEntity entity){ + private GenreDto toDto(GenreEntity entity) { return modelMapper.map(entity, GenreDto.class); } - private GenreEntity toEntity(GenreDto dto){ + private GenreEntity toEntity(GenreDto dto) { return modelMapper.map(dto, GenreEntity.class); } @GetMapping - public List getAll(){ - return genreService.getAll().stream().map(this::toDto).toList(); + public String getAll(Model model) { + model.addAttribute( + "items", + genreService.getAll().stream() + .map(this::toDto) + .toList()); + return GENRE_VIEW; } - @GetMapping("/{id}") - public GenreDto get(@PathVariable(name="id") Long id){ - return toDto(genreService.get(id)); + @GetMapping("/edit/") + public String create(Model model) { + model.addAttribute(GENRE_ATTRIBUTE, new GenreDto()); + return GENRE_EDIT_VIEW; } - @PostMapping - public GenreDto create(@RequestBody @Valid GenreDto dto){ - return toDto(genreService.create(toEntity(dto))); + @PostMapping("/edit/") + public String create( + @ModelAttribute(name = GENRE_ATTRIBUTE) @Valid GenreDto genre, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return GENRE_EDIT_VIEW; + } + genreService.create(toEntity(genre)); + return Constants.REDIRECT_VIEW + URL; } - @PutMapping("/{id}") - public GenreDto update(@PathVariable(name="id") Long id, @RequestBody GenreDto dto){ - return toDto(genreService.update(id, toEntity(dto))); + @GetMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + Model model) { + if (id <= 0) { + throw new IllegalArgumentException(); + } + model.addAttribute(GENRE_ATTRIBUTE, toDto(genreService.get(id))); + return GENRE_EDIT_VIEW; } - - @DeleteMapping("/{id}") - public GenreDto delete(@PathVariable(name="id") Long id){ - return toDto(genreService.delete(id)); + + @PostMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + @ModelAttribute(name = GENRE_ATTRIBUTE) @Valid GenreDto genre, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return GENRE_EDIT_VIEW; + } + if (id <= 0) { + throw new IllegalArgumentException(); + } + genreService.update(id, toEntity(genre)); + return Constants.REDIRECT_VIEW + URL; + } + + @PostMapping("/delete/{id}") + public String delete( + @PathVariable(name = "id") Long id) { + genreService.delete(id); + return Constants.REDIRECT_VIEW + URL; } } diff --git a/src/main/java/com/example/demo/orders/api/OrderController.java b/src/main/java/com/example/demo/orders/api/OrderController.java deleted file mode 100644 index 7e2c55b..0000000 --- a/src/main/java/com/example/demo/orders/api/OrderController.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.example.demo.orders.api; - -import org.modelmapper.ModelMapper; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -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.RequestParam; -import org.springframework.web.bind.annotation.RestController; - - -import com.example.demo.core.configuration.Constants; -import com.example.demo.games.model.GameEntity; -import com.example.demo.games.service.GameService; -import com.example.demo.orders.model.OrderEntity; -import com.example.demo.orders.service.OrderService; -import com.example.demo.users.service.UserService; -import com.example.demo.core.api.PageDtoMapper; - -import jakarta.validation.Valid; - -@RestController -@RequestMapping(Constants.API_URL + "/user/{user}/order") -public class OrderController { - private final GameService gameService; - private final ModelMapper modelMapper; - private final OrderService orderService; - - public OrderController(GameService gameService, ModelMapper modelMapper, OrderService orderService, UserService userService){ - this.gameService = gameService; - this.modelMapper = modelMapper; - this.orderService = orderService; - } - - private OrderDto toDto(OrderEntity entity){ - var dto = new OrderDto(); - dto.setId(entity.getId()); - dto.setUserId(entity.getUser().getId()); - dto.setGames(entity.getGames().stream().map(GameEntity::getId).toList()); - return dto; - } - - private OrderEntity toEntity(OrderDto dto){ - final OrderEntity entity = modelMapper.map(dto, OrderEntity.class); - var games = dto.getGames(); - for(var game : games){ - entity.setGames(gameService.get(game)); - } - return entity; - } - - @GetMapping - public com.example.demo.core.api.PageDto getAll( - @RequestParam(name = "userId", defaultValue = "") Long userId, - @RequestParam(name = "page", defaultValue = "0") int page, - @RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE)int size){ - return PageDtoMapper.toDto(orderService.getAll(userId, page, size), this::toDto); - } - - - @GetMapping("/{id}") - public OrderDto get( - @PathVariable(name = "user") Long userId, - @PathVariable(name = "id")Long id) { - return toDto(orderService.get(userId, id)); - } - - @PostMapping - public OrderDto create( - @PathVariable(name = "user") Long userId, - @RequestBody @Valid OrderDto dto){ - return toDto(orderService.create(userId, toEntity(dto))); - } - - @DeleteMapping("/{id}") - public OrderDto delete( - @PathVariable(name = "user") Long userId, - @PathVariable(name = "id") Long id){ - return toDto(orderService.delete(userId, id)); - } -} diff --git a/src/main/java/com/example/demo/orders/api/OrderDto.java b/src/main/java/com/example/demo/orders/api/OrderDto.java index abf1d68..d25035c 100644 --- a/src/main/java/com/example/demo/orders/api/OrderDto.java +++ b/src/main/java/com/example/demo/orders/api/OrderDto.java @@ -3,40 +3,27 @@ package com.example.demo.orders.api; import java.util.ArrayList; import java.util.List; -import com.fasterxml.jackson.annotation.JsonProperty; - -import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; public class OrderDto { - @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; @NotNull - @Min(1) - private Long userId; - @NotNull private final List games = new ArrayList<>(); - public Long getId(){ + public Long getId() { return id; } - public void setId(Long id){ + + public void setId(Long id) { this.id = id; } - public List getGames(){ + public List getGames() { return games; } - public void setGames(List games){ + + public void setGames(List games) { this.games.clear(); this.games.addAll(games); } - - public Long getUserId(){ - return userId; - } - - public void setUserId(Long userId){ - this.userId = userId; - } } diff --git a/src/main/java/com/example/demo/orders/model/OrderEntity.java b/src/main/java/com/example/demo/orders/model/OrderEntity.java index e71cd60..e2678fb 100644 --- a/src/main/java/com/example/demo/orders/model/OrderEntity.java +++ b/src/main/java/com/example/demo/orders/model/OrderEntity.java @@ -18,7 +18,7 @@ import jakarta.persistence.Table; @Entity @Table(name = "orders") -public class OrderEntity extends BaseEntity{ +public class OrderEntity extends BaseEntity { // @Column(nullable = false) // private double sum; @ManyToOne @@ -27,54 +27,57 @@ public class OrderEntity extends BaseEntity{ @ManyToMany() private Set games = new HashSet<>(); - public OrderEntity(){ + public OrderEntity() { } - public OrderEntity(UserEntity user, List games){ - this.user = user; + public OrderEntity(List games) { this.games.clear(); this.games.addAll(games); } // public double getSum(){ - // for(var game : games){ - // sum += game.getPrice(); - // } - - // return sum; + // for(var game : games){ + // sum += game.getPrice(); // } - public UserEntity getUser(){ + // return sum; + // } + + public UserEntity getUser() { return user; } - public void setUser(UserEntity user){ + + public void setUser(UserEntity user) { this.user = user; - if(!user.getOrders().contains(this)){ + if (!user.getOrders().contains(this)) { user.getOrders().add(this); } } - public Set getGames(){ + public Set getGames() { return games; } - public void setGames(GameEntity game){ + + public void setGames(GameEntity game) { this.games.add(game); } @Override - public int hashCode(){ + public int hashCode() { return Objects.hash(id, games); } @Override - public boolean equals(Object obj){ - if(this == obj) return true; - if(obj == null || getClass() != obj.getClass()) return false; + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; final OrderEntity other = (OrderEntity) obj; return Objects.equals(other.getId(), id) - //&& Objects.equals(other.getSum(), sum) - && Objects.equals(other.getGames(), games); + // && Objects.equals(other.getSum(), sum) + && Objects.equals(other.getGames(), games); } } diff --git a/src/main/java/com/example/demo/orders/repository/OrderRepository.java b/src/main/java/com/example/demo/orders/repository/OrderRepository.java index 31d4cdf..9015a75 100644 --- a/src/main/java/com/example/demo/orders/repository/OrderRepository.java +++ b/src/main/java/com/example/demo/orders/repository/OrderRepository.java @@ -11,7 +11,8 @@ import org.springframework.data.repository.PagingAndSortingRepository; import com.example.demo.orders.model.OrderEntity; -public interface OrderRepository extends CrudRepository, PagingAndSortingRepository { +public interface OrderRepository + extends CrudRepository, PagingAndSortingRepository { Optional findOneByUserIdAndId(long userId, long id); List findByUserId(long userId); @@ -20,6 +21,6 @@ public interface OrderRepository extends CrudRepository, Pagi Page findByUserId(long userId, Pageable pageable); List findAll(); - - //Можно сделать запрос на сумму JPQL + + // Можно сделать запрос на сумму JPQL } diff --git a/src/main/java/com/example/demo/orders/service/OrderService.java b/src/main/java/com/example/demo/orders/service/OrderService.java index af1bf3e..210ec35 100644 --- a/src/main/java/com/example/demo/orders/service/OrderService.java +++ b/src/main/java/com/example/demo/orders/service/OrderService.java @@ -1,11 +1,13 @@ package com.example.demo.orders.service; import java.util.List; +import java.util.stream.StreamSupport; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; import com.example.demo.core.error.NotFoundException; @@ -19,37 +21,38 @@ public class OrderService { private final OrderRepository repository; private final UserService userService; - public OrderService(OrderRepository repository, UserService userService){ + public OrderService(OrderRepository repository, UserService userService) { this.repository = repository; this.userService = userService; } - @Transactional(readOnly = true) - public Page getAll(long userId, int page, int size){ - final Pageable pageRequest = PageRequest.of(page, size); + public Page getAll(long userId, int page, int size) { + final Pageable pageRequest = PageRequest.of(page, size, Sort.by("id")); userService.get(userId); return repository.findByUserId(userId, pageRequest); } @Transactional(readOnly = true) - public List getAll(long userId){ + public List getAll(long userId) { userService.get(userId); return repository.findByUserId(userId); } - public List getAll(){ + + public List getAll() { return repository.findAll(); } @Transactional(readOnly = true) - public OrderEntity get(long userId, long id){ + public OrderEntity get(long userId, long id) { userService.get(userId); - return repository.findOneByUserIdAndId(userId, id).orElseThrow(() -> new NotFoundException(OrderEntity.class, id)); + return repository.findOneByUserIdAndId(userId, id) + .orElseThrow(() -> new NotFoundException(OrderEntity.class, id)); } @Transactional - public OrderEntity create(long userId, OrderEntity entity){ - if(entity == null){ + public OrderEntity create(long userId, OrderEntity entity) { + if (entity == null) { throw new IllegalArgumentException("Entity is null"); } final UserEntity existsUser = userService.get(userId); @@ -58,7 +61,17 @@ public class OrderService { } @Transactional - public OrderEntity delete(long userId, long id){ + public List createAll(long userId, List entities) { + if (entities == null || entities.isEmpty()) { + throw new IllegalArgumentException("Orders list is null or empty"); + } + final UserEntity existsUser = userService.get(userId); + entities.forEach(entity -> entity.setUser(existsUser)); + return StreamSupport.stream(repository.saveAll(entities).spliterator(), false).toList(); + } + + @Transactional + public OrderEntity delete(long userId, long id) { userService.get(userId); final OrderEntity existsEntity = get(userId, id); repository.delete(existsEntity); diff --git a/src/main/java/com/example/demo/types/api/TypeController.java b/src/main/java/com/example/demo/types/api/TypeController.java index 2938544..af64bb9 100644 --- a/src/main/java/com/example/demo/types/api/TypeController.java +++ b/src/main/java/com/example/demo/types/api/TypeController.java @@ -1,16 +1,14 @@ package com.example.demo.types.api; -import java.util.List; - import org.modelmapper.ModelMapper; -import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; import com.example.demo.core.configuration.Constants; import com.example.demo.types.model.TypeEntity; @@ -18,47 +16,90 @@ import com.example.demo.types.service.TypeService; import jakarta.validation.Valid; -@RestController -@RequestMapping(Constants.API_URL + "/type") +@Controller +@RequestMapping(TypeController.URL) public class TypeController { + + public static final String URL = Constants.ADMIN_PREFIX + "/type"; + private static final String TYPE_VIEW = "type"; + private static final String TYPE_EDIT_VIEW = "type-edit"; + private static final String TYPE_ATTRIBUTE = "type"; + private final TypeService typeService; private final ModelMapper modelMapper; - public TypeController(TypeService typeService, ModelMapper modelMapper){ + public TypeController(TypeService typeService, ModelMapper modelMapper) { this.typeService = typeService; this.modelMapper = modelMapper; } - private TypeDto toDto(TypeEntity entity){ + private TypeDto toDto(TypeEntity entity) { return modelMapper.map(entity, TypeDto.class); } - private TypeEntity toEntity(TypeDto dto){ + private TypeEntity toEntity(TypeDto dto) { return modelMapper.map(dto, TypeEntity.class); } @GetMapping - public List getAll(){ - return typeService.getAll().stream().map(this::toDto).toList(); + public String getAll(Model model) { + model.addAttribute( + "items", + typeService.getAll().stream() + .map(this::toDto) + .toList()); + return TYPE_VIEW; } - @GetMapping("/{id}") - public TypeDto get(@PathVariable(name = "id") Long id){ - return toDto(typeService.get(id)); + @GetMapping("/edit/") + public String create(Model model) { + model.addAttribute(TYPE_ATTRIBUTE, new TypeDto()); + return TYPE_EDIT_VIEW; } - @PostMapping - public TypeDto create(@RequestBody @Valid TypeDto dto){ - return toDto(typeService.create(toEntity(dto))); + @PostMapping("/edit/") + public String create( + @ModelAttribute(name = TYPE_ATTRIBUTE) @Valid TypeDto type, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return TYPE_EDIT_VIEW; + } + typeService.create(toEntity(type)); + return Constants.REDIRECT_VIEW + URL; } - @PutMapping("/{id}") - public TypeDto update(@PathVariable(name = "id") Long id, @RequestBody TypeDto dto){ - return toDto(typeService.update(id, toEntity(dto))); + @GetMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + Model model) { + if (id <= 0) { + throw new IllegalArgumentException(); + } + model.addAttribute(TYPE_ATTRIBUTE, toDto(typeService.get(id))); + return TYPE_EDIT_VIEW; } - @DeleteMapping("/{id}") - public TypeDto delete(@PathVariable(name = "id") Long id){ - return toDto(typeService.delete(id)); + @PostMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + @ModelAttribute(name = TYPE_ATTRIBUTE) @Valid TypeDto type, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return TYPE_EDIT_VIEW; + } + if (id <= 0) { + throw new IllegalArgumentException(); + } + typeService.update(id, toEntity(type)); + return Constants.REDIRECT_VIEW + URL; + } + + @PostMapping("/delete/{id}") + public String delete( + @PathVariable(name = "id") Long id) { + typeService.delete(id); + return Constants.REDIRECT_VIEW + URL; } } diff --git a/src/main/java/com/example/demo/types/api/TypeDto.java b/src/main/java/com/example/demo/types/api/TypeDto.java index e451a22..98f3fff 100644 --- a/src/main/java/com/example/demo/types/api/TypeDto.java +++ b/src/main/java/com/example/demo/types/api/TypeDto.java @@ -1,30 +1,27 @@ package com.example.demo.types.api; -import com.fasterxml.jackson.annotation.JsonProperty; - import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; public class TypeDto { - @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; @NotBlank @Size(min = 1, max = 50) private String name; - public Long getId(){ + public Long getId() { return id; } - - public void setId(Long id){ + + public void setId(Long id) { this.id = id; } - public String getName(){ + public String getName() { return name; } - - public void setName(String name){ + + public void setName(String name) { this.name = name; } } diff --git a/src/main/java/com/example/demo/users/api/UserCartController.java b/src/main/java/com/example/demo/users/api/UserCartController.java new file mode 100644 index 0000000..3be1044 --- /dev/null +++ b/src/main/java/com/example/demo/users/api/UserCartController.java @@ -0,0 +1,128 @@ +package com.example.demo.users.api; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.modelmapper.ModelMapper; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; +import org.springframework.web.bind.support.SessionStatus; + +import com.example.demo.core.configuration.Constants; +import com.example.demo.core.security.UserPrincipal; +import com.example.demo.core.session.SessionCart; +import com.example.demo.games.api.GameDto; +import com.example.demo.games.model.GameEntity; +import com.example.demo.games.service.GameService; +import com.example.demo.genres.model.GenreEntity; +import com.example.demo.orders.model.OrderEntity; +import com.example.demo.orders.service.OrderService; + +import jakarta.validation.Valid; + +@Controller +@RequestMapping(UserCartController.URL) +@SessionAttributes("games") +public class UserCartController { + public static final String URL = "/cart"; + private static final String ORDER_VIEW = "cart"; + private static final String ORDER_ATTRIBUTE = "order"; + private static final String CART_ATTRIBUTE = "cart"; + + private final GameService gameService; + private final OrderService orderService; + private final SessionCart cart; + private final ModelMapper modelMapper; + + public UserCartController( + GameService gameService, + OrderService orderService, + SessionCart cart, + ModelMapper modelMapper) { + this.gameService = gameService; + this.orderService = orderService; + this.cart = cart; + this.modelMapper = modelMapper; + } + + private GameDto toGameDto(GameEntity entity) { + var dto = new GameDto(); + dto.setId(entity.getId()); + dto.setGenres(entity.getGenres().stream().map(GenreEntity::getId).toList()); + dto.setDescription(entity.getDescription()); + dto.setName(entity.getName()); + dto.setPrice(entity.getPrice()); + dto.setTypeId(entity.getType().getId()); + return dto; + } + + private List toOrderEntities(Collection dtos) { + final Set gameIds = dtos.stream() + .map(UserCartDto::getGame) + .collect(Collectors.toSet()); + final Map games = gameService.getByIds(gameIds).stream() + .collect(Collectors.toMap(GameEntity::getId, Function.identity())); + return dtos.stream() + .map(dto -> { + final OrderEntity entity = modelMapper.map(dto, OrderEntity.class); + entity.setGames(games.get(dto.getGame())); + return entity; + }).toList(); + } + + @GetMapping + public String getCart(Model model) { + model.addAttribute("games", + gameService.getAll(0, 0).stream() + .map(this::toGameDto) + .toList()); + model.addAttribute(ORDER_ATTRIBUTE, new UserCartDto()); + model.addAttribute(CART_ATTRIBUTE, cart.values()); + return ORDER_VIEW; + } + + @PostMapping + public String addOrderToCart( + @ModelAttribute(name = ORDER_ATTRIBUTE) @Valid UserCartDto order, + BindingResult bindingResult, + SessionStatus status, + Model model) { + if (bindingResult.hasErrors()) { + return ORDER_VIEW; + } + status.setComplete(); + order.setGameName(gameService.get(order.getGame()).getName()); + order.setPrice(gameService.get(order.getGame()).getPrice()); + cart.computeIfPresent(order.hashCode(), (key, value) -> { + return value; + }); + cart.put(order.hashCode(), order); + return Constants.REDIRECT_VIEW + URL; + } + + @PostMapping("/save") + public String saveCart( + Model model, + @AuthenticationPrincipal UserPrincipal principal) { + orderService.createAll(principal.getId(), toOrderEntities(cart.values())); + cart.clear(); + return Constants.REDIRECT_VIEW + URL; + } + + @PostMapping("/clear") + public String clearCart() { + cart.clear(); + return Constants.REDIRECT_VIEW + URL; + } +} diff --git a/src/main/java/com/example/demo/users/api/UserCartDto.java b/src/main/java/com/example/demo/users/api/UserCartDto.java new file mode 100644 index 0000000..b95281c --- /dev/null +++ b/src/main/java/com/example/demo/users/api/UserCartDto.java @@ -0,0 +1,53 @@ +package com.example.demo.users.api; + +import java.util.Objects; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + +public class UserCartDto { + @NotNull + private Long game; + private String gameName; + @Min(1000) + private Double price; + + public Long getGame() { + return game; + } + + public void setGame(Long gameId) { + this.game = gameId; + } + + public String getGameName() { + return gameName; + } + + public void setGameName(String gameName) { + this.gameName = gameName; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + @Override + public int hashCode() { + return Objects.hash(game, price); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + UserCartDto other = (UserCartDto) obj; + return Objects.equals(game, other.game) && Objects.equals(price, other.price); + } +} diff --git a/src/main/java/com/example/demo/users/api/UserController.java b/src/main/java/com/example/demo/users/api/UserController.java index 102cf11..8f2f882 100644 --- a/src/main/java/com/example/demo/users/api/UserController.java +++ b/src/main/java/com/example/demo/users/api/UserController.java @@ -1,18 +1,22 @@ package com.example.demo.users.api; +import java.util.Map; + import org.modelmapper.ModelMapper; -import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; + import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +import com.example.demo.core.api.PageAttributesMapper; -import com.example.demo.core.api.PageDto; -import com.example.demo.core.api.PageDtoMapper; import com.example.demo.core.configuration.Constants; import com.example.demo.orders.service.OrderService; import com.example.demo.users.model.UserEntity; @@ -20,49 +24,103 @@ import com.example.demo.users.service.UserService; import jakarta.validation.Valid; -@RestController -@RequestMapping(Constants.API_URL+"/user") +@Controller +@RequestMapping(UserController.URL) public class UserController { + + public static final String URL = Constants.ADMIN_PREFIX + "/user"; + private static final String USER_VIEW = "user"; + private static final String USER_EDIT_VIEW = "user-edit"; + private static final String PAGE_ATTRIBUTE = "page"; + private static final String USER_ATTRIBUTE = "user"; + private final ModelMapper modelMapper; private final UserService userService; - public UserController(OrderService orderService, ModelMapper modelMapper, UserService userService){ + public UserController(OrderService orderService, ModelMapper modelMapper, UserService userService) { this.modelMapper = modelMapper; this.userService = userService; } - private UserDto toDto(UserEntity entity){ + private UserDto toDto(UserEntity entity) { return modelMapper.map(entity, UserDto.class); } - private UserEntity toEntity(UserDto dto){ + private UserEntity toEntity(UserDto dto) { return modelMapper.map(dto, UserEntity.class); } @GetMapping - public PageDto getAll( - @RequestParam(name = "page", defaultValue = "0") int page, - @RequestParam(name = "size", defaultValue = Constants.DEFAULT_PAGE_SIZE) int size) { - return PageDtoMapper.toDto(userService.getAll(page, size), this::toDto); + public String getAll( + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + Model model) { + final Map attributes = PageAttributesMapper.toAttributes( + userService.getAll(page, Constants.DEFAULT_PAGE_SIZE), this::toDto); + model.addAllAttributes(attributes); + model.addAttribute(PAGE_ATTRIBUTE, page); + return USER_VIEW; } - @GetMapping("/{id}") - public UserDto get(@PathVariable(name = "id") Long id){ - return toDto(userService.get(id)); + @GetMapping("/edit/") + public String create( + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + Model model) { + model.addAttribute(USER_ATTRIBUTE, new UserDto()); + model.addAttribute(PAGE_ATTRIBUTE, page); + return USER_EDIT_VIEW; } - @PostMapping - public UserDto create(@RequestBody @Valid UserDto dto){ - return toDto(userService.create(toEntity(dto))); + @PostMapping("/edit/") + public String create( + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + @ModelAttribute(name = USER_ATTRIBUTE) @Valid UserDto user, + BindingResult bindingResult, + Model model, + RedirectAttributes redirectAttributes) { + if (bindingResult.hasErrors()) { + model.addAttribute(PAGE_ATTRIBUTE, page); + return USER_EDIT_VIEW; + } + redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page); + userService.create(toEntity(user)); + return Constants.REDIRECT_VIEW + URL; } - @PutMapping("/{id}") - public UserDto update(@PathVariable(name = "id") Long id, @RequestBody UserDto dto){ - return toDto(userService.update(id, toEntity(dto))); + @GetMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + Model model) { + if (id <= 0) { + throw new IllegalArgumentException(); + } + model.addAttribute(USER_ATTRIBUTE, toDto(userService.get(id))); + model.addAttribute(PAGE_ATTRIBUTE, page); + return USER_EDIT_VIEW; } - @DeleteMapping("/{id}") - public UserDto delete(@PathVariable(name = "id")Long id){ + @PostMapping("/edit/{id}") + public String update( + @PathVariable(name = "id") Long id, + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + @ModelAttribute(name = USER_ATTRIBUTE) @Valid UserDto user, + BindingResult bindingResult, + Model model, + RedirectAttributes redirectAttributes) { + if (bindingResult.hasErrors()) { + model.addAttribute(PAGE_ATTRIBUTE, page); + return USER_EDIT_VIEW; + } + if (id <= 0) { + throw new IllegalArgumentException(); + } + redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page); + userService.update(id, toEntity(user)); + return Constants.REDIRECT_VIEW + URL; + } + + @PostMapping("/delete/{id}") + public UserDto delete(@PathVariable(name = "id") Long id) { return toDto(userService.delete(id)); } } diff --git a/src/main/java/com/example/demo/users/api/UserDto.java b/src/main/java/com/example/demo/users/api/UserDto.java index a0e0584..11ca987 100644 --- a/src/main/java/com/example/demo/users/api/UserDto.java +++ b/src/main/java/com/example/demo/users/api/UserDto.java @@ -1,12 +1,9 @@ package com.example.demo.users.api; -import com.fasterxml.jackson.annotation.JsonProperty; - import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; public class UserDto { - @JsonProperty(access = JsonProperty.Access.READ_ONLY) private Long id; @NotBlank @Size(min = 2, max = 20) @@ -14,35 +11,37 @@ public class UserDto { @NotBlank @Size(min = 2, max = 20) private String email; - @NotBlank - @Size(min = 2, max = 20) - private String password; + private String role; - public Long getId(){ + public Long getId() { return id; } - public void setId(Long id){ + + public void setId(Long id) { this.id = id; } - public String getLogin(){ + public String getLogin() { return login; } - public void setLogin(String login){ + + public void setLogin(String login) { this.login = login; } - public String getEmail(){ + public String getEmail() { return email; } - public void setEmail(String email){ + + public void setEmail(String email) { this.email = email; } - public String getPassword(){ - return password; + public String getRole() { + return role; } - public void setPassword(String password){ - this.password = password; + + public void setRole(String role) { + this.role = role; } } diff --git a/src/main/java/com/example/demo/users/api/UserProfileController.java b/src/main/java/com/example/demo/users/api/UserProfileController.java new file mode 100644 index 0000000..f480f40 --- /dev/null +++ b/src/main/java/com/example/demo/users/api/UserProfileController.java @@ -0,0 +1,82 @@ +package com.example.demo.users.api; + +import org.modelmapper.ModelMapper; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import com.example.demo.core.api.PageAttributesMapper; +import com.example.demo.core.configuration.Constants; +import com.example.demo.core.security.UserPrincipal; +import com.example.demo.games.api.GameDto; +import com.example.demo.games.model.GameEntity; +import com.example.demo.games.service.GameService; +import com.example.demo.genres.model.GenreEntity; +import com.example.demo.orders.api.OrderDto; +import com.example.demo.orders.model.OrderEntity; +import com.example.demo.orders.service.OrderService; +import com.example.demo.users.service.UserService; + +@Controller +public class UserProfileController { + private static final String PROFILE_VIEW = "profile"; + + private static final String PAGE_ATTRIBUTE = "page"; + private static final String TYPEID_ATTRIBUTE = "gameId"; + private static final String PROFILE_ATTRIBUTE = "profile"; + + private final OrderService orderService; + private final GameService gameService; + private final UserService userService; + private final ModelMapper modelMapper; + + public UserProfileController( + OrderService orderService, + GameService gameService, + UserService userService, + ModelMapper modelMapper) { + this.orderService = orderService; + this.gameService = gameService; + this.userService = userService; + this.modelMapper = modelMapper; + } + + private OrderDto toDto(OrderEntity entity) { + var dto = new OrderDto(); + dto.setId(entity.getId()); + dto.setGames(entity.getGames().stream().map(GameEntity::getId).toList()); + return dto; + } + + private GameDto toGameDto(GameEntity entity) { + var dto = new GameDto(); + dto.setId(entity.getId()); + dto.setGenres(entity.getGenres().stream().map(GenreEntity::getId).toList()); + dto.setDescription(entity.getDescription()); + dto.setName(entity.getName()); + dto.setPrice(entity.getPrice()); + dto.setTypeId(entity.getType().getId()); + return dto; + } + + @GetMapping + public String getProfile( + @RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, + @RequestParam(name = TYPEID_ATTRIBUTE, defaultValue = "0") int typeId, + Model model, + @AuthenticationPrincipal UserPrincipal principal) { + final long userId = principal.getId(); + model.addAttribute(PAGE_ATTRIBUTE, page); + model.addAttribute(TYPEID_ATTRIBUTE, typeId); + model.addAllAttributes(PageAttributesMapper.toAttributes( + orderService.getAll(userId, page, Constants.DEFAULT_PAGE_SIZE), + this::toDto)); + model.addAttribute("games", + gameService.getAll(0, 0).stream() + .map(this::toGameDto) + .toList()); + return PROFILE_VIEW; + } +} diff --git a/src/main/java/com/example/demo/users/api/UserSignupController.java b/src/main/java/com/example/demo/users/api/UserSignupController.java new file mode 100644 index 0000000..01d0509 --- /dev/null +++ b/src/main/java/com/example/demo/users/api/UserSignupController.java @@ -0,0 +1,63 @@ +package com.example.demo.users.api; + +import java.util.Objects; + +import org.modelmapper.ModelMapper; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.example.demo.core.configuration.Constants; +import com.example.demo.users.model.UserEntity; +import com.example.demo.users.service.UserService; + +import jakarta.validation.Valid; + +@Controller +@RequestMapping(UserSignupController.URL) +public class UserSignupController { + public static final String URL = "/signup"; + + private static final String SIGNUP_VIEW = "signup"; + private static final String USER_ATTRIBUTE = "user"; + + private final UserService userService; + private final ModelMapper modelMapper; + + public UserSignupController( + UserService userService, + ModelMapper modelMapper) { + this.userService = userService; + this.modelMapper = modelMapper; + } + + private UserEntity toEntity(UserSignupDto dto) { + return modelMapper.map(dto, UserEntity.class); + } + + @GetMapping + public String getSignup(Model model) { + model.addAttribute(USER_ATTRIBUTE, new UserSignupDto()); + return SIGNUP_VIEW; + } + @PostMapping + public String signup( + @ModelAttribute(name = USER_ATTRIBUTE) @Valid UserSignupDto user, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + return SIGNUP_VIEW; + } + if (!Objects.equals(user.getPassword(), user.getPasswordConfirm())) { + bindingResult.rejectValue("password", "signup:passwords", "Пароли не совпадают."); + model.addAttribute(USER_ATTRIBUTE, user); + return SIGNUP_VIEW; + } + userService.create(toEntity(user)); + return Constants.REDIRECT_VIEW + Constants.LOGIN_URL + "?signup"; + } +} diff --git a/src/main/java/com/example/demo/users/api/UserSignupDto.java b/src/main/java/com/example/demo/users/api/UserSignupDto.java new file mode 100644 index 0000000..9530e92 --- /dev/null +++ b/src/main/java/com/example/demo/users/api/UserSignupDto.java @@ -0,0 +1,51 @@ +package com.example.demo.users.api; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public class UserSignupDto { + @NotBlank + @Size(min = 3, max = 20) + private String login; + @NotBlank + @Size(min = 3, max = 20) + private String email; + @NotBlank + @Size(min = 3, max = 20) + private String password; + @NotBlank + @Size(min = 3, max = 20) + private String passwordConfirm; + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getPasswordConfirm() { + return passwordConfirm; + } + + public void setPasswordConfirm(String passwordConfirm) { + this.passwordConfirm = passwordConfirm; + } +} diff --git a/src/main/java/com/example/demo/users/model/UserEntity.java b/src/main/java/com/example/demo/users/model/UserEntity.java index e093a4a..ddd8663 100644 --- a/src/main/java/com/example/demo/users/model/UserEntity.java +++ b/src/main/java/com/example/demo/users/model/UserEntity.java @@ -20,8 +20,9 @@ public class UserEntity extends BaseEntity{ private String login; @Column(nullable = false, unique = true, length = 20) private String email; - @Column(nullable = false, unique = true, length = 20) + @Column(nullable = false, length = 60) private String password; + private UserRole role; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) @OrderBy("id ASC") private List orders = new ArrayList<>(); @@ -33,6 +34,7 @@ public class UserEntity extends BaseEntity{ this.login = login; this.email = email; this.password = password; + this.role = UserRole.USER; } public String getLogin(){ @@ -56,6 +58,14 @@ public class UserEntity extends BaseEntity{ this.password = password; } + public UserRole getRole() { + return role; + } + + public void setRole(UserRole role) { + this.role = role; + } + public List getOrders(){ return orders; } diff --git a/src/main/java/com/example/demo/users/model/UserRole.java b/src/main/java/com/example/demo/users/model/UserRole.java new file mode 100644 index 0000000..86056ca --- /dev/null +++ b/src/main/java/com/example/demo/users/model/UserRole.java @@ -0,0 +1,15 @@ +package com.example.demo.users.model; + +import org.springframework.security.core.GrantedAuthority; + +public enum UserRole implements GrantedAuthority{ + ADMIN, + USER; + + private static final String PREFIX = "ROLE_"; + + @Override + public String getAuthority() { + return PREFIX + this.name(); + } +} diff --git a/src/main/java/com/example/demo/users/service/UserService.java b/src/main/java/com/example/demo/users/service/UserService.java index 040b5d4..867d956 100644 --- a/src/main/java/com/example/demo/users/service/UserService.java +++ b/src/main/java/com/example/demo/users/service/UserService.java @@ -4,60 +4,100 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; import java.util.stream.StreamSupport; import org.springframework.data.domain.Page; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.data.domain.PageRequest; +import org.springframework.util.StringUtils; +import com.example.demo.core.configuration.Constants; import com.example.demo.core.error.NotFoundException; +import com.example.demo.core.security.UserPrincipal; import com.example.demo.users.model.UserEntity; +import com.example.demo.users.model.UserRole; import com.example.demo.users.repository.UserRepository; @Service -public class UserService { +public class UserService implements UserDetailsService { private final UserRepository repository; + private final PasswordEncoder passwordEncoder; - public UserService(UserRepository repository){ + public UserService(UserRepository repository, PasswordEncoder passwordEncoder) { this.repository = repository; + this.passwordEncoder = passwordEncoder; + } + + private void checkLogin(Long id, String login) { + final Optional existsUser = repository.findByLoginIgnoreCase(login); + if (existsUser.isPresent() && !existsUser.get().getId().equals(id)) { + throw new IllegalArgumentException( + String.format("User with login %s is already exists", login)); + } } @Transactional(readOnly = true) - public List getAll(){ + public List getAll() { return StreamSupport.stream(repository.findAll().spliterator(), false).toList(); } @Transactional(readOnly = true) public Page getAll(int page, int size) { - return repository.findAll(PageRequest.of(page, size)); + return repository.findAll(PageRequest.of(page, size, Sort.by("id"))); } @Transactional(readOnly = true) - public UserEntity get(Long id){ - return repository.findById(id).orElseThrow(() -> new NotFoundException(UserEntity.class, id)); + public UserEntity get(Long id) { + return repository.findById(id).orElseThrow(() -> new NotFoundException(UserEntity.class, id)); + } + + @Transactional(readOnly = true) + public UserEntity getByLogin(String login) { + return repository.findByLoginIgnoreCase(login) + .orElseThrow(() -> new IllegalArgumentException("Invalid login")); } @Transactional - public UserEntity create(UserEntity entity){ + public UserEntity create(UserEntity entity) { if (entity == null) { throw new IllegalArgumentException("Entity is null"); } + checkLogin(null, entity.getLogin()); + final String password = Optional.ofNullable(entity.getPassword()).orElse(""); + entity.setPassword( + passwordEncoder.encode( + StringUtils.hasText(password.strip()) ? password : Constants.DEFAULT_PASSWORD)); + entity.setRole(Optional.ofNullable(entity.getRole()).orElse(UserRole.USER)); + repository.save(entity); return repository.save(entity); } @Transactional - public UserEntity update(Long id, UserEntity entity){ + public UserEntity update(Long id, UserEntity entity) { final UserEntity existEntity = get(id); + checkLogin(id, entity.getLogin()); existEntity.setLogin(entity.getLogin()); existEntity.setEmail(entity.getEmail()); - existEntity.setPassword(entity.getPassword()); repository.save(existEntity); return existEntity; } @Transactional - public UserEntity delete(Long id){ + public UserEntity delete(Long id) { final UserEntity existEntity = get(id); repository.delete(existEntity); return existEntity; } + + @Override + @Transactional(readOnly = true) + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + final UserEntity existsUser = getByLogin(username); + return new UserPrincipal(existsUser); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f803d58..97cc8c1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,4 @@ +# Server spring.main.banner-mode=off server.port=8080 diff --git a/src/main/resources/public/css/style.css b/src/main/resources/public/css/style.css new file mode 100644 index 0000000..7423490 --- /dev/null +++ b/src/main/resources/public/css/style.css @@ -0,0 +1,67 @@ +html, +body { + height: 100%; +} + +h1 { + font-size: 1.5em; +} + +h2 { + font-size: 1.25em; +} + +h3 { + font-size: 1.1em; +} + +td form { + margin: 0; + padding: 0; + margin-top: -.25em; +} + +.button-fixed-width { + width: 150px; +} + +.button-link { + padding: 0; +} + +.invalid-feedback { + display: block; +} + +.w-10 { + width: 10% !important; +} + +.my-navbar { + background-color: #3c3c3c !important; +} + +.my-navbar .link a:hover { + text-decoration: underline; +} + +.my-navbar .logo { + width: 26px; + height: 26px; +} + +.my-footer { + background-color: #2c2c2c; + height: 32px; + color: rgba(255, 255, 255, 0.5); +} + +.cart-image { + width: 3.1rem; + padding: 0.25rem; + border-radius: 0.5rem; +} + +.cart-item { + height: auto; +} \ No newline at end of file diff --git a/src/main/resources/public/favicon.svg b/src/main/resources/public/favicon.svg new file mode 100644 index 0000000..7a161ba --- /dev/null +++ b/src/main/resources/public/favicon.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/src/main/resources/templates/cart.html b/src/main/resources/templates/cart.html new file mode 100644 index 0000000..a19c372 --- /dev/null +++ b/src/main/resources/templates/cart.html @@ -0,0 +1,68 @@ + + + + + Корзина + + + +
+
+
+ Корзина +
+ +
+
+
+
+
+ [[${cartItem.gameName}]] + +
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+ + +
+
+
+ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/default.html b/src/main/resources/templates/default.html new file mode 100644 index 0000000..2be9f25 --- /dev/null +++ b/src/main/resources/templates/default.html @@ -0,0 +1,75 @@ + + + + + + + + My shop + + + + + + + +
+
+
+
+ Автор, [[${#dates.year(#dates.createNow())}]] +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html new file mode 100644 index 0000000..faa6b0a --- /dev/null +++ b/src/main/resources/templates/error.html @@ -0,0 +1,37 @@ + + + + + Ошибка + + + +
+
    + +
  • + Неизвестная ошибка +
  • +
    + +
  • + Ошибка: [[${message}]] +
  • +
    + +
  • + Адрес: [[${url}]] +
  • +
  • + Класс исключения: [[${exception}]] +
  • +
  • + [[${method}]] ([[${file}]]:[[${line}]]) +
  • +
    +
+ На главную +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/game.html b/src/main/resources/templates/game.html new file mode 100644 index 0000000..43bd0cb --- /dev/null +++ b/src/main/resources/templates/game.html @@ -0,0 +1,55 @@ + + + + + Игры + + + +
+ +

Данные отсутствуют

+ +

Игры

+ + + + + + + + + + + + + + + + + + + + + + + + +
IDНазваниеЦенаОписание
+
+ +
+
+
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/genre-edit.html b/src/main/resources/templates/genre-edit.html new file mode 100644 index 0000000..7d981b7 --- /dev/null +++ b/src/main/resources/templates/genre-edit.html @@ -0,0 +1,28 @@ + + + + + Редакторовать жанр + + + +
+
+
+ + +
+
+ + +
+
+
+ + Отмена +
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/genre.html b/src/main/resources/templates/genre.html new file mode 100644 index 0000000..817ccfc --- /dev/null +++ b/src/main/resources/templates/genre.html @@ -0,0 +1,51 @@ + + + + + Жанры игр + + + +
+ +

Данные отсутствуют

+ +

Жанры игр

+ + + + + + + + + + + + + + + + + + + + +
IDЖанр
+
+ +
+
+
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..a44fde8 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,42 @@ + + + + + Вход + + + +
+
+
+ Неверный логин или пароль +
+
+ Выход успешно произведен +
+
+ Пользователь успешно создан +
+
+ + +
+
+ + +
+
+ + +
+
+ + Регистрация +
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/orders.html b/src/main/resources/templates/orders.html new file mode 100644 index 0000000..8a5340c --- /dev/null +++ b/src/main/resources/templates/orders.html @@ -0,0 +1,62 @@ + + + + + + +

Данные отсутствуют

+ + + + + + + + + + + + + + + + + + + +
IDИгры
+ + + + + + + + + + + + +
Название игры
+
+
+ + + +
+
+
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/pagination.html b/src/main/resources/templates/pagination.html new file mode 100644 index 0000000..b11664a --- /dev/null +++ b/src/main/resources/templates/pagination.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/profile.html b/src/main/resources/templates/profile.html new file mode 100644 index 0000000..57e7454 --- /dev/null +++ b/src/main/resources/templates/profile.html @@ -0,0 +1,25 @@ + + + + + Личный кабинет + + + +
+ + +
+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 0000000..ef77769 --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,40 @@ + + + + + Вход + + + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + Отмена +
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/type-edit.html b/src/main/resources/templates/type-edit.html new file mode 100644 index 0000000..91f03ca --- /dev/null +++ b/src/main/resources/templates/type-edit.html @@ -0,0 +1,28 @@ + + + + + Редакторовать тип заказа + + + +
+
+
+ + +
+
+ + +
+
+
+ + Отмена +
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/type.html b/src/main/resources/templates/type.html new file mode 100644 index 0000000..0385aa1 --- /dev/null +++ b/src/main/resources/templates/type.html @@ -0,0 +1,50 @@ + + + + + Типы игр + + + +
+ +

Данные отсутствуют

+ +

Типы игр

+ + + + + + + + + + + + + + + + + + + +
IDТип игры
+
+ +
+
+
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user-edit.html b/src/main/resources/templates/user-edit.html new file mode 100644 index 0000000..90d2254 --- /dev/null +++ b/src/main/resources/templates/user-edit.html @@ -0,0 +1,34 @@ + + + + + Редакторовать пользователя + + + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + Отмена +
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/user.html b/src/main/resources/templates/user.html new file mode 100644 index 0000000..1fa8c7b --- /dev/null +++ b/src/main/resources/templates/user.html @@ -0,0 +1,58 @@ + + + + + Пользователи + + + +
+ +

Данные отсутствуют

+ +

Пользователи

+ + + + + + + + + + + + + + + + + + + + + +
IDИмя пользователяПочта
+
+ + +
+
+
+ + +
+
+
+ + +
+ + + \ No newline at end of file diff --git a/src/test/java/com/example/demo/OrderServiceTest.java b/src/test/java/com/example/demo/OrderServiceTest.java index 9124b3d..70038f7 100644 --- a/src/test/java/com/example/demo/OrderServiceTest.java +++ b/src/test/java/com/example/demo/OrderServiceTest.java @@ -53,27 +53,27 @@ class OrderServiceTest { private OrderEntity order1; @BeforeEach - void createData(){ + void createData() { genre1 = genreService.create(new GenreEntity("Приключения")); genre2 = genreService.create(new GenreEntity("Симулятор")); type1 = typeService.create(new TypeEntity("Игра")); type2 = typeService.create(new TypeEntity("Программа")); - genres1 = new ArrayList(); - genres1.add(genre1); - genres1.add(genre2); + genres1 = new ArrayList(); + genres1.add(genre1); + genres1.add(genre2); - genres2 = new ArrayList(); - genres2.add(genre2); + genres2 = new ArrayList(); + genres2.add(genre2); - game1 = gameService.create(new GameEntity(type1,"Game1",2100.0,"good game", genres1)); - game2 = gameService.create(new GameEntity( type2, "Game2", 1200.0,"bad game", genres2)); - games = new ArrayList(); - games.add(game1); - games.add(game2); + game1 = gameService.create(new GameEntity(type1, "Game1", 2100.0, "good game", genres1)); + game2 = gameService.create(new GameEntity(type2, "Game2", 1200.0, "bad game", genres2)); + games = new ArrayList(); + games.add(game1); + games.add(game2); - user1 = userService.create(new UserEntity( "login1", "email@mail.com", "qwerty123")); - order1 = orderService.create(user1.getId(), new OrderEntity(user1,games)); + user1 = userService.create(new UserEntity("login1", "email@mail.com", "qwerty123")); + order1 = orderService.create(user1.getId(), new OrderEntity(games)); removeData(); genre1 = genreService.create(new GenreEntity("Приключения")); @@ -81,50 +81,51 @@ class OrderServiceTest { type1 = typeService.create(new TypeEntity("Игра")); type2 = typeService.create(new TypeEntity("Программа")); - genres1 = new ArrayList(); - genres1.add(genre1); - genres1.add(genre2); + genres1 = new ArrayList(); + genres1.add(genre1); + genres1.add(genre2); - genres2 = new ArrayList(); - genres2.add(genre2); + genres2 = new ArrayList(); + genres2.add(genre2); - game1 = gameService.create(new GameEntity(type1,"Game1",2100.0,"good game", genres1)); - game2 = gameService.create(new GameEntity( type2, "Game2", 1200.0,"bad game", genres2)); - games = new ArrayList(); - games.add(game1); - games.add(game2); + game1 = gameService.create(new GameEntity(type1, "Game1", 2100.0, "good game", genres1)); + game2 = gameService.create(new GameEntity(type2, "Game2", 1200.0, "bad game", genres2)); + games = new ArrayList(); + games.add(game1); + games.add(game2); - user1 = userService.create(new UserEntity( "login1", "email@mail.com", "qwerty123")); - order1 = orderService.create(user1.getId(), new OrderEntity(user1,games)); - orderService.create(user1.getId(), new OrderEntity(user1,games)); + user1 = userService.create(new UserEntity("login1", "email@mail.com", "qwerty123")); + order1 = orderService.create(user1.getId(), new OrderEntity(games)); + orderService.create(user1.getId(), new OrderEntity(games)); } @AfterEach - void removeData(){ - orderService.getAll().forEach(item -> orderService.delete(item.getUser().getId(),item.getId())); + void removeData() { + orderService.getAll().forEach(item -> orderService.delete(item.getUser().getId(), item.getId())); userService.getAll().forEach(item -> userService.delete(item.getId())); - gameService.getAll(0,0).forEach(item -> gameService.delete(item.getId())); + gameService.getAll(0, 0).forEach(item -> gameService.delete(item.getId())); typeService.getAll().forEach(item -> typeService.delete(item.getId())); genreService.getAll().forEach(item -> genreService.delete(item.getId())); } @Test - void getTest(){ + void getTest() { Assertions.assertThrows(NotFoundException.class, () -> gameService.get(0L)); } @Test @Order(1) - void createTest(){ + void createTest() { Assertions.assertEquals(2, orderService.getAll(user1.getId()).size()); } @Test @Order(2) - void deleteTest(){ - orderService.delete(user1.getId(),order1.getId()); + void deleteTest() { + orderService.delete(user1.getId(), order1.getId()); Assertions.assertEquals(1, orderService.getAll(user1.getId()).size()); } } -//зависимости, core->security, user(loadUserByUserName, userrole), core->configuration, дохуя контроллеров юзера core->session +// зависимости, core->security, user(loadUserByUserName, userrole), +// core->configuration, дохуя контроллеров юзера core->session