From b7bfd817e92383020965e3a51a3162d2f8550159 Mon Sep 17 00:00:00 2001 From: Takiguchi Date: Thu, 1 Aug 2019 21:47:15 +0200 Subject: [PATCH] Refactorization and add metrics system. --- keystore.p12 | Bin 2583 -> 4258 bytes pom.xml | 2 +- .../org/codiki/account/AccountController.java | 12 +++- .../org/codiki/core/config/CoreConfig.java | 14 ++++ .../org/codiki/core/entities/dto/Metrics.java | 37 ++++++++++ .../org/codiki/metrics/MetricsController.java | 26 ++++++++ .../org/codiki/metrics/MetricsService.java | 44 ++++++++++++ .../java/org/codiki/posts/PostController.java | 63 +++++++++--------- src/main/resources/application.yml | 2 + src/main/ts/src/app/app.module.ts | 6 +- src/main/ts/src/app/app.routing.ts | 2 + src/main/ts/src/app/core/entities.ts | 8 +++ .../ts/src/app/footer/footer.component.html | 7 ++ .../ts/src/app/footer/footer.component.scss | 5 ++ .../health-check/health-check.component.html | 23 +++++++ .../health-check/health-check.component.scss | 0 .../health-check/health-check.component.ts | 23 +++++++ .../app/health-check/health-check.service.ts | 16 +++++ src/main/ts/src/app/home/home.service.ts | 2 +- 19 files changed, 257 insertions(+), 35 deletions(-) mode change 100755 => 100644 keystore.p12 create mode 100644 src/main/java/org/codiki/core/config/CoreConfig.java create mode 100644 src/main/java/org/codiki/core/entities/dto/Metrics.java create mode 100644 src/main/java/org/codiki/metrics/MetricsController.java create mode 100644 src/main/java/org/codiki/metrics/MetricsService.java create mode 100644 src/main/ts/src/app/health-check/health-check.component.html create mode 100644 src/main/ts/src/app/health-check/health-check.component.scss create mode 100644 src/main/ts/src/app/health-check/health-check.component.ts create mode 100644 src/main/ts/src/app/health-check/health-check.service.ts diff --git a/keystore.p12 b/keystore.p12 old mode 100755 new mode 100644 index 3ea124299457842d5dac1ba0726eeab2b28fff88..1296fc27c7fe1d6ad7e0b677601e96917fcb2fcb GIT binary patch literal 4258 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 literal 2583 zcmY+EWmFT48ppS>jSguBOpv%RP&Qhmq=x|rj!;S@6p)sZiKH-<7=kpTV|0fC5+Wtt z$SA>}6qs|w<=%7e`=0m1bDnd4|NrxR{2{{_I6y!eWElM*lpYaf5JhGN(gJhB=--0F z=$p@QJu(dP;2#mh3LFN(oZ(w%a}&z=zbhsNASfpcOhtx)$w)~k!~gNwbAB*qcepY- zLP>f~PLsRlVd6l(Pi1s6hz8JQ3=RYLS(5oyoIAx_jJ!eztz}v4+iokyvr|uW1+D4( zRz_3*@Hiv98f21V>;+vD3fn8qVi#9`rLdBlvxnO}8qqdpEx>!>RdOhE9~fZf`Mk9M z-byy!QrVz`_t4TF_Uwv9{bU52Jg!61XaV1?FvZ?a8#8s(c1+3E=BnG(RDM6`GJ8iUwJh`QBs!XMum#A;H-Eri7D=sY>IOG z<2^3A8M6rGu5RMZHVE% ztF1?Z+fHMy`df@|@6*~X`ys6LTDd>sFI}XK6%|Ds%3#Ii15S7{3C{Jkr2eAG+#MJK zs_gvO;IdyW;)f42_0KAuBHD|s^@a7DF;gc>>4Ytu85YZVEy3&q)nzZR1@57f%_f$kY3j~>d7o(8Q zx9#6b>F75&ZauBKo}?wM2tjUDUdl5im;4&KiDIWtT@2K~I2GuiKT}M=yA$$+)#^GoD|SHKXdlh!`|UU3!^rKPyd#7O-EhJ+aY ztXsSsUQLdq(+KlVk-P;ip5428%cLH^KL5(#(2WEC+Ni0yo=G^E_LW!L2>5;AHJ-Mu z&a|mLhya(z)6sl?RZMA6x#2gO?P>Q$kwN`szbO0slbaO=OHsN&m-E&vtT+$-FM+D6 zbiF6}`-&c^p0l?mb`zepo~kWn)Bj|0QINpRKlb3_s{i~;sVdnb)Rq-Rprfi+z7pq7 zZ*d8_yIi_-p4RjwpuhS4!QilX_0PdaJ2I*r1_Lc6p+`J z_GcukquzfDd~`6c@q2dB;W_ZaxkRDE-{y(AU5sUM&}fBMLlaeYwG#a>aL=$1WHFTKI@9`gB|?wuQ)8cCGt$VM$|^<2E2441!e!vALfQE}M$J_}o`xmnO0 zz$v_HX2ii0R_viK$=w8M_Y2*w2kgnFI;GLCEmKNEOmynlN+3zbudx}E+NzzymUfx;S5kmgId>HT=pHkQ?YGg)gV?f(|R{aYP+xFG_W%x+L^>g@S zPupUnha1-=FrJS)(5gduS<~)i`J$pl-feH0t)$)%h)H`W73`g#UxVYZEk$wv}E&N}CQZ4Rzi~z1GM+ZioAo9xXZP2BL)jMXmzYyor1GvH>vM?en zKHb(5H|R>?(|WMntTrN&3HUaKa5%Y4Y`lJ?l7@hU!HncNZ@r3UCrRBqzk3S()HLYzG(ZkUiIkY zuE3WM@2;rLGODjG4pvG?TI(J`(a%NseQk~4gL{dFSnrt?zG%LO9HWoIUtCdU)~ zVmwkV8m`c1tnB2p;VaGMVlJ#OW&wd(CdrSR>@uEEmbF3H(TamR(FlE?N=Qz<3XI%U z00eFvsNeFE>`u~2ChfZ{@{Ko?i+N~_4;XNoNWRi8FREuJO@g%R#rx>sFo$zH_UQ|O zaZhy3me7+ut7-O@fn}vEf;TNLzIbMWED!APC#=0e^W;l3QS4OcMesx|?-0Y}2moT` zAuisXSyiW3j7%=8aFe@tm@Y7#dZ#W1>GTmB+A>dEXj;p$ihS)PsHpk3!gb;h?T{xV^sPjgj&6IpfZg5`~UZG;J z_u4fv1(6#GUsz!|Op{PIq&iXDIl#nE;GZ^%M fIcI|e+cUgdnm(qjetc!^(s9BTz6+uOM&org.codiki codiki - 1.0.1 + 1.1.0 jar codiki diff --git a/src/main/java/org/codiki/account/AccountController.java b/src/main/java/org/codiki/account/AccountController.java index 15ed7e0..c44870c 100755 --- a/src/main/java/org/codiki/account/AccountController.java +++ b/src/main/java/org/codiki/account/AccountController.java @@ -46,8 +46,16 @@ public class AccountController { @JsonView(View.UserDTO.class) @PostMapping("/login") - public User login(@RequestBody final User pUser) throws BadCredentialsException { - return accountService.authenticate(pUser); + public User login(@RequestBody final User pUser, HttpServletResponse pResponse) throws BadCredentialsException { + User result = null; + + try { + result = accountService.authenticate(pUser); + } catch(BadCredentialsException ex) { + pResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + + return result; } @GetMapping("/logout") diff --git a/src/main/java/org/codiki/core/config/CoreConfig.java b/src/main/java/org/codiki/core/config/CoreConfig.java new file mode 100644 index 0000000..a2f181f --- /dev/null +++ b/src/main/java/org/codiki/core/config/CoreConfig.java @@ -0,0 +1,14 @@ +package org.codiki.core.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Clock; + +@Configuration +public class CoreConfig { + @Bean + public Clock clock() { + return Clock.systemDefaultZone(); + } +} diff --git a/src/main/java/org/codiki/core/entities/dto/Metrics.java b/src/main/java/org/codiki/core/entities/dto/Metrics.java new file mode 100644 index 0000000..02393ab --- /dev/null +++ b/src/main/java/org/codiki/core/entities/dto/Metrics.java @@ -0,0 +1,37 @@ +package org.codiki.core.entities.dto; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class Metrics { + /** Rest API version number. */ + private String version; + /** Application start date. */ + private LocalDateTime uptime; + /** Platform name. */ + private String platform; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public LocalDateTime getUptime() { + return uptime; + } + + public void setUptime(LocalDateTime uptime) { + this.uptime = uptime; + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } +} diff --git a/src/main/java/org/codiki/metrics/MetricsController.java b/src/main/java/org/codiki/metrics/MetricsController.java new file mode 100644 index 0000000..910c5e4 --- /dev/null +++ b/src/main/java/org/codiki/metrics/MetricsController.java @@ -0,0 +1,26 @@ +package org.codiki.metrics; + +import org.codiki.core.entities.dto.Metrics; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/metrics") +public class MetricsController { + + private MetricsService metricsService; + + /** + * Constructor. + * @param metricsService Metrics service. + */ + public MetricsController(MetricsService metricsService) { + this.metricsService = metricsService; + } + + @GetMapping("/healthCheck") + public Metrics healthCheck() { + return metricsService.getMetrics(); + } +} diff --git a/src/main/java/org/codiki/metrics/MetricsService.java b/src/main/java/org/codiki/metrics/MetricsService.java new file mode 100644 index 0000000..94a5e93 --- /dev/null +++ b/src/main/java/org/codiki/metrics/MetricsService.java @@ -0,0 +1,44 @@ +package org.codiki.metrics; + +import org.codiki.core.entities.dto.Metrics; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Clock; +import java.time.LocalDateTime; + +@Service +public class MetricsService { + /** Application start date. */ + private LocalDateTime uptime; + /** Application version number. */ + private String appVersion; + /** Platform name. */ + private String appPlatform; + + /** + * Constructor. + * @param clock System clock. + */ + public MetricsService(Clock clock, + @Value("${app.version}") String appVersion, + @Value("${app.platform}") String appPlatform) { + uptime = LocalDateTime.now(clock); + this.appVersion = appVersion; + this.appPlatform = appPlatform; + } + + /** + * Returns application metrics like uptime, version number or platform name and others. + * @return Application metrics. + */ + public Metrics getMetrics() { + Metrics metrics = new Metrics(); + + metrics.setUptime(uptime); + metrics.setVersion(appVersion); + metrics.setPlatform(appPlatform); + + return metrics; + } +} diff --git a/src/main/java/org/codiki/posts/PostController.java b/src/main/java/org/codiki/posts/PostController.java index 9ca880c..6110cef 100755 --- a/src/main/java/org/codiki/posts/PostController.java +++ b/src/main/java/org/codiki/posts/PostController.java @@ -18,6 +18,7 @@ import org.codiki.core.entities.persistence.User; import org.codiki.core.repositories.PostRepository; import org.codiki.core.services.ParserService; import org.codiki.core.services.UserService; +import org.codiki.core.utils.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.web.bind.annotation.DeleteMapping; @@ -36,23 +37,37 @@ import com.fasterxml.jackson.annotation.JsonView; public class PostController { private static final int LIMIT_POSTS_HOME = 20; - - @Autowired + /** Service to parse post content. */ private ParserService parserService; - - @Autowired + /** Posts repository. */ private PostRepository postRepository; - - @Autowired + /** Posts business service. */ private PostService postService; - - @Autowired + /** Users business service. */ private UserService userService; - + + /** + * Constructor. + * @param parserService Service to parse post content. + * @param postRepository Posts repository. + * @param postService Posts business service. + * @param userService Users business service. + */ + public PostController(ParserService parserService, + PostRepository postRepository, + PostService postService, + UserService userService) { + this.parserService = parserService; + this.postRepository = postRepository; + this.postService = postService; + this.userService = userService; + } + @GetMapping public List getAll() { return StreamSupport.stream(postRepository.findAll().spliterator(), false) - .map(PostDTO::new).collect(Collectors.toList()); + .map(PostDTO::new) + .collect(Collectors.toList()); } @JsonView(View.PostDTO.class) @@ -70,16 +85,11 @@ public class PostController { @GetMapping("/{postKey}/source") public Post getByKeyAndSource(@PathVariable("postKey")final String pPostKey, final HttpServletResponse response) { - Post result = null; - - final Optional post = postRepository.getByKey(pPostKey); - if(post.isPresent()) { - result = post.get(); - } else { - response.setStatus(HttpServletResponse.SC_NOT_FOUND); - } - - return result; + return postRepository.getByKey(pPostKey) + .orElseGet(() -> { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + }); } @JsonView(View.PostDTO.class) @@ -121,9 +131,10 @@ public class PostController { @JsonView(View.PostDTO.class) @PostMapping("/preview") public Post preview(@RequestBody final Post pPost) { - pPost.setImage(pPost.getImage() == null || "".equals(pPost.getImage()) + pPost.setImage(StringUtils.isNull(pPost.getImage()) ? "https://news-cdn.softpedia.com/images/news2/this-is-the-default-wallpaper-of-the-gnome-3-20-desktop-environment-500743-2.jpg" : pPost.getImage()); + pPost.setText(parserService.parse(pPost.getText())); return pPost; @@ -133,15 +144,7 @@ public class PostController { @PostMapping("/") public Post insert(@RequestBody final PostDTO pPost, final HttpServletRequest pRequest, final HttpServletResponse pResponse, final Principal pPrincipal) { - Post result = null; - - Optional postCreated = postService.insert(pPost, pRequest, pResponse, pPrincipal); - - if(postCreated.isPresent()) { - result = postCreated.get(); - } - - return result; + return postService.insert(pPost, pRequest, pResponse, pPrincipal).orElse(null); } @PutMapping("/") diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 654b71d..25418f2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,8 @@ app: name: Codiki description: A wiki application. + version: 1.2.0 + platform: develop codiki: files: diff --git a/src/main/ts/src/app/app.module.ts b/src/main/ts/src/app/app.module.ts index 81719e3..8fe9db7 100755 --- a/src/main/ts/src/app/app.module.ts +++ b/src/main/ts/src/app/app.module.ts @@ -36,6 +36,7 @@ import { ForbiddenComponent } from './forbidden/forbidden.component'; import { SearchComponent } from './search/search.component'; import { SigninComponent } from './signin/signin.component'; import { VersionRevisionComponent } from './version-revisions/version-revisions.component'; +import { HealthCheckComponent } from './health-check/health-check.component'; // Reusable components import { PostCardComponent } from './core/post-card/post-card.component'; @@ -57,6 +58,7 @@ import { CreateUpdatePostService } from './posts/create-update/create-update-pos import { SearchService } from './search/search.service'; import { SigninService } from './signin/signin.service'; import { VersionRevisionService } from './version-revisions/version-revisions.service'; +import { HealthCheckService } from './health-check/health-check.service'; @NgModule({ declarations: [ @@ -81,7 +83,8 @@ import { VersionRevisionService } from './version-revisions/version-revisions.se SearchComponent, SearchBarComponent, ProgressBarComponent, - ForbiddenComponent + ForbiddenComponent, + HealthCheckComponent ], imports: [ BrowserModule, @@ -110,6 +113,7 @@ import { VersionRevisionService } from './version-revisions/version-revisions.se CreateUpdatePostService, VersionRevisionService, SearchService, + HealthCheckService, { provide: HTTP_INTERCEPTORS, useClass: UnauthorizedInterceptor, multi: true } ], bootstrap: [AppComponent] diff --git a/src/main/ts/src/app/app.routing.ts b/src/main/ts/src/app/app.routing.ts index 4504b6c..cec34a5 100755 --- a/src/main/ts/src/app/app.routing.ts +++ b/src/main/ts/src/app/app.routing.ts @@ -14,6 +14,7 @@ import { PostComponent } from './posts/post.component'; import { ByCategoryComponent } from './posts/byCategory/by-category.component'; import { CreateUpdatePostComponent } from './posts/create-update/create-update-post.component'; import { VersionRevisionComponent } from './version-revisions/version-revisions.component'; +import { HealthCheckComponent } from './health-check/health-check.component'; import { SearchComponent } from './search/search.component'; export const appRoutes: Routes = [ @@ -31,6 +32,7 @@ export const appRoutes: Routes = [ { path: 'changePassword', component: ChangePasswordComponent, canActivate: [AuthGuard] }, { path: 'profilEdit', component: ProfilEditionComponent, canActivate: [AuthGuard] }, { path: 'versionrevisions', component: VersionRevisionComponent }, + { path: 'healthCheck', component: HealthCheckComponent }, { path: '', redirectTo: '/home', pathMatch: 'full' }, { path: '**', redirectTo: '/home' } ]; diff --git a/src/main/ts/src/app/core/entities.ts b/src/main/ts/src/app/core/entities.ts index 6c7a445..e4b96b3 100755 --- a/src/main/ts/src/app/core/entities.ts +++ b/src/main/ts/src/app/core/entities.ts @@ -73,3 +73,11 @@ export class VersionRevision { public bugfix: boolean ) { } } + +export class Metrics { + constructor( + public version: String, + public uptime: Date, + public platform: String + ) { } +} diff --git a/src/main/ts/src/app/footer/footer.component.html b/src/main/ts/src/app/footer/footer.component.html index 0ff665c..6377b3e 100644 --- a/src/main/ts/src/app/footer/footer.component.html +++ b/src/main/ts/src/app/footer/footer.component.html @@ -7,6 +7,13 @@ {{appVersion}} + + diff --git a/src/main/ts/src/app/footer/footer.component.scss b/src/main/ts/src/app/footer/footer.component.scss index 3004449..c29f09d 100644 --- a/src/main/ts/src/app/footer/footer.component.scss +++ b/src/main/ts/src/app/footer/footer.component.scss @@ -23,3 +23,8 @@ span.anticopy { display: inline; cursor: pointer; } + +#healthCheck { + margin-left: 10px; + cursor: pointer; +} diff --git a/src/main/ts/src/app/health-check/health-check.component.html b/src/main/ts/src/app/health-check/health-check.component.html new file mode 100644 index 0000000..5c986d6 --- /dev/null +++ b/src/main/ts/src/app/health-check/health-check.component.html @@ -0,0 +1,23 @@ +
+ + + + + +

Status du serveur

+
+ +
    +
  • + Plateforme {{metrics.platform}} +
  • +
  • + Version {{metrics.version}} +
  • +
  • + Démarré depuis {{metrics.uptime}} +
  • +
+
+
+
diff --git a/src/main/ts/src/app/health-check/health-check.component.scss b/src/main/ts/src/app/health-check/health-check.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/main/ts/src/app/health-check/health-check.component.ts b/src/main/ts/src/app/health-check/health-check.component.ts new file mode 100644 index 0000000..c31ce0d --- /dev/null +++ b/src/main/ts/src/app/health-check/health-check.component.ts @@ -0,0 +1,23 @@ +import { HealthCheckService } from './health-check.service'; +import { Component, OnInit } from '@angular/core'; +import { Metrics } from '../core/entities'; + +@Component({ + selector: 'app-health-check', + templateUrl: './health-check.component.html', + styleUrls: ['./health-check.component.scss'] +}) +export class HealthCheckComponent implements OnInit { + metrics: Metrics = new Metrics('1.0.0', null, '?'); + + constructor( + private healthCheckService: HealthCheckService + ) {} + + ngOnInit() { + this.healthCheckService.healthCheck().subscribe(metrics => { + this.metrics = metrics; + }); + } + +} diff --git a/src/main/ts/src/app/health-check/health-check.service.ts b/src/main/ts/src/app/health-check/health-check.service.ts new file mode 100644 index 0000000..f5d1e68 --- /dev/null +++ b/src/main/ts/src/app/health-check/health-check.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { Metrics } from '../core/entities'; + +@Injectable({ + providedIn: 'root' +}) +export class HealthCheckService { + + constructor(private http: HttpClient) {} + + healthCheck(): Observable { + return this.http.get('/api/metrics/healthCheck'); + } +} diff --git a/src/main/ts/src/app/home/home.service.ts b/src/main/ts/src/app/home/home.service.ts index ea16f7e..1050880 100755 --- a/src/main/ts/src/app/home/home.service.ts +++ b/src/main/ts/src/app/home/home.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Post } from '../core/entities';