diff --git a/README.md b/README.md index 7bf114c7..cbb21d63 100644 --- a/README.md +++ b/README.md @@ -104,10 +104,10 @@ $ mvnw test -Dtest=UsuariosControllerIntegrationTests#should_save_a_new_user ## Documentação do Swagger -Assim que a aplicação estiver de pé, fica disponível em: [localhost:8080/api/documentation/swagger-ui/#/](localhost:8080/api/documentation/swagger-ui/#/) +Assim que a aplicação estiver de pé, fica disponível em: [localhost:8080/documentation/swagger-ui/#/](localhost:8080/documentation/swagger-ui/#/) -[exemplo no heroku](https://throyer-crud-api.herokuapp.com/api/documentation/swagger-ui/#/) +[exemplo no heroku](https://throyer-crud-api.herokuapp.com/documentation/swagger-ui/#/) ## Postman Clique [**aqui**](./postman/crud_api.postman_collection.json) para acessar o aquivo `json` da coleção do postman. diff --git a/pom.xml b/pom.xml index 8dbdac59..89460baa 100644 --- a/pom.xml +++ b/pom.xml @@ -1,181 +1,214 @@ - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.5.2 - - - com.github.throyer.common.spring-boot - api - 1.0.0.RELEASE - common-api - Common Spring Boot API - - - 16 - - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-validation - - - org.springframework.boot - spring-boot-starter-mail - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - - - com.github.javafaker - javafaker - 1.0.2 - - - - - - org.springframework.security - spring-security-data - 5.5.0 - - - - - - org.flywaydb - flyway-core - - - org.springframework.boot - spring-boot-starter-jooq - - - - - io.springfox - springfox-boot-starter - 3.0.0 - - - - - io.jsonwebtoken - jjwt - 0.9.1 - - - - org.springframework.boot - spring-boot-devtools - runtime - true - - - - com.h2database - h2 - runtime - - - mysql - mysql-connector-java - runtime - - - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - org.springframework.security - spring-security-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.sonarsource.scanner.maven - sonar-maven-plugin - 3.9.0.2155 - - - org.jacoco - jacoco-maven-plugin - 0.8.7 - - - - prepare-agent - - - - report - prepare-package - - report - - - - - - db/migration/**/* - - - - - com.google.cloud.tools - jib-maven-plugin - 3.1.4 - - - openjdk:16 - - - com.github.throyer.common.spring-boot.${project.artifactId}:${project.version} - - - ${maven.build.timestamp} - - 8080 - - - true - - - - + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.6 + + + com.github.throyer.common.spring-boot + api + 3.0.0 + Common API + Exemplo de api simples com Spring Boot + + 16 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.projectlombok + lombok + true + + + + + com.github.javafaker + javafaker + 1.0.2 + + + + + + org.springframework.security + spring-security-data + 5.5.0 + + + + + + org.flywaydb + flyway-core + + + org.springframework.boot + spring-boot-starter-jooq + + + + + io.springfox + springfox-boot-starter + 3.0.0 + + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + org.webjars + webjars-locator + 0.42 + + + + + org.webjars + font-awesome + 5.15.4 + + + + + org.webjars + bootstrap + 5.1.3 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + com.h2database + h2 + runtime + + + mysql + mysql-connector-java + runtime + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + build-info + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.9.0.2155 + + + org.jacoco + jacoco-maven-plugin + 0.8.7 + + + + prepare-agent + + + + report + prepare-package + + report + + + + + + db/migration/**/* + + + + + com.google.cloud.tools + jib-maven-plugin + 3.1.4 + + + openjdk:16 + + + com.github.throyer.common.spring-boot.${project.artifactId}:${project.version} + + + ${maven.build.timestamp} + + 8080 + + + true + + + + \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/api/CommonApiApplication.java b/src/main/java/com/github/throyer/common/springboot/CommonApiApplication.java similarity index 85% rename from src/main/java/com/github/throyer/common/springboot/api/CommonApiApplication.java rename to src/main/java/com/github/throyer/common/springboot/CommonApiApplication.java index a41bf5d6..41648494 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/CommonApiApplication.java +++ b/src/main/java/com/github/throyer/common/springboot/CommonApiApplication.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api; +package com.github.throyer.common.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/src/main/java/com/github/throyer/common/springboot/api/configurations/SpringSecurityConfiguration.java b/src/main/java/com/github/throyer/common/springboot/api/configurations/SpringSecurityConfiguration.java deleted file mode 100644 index 5041e760..00000000 --- a/src/main/java/com/github/throyer/common/springboot/api/configurations/SpringSecurityConfiguration.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.github.throyer.common.springboot.api.configurations; - -import static com.github.throyer.common.springboot.api.errors.ValidationHandlers.forbidden; - -import com.github.throyer.common.springboot.api.domain.services.security.SecurityService; -import com.github.throyer.common.springboot.api.middlewares.AuthorizationMiddleware; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@Configuration -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter { - - private static final String EVERY_HTML = "/**.html"; - private static final String SWAGGER_DOCS = "/documentation/**"; - - @Autowired - private SecurityService authService; - - @Autowired - private BCryptPasswordEncoder encoder; - - @Autowired - private AuthorizationMiddleware filter; - - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(authService) - .passwordEncoder(encoder); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .csrf() - .disable() - .authorizeRequests() - .antMatchers(HttpMethod.GET, "/") - .permitAll() - .antMatchers(HttpMethod.POST, "/users") - .permitAll() - .antMatchers(HttpMethod.POST, "/sessions/**") - .permitAll() - .antMatchers(HttpMethod.POST, "/recoveries/**") - .permitAll() - .antMatchers(HttpMethod.GET, "/documentation/**") - .permitAll() - .anyRequest() - .authenticated() - .and() - .exceptionHandling() - .authenticationEntryPoint((request, response, exception) -> forbidden(response)) - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); - } - - @Override - public void configure(WebSecurity web) throws Exception { - web - .ignoring() - .antMatchers(EVERY_HTML, SWAGGER_DOCS); - } - - @Override - @Bean - protected AuthenticationManager authenticationManager() throws Exception { - return super.authenticationManager(); - } - - @Bean - public SecurityEvaluationContextExtension securityEvaluationContextExtension() { - return new SecurityEvaluationContextExtension(); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/api/configurations/SwaggerConfiguration.java b/src/main/java/com/github/throyer/common/springboot/api/configurations/SwaggerConfiguration.java deleted file mode 100644 index 66ed60c4..00000000 --- a/src/main/java/com/github/throyer/common/springboot/api/configurations/SwaggerConfiguration.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.github.throyer.common.springboot.api.configurations; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.ApiKey; -import springfox.documentation.service.AuthorizationScope; -import springfox.documentation.service.Contact; -import springfox.documentation.service.SecurityReference; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.contexts.SecurityContext; -import springfox.documentation.spring.web.plugins.Docket; - -@Configuration -public class SwaggerConfiguration { - - private ApiKey apiKey() { - return new ApiKey("JWT", "Authorization", "header"); - } - - private SecurityContext securityContext() { - return SecurityContext.builder().securityReferences(defaultAuth()).build(); - } - - private List defaultAuth() { - AuthorizationScope authorizationScope = new AuthorizationScope( - "global", - "accessEverything" - ); - AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; - authorizationScopes[0] = authorizationScope; - return Arrays.asList(new SecurityReference("JWT", authorizationScopes)); - } - - @Bean - public Docket api() { - return new Docket(DocumentationType.OAS_30) - .useDefaultResponseMessages(false) - .apiInfo(apiInfo()) - .securityContexts(Arrays.asList( securityContext())) - .securitySchemes(Arrays.asList(apiKey())) - .select() - .apis(RequestHandlerSelectors.basePackage("com.github.throyer.common.springboot.api")) - .paths(PathSelectors.any()) - .build(); - } - - private ApiInfo apiInfo() { - return new ApiInfo( - "Common API", - "Exemplo de api simples com Spring Boot", - "1.0.0", - "https://github.com/Throyer", - new Contact( - "Throyer", - "https://github.com/Throyer", - "throyer.dev@gmail.com" - ), - "GNU General Public License v3.0", - "https://github.com/Throyer/springboot-api-crud/blob/master/LICENSE", - Collections.emptyList() - ); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/api/controllers/HomeController.java b/src/main/java/com/github/throyer/common/springboot/api/controllers/HomeController.java deleted file mode 100644 index 906e61ab..00000000 --- a/src/main/java/com/github/throyer/common/springboot/api/controllers/HomeController.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.throyer.common.springboot.api.controllers; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import io.swagger.annotations.Api; - -@Api(tags = "Status check") -@RestController -@RequestMapping("/") -public class HomeController { - - public class StatusCheck { - private final String message = "Is a live!"; - public String getMessage() { - return message; - } - } - - private StatusCheck status = new StatusCheck(); - - @GetMapping - public StatusCheck index() { - return status; - } -} \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/shared/Entity.java b/src/main/java/com/github/throyer/common/springboot/api/domain/models/shared/Entity.java deleted file mode 100644 index 3752d4d3..00000000 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/shared/Entity.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.github.throyer.common.springboot.api.domain.models.shared; - -public interface Entity { - Long getId(); -} diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/shared/HasEmail.java b/src/main/java/com/github/throyer/common/springboot/api/domain/models/shared/HasEmail.java deleted file mode 100644 index 038a9c42..00000000 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/shared/HasEmail.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.github.throyer.common.springboot.api.domain.models.shared; - -public interface HasEmail { - public String getEmail(); -} diff --git a/src/main/java/com/github/throyer/common/springboot/api/utils/Constants.java b/src/main/java/com/github/throyer/common/springboot/api/utils/Constants.java deleted file mode 100644 index a91e36b3..00000000 --- a/src/main/java/com/github/throyer/common/springboot/api/utils/Constants.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.github.throyer.common.springboot.api.utils; - -import com.github.throyer.common.springboot.api.domain.services.security.JsonWebToken; - -public class Constants { - public class SECURITY { - public static final JsonWebToken JWT = new JsonWebToken(); - public static final Long HOUR_IN_SECONDS = 3600L; - public static final String ROLES_KEY_ON_JWT = "roles"; - public static final String INVALID_USERNAME = "Nome de usuário invalido."; - public static final String CREATE_SESSION_ERROR_MESSAGE = "Senha ou Usuário inválidos."; - public static final String REFRESH_SESSION_ERROR_MESSAGE = "Refresh token expirado ou inválido."; - } -} diff --git a/src/main/java/com/github/throyer/common/springboot/configurations/SpringSecurityConfiguration.java b/src/main/java/com/github/throyer/common/springboot/configurations/SpringSecurityConfiguration.java new file mode 100644 index 00000000..551572db --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/configurations/SpringSecurityConfiguration.java @@ -0,0 +1,154 @@ +package com.github.throyer.common.springboot.configurations; + +import static com.github.throyer.common.springboot.errors.ValidationHandlers.forbidden; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.ACESSO_NEGADO_URL; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.DAY_MILLISECONDS; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.HOME_URL; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.LOGIN_ERROR_URL; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.LOGIN_URL; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.LOGOUT_URL; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.PASSWORD_PARAMETER; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.SESSION_COOKIE_NAME; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.STATIC_FILES; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.USERNAME_PARAMETER; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; +import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS; + +import com.github.throyer.common.springboot.domain.services.security.SecurityService; +import com.github.throyer.common.springboot.middlewares.AuthorizationMiddleware; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.stereotype.Component; + +@Component +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SpringSecurityConfiguration { + + @Autowired + private SecurityService securityService; + + @Autowired + private BCryptPasswordEncoder encoder; + + @Autowired + private AuthorizationMiddleware filter; + + private static String SECRET; + + public SpringSecurityConfiguration(@Value("${token.secret}") String secret) { + SpringSecurityConfiguration.SECRET = secret; + } + + @Order(1) + @Configuration + public class Api extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(securityService) + .passwordEncoder(encoder); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .antMatcher("/api/**") + .authorizeRequests() + .antMatchers(GET, "/api") + .permitAll() + .antMatchers(POST, "/api/users") + .permitAll() + .antMatchers(POST, "/api/sessions/**") + .permitAll() + .antMatchers(POST, "/api/recoveries/**") + .permitAll() + .antMatchers(GET, "/api/documentation/**") + .permitAll() + .anyRequest() + .authenticated() + .and() + .csrf() + .disable() + .exceptionHandling() + .authenticationEntryPoint((request, response, exception) -> forbidden(response)) + .and() + .sessionManagement() + .sessionCreationPolicy(STATELESS) + .and() + .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web + .ignoring() + .antMatchers(STATIC_FILES); + } + + @Bean + @Override + protected AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } + } + + @Order(2) + @Configuration + public class App extends WebSecurityConfigurerAdapter { + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth. + userDetailsService(securityService) + .passwordEncoder(encoder); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + + http + .antMatcher("/app/**") + .authorizeRequests() + .antMatchers(GET, LOGIN_URL) + .permitAll() + .anyRequest() + .authenticated() + .and() + .csrf() + .disable() + .formLogin() + .loginPage(LOGIN_URL) + .failureUrl(LOGIN_ERROR_URL) + .defaultSuccessUrl(HOME_URL) + .usernameParameter(USERNAME_PARAMETER) + .passwordParameter(PASSWORD_PARAMETER) + .and() + .rememberMe() + .key(SECRET) + .tokenValiditySeconds(DAY_MILLISECONDS) + .and() + .logout() + .deleteCookies(SESSION_COOKIE_NAME) + .logoutRequestMatcher(new AntPathRequestMatcher(LOGOUT_URL)) + .logoutSuccessUrl("/app") + .and() + .exceptionHandling() + .accessDeniedPage(ACESSO_NEGADO_URL); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/api/configurations/SpringWebConfiguration.java b/src/main/java/com/github/throyer/common/springboot/configurations/SpringWebConfiguration.java similarity index 52% rename from src/main/java/com/github/throyer/common/springboot/api/configurations/SpringWebConfiguration.java rename to src/main/java/com/github/throyer/common/springboot/configurations/SpringWebConfiguration.java index 2b8c49a3..6bb24a08 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/configurations/SpringWebConfiguration.java +++ b/src/main/java/com/github/throyer/common/springboot/configurations/SpringWebConfiguration.java @@ -1,10 +1,12 @@ -package com.github.throyer.common.springboot.api.configurations; +package com.github.throyer.common.springboot.configurations; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @EnableWebMvc @@ -23,4 +25,20 @@ public void addCorsMappings(CorsRegistry registry) { public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry + .addResourceHandler("/**") + .addResourceLocations("classpath:/static/"); + + registry + .addResourceHandler("/webjars/**") + .addResourceLocations("/webjars/"); + } + + @Bean + public SecurityEvaluationContextExtension securityEvaluationContextExtension() { + return new SecurityEvaluationContextExtension(); + } } \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/configurations/SwaggerConfiguration.java b/src/main/java/com/github/throyer/common/springboot/configurations/SwaggerConfiguration.java new file mode 100644 index 00000000..2ea91cba --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/configurations/SwaggerConfiguration.java @@ -0,0 +1,99 @@ +package com.github.throyer.common.springboot.configurations; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static springfox.documentation.builders.PathSelectors.any; +import static springfox.documentation.builders.RequestHandlerSelectors.basePackage; +import static springfox.documentation.spi.DocumentationType.OAS_30; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.info.BuildProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import springfox.documentation.builders.ResponseBuilder; +import springfox.documentation.builders.ResponseMessageBuilder; + +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.service.AuthorizationScope; +import springfox.documentation.service.Contact; +import springfox.documentation.service.SecurityReference; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.Docket; + +@Component +@Configuration +public class SwaggerConfiguration { + + @Autowired + BuildProperties build; + + private ApiKey apiKey() { + return new ApiKey("JWT", "Authorization", "header"); + } + + private SecurityContext securityContext() { + return SecurityContext + .builder() + .securityReferences(defaultAuth()).build(); + } + + private List defaultAuth() { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + return asList(new SecurityReference("JWT", authorizationScopes)); + } + + @Bean + public Docket api() { + return new Docket(OAS_30) + .useDefaultResponseMessages(false) + .apiInfo(apiInfo()) + .securityContexts(asList(securityContext())) + .securitySchemes(asList(apiKey())).select() + .apis(basePackage("com.github.throyer.common.springboot.controllers.api")) + .paths(any()) + .build() + .useDefaultResponseMessages(false) + .globalResponses(HttpMethod.GET, List.of( + new ResponseBuilder().code("500").description("Internal Server Error").build(), + new ResponseBuilder().code("403").description("Forbidden").build(), + new ResponseBuilder().code("404").description("Not Found").build() + )).globalResponses(HttpMethod.POST, List.of( + new ResponseBuilder().code("500").description("Internal Server Error").build(), + new ResponseBuilder().code("403").description("Forbidden").build(), + new ResponseBuilder().code("404").description("Not Found").build(), + new ResponseBuilder().code("400").description("Bad Request").build(), + new ResponseBuilder().code("422").description("Unprocessable Entity").build(), + new ResponseBuilder().code("409").description("Conflict").build() + )).globalResponses(HttpMethod.PUT, List.of( + new ResponseBuilder().code("500").description("Internal Server Error").build(), + new ResponseBuilder().code("403").description("Forbidden").build(), + new ResponseBuilder().code("400").description("Bad Request").build(), + new ResponseBuilder().code("422").description("Unprocessable Entity").build(), + new ResponseBuilder().code("409").description("Conflict").build(), + new ResponseBuilder().code("404").description("Not Found").build() + )).globalResponses(HttpMethod.DELETE, List.of( + new ResponseBuilder().code("500").description("Internal Server Error").build(), + new ResponseBuilder().code("404").description("Not Found").build() + )); + } + + private ApiInfo apiInfo() { + return new ApiInfo( + build.getName(), + "Exemplo de api simples com Spring Boot", + build.getVersion(), + "https://github.com/Throyer", + new Contact("Throyer", "https://github.com/Throyer", "throyer.dev@gmail.com"), + "GNU General Public License v3.0", + "https://github.com/Throyer/springboot-api-crud/blob/master/LICENSE", + emptyList() + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/controllers/api/ApiController.java b/src/main/java/com/github/throyer/common/springboot/controllers/api/ApiController.java new file mode 100644 index 00000000..0996c310 --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/controllers/api/ApiController.java @@ -0,0 +1,19 @@ +package com.github.throyer.common.springboot.controllers.api; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.annotations.Api; +import com.github.throyer.common.springboot.utils.Hello; + +@Api(tags = "Status check", produces = "application/json") +@RestController +@RequestMapping("/api") +public class ApiController { + + @GetMapping + public Hello index() { + return () -> "Is a live!"; + } +} diff --git a/src/main/java/com/github/throyer/common/springboot/api/controllers/RecoveriesController.java b/src/main/java/com/github/throyer/common/springboot/controllers/api/RecoveriesController.java similarity index 65% rename from src/main/java/com/github/throyer/common/springboot/api/controllers/RecoveriesController.java rename to src/main/java/com/github/throyer/common/springboot/controllers/api/RecoveriesController.java index 0c7dd2f1..448f2768 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/controllers/RecoveriesController.java +++ b/src/main/java/com/github/throyer/common/springboot/controllers/api/RecoveriesController.java @@ -1,12 +1,13 @@ -package com.github.throyer.common.springboot.api.controllers; +package com.github.throyer.common.springboot.controllers.api; -import com.github.throyer.common.springboot.api.domain.services.user.RecoveryPasswordService; -import com.github.throyer.common.springboot.api.domain.services.user.dto.RecoveryConfirm; -import com.github.throyer.common.springboot.api.domain.services.user.dto.RecoveryRequest; -import com.github.throyer.common.springboot.api.domain.services.user.dto.RecoveryUpdate; +import static org.springframework.http.HttpStatus.NO_CONTENT; + +import com.github.throyer.common.springboot.domain.services.user.RecoveryPasswordService; +import com.github.throyer.common.springboot.domain.services.user.dto.RecoveryConfirm; +import com.github.throyer.common.springboot.domain.services.user.dto.RecoveryRequest; +import com.github.throyer.common.springboot.domain.services.user.dto.RecoveryUpdate; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -17,14 +18,14 @@ @Api(tags = "Password recovery", produces = "application/json") @RestController -@RequestMapping("/recoveries") +@RequestMapping("/api/recoveries") public class RecoveriesController { @Autowired private RecoveryPasswordService service; - @ResponseStatus(HttpStatus.NO_CONTENT) @PostMapping + @ResponseStatus(NO_CONTENT) public void index(@RequestBody RecoveryRequest request) { service.recovery(request.getEmail()); } @@ -34,8 +35,8 @@ public void confirm(@RequestBody RecoveryConfirm confirm) { service.confirm(confirm.getEmail(), confirm.getCode()); } - @ResponseStatus(HttpStatus.NO_CONTENT) @PostMapping("/update") + @ResponseStatus(NO_CONTENT) public void update(@RequestBody RecoveryUpdate update) { service.update(update.getEmail(), update.getCode(), update.getPassword()); } diff --git a/src/main/java/com/github/throyer/common/springboot/api/controllers/RolesController.java b/src/main/java/com/github/throyer/common/springboot/controllers/api/RolesController.java similarity index 68% rename from src/main/java/com/github/throyer/common/springboot/api/controllers/RolesController.java rename to src/main/java/com/github/throyer/common/springboot/controllers/api/RolesController.java index c7239cf4..300e22f5 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/controllers/RolesController.java +++ b/src/main/java/com/github/throyer/common/springboot/controllers/api/RolesController.java @@ -1,11 +1,11 @@ -package com.github.throyer.common.springboot.api.controllers; +package com.github.throyer.common.springboot.controllers.api; -import static com.github.throyer.common.springboot.api.utils.Responses.ok; +import static com.github.throyer.common.springboot.utils.Responses.ok; import java.util.List; -import com.github.throyer.common.springboot.api.domain.models.entity.Role; -import com.github.throyer.common.springboot.api.domain.repositories.RoleRepository; +import com.github.throyer.common.springboot.domain.models.entity.Role; +import com.github.throyer.common.springboot.domain.repositories.RoleRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; @@ -18,7 +18,7 @@ @Api(tags = "User role") @RestController -@RequestMapping("/roles") +@RequestMapping("/api/roles") @PreAuthorize("hasAnyAuthority('ADM')") public class RolesController { diff --git a/src/main/java/com/github/throyer/common/springboot/api/controllers/SessionsController.java b/src/main/java/com/github/throyer/common/springboot/controllers/api/SessionsController.java similarity index 61% rename from src/main/java/com/github/throyer/common/springboot/api/controllers/SessionsController.java rename to src/main/java/com/github/throyer/common/springboot/controllers/api/SessionsController.java index bd282824..96f66d1b 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/controllers/SessionsController.java +++ b/src/main/java/com/github/throyer/common/springboot/controllers/api/SessionsController.java @@ -1,12 +1,12 @@ -package com.github.throyer.common.springboot.api.controllers; +package com.github.throyer.common.springboot.controllers.api; import javax.validation.Valid; -import com.github.throyer.common.springboot.api.domain.services.security.SessionService; -import com.github.throyer.common.springboot.api.domain.services.security.dto.RefreshTokenRequest; -import com.github.throyer.common.springboot.api.domain.services.security.dto.RefreshTokenResponse; -import com.github.throyer.common.springboot.api.domain.services.security.dto.TokenRequest; -import com.github.throyer.common.springboot.api.domain.services.security.dto.TokenResponse; +import com.github.throyer.common.springboot.domain.services.security.SessionService; +import com.github.throyer.common.springboot.domain.services.security.dto.RefreshTokenRequest; +import com.github.throyer.common.springboot.domain.services.security.dto.RefreshTokenResponse; +import com.github.throyer.common.springboot.domain.services.security.dto.TokenRequest; +import com.github.throyer.common.springboot.domain.services.security.dto.TokenResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; @@ -19,7 +19,7 @@ @Api(tags = "Session") @RestController -@RequestMapping("/sessions") +@RequestMapping("/api/sessions") public class SessionsController { @Autowired diff --git a/src/main/java/com/github/throyer/common/springboot/api/controllers/UsersController.java b/src/main/java/com/github/throyer/common/springboot/controllers/api/UsersController.java similarity index 65% rename from src/main/java/com/github/throyer/common/springboot/api/controllers/UsersController.java rename to src/main/java/com/github/throyer/common/springboot/controllers/api/UsersController.java index 4f587b53..fef558b1 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/controllers/UsersController.java +++ b/src/main/java/com/github/throyer/common/springboot/controllers/api/UsersController.java @@ -1,20 +1,22 @@ -package com.github.throyer.common.springboot.api.controllers; +package com.github.throyer.common.springboot.controllers.api; -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.models.pagination.Page; -import com.github.throyer.common.springboot.api.domain.models.pagination.Pagination; -import com.github.throyer.common.springboot.api.domain.services.user.CreateUserService; -import com.github.throyer.common.springboot.api.domain.services.user.FindUserService; -import com.github.throyer.common.springboot.api.domain.services.user.RemoveUserService; -import com.github.throyer.common.springboot.api.domain.services.user.UpdateUserService; -import com.github.throyer.common.springboot.api.domain.services.user.dto.CreateUser; -import com.github.throyer.common.springboot.api.domain.services.user.dto.SearchUser; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UpdateUser; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UserDetails; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.NO_CONTENT; + +import com.github.throyer.common.springboot.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.pagination.Page; +import com.github.throyer.common.springboot.domain.models.pagination.Pagination; +import com.github.throyer.common.springboot.domain.services.user.CreateUserService; +import com.github.throyer.common.springboot.domain.services.user.FindUserService; +import com.github.throyer.common.springboot.domain.services.user.RemoveUserService; +import com.github.throyer.common.springboot.domain.services.user.UpdateUserService; +import com.github.throyer.common.springboot.domain.services.user.dto.CreateUser; +import com.github.throyer.common.springboot.domain.services.user.dto.SearchUser; +import com.github.throyer.common.springboot.domain.services.user.dto.UpdateUser; +import com.github.throyer.common.springboot.domain.services.user.dto.UserDetails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -32,7 +34,7 @@ @Api(tags = "User") @RestController -@RequestMapping("/users") +@RequestMapping("/api/users") public class UsersController { @Autowired @@ -59,8 +61,8 @@ public ResponseEntity show(@PathVariable Long id) { return findService.find(id); } - @ResponseStatus(HttpStatus.CREATED) @PostMapping + @ResponseStatus(CREATED) public ResponseEntity save(@Validated @RequestBody CreateUser body) { return createService.create(body); } @@ -74,9 +76,9 @@ public ResponseEntity update( return updateService.update(id, body); } - @ResponseStatus(code = HttpStatus.NO_CONTENT) - @PreAuthorize("hasAnyAuthority('ADM')") @DeleteMapping("/{id}") + @ResponseStatus(NO_CONTENT) + @PreAuthorize("hasAnyAuthority('ADM')") public ResponseEntity destroy(@PathVariable Long id) { return removeService.remove(id); } diff --git a/src/main/java/com/github/throyer/common/springboot/controllers/app/AppController.java b/src/main/java/com/github/throyer/common/springboot/controllers/app/AppController.java new file mode 100644 index 00000000..80d92deb --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/controllers/app/AppController.java @@ -0,0 +1,16 @@ +package com.github.throyer.common.springboot.controllers.app; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/app") +public class AppController { + + @GetMapping + public String index(Model model) { + return "app/index"; + } +} diff --git a/src/main/java/com/github/throyer/common/springboot/controllers/app/LoginController.java b/src/main/java/com/github/throyer/common/springboot/controllers/app/LoginController.java new file mode 100644 index 00000000..06da849e --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/controllers/app/LoginController.java @@ -0,0 +1,14 @@ +package com.github.throyer.common.springboot.controllers.app; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/app/login") +public class LoginController { + @GetMapping + public String login() { + return "app/login/index"; + } +} diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/builders/UserBuilder.java b/src/main/java/com/github/throyer/common/springboot/domain/builders/UserBuilder.java similarity index 80% rename from src/main/java/com/github/throyer/common/springboot/api/domain/builders/UserBuilder.java rename to src/main/java/com/github/throyer/common/springboot/domain/builders/UserBuilder.java index 2928439f..f47b2eb9 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/builders/UserBuilder.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/builders/UserBuilder.java @@ -1,14 +1,14 @@ -package com.github.throyer.common.springboot.api.domain.builders; +package com.github.throyer.common.springboot.domain.builders; import java.util.ArrayList; import java.util.List; -import com.github.throyer.common.springboot.api.domain.models.entity.Role; -import com.github.throyer.common.springboot.api.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.entity.Role; +import com.github.throyer.common.springboot.domain.models.entity.User; public class UserBuilder { - private User user; + private final User user; private List roles = new ArrayList<>(); public static UserBuilder createUser(String name) { @@ -36,7 +36,7 @@ public UserBuilder setId(Long id) { return this; } - public UserBuilder setAtivo(Boolean active) { + public UserBuilder setActive(Boolean active) { user.setActive(active); return this; } diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/emails/RecoveryEmail.java b/src/main/java/com/github/throyer/common/springboot/domain/models/emails/RecoveryEmail.java similarity index 84% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/emails/RecoveryEmail.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/emails/RecoveryEmail.java index 94bd3fc4..47060eda 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/emails/RecoveryEmail.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/emails/RecoveryEmail.java @@ -1,6 +1,6 @@ -package com.github.throyer.common.springboot.api.domain.models.emails; +package com.github.throyer.common.springboot.domain.models.emails; -import com.github.throyer.common.springboot.api.domain.services.email.Email; +import com.github.throyer.common.springboot.domain.services.email.Email; import org.thymeleaf.context.Context; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/BasicEntity.java b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/Auditable.java similarity index 66% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/BasicEntity.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/entity/Auditable.java index 12e66e3d..7a94f58e 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/BasicEntity.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/Auditable.java @@ -1,12 +1,14 @@ -package com.github.throyer.common.springboot.api.domain.models.entity; +package com.github.throyer.common.springboot.domain.models.entity; -import static com.github.throyer.common.springboot.api.domain.services.security.SecurityService.authorized; +import static com.github.throyer.common.springboot.domain.services.security.SecurityService.authorized; +import static java.time.LocalDateTime.now; +import static java.util.Optional.ofNullable; +import static javax.persistence.FetchType.LAZY; import java.time.LocalDateTime; import java.util.Optional; import javax.persistence.Column; -import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.MappedSuperclass; @@ -14,22 +16,13 @@ import javax.persistence.PreUpdate; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.github.throyer.common.springboot.api.domain.models.shared.Entity; +import com.github.throyer.common.springboot.domain.models.shared.Entity; @MappedSuperclass -public abstract class BasicEntity implements Entity { +public abstract class Auditable implements Entity { public static final String NON_DELETED_CLAUSE = "deleted_at IS NULL"; - public static final String SET_ALL_DELETED_SQL = """ - UPDATE - #{#entityName} - SET - deleted_at = CURRENT_TIMESTAMP - """; - - public static final String SET_DELETED_SQL = SET_ALL_DELETED_SQL + "WHERE id = ?1"; - @Override public abstract Long getId(); @@ -46,34 +39,34 @@ public abstract class BasicEntity implements Entity { private LocalDateTime deletedAt; @JoinColumn(name = "created_by") - @ManyToOne(optional = true, fetch = FetchType.LAZY) + @ManyToOne(optional = true, fetch = LAZY) private User createdBy; @JoinColumn(name = "updated_by") - @ManyToOne(optional = true, fetch = FetchType.LAZY) + @ManyToOne(optional = true, fetch = LAZY) private User updatedBy; @JoinColumn(name = "deleted_by") - @ManyToOne(optional = true, fetch = FetchType.LAZY) + @ManyToOne(optional = true, fetch = LAZY) private User deletedBy; @JsonIgnore public Optional getCreatedBy() { - return Optional.ofNullable(createdBy); + return ofNullable(createdBy); } @JsonIgnore public Optional getUpdatedBy() { - return Optional.ofNullable(updatedBy); + return ofNullable(updatedBy); } @JsonIgnore public Optional getDeletedBy() { - return Optional.ofNullable(deletedBy); + return ofNullable(deletedBy); } @Column(name = "active", nullable = false) - private Boolean ativo = true; + private Boolean active = true; public LocalDateTime getCreatedAt() { return createdAt; @@ -100,16 +93,16 @@ public void setDeletedAt(LocalDateTime deletedAt) { } public Boolean isActive() { - return this.ativo; + return this.active; } public void setActive(Boolean active) { - this.ativo = active; + this.active = active; } @PrePersist private void save() { - createdAt = LocalDateTime.now(); + createdAt = now(); createdBy = authorized() .map(authorized -> new User(authorized.getId())) .orElse(null); @@ -117,7 +110,7 @@ private void save() { @PreUpdate private void update() { - updatedAt = LocalDateTime.now(); + updatedAt = now(); updatedBy = authorized() .map(authorized -> new User(authorized.getId())) .orElse(null); diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/Recovery.java b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/Recovery.java similarity index 93% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/Recovery.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/entity/Recovery.java index 9232de11..afcabec8 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/Recovery.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/Recovery.java @@ -1,6 +1,6 @@ -package com.github.throyer.common.springboot.api.domain.models.entity; +package com.github.throyer.common.springboot.domain.models.entity; -import static com.github.throyer.common.springboot.api.utils.Random.code; +import static com.github.throyer.common.springboot.utils.Random.code; import java.time.LocalDateTime; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/RefreshToken.java b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/RefreshToken.java similarity index 95% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/RefreshToken.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/entity/RefreshToken.java index 94bff03f..d796dae1 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/RefreshToken.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/RefreshToken.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.models.entity; +package com.github.throyer.common.springboot.domain.models.entity; import java.time.LocalDateTime; import java.util.UUID; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/Role.java b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/Role.java similarity index 80% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/Role.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/entity/Role.java index 438cda5e..b0cdddd8 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/Role.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/Role.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.models.entity; +package com.github.throyer.common.springboot.domain.models.entity; import java.util.Objects; @@ -16,26 +16,8 @@ @Entity @Table(name = "role") -@Where(clause = BasicEntity.NON_DELETED_CLAUSE) -public class Role extends BasicEntity implements GrantedAuthority { - - public static final String DELETE_SQL = """ - UPDATE - #{#entityName} - SET - deleted_name = ( - SELECT name FROM #{#entityName} WHERE id = ?1 - ), - name = NULL, - deleted_initials = ( - SELECT name FROM #{#entityName} WHERE id = ?1 - ), - initials = NULL, - deleted_at = CURRENT_TIMESTAMP, - active = 0, - deleted_by = ?#{principal?.id} - WHERE id = ?1 - """; +@Where(clause = Auditable.NON_DELETED_CLAUSE) +public class Role extends Auditable implements GrantedAuthority { private static final long serialVersionUID = -8524505911742593369L; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/User.java b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/User.java similarity index 83% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/User.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/entity/User.java index edb1b66d..99db5b63 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/entity/User.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/entity/User.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.models.entity; +package com.github.throyer.common.springboot.domain.models.entity; import java.io.Serializable; import java.security.Principal; @@ -21,36 +21,20 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty.Access; -import com.github.throyer.common.springboot.api.domain.models.pagination.SortableProperty; -import com.github.throyer.common.springboot.api.domain.models.security.Authorized; -import com.github.throyer.common.springboot.api.domain.models.shared.HasEmail; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UpdateUser; +import com.github.throyer.common.springboot.domain.models.pagination.SortableProperty; +import com.github.throyer.common.springboot.domain.models.security.Authorized; +import com.github.throyer.common.springboot.domain.models.shared.HasEmail; +import com.github.throyer.common.springboot.domain.services.user.dto.UpdateUser; import org.hibernate.annotations.Where; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Entity @Table(name = "user") -@Where(clause = BasicEntity.NON_DELETED_CLAUSE) -public class User extends BasicEntity implements Serializable, HasEmail { +@Where(clause = Auditable.NON_DELETED_CLAUSE) +public class User extends Auditable implements Serializable, HasEmail { public static final Integer PASSWORD_STRENGTH = 10; - public static final String DELETE_SQL = """ - UPDATE - #{#entityName} - SET - deleted_email = ( - SELECT - email - FROM - #{#entityName} - WHERE id = ?1), - email = NULL, - deleted_at = CURRENT_TIMESTAMP, - active = 0, - deleted_by = ?#{principal?.id} - WHERE id = ?1 - """; private static final long serialVersionUID = -8080540494839892473L; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/Page.java b/src/main/java/com/github/throyer/common/springboot/domain/models/pagination/Page.java similarity index 92% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/Page.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/pagination/Page.java index 299b6042..cf10ae4c 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/Page.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/pagination/Page.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.models.pagination; +package com.github.throyer.common.springboot.domain.models.pagination; import java.util.Collection; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/Pagination.java b/src/main/java/com/github/throyer/common/springboot/domain/models/pagination/Pagination.java similarity index 83% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/Pagination.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/pagination/Pagination.java index 98b54df9..6cf4097c 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/Pagination.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/pagination/Pagination.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.models.pagination; +package com.github.throyer.common.springboot.domain.models.pagination; import java.lang.reflect.Field; import java.util.ArrayList; @@ -10,8 +10,8 @@ import javax.persistence.Entity; -import com.github.throyer.common.springboot.api.domain.validation.InvalidSortException; -import com.github.throyer.common.springboot.api.domain.validation.SimpleError; +import com.github.throyer.common.springboot.domain.validation.InvalidSortException; +import com.github.throyer.common.springboot.domain.validation.SimpleError; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -20,6 +20,10 @@ import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; +import static java.util.Objects.nonNull; +import static org.springframework.data.domain.PageRequest.of; +import static org.springframework.data.domain.Sort.by; + public class Pagination { private static final int FIRST_PAGE = 0; @@ -36,7 +40,7 @@ public int getPage() { } public void setPage(int page) { - if (Objects.nonNull(page) && page >= FIRST_PAGE) { + if (nonNull(page) && page >= FIRST_PAGE) { this.page = page; } else { page = FIRST_PAGE; @@ -48,7 +52,7 @@ public int getSize() { } public void setSize(int size) { - if (Objects.nonNull(size) && size >= MIN_SIZE && size <= MAX_SIZE) { + if (nonNull(size) && size >= MIN_SIZE && size <= MAX_SIZE) { this.size = size; } else { this.size = DEFAULT_SIZE; @@ -56,11 +60,11 @@ public void setSize(int size) { } public Pageable build() { - return PageRequest.of(page, size); + return of(page, size); } public Pageable build(Sort sort) { - return PageRequest.of(page, size, sort); + return of(page, size, sort); } public Pageable build(Sort query, Class entity) { @@ -82,7 +86,7 @@ public Pageable build(Sort query, Class entity) { if (optional.isPresent()) { orders.add(getOrder(order, optional.get())); } else { - errors.add(new SimpleError(order.getProperty(), "Filtro invalido")); + errors.add(new SimpleError(order.getProperty(), "Filtro inválido")); } } @@ -90,7 +94,7 @@ public Pageable build(Sort query, Class entity) { throw new InvalidSortException("Filtros inválidos", errors); } - return PageRequest.of(page, size, Sort.by(orders)); + return of(page, size, by(orders)); } private static Boolean belongs(Field field, Order order) { diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/SortableProperty.java b/src/main/java/com/github/throyer/common/springboot/domain/models/pagination/SortableProperty.java similarity index 82% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/SortableProperty.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/pagination/SortableProperty.java index a8765a28..1ebe10f8 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/pagination/SortableProperty.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/pagination/SortableProperty.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.models.pagination; +package com.github.throyer.common.springboot.domain.models.pagination; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/models/security/Authorized.java b/src/main/java/com/github/throyer/common/springboot/domain/models/security/Authorized.java similarity index 86% rename from src/main/java/com/github/throyer/common/springboot/api/domain/models/security/Authorized.java rename to src/main/java/com/github/throyer/common/springboot/domain/models/security/Authorized.java index fbaeaa27..c675040b 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/models/security/Authorized.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/security/Authorized.java @@ -1,8 +1,8 @@ -package com.github.throyer.common.springboot.api.domain.models.security; +package com.github.throyer.common.springboot.domain.models.security; import java.util.List; -import com.github.throyer.common.springboot.api.domain.models.entity.Role; +import com.github.throyer.common.springboot.domain.models.entity.Role; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.userdetails.User; @@ -18,7 +18,7 @@ public Authorized(Long id, List authorities) { this.id = id; } - public Authorized(com.github.throyer.common.springboot.api.domain.models.entity.User user) { + public Authorized(com.github.throyer.common.springboot.domain.models.entity.User user) { super( user.getEmail(), user.getPassword(), diff --git a/src/main/java/com/github/throyer/common/springboot/domain/models/shared/Entity.java b/src/main/java/com/github/throyer/common/springboot/domain/models/shared/Entity.java new file mode 100644 index 00000000..1a807802 --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/shared/Entity.java @@ -0,0 +1,5 @@ +package com.github.throyer.common.springboot.domain.models.shared; + +public interface Entity { + Long getId(); +} diff --git a/src/main/java/com/github/throyer/common/springboot/domain/models/shared/HasEmail.java b/src/main/java/com/github/throyer/common/springboot/domain/models/shared/HasEmail.java new file mode 100644 index 00000000..f3801e52 --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/domain/models/shared/HasEmail.java @@ -0,0 +1,5 @@ +package com.github.throyer.common.springboot.domain.models.shared; + +public interface HasEmail { + public String getEmail(); +} diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RecoveryRepository.java b/src/main/java/com/github/throyer/common/springboot/domain/repositories/RecoveryRepository.java similarity index 79% rename from src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RecoveryRepository.java rename to src/main/java/com/github/throyer/common/springboot/domain/repositories/RecoveryRepository.java index 3ec41b24..3fe29c1e 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RecoveryRepository.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/repositories/RecoveryRepository.java @@ -1,8 +1,8 @@ -package com.github.throyer.common.springboot.api.domain.repositories; +package com.github.throyer.common.springboot.domain.repositories; import java.util.Optional; -import com.github.throyer.common.springboot.api.domain.models.entity.Recovery; +import com.github.throyer.common.springboot.domain.models.entity.Recovery; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RefreshTokenRepository.java b/src/main/java/com/github/throyer/common/springboot/domain/repositories/RefreshTokenRepository.java similarity index 87% rename from src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RefreshTokenRepository.java rename to src/main/java/com/github/throyer/common/springboot/domain/repositories/RefreshTokenRepository.java index 6d48e33f..0b6f6914 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RefreshTokenRepository.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/repositories/RefreshTokenRepository.java @@ -1,10 +1,10 @@ -package com.github.throyer.common.springboot.api.domain.repositories; +package com.github.throyer.common.springboot.domain.repositories; import java.util.Optional; import javax.transaction.Transactional; -import com.github.throyer.common.springboot.api.domain.models.entity.RefreshToken; +import com.github.throyer.common.springboot.domain.models.entity.RefreshToken; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RoleRepository.java b/src/main/java/com/github/throyer/common/springboot/domain/repositories/RoleRepository.java similarity index 59% rename from src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RoleRepository.java rename to src/main/java/com/github/throyer/common/springboot/domain/repositories/RoleRepository.java index 6b40237d..782d2522 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/RoleRepository.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/repositories/RoleRepository.java @@ -1,8 +1,8 @@ -package com.github.throyer.common.springboot.api.domain.repositories; +package com.github.throyer.common.springboot.domain.repositories; import java.util.Optional; -import com.github.throyer.common.springboot.api.domain.models.entity.Role; +import com.github.throyer.common.springboot.domain.models.entity.Role; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -13,9 +13,25 @@ public interface RoleRepository extends SoftDeleteRepository { @Override - @Query(Role.DELETE_SQL) - @Transactional @Modifying + @Transactional + @Query(""" + UPDATE + #{#entityName} + SET + deleted_name = ( + SELECT name FROM #{#entityName} WHERE id = ?1 + ), + name = NULL, + deleted_initials = ( + SELECT name FROM #{#entityName} WHERE id = ?1 + ), + initials = NULL, + deleted_at = CURRENT_TIMESTAMP, + active = 0, + deleted_by = ?#{principal?.id} + WHERE id = ?1 + """) void deleteById(Long id); @Override diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/SoftDeleteRepository.java b/src/main/java/com/github/throyer/common/springboot/domain/repositories/SoftDeleteRepository.java similarity index 61% rename from src/main/java/com/github/throyer/common/springboot/api/domain/repositories/SoftDeleteRepository.java rename to src/main/java/com/github/throyer/common/springboot/domain/repositories/SoftDeleteRepository.java index 1e462601..faedf6ba 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/SoftDeleteRepository.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/repositories/SoftDeleteRepository.java @@ -1,6 +1,6 @@ -package com.github.throyer.common.springboot.api.domain.repositories; +package com.github.throyer.common.springboot.domain.repositories; -import com.github.throyer.common.springboot.api.domain.models.entity.BasicEntity; +import com.github.throyer.common.springboot.domain.models.entity.Auditable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -10,12 +10,18 @@ import org.springframework.transaction.annotation.Transactional; @NoRepositoryBean -public interface SoftDeleteRepository extends JpaRepository, JpaSpecificationExecutor { +public interface SoftDeleteRepository extends JpaRepository, JpaSpecificationExecutor { @Override - @Query(BasicEntity.SET_DELETED_SQL) - @Transactional @Modifying + @Transactional + @Query(""" + UPDATE + #{#entityName} + SET + deleted_at = CURRENT_TIMESTAMP + WHERE id = ?1 + """) void deleteById(Long id); @Override @@ -31,8 +37,13 @@ default void deleteAll(Iterable entities) { } @Override - @Query(BasicEntity.SET_ALL_DELETED_SQL) - @Transactional @Modifying + @Transactional + @Query(""" + UPDATE + #{#entityName} + SET + deleted_at = CURRENT_TIMESTAMP + """) void deleteAll(); } \ No newline at end of file diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/UserRepository.java b/src/main/java/com/github/throyer/common/springboot/domain/repositories/UserRepository.java similarity index 64% rename from src/main/java/com/github/throyer/common/springboot/api/domain/repositories/UserRepository.java rename to src/main/java/com/github/throyer/common/springboot/domain/repositories/UserRepository.java index 65472371..8d5290c9 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/repositories/UserRepository.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/repositories/UserRepository.java @@ -1,8 +1,8 @@ -package com.github.throyer.common.springboot.api.domain.repositories; +package com.github.throyer.common.springboot.domain.repositories; import java.util.Optional; -import com.github.throyer.common.springboot.api.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.entity.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -15,9 +15,24 @@ public interface UserRepository extends SoftDeleteRepository { @Override - @Query(User.DELETE_SQL) @Transactional @Modifying + @Query(""" + UPDATE + #{#entityName} + SET + deleted_email = ( + SELECT + email + FROM + #{#entityName} + WHERE id = ?1), + email = NULL, + deleted_at = CURRENT_TIMESTAMP, + active = 0, + deleted_by = ?#{principal?.id} + WHERE id = ?1 + """) void deleteById(Long id); @Override @@ -39,15 +54,15 @@ default void deleteAll(Iterable entities) { public Optional findOptionalByIdAndDeletedAtIsNull(Long id); @Query(""" - SELECT user FROM User user - JOIN FETCH user.roles + SELECT user FROM #{#entityName} user + LEFT JOIN FETCH user.roles WHERE user.id = ?1 """) public Optional findOptionalByIdAndDeletedAtIsNullFetchRoles(Long id); @Query(""" - SELECT user FROM User user - JOIN FETCH user.roles + SELECT user FROM #{#entityName} user + LEFT JOIN FETCH user.roles WHERE user.email = ?1 """) public Optional findOptionalByEmailFetchRoles(String email); diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/email/Email.java b/src/main/java/com/github/throyer/common/springboot/domain/services/email/Email.java similarity index 70% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/email/Email.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/email/Email.java index 9601db0e..388a5b7e 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/email/Email.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/email/Email.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.email; +package com.github.throyer.common.springboot.domain.services.email; import org.thymeleaf.context.Context; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/email/MailService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/email/MailService.java similarity index 95% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/email/MailService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/email/MailService.java index 0c977a26..2dbbbc30 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/email/MailService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/email/MailService.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.email; +package com.github.throyer.common.springboot.domain.services.email; import javax.mail.MessagingException; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/JsonWebToken.java b/src/main/java/com/github/throyer/common/springboot/domain/services/security/JsonWebToken.java similarity index 78% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/security/JsonWebToken.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/security/JsonWebToken.java index 7b52bd3c..04190c6f 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/JsonWebToken.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/security/JsonWebToken.java @@ -1,6 +1,6 @@ -package com.github.throyer.common.springboot.api.domain.services.security; +package com.github.throyer.common.springboot.domain.services.security; -import static com.github.throyer.common.springboot.api.utils.Constants.SECURITY.ROLES_KEY_ON_JWT; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.ROLES_KEY_ON_JWT; import java.time.LocalDateTime; import java.time.ZoneId; @@ -9,9 +9,9 @@ import java.util.List; import java.util.stream.Collectors; -import com.github.throyer.common.springboot.api.domain.models.entity.Role; -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.models.security.Authorized; +import com.github.throyer.common.springboot.domain.models.entity.Role; +import com.github.throyer.common.springboot.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.security.Authorized; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/SecurityService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/security/SecurityService.java similarity index 70% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/security/SecurityService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/security/SecurityService.java index 18644446..8ff008fb 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/SecurityService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/security/SecurityService.java @@ -1,13 +1,16 @@ -package com.github.throyer.common.springboot.api.domain.services.security; +package com.github.throyer.common.springboot.domain.services.security; -import static com.github.throyer.common.springboot.api.utils.Constants.SECURITY.INVALID_USERNAME; -import static com.github.throyer.common.springboot.api.utils.Constants.SECURITY.JWT; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.INVALID_USERNAME; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.JWT; +import static java.util.Objects.nonNull; +import static java.util.Optional.empty; +import static java.util.Optional.of; import java.util.Objects; import java.util.Optional; -import com.github.throyer.common.springboot.api.domain.models.security.Authorized; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.models.security.Authorized; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,7 +38,7 @@ public SecurityService(@Value("${token.secret}") String secret) { @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - return new Authorized(repository.findOptionalByEmail(email) + return new Authorized(repository.findOptionalByEmailFetchRoles(email) .orElseThrow(() -> new UsernameNotFoundException(INVALID_USERNAME))); } @@ -54,12 +57,12 @@ public static Optional authorized() { try { var principal = getPrincipal(); - if (Objects.nonNull(principal) && principal instanceof Authorized authorized) { - return Optional.of(authorized); + if (nonNull(principal) && principal instanceof Authorized authorized) { + return of(authorized); } - return Optional.empty(); + return empty(); } catch (Exception exception) { - return Optional.empty(); + return empty(); } } @@ -67,7 +70,7 @@ public static Optional authorized() { private static Object getPrincipal() { var authentication = SecurityContextHolder.getContext() .getAuthentication(); - if (Objects.nonNull(authentication)) { + if (nonNull(authentication)) { return authentication.getPrincipal(); } return null; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/SessionService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/security/SessionService.java similarity index 67% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/security/SessionService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/security/SessionService.java index 1f1464ad..c9460e58 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/SessionService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/security/SessionService.java @@ -1,20 +1,20 @@ -package com.github.throyer.common.springboot.api.domain.services.security; +package com.github.throyer.common.springboot.domain.services.security; -import static com.github.throyer.common.springboot.api.utils.Constants.SECURITY.CREATE_SESSION_ERROR_MESSAGE; -import static com.github.throyer.common.springboot.api.utils.Constants.SECURITY.REFRESH_SESSION_ERROR_MESSAGE; -import static com.github.throyer.common.springboot.api.utils.Constants.SECURITY.JWT; -import static com.github.throyer.common.springboot.api.utils.Responses.ok; -import static com.github.throyer.common.springboot.api.utils.Responses.forbidden; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.CREATE_SESSION_ERROR_MESSAGE; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.REFRESH_SESSION_ERROR_MESSAGE; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.JWT; +import static com.github.throyer.common.springboot.utils.Responses.ok; +import static com.github.throyer.common.springboot.utils.Responses.forbidden; import java.time.LocalDateTime; -import com.github.throyer.common.springboot.api.domain.models.entity.RefreshToken; -import com.github.throyer.common.springboot.api.domain.repositories.RefreshTokenRepository; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; -import com.github.throyer.common.springboot.api.domain.services.security.dto.RefreshTokenRequest; -import com.github.throyer.common.springboot.api.domain.services.security.dto.RefreshTokenResponse; -import com.github.throyer.common.springboot.api.domain.services.security.dto.TokenRequest; -import com.github.throyer.common.springboot.api.domain.services.security.dto.TokenResponse; +import com.github.throyer.common.springboot.domain.models.entity.RefreshToken; +import com.github.throyer.common.springboot.domain.repositories.RefreshTokenRepository; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.services.security.dto.RefreshTokenRequest; +import com.github.throyer.common.springboot.domain.services.security.dto.RefreshTokenResponse; +import com.github.throyer.common.springboot.domain.services.security.dto.TokenRequest; +import com.github.throyer.common.springboot.domain.services.security.dto.TokenResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/RefreshTokenRequest.java b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/RefreshTokenRequest.java similarity index 86% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/RefreshTokenRequest.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/RefreshTokenRequest.java index 1ca27b86..f79ae965 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/RefreshTokenRequest.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/RefreshTokenRequest.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.security.dto; +package com.github.throyer.common.springboot.domain.services.security.dto; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/RefreshTokenResponse.java b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/RefreshTokenResponse.java similarity index 87% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/RefreshTokenResponse.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/RefreshTokenResponse.java index 07ed02cc..ec2e0a75 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/RefreshTokenResponse.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/RefreshTokenResponse.java @@ -1,11 +1,11 @@ -package com.github.throyer.common.springboot.api.domain.services.security.dto; +package com.github.throyer.common.springboot.domain.services.security.dto; import java.time.LocalDateTime; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonFormat.Shape; -import com.github.throyer.common.springboot.api.domain.models.entity.RefreshToken; +import com.github.throyer.common.springboot.domain.models.entity.RefreshToken; public class RefreshTokenResponse { private final String token; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/TokenRequest.java b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/TokenRequest.java similarity index 94% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/TokenRequest.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/TokenRequest.java index f223b5d9..d1b0619e 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/TokenRequest.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/TokenRequest.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.security.dto; +package com.github.throyer.common.springboot.domain.services.security.dto; import java.util.Objects; import javax.validation.constraints.NotEmpty; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/TokenResponse.java b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/TokenResponse.java similarity index 79% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/TokenResponse.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/TokenResponse.java index 27413fb0..f65f179d 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/security/dto/TokenResponse.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/security/dto/TokenResponse.java @@ -1,13 +1,13 @@ -package com.github.throyer.common.springboot.api.domain.services.security.dto; +package com.github.throyer.common.springboot.domain.services.security.dto; import java.time.LocalDateTime; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat.Shape; import com.fasterxml.jackson.annotation.JsonProperty; -import com.github.throyer.common.springboot.api.domain.models.entity.RefreshToken; -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UserDetails; +import com.github.throyer.common.springboot.domain.models.entity.RefreshToken; +import com.github.throyer.common.springboot.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.services.user.dto.UserDetails; public class TokenResponse { private final UserDetails user; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/CreateUserService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/CreateUserService.java similarity index 55% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/CreateUserService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/CreateUserService.java index 13182ba9..aab9ad03 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/CreateUserService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/CreateUserService.java @@ -1,14 +1,14 @@ -package com.github.throyer.common.springboot.api.domain.services.user; +package com.github.throyer.common.springboot.domain.services.user; -import static com.github.throyer.common.springboot.api.domain.validation.EmailValidations.validateEmailUniqueness; -import static com.github.throyer.common.springboot.api.utils.Responses.created; +import static com.github.throyer.common.springboot.domain.validation.EmailValidations.validateEmailUniqueness; +import static com.github.throyer.common.springboot.utils.Responses.created; import java.util.List; -import com.github.throyer.common.springboot.api.domain.repositories.RoleRepository; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; -import com.github.throyer.common.springboot.api.domain.services.user.dto.CreateUser; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UserDetails; +import com.github.throyer.common.springboot.domain.repositories.RoleRepository; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.services.user.dto.CreateUser; +import com.github.throyer.common.springboot.domain.services.user.dto.UserDetails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/FindUserService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/FindUserService.java similarity index 73% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/FindUserService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/FindUserService.java index b5083f9b..eba29a3e 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/FindUserService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/FindUserService.java @@ -1,11 +1,11 @@ -package com.github.throyer.common.springboot.api.domain.services.user; - -import static com.github.throyer.common.springboot.api.domain.models.pagination.Page.of; -import static com.github.throyer.common.springboot.api.domain.services.security.SecurityService.authorized; -import static com.github.throyer.common.springboot.api.utils.Responses.notFound; -import static com.github.throyer.common.springboot.api.utils.Responses.ok; -import static com.github.throyer.common.springboot.api.utils.Responses.unauthorized; -import static com.github.throyer.common.springboot.api.utils.SQLUtils.replace; +package com.github.throyer.common.springboot.domain.services.user; + +import static com.github.throyer.common.springboot.domain.models.pagination.Page.of; +import static com.github.throyer.common.springboot.domain.services.security.SecurityService.authorized; +import static com.github.throyer.common.springboot.utils.Responses.notFound; +import static com.github.throyer.common.springboot.utils.Responses.ok; +import static com.github.throyer.common.springboot.utils.Responses.unauthorized; +import static com.github.throyer.common.springboot.utils.SQLUtils.replace; import static javax.persistence.criteria.JoinType.LEFT; import java.text.Normalizer; @@ -16,12 +16,12 @@ import javax.persistence.criteria.Expression; import javax.persistence.criteria.Predicate; -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.models.pagination.Page; -import com.github.throyer.common.springboot.api.domain.models.pagination.Pagination; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; -import com.github.throyer.common.springboot.api.domain.services.user.dto.SearchUser; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UserDetails; +import com.github.throyer.common.springboot.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.pagination.Page; +import com.github.throyer.common.springboot.domain.models.pagination.Pagination; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.services.user.dto.SearchUser; +import com.github.throyer.common.springboot.domain.services.user.dto.UserDetails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/RecoveryPasswordService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/RecoveryPasswordService.java similarity index 82% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/RecoveryPasswordService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/RecoveryPasswordService.java index cd7ee32a..76ae5b67 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/RecoveryPasswordService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/RecoveryPasswordService.java @@ -1,10 +1,10 @@ -package com.github.throyer.common.springboot.api.domain.services.user; +package com.github.throyer.common.springboot.domain.services.user; -import com.github.throyer.common.springboot.api.domain.models.emails.RecoveryEmail; -import com.github.throyer.common.springboot.api.domain.models.entity.Recovery; -import com.github.throyer.common.springboot.api.domain.repositories.RecoveryRepository; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; -import com.github.throyer.common.springboot.api.domain.services.email.MailService; +import com.github.throyer.common.springboot.domain.models.emails.RecoveryEmail; +import com.github.throyer.common.springboot.domain.models.entity.Recovery; +import com.github.throyer.common.springboot.domain.repositories.RecoveryRepository; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.services.email.MailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/RemoveUserService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/RemoveUserService.java similarity index 54% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/RemoveUserService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/RemoveUserService.java index b2ec9a97..b6dc75a1 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/RemoveUserService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/RemoveUserService.java @@ -1,10 +1,10 @@ -package com.github.throyer.common.springboot.api.domain.services.user; +package com.github.throyer.common.springboot.domain.services.user; -import static com.github.throyer.common.springboot.api.utils.Responses.noContent; -import static com.github.throyer.common.springboot.api.utils.Responses.notFound; +import static com.github.throyer.common.springboot.utils.Responses.noContent; +import static com.github.throyer.common.springboot.utils.Responses.notFound; -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/UpdateUserService.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/UpdateUserService.java similarity index 51% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/UpdateUserService.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/UpdateUserService.java index 89c9715a..5703feaa 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/UpdateUserService.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/UpdateUserService.java @@ -1,14 +1,14 @@ -package com.github.throyer.common.springboot.api.domain.services.user; +package com.github.throyer.common.springboot.domain.services.user; -import static com.github.throyer.common.springboot.api.domain.services.security.SecurityService.authorized; -import static com.github.throyer.common.springboot.api.domain.validation.EmailValidations.validateEmailUniquenessOnModify; -import static com.github.throyer.common.springboot.api.utils.Responses.notFound; -import static com.github.throyer.common.springboot.api.utils.Responses.ok; -import static com.github.throyer.common.springboot.api.utils.Responses.unauthorized; +import static com.github.throyer.common.springboot.domain.services.security.SecurityService.authorized; +import static com.github.throyer.common.springboot.domain.validation.EmailValidations.validateEmailUniquenessOnModify; +import static com.github.throyer.common.springboot.utils.Responses.notFound; +import static com.github.throyer.common.springboot.utils.Responses.ok; +import static com.github.throyer.common.springboot.utils.Responses.unauthorized; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UpdateUser; -import com.github.throyer.common.springboot.api.domain.services.user.dto.UserDetails; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.services.user.dto.UpdateUser; +import com.github.throyer.common.springboot.domain.services.user.dto.UserDetails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/CreateUser.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/CreateUser.java similarity index 86% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/CreateUser.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/CreateUser.java index 26eda022..feac7049 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/CreateUser.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/CreateUser.java @@ -1,13 +1,13 @@ -package com.github.throyer.common.springboot.api.domain.services.user.dto; +package com.github.throyer.common.springboot.domain.services.user.dto; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; -import com.github.throyer.common.springboot.api.domain.builders.UserBuilder; -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.models.shared.HasEmail; +import com.github.throyer.common.springboot.domain.builders.UserBuilder; +import com.github.throyer.common.springboot.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.shared.HasEmail; public class CreateUser implements HasEmail { diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryConfirm.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryConfirm.java similarity index 88% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryConfirm.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryConfirm.java index edc812ec..1d21c0d9 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryConfirm.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryConfirm.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.user.dto; +package com.github.throyer.common.springboot.domain.services.user.dto; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryRequest.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryRequest.java similarity index 83% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryRequest.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryRequest.java index a10aefcc..dbd037df 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryRequest.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryRequest.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.user.dto; +package com.github.throyer.common.springboot.domain.services.user.dto; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryUpdate.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryUpdate.java similarity index 91% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryUpdate.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryUpdate.java index 72bcf88f..6cb3c15e 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/RecoveryUpdate.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/RecoveryUpdate.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.user.dto; +package com.github.throyer.common.springboot.domain.services.user.dto; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/SearchUser.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/SearchUser.java similarity index 91% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/SearchUser.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/SearchUser.java index ac0d462a..2649fb9c 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/SearchUser.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/SearchUser.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.services.user.dto; +package com.github.throyer.common.springboot.domain.services.user.dto; import java.util.List; import java.util.Objects; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/UpdateUser.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/UpdateUser.java similarity index 83% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/UpdateUser.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/UpdateUser.java index b1975a32..bf59107e 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/UpdateUser.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/UpdateUser.java @@ -1,10 +1,10 @@ -package com.github.throyer.common.springboot.api.domain.services.user.dto; +package com.github.throyer.common.springboot.domain.services.user.dto; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -import com.github.throyer.common.springboot.api.domain.models.shared.HasEmail; +import com.github.throyer.common.springboot.domain.models.shared.HasEmail; public class UpdateUser implements HasEmail { diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/UserDetails.java b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/UserDetails.java similarity index 76% rename from src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/UserDetails.java rename to src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/UserDetails.java index c6cc2ea6..d84250ff 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/services/user/dto/UserDetails.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/services/user/dto/UserDetails.java @@ -1,9 +1,9 @@ -package com.github.throyer.common.springboot.api.domain.services.user.dto; +package com.github.throyer.common.springboot.domain.services.user.dto; import java.util.List; -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.models.shared.Entity; +import com.github.throyer.common.springboot.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.shared.Entity; public class UserDetails implements Entity { private final Long id; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/EmailNotUniqueException.java b/src/main/java/com/github/throyer/common/springboot/domain/validation/EmailNotUniqueException.java similarity index 92% rename from src/main/java/com/github/throyer/common/springboot/api/domain/validation/EmailNotUniqueException.java rename to src/main/java/com/github/throyer/common/springboot/domain/validation/EmailNotUniqueException.java index 4d71e867..5bfe76e2 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/EmailNotUniqueException.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/validation/EmailNotUniqueException.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.validation; +package com.github.throyer.common.springboot.domain.validation; import java.util.List; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/EmailValidations.java b/src/main/java/com/github/throyer/common/springboot/domain/validation/EmailValidations.java similarity index 84% rename from src/main/java/com/github/throyer/common/springboot/api/domain/validation/EmailValidations.java rename to src/main/java/com/github/throyer/common/springboot/domain/validation/EmailValidations.java index 90dc2fc0..f522cc25 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/EmailValidations.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/validation/EmailValidations.java @@ -1,9 +1,9 @@ -package com.github.throyer.common.springboot.api.domain.validation; +package com.github.throyer.common.springboot.domain.validation; import java.util.List; -import com.github.throyer.common.springboot.api.domain.models.shared.HasEmail; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.models.shared.HasEmail; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/InvalidSortException.java b/src/main/java/com/github/throyer/common/springboot/domain/validation/InvalidSortException.java similarity index 92% rename from src/main/java/com/github/throyer/common/springboot/api/domain/validation/InvalidSortException.java rename to src/main/java/com/github/throyer/common/springboot/domain/validation/InvalidSortException.java index a02f1e7f..0210f19c 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/InvalidSortException.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/validation/InvalidSortException.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.validation; +package com.github.throyer.common.springboot.domain.validation; import java.util.List; diff --git a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/SimpleError.java b/src/main/java/com/github/throyer/common/springboot/domain/validation/SimpleError.java similarity index 95% rename from src/main/java/com/github/throyer/common/springboot/api/domain/validation/SimpleError.java rename to src/main/java/com/github/throyer/common/springboot/domain/validation/SimpleError.java index f78852a2..baf705d9 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/domain/validation/SimpleError.java +++ b/src/main/java/com/github/throyer/common/springboot/domain/validation/SimpleError.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.domain.validation; +package com.github.throyer.common.springboot.domain.validation; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; diff --git a/src/main/java/com/github/throyer/common/springboot/api/errors/ValidationHandlers.java b/src/main/java/com/github/throyer/common/springboot/errors/ValidationHandlers.java similarity index 73% rename from src/main/java/com/github/throyer/common/springboot/api/errors/ValidationHandlers.java rename to src/main/java/com/github/throyer/common/springboot/errors/ValidationHandlers.java index b0e3bc73..42f2cea6 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/errors/ValidationHandlers.java +++ b/src/main/java/com/github/throyer/common/springboot/errors/ValidationHandlers.java @@ -1,16 +1,18 @@ -package com.github.throyer.common.springboot.api.errors; +package com.github.throyer.common.springboot.errors; import java.util.List; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; -import com.github.throyer.common.springboot.api.domain.validation.EmailNotUniqueException; -import com.github.throyer.common.springboot.api.domain.validation.InvalidSortException; -import com.github.throyer.common.springboot.api.domain.validation.SimpleError; -import static com.github.throyer.common.springboot.api.utils.JsonUtils.toJson; +import com.github.throyer.common.springboot.domain.validation.EmailNotUniqueException; +import com.github.throyer.common.springboot.domain.validation.InvalidSortException; +import com.github.throyer.common.springboot.domain.validation.SimpleError; +import static com.github.throyer.common.springboot.utils.JsonUtils.toJson; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.validation.FieldError; @@ -23,13 +25,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - @RestControllerAdvice public class ValidationHandlers { private static final Logger LOGGER = LoggerFactory.getLogger(ValidationHandlers.class); - @ResponseStatus(code = HttpStatus.BAD_REQUEST) + @ResponseStatus(code = BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public List badRequest(MethodArgumentNotValidException exception) { return exception.getBindingResult() @@ -39,7 +40,7 @@ public List badRequest(MethodArgumentNotValidException exception) { .collect(Collectors.toList()); } - @ResponseStatus(code = HttpStatus.BAD_REQUEST) + @ResponseStatus(code = BAD_REQUEST) @ExceptionHandler(EmailNotUniqueException.class) public List badRequest(EmailNotUniqueException exception) { return exception.getErrors(); @@ -52,24 +53,24 @@ public ResponseEntity status(ResponseStatusException exception) { .body(new SimpleError(exception.getReason(), exception.getStatus())); } - @ResponseStatus(code = HttpStatus.BAD_REQUEST) + @ResponseStatus(code = BAD_REQUEST) @ExceptionHandler(InvalidSortException.class) public List badRequest(InvalidSortException exception) { return exception.getErrors(); } - @ResponseStatus(code = HttpStatus.UNAUTHORIZED) + @ResponseStatus(code = UNAUTHORIZED) @ExceptionHandler(AccessDeniedException.class) public SimpleError unauthorized(AccessDeniedException exception) { - return new SimpleError(exception.getMessage(), HttpStatus.UNAUTHORIZED); + return new SimpleError(exception.getMessage(), UNAUTHORIZED); } public static void forbidden(HttpServletResponse response) { try { - response.setStatus(HttpStatus.FORBIDDEN.value()); + response.setStatus(FORBIDDEN.value()); response.setContentType("application/json"); response.getWriter().write(toJson( - new SimpleError("Can't find token on Authorization header.", HttpStatus.FORBIDDEN) + new SimpleError("Can't find token on Authorization header.", FORBIDDEN) )); } catch (Exception exception) { LOGGER.error("can't write response error on token expired or invalid exception", exception); diff --git a/src/main/java/com/github/throyer/common/springboot/api/middlewares/AuthorizationMiddleware.java b/src/main/java/com/github/throyer/common/springboot/middlewares/AuthorizationMiddleware.java similarity index 65% rename from src/main/java/com/github/throyer/common/springboot/api/middlewares/AuthorizationMiddleware.java rename to src/main/java/com/github/throyer/common/springboot/middlewares/AuthorizationMiddleware.java index b75e49d9..642aaeac 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/middlewares/AuthorizationMiddleware.java +++ b/src/main/java/com/github/throyer/common/springboot/middlewares/AuthorizationMiddleware.java @@ -1,7 +1,7 @@ -package com.github.throyer.common.springboot.api.middlewares; +package com.github.throyer.common.springboot.middlewares; -import static com.github.throyer.common.springboot.api.domain.services.security.SecurityService.authorize; -import static com.github.throyer.common.springboot.api.utils.TokenUtils.authorization; +import static com.github.throyer.common.springboot.domain.services.security.SecurityService.authorize; +import static com.github.throyer.common.springboot.utils.TokenUtils.authorization; import static java.util.Optional.ofNullable; import java.io.IOException; @@ -11,6 +11,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.github.throyer.common.springboot.domain.services.security.SecurityService; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -26,7 +27,7 @@ protected void doFilterInternal( throws ServletException, IOException { ofNullable(authorization(request)) - .ifPresent((token) -> authorize(token)); + .ifPresent(SecurityService::authorize); filter.doFilter(request, response); } diff --git a/src/main/java/com/github/throyer/common/springboot/utils/Constants.java b/src/main/java/com/github/throyer/common/springboot/utils/Constants.java new file mode 100644 index 00000000..32d90665 --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/utils/Constants.java @@ -0,0 +1,39 @@ +package com.github.throyer.common.springboot.utils; + +import com.github.throyer.common.springboot.domain.services.security.JsonWebToken; + +public class Constants { + public class SECURITY { + public static final JsonWebToken JWT = new JsonWebToken(); + public static final Long HOUR_IN_SECONDS = 3600L; + public static final Integer DAY_MILLISECONDS = 86400; + + public static final String ROLES_KEY_ON_JWT = "roles"; + public static final String INVALID_USERNAME = "Nome de usuário invalido."; + public static final String CREATE_SESSION_ERROR_MESSAGE = "Senha ou Usuário inválidos."; + public static final String REFRESH_SESSION_ERROR_MESSAGE = "Refresh token expirado ou inválido."; + + public static final String USERNAME_PARAMETER = "email"; + public static final String PASSWORD_PARAMETER = "password"; + + public static final String HOME_URL = "/app"; + public static final String LOGIN_URL = "/app/login"; + public static final String LOGIN_ERROR_URL = LOGIN_URL + "?error=true"; + public static final String ACESSO_NEGADO_URL = LOGIN_URL + "?denied=true"; + public static final String LOGOUT_URL = "/app/logout"; + + public static final String SESSION_COOKIE_NAME = "JSESSIONID"; + + public static final String[] STATIC_FILES = { + "/robots.txt", + "/font/**", + "/css/**", + "/webjars/**", + "/webjars/", + "/js/**", + "/favicon.ico", + "/**.html", + "/documentation/**" + }; + } +} diff --git a/src/main/java/com/github/throyer/common/springboot/utils/Hello.java b/src/main/java/com/github/throyer/common/springboot/utils/Hello.java new file mode 100644 index 00000000..22f2ada8 --- /dev/null +++ b/src/main/java/com/github/throyer/common/springboot/utils/Hello.java @@ -0,0 +1,5 @@ +package com.github.throyer.common.springboot.utils; + +public interface Hello { + public String getMessage(); +} diff --git a/src/main/java/com/github/throyer/common/springboot/api/utils/JsonUtils.java b/src/main/java/com/github/throyer/common/springboot/utils/JsonUtils.java similarity index 90% rename from src/main/java/com/github/throyer/common/springboot/api/utils/JsonUtils.java rename to src/main/java/com/github/throyer/common/springboot/utils/JsonUtils.java index e8ce1130..b9e7a511 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/utils/JsonUtils.java +++ b/src/main/java/com/github/throyer/common/springboot/utils/JsonUtils.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.utils; +package com.github.throyer.common.springboot.utils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/main/java/com/github/throyer/common/springboot/api/utils/Migrations.java b/src/main/java/com/github/throyer/common/springboot/utils/Migrations.java similarity index 90% rename from src/main/java/com/github/throyer/common/springboot/api/utils/Migrations.java rename to src/main/java/com/github/throyer/common/springboot/utils/Migrations.java index 877d959c..64ab4d56 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/utils/Migrations.java +++ b/src/main/java/com/github/throyer/common/springboot/utils/Migrations.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.utils; +package com.github.throyer.common.springboot.utils; import static org.jooq.impl.DSL.field; diff --git a/src/main/java/com/github/throyer/common/springboot/api/utils/Random.java b/src/main/java/com/github/throyer/common/springboot/utils/Random.java similarity index 78% rename from src/main/java/com/github/throyer/common/springboot/api/utils/Random.java rename to src/main/java/com/github/throyer/common/springboot/utils/Random.java index f3c4df3b..d0d4c470 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/utils/Random.java +++ b/src/main/java/com/github/throyer/common/springboot/utils/Random.java @@ -1,13 +1,13 @@ -package com.github.throyer.common.springboot.api.utils; +package com.github.throyer.common.springboot.utils; -import static com.github.throyer.common.springboot.api.domain.builders.UserBuilder.createUser; +import static com.github.throyer.common.springboot.domain.builders.UserBuilder.createUser; import java.util.List; import java.util.Locale; import com.github.javafaker.Faker; -import com.github.throyer.common.springboot.api.domain.models.entity.Role; -import com.github.throyer.common.springboot.api.domain.models.entity.User; +import com.github.throyer.common.springboot.domain.models.entity.Role; +import com.github.throyer.common.springboot.domain.models.entity.User; public class Random { @@ -27,7 +27,7 @@ public static String code() { } public static String password() { - return FAKER.regexify("[a-z]{5,13}[1-9]{1,5}[A-Z]{1,5}[#?!@$ %^&*-]{1,5}"); + return FAKER.regexify("[a-z]{5,13}[1-9]{1,5}[A-Z]{1,5}[#?!@$%^&*-]{1,5}"); } public static User randomUser() { diff --git a/src/main/java/com/github/throyer/common/springboot/api/utils/Responses.java b/src/main/java/com/github/throyer/common/springboot/utils/Responses.java similarity index 95% rename from src/main/java/com/github/throyer/common/springboot/api/utils/Responses.java rename to src/main/java/com/github/throyer/common/springboot/utils/Responses.java index c3e21fc7..a07aae71 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/utils/Responses.java +++ b/src/main/java/com/github/throyer/common/springboot/utils/Responses.java @@ -1,8 +1,8 @@ -package com.github.throyer.common.springboot.api.utils; +package com.github.throyer.common.springboot.utils; import java.net.URI; -import com.github.throyer.common.springboot.api.domain.models.shared.Entity; +import com.github.throyer.common.springboot.domain.models.shared.Entity; import org.springframework.data.repository.CrudRepository; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/github/throyer/common/springboot/api/utils/SQLUtils.java b/src/main/java/com/github/throyer/common/springboot/utils/SQLUtils.java similarity index 92% rename from src/main/java/com/github/throyer/common/springboot/api/utils/SQLUtils.java rename to src/main/java/com/github/throyer/common/springboot/utils/SQLUtils.java index b7e82875..24af464d 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/utils/SQLUtils.java +++ b/src/main/java/com/github/throyer/common/springboot/utils/SQLUtils.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api.utils; +package com.github.throyer.common.springboot.utils; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.Expression; diff --git a/src/main/java/com/github/throyer/common/springboot/api/utils/TokenUtils.java b/src/main/java/com/github/throyer/common/springboot/utils/TokenUtils.java similarity index 87% rename from src/main/java/com/github/throyer/common/springboot/api/utils/TokenUtils.java rename to src/main/java/com/github/throyer/common/springboot/utils/TokenUtils.java index 74792547..7326ae62 100644 --- a/src/main/java/com/github/throyer/common/springboot/api/utils/TokenUtils.java +++ b/src/main/java/com/github/throyer/common/springboot/utils/TokenUtils.java @@ -1,6 +1,6 @@ -package com.github.throyer.common.springboot.api.utils; +package com.github.throyer.common.springboot.utils; -import static com.github.throyer.common.springboot.api.utils.Constants.SECURITY.JWT; +import static com.github.throyer.common.springboot.utils.Constants.SECURITY.JWT; import java.time.LocalDateTime; import java.util.List; @@ -8,7 +8,7 @@ import javax.servlet.http.HttpServletRequest; -import com.github.throyer.common.springboot.api.domain.models.entity.Role; +import com.github.throyer.common.springboot.domain.models.entity.Role; public class TokenUtils { diff --git a/src/main/java/db/migration/V2021052906051622322329__insert_admin_and_roles.java b/src/main/java/db/migration/V2021052906051622322329__insert_admin_and_roles.java deleted file mode 100644 index fcb7a545..00000000 --- a/src/main/java/db/migration/V2021052906051622322329__insert_admin_and_roles.java +++ /dev/null @@ -1,75 +0,0 @@ -package db.migration; - -import static com.github.throyer.common.springboot.api.utils.Migrations.findOptionalId; -import static org.jooq.impl.DSL.field; -import static org.jooq.impl.DSL.table; -import static org.jooq.impl.DSL.using; - -import com.github.throyer.common.springboot.api.domain.models.entity.User; -import com.github.throyer.common.springboot.api.domain.services.user.dto.CreateUser; - -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - -public class V2021052906051622322329__insert_admin_and_roles extends BaseJavaMigration { - public void migrate(Context context) throws Exception { - var create = using(context.getConnection()); - create.transaction(configuration -> { - - var admin = new CreateUser("admin", "admin@email.com", "admin") - .toUser(); - - var encoder = new BCryptPasswordEncoder(User.PASSWORD_STRENGTH); - - var dsl = using(configuration); - - dsl.insertInto( - table("user"), - field("name"), - field("email"), - field("password") - ) - .values(admin.getName(), admin.getEmail(), encoder.encode(admin.getPassword())) - .execute(); - - dsl.insertInto( - table("role"), - field("name"), - field("initials"), - field("description"), - field("created_by") - ) - .values("ADMINISTRADOR", "ADM", "Administrador", - findOptionalId(dsl, - table("user"), - field("email").equal(admin.getEmail())) - .orElseThrow()) - .values("USER", "USER", "Usuário", - findOptionalId(dsl, - table("user"), - field("email").equal(admin.getEmail())) - .orElseThrow()) - .execute(); - - dsl.insertInto( - table("user_role"), - field("user_id"), - field("role_id") - ) - .values( - findOptionalId(dsl, table("user"), field("email").equal("admin@email.com")) - .orElseThrow(), - findOptionalId(dsl, table("role"), field("initials").equal("ADM")) - .orElseThrow() - ) - .values( - findOptionalId(dsl, table("user"), field("email").equal("admin@email.com")) - .orElseThrow(), - findOptionalId(dsl, table("role"), field("initials").equal("USER")) - .orElseThrow() - ) - .execute(); - }); - } -} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b49e68cb..d05cd841 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -11,9 +11,6 @@ spring.output.ansi.enabled=always spring.jpa.properties.hibernate.format_sql=true spring.jpa.show-sql=${show-sql:true} -# Contexto -server.servlet.context-path=${contexto:/api} - # Banco de dados spring.datasource.hikari.maximum-pool-size=${max-connections:5} spring.datasource.url=jdbc:mysql://${db-url:localhost:3306/common_app}?useSSL=false&createDatabaseIfNotExist=true&serverTimezone=America/Sao_Paulo @@ -22,8 +19,6 @@ spring.datasource.password=${db-password:root} spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.jpa.properties.javax.persistence.validation.mode=none - -# lazy load spring.jpa.open-in-view=false # swagger diff --git a/src/main/resources/db/migration/V2021052906051622322329__insert_admin_and_roles.sql b/src/main/resources/db/migration/V2021052906051622322329__insert_admin_and_roles.sql new file mode 100644 index 00000000..a2781906 --- /dev/null +++ b/src/main/resources/db/migration/V2021052906051622322329__insert_admin_and_roles.sql @@ -0,0 +1,31 @@ +-- variables +SET @name = 'admin'; +SET @email = 'admin@email.com'; +SET @password = '$2a$10$QBuMJLbVmHzgvTwpxDynSetACNdCBjU5zgo.81RWEDzH46aUrgcNK'; +SET @adm = 'ADM'; +SET @user = 'USER'; + +-- insert admin +INSERT INTO user + (name, email, password) +VALUES + (@name, @email, @password); + +-- insert roles +INSERT INTO role + (name, initials, description, created_by) +VALUES + ('ADMINISTRADOR', @adm, 'Administrador do sistema', (SELECT id FROM user WHERE email = @email)), + ('USER', @user, 'Usuário do sistema', (SELECT id FROM user WHERE email = @email)); + +-- put roles into admin +INSERT INTO user_role + (user_id, role_id) +VALUES + ( + (SELECT id FROM user WHERE email = @email), + (SELECT id FROM role WHERE initials = @adm) + ),( + (SELECT id FROM user WHERE email = @email), + (SELECT id FROM role WHERE initials = @user) + ); \ No newline at end of file diff --git a/src/main/resources/static/css/login.css b/src/main/resources/static/css/login.css new file mode 100644 index 00000000..e1a2fcb2 --- /dev/null +++ b/src/main/resources/static/css/login.css @@ -0,0 +1,39 @@ +.form { + width: 100%; + max-width: 330px; + padding: 15px; + margin: auto; +} + +.form > .icon { + display: flex; + justify-content: center; +} + +.form .checkbox { + font-weight: 400; +} + +.form .form-control { + position: relative; + box-sizing: border-box; + height: auto; + padding: 10px; + font-size: 16px; +} + +.form .form-control:focus { + z-index: 2; +} + +.form input[type="email"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.form input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/src/main/resources/static/css/styles.css b/src/main/resources/static/css/styles.css new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/static/js/main.js b/src/main/resources/static/js/main.js new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/templates/app/fragments/imports.html b/src/main/resources/templates/app/fragments/imports.html new file mode 100644 index 00000000..d3fa6a18 --- /dev/null +++ b/src/main/resources/templates/app/fragments/imports.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/main/resources/templates/app/fragments/layout.html b/src/main/resources/templates/app/fragments/layout.html new file mode 100644 index 00000000..0cc7b3c0 --- /dev/null +++ b/src/main/resources/templates/app/fragments/layout.html @@ -0,0 +1,58 @@ + + + + + + + Common API + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/app/fragments/navbar.html b/src/main/resources/templates/app/fragments/navbar.html new file mode 100644 index 00000000..e4b39c4c --- /dev/null +++ b/src/main/resources/templates/app/fragments/navbar.html @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/src/main/resources/templates/app/index.html b/src/main/resources/templates/app/index.html new file mode 100644 index 00000000..68e5ffa2 --- /dev/null +++ b/src/main/resources/templates/app/index.html @@ -0,0 +1,102 @@ + + Home +
+
+
+ + + +
+ +
+ +

Explore the project

+

+ This is a simple API and Web App (MVC) + project with a crud of users with as + many good practices as I can. +

+
    +
  • + Swagger +
  • +
  • + Database migrations (java based) +
  • +
  • + JWT and Refresh token +
  • +
  • + Integration with SMTP services (Email) +
  • +
+

+ It was meant to be used as a base for larger projects. +

+ + + +
+ +
+
+

Other projects

+

There is a project on nodejs with a similar idea.

+ +
+ +
+

Project features

+

The idea is to have as many good practices and standards as possible, here are some already + implemented

+
    +
  • JWT
  • +
  • Refresh token
  • +
  • Tests with JUnity
  • +
  • Test coverage report (Jacoco)
  • +
  • Database migrations
  • +
  • Java + Based migrations
  • +
  • Soft delete
  • +
  • Swagger
  • +
  • Email (SMTP)
  • +
  • Lazy load
  • +
  • Audit fields (created_at, updated_at etc)
  • +
+
+
+
+
+
+ Throyer · © 2021 +
+
+ +
\ No newline at end of file diff --git a/src/main/resources/templates/app/login/index.html b/src/main/resources/templates/app/login/index.html new file mode 100644 index 00000000..7d557dc8 --- /dev/null +++ b/src/main/resources/templates/app/login/index.html @@ -0,0 +1,94 @@ + + + Login + + + + + + +
+
+ +
+

Fazer login

+ + + + + + + +
+
+ + +
+
+ +
+ +
+ + + + +
+ + + + diff --git a/src/test/java/com/github/throyer/common/springboot/api/CommonApiApplicationTests.java b/src/test/java/com/github/throyer/common/springboot/CommonApiApplicationTests.java similarity index 78% rename from src/test/java/com/github/throyer/common/springboot/api/CommonApiApplicationTests.java rename to src/test/java/com/github/throyer/common/springboot/CommonApiApplicationTests.java index a0aa3fb9..87eb838b 100644 --- a/src/test/java/com/github/throyer/common/springboot/api/CommonApiApplicationTests.java +++ b/src/test/java/com/github/throyer/common/springboot/CommonApiApplicationTests.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api; +package com.github.throyer.common.springboot; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/com/github/throyer/common/springboot/api/SwaggerTests.java b/src/test/java/com/github/throyer/common/springboot/SwaggerTests.java similarity index 95% rename from src/test/java/com/github/throyer/common/springboot/api/SwaggerTests.java rename to src/test/java/com/github/throyer/common/springboot/SwaggerTests.java index 187ab384..513ad398 100644 --- a/src/test/java/com/github/throyer/common/springboot/api/SwaggerTests.java +++ b/src/test/java/com/github/throyer/common/springboot/SwaggerTests.java @@ -1,4 +1,4 @@ -package com.github.throyer.common.springboot.api; +package com.github.throyer.common.springboot; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; diff --git a/src/test/java/com/github/throyer/common/springboot/api/controllers/SessionsTests.java b/src/test/java/com/github/throyer/common/springboot/controllers/SessionsTests.java similarity index 85% rename from src/test/java/com/github/throyer/common/springboot/api/controllers/SessionsTests.java rename to src/test/java/com/github/throyer/common/springboot/controllers/SessionsTests.java index eedef94a..d783dce9 100644 --- a/src/test/java/com/github/throyer/common/springboot/api/controllers/SessionsTests.java +++ b/src/test/java/com/github/throyer/common/springboot/controllers/SessionsTests.java @@ -1,7 +1,7 @@ -package com.github.throyer.common.springboot.api.controllers; +package com.github.throyer.common.springboot.controllers; -import static com.github.throyer.common.springboot.api.utils.JsonUtils.toJson; -import static com.github.throyer.common.springboot.api.utils.Random.randomUser; +import static com.github.throyer.common.springboot.utils.JsonUtils.toJson; +import static com.github.throyer.common.springboot.utils.Random.randomUser; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -9,7 +9,7 @@ import java.util.Map; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -37,7 +37,7 @@ public class SessionsTests { UserRepository repository; @Test - @DisplayName("Deve criar gerar o token quando a senha estiver correta.") + @DisplayName("Deve gerar o token quando a senha estiver correta.") public void should_sigh_in_with_correct_password() throws Exception { var user = randomUser(); @@ -54,7 +54,7 @@ public void should_sigh_in_with_correct_password() throws Exception { } """; - var request = post("/sessions") + var request = post("/api/sessions") .content(String.format(body, email, password)) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); @@ -74,7 +74,7 @@ public void dont_should_sigh_in_with_wrong_password() throws Exception { "password", "Írineu! você não sabe, nem eu!" )); - var request = post("/sessions") + var request = post("/api/sessions") .content(body) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); @@ -87,7 +87,7 @@ public void dont_should_sigh_in_with_wrong_password() throws Exception { @DisplayName("Não deve aceitar requisições sem o token no cabeçalho quando as rotas forem protegidas.") public void dont_should_accept_requests_without_token_on_header_when_authorized_route() throws Exception { - var request = get("/users"); + var request = get("/api/users"); api.perform(request) .andDo(print()) diff --git a/src/test/java/com/github/throyer/common/springboot/api/controllers/UsersTests.java b/src/test/java/com/github/throyer/common/springboot/controllers/UsersTests.java similarity index 86% rename from src/test/java/com/github/throyer/common/springboot/api/controllers/UsersTests.java rename to src/test/java/com/github/throyer/common/springboot/controllers/UsersTests.java index d5ca25c8..e2950965 100644 --- a/src/test/java/com/github/throyer/common/springboot/api/controllers/UsersTests.java +++ b/src/test/java/com/github/throyer/common/springboot/controllers/UsersTests.java @@ -1,10 +1,10 @@ -package com.github.throyer.common.springboot.api.controllers; +package com.github.throyer.common.springboot.controllers; -import static com.github.throyer.common.springboot.api.utils.JsonUtils.toJson; -import static com.github.throyer.common.springboot.api.utils.Random.FAKER; -import static com.github.throyer.common.springboot.api.utils.Random.password; -import static com.github.throyer.common.springboot.api.utils.Random.randomUser; -import static com.github.throyer.common.springboot.api.utils.TokenUtils.token; +import static com.github.throyer.common.springboot.utils.JsonUtils.toJson; +import static com.github.throyer.common.springboot.utils.Random.FAKER; +import static com.github.throyer.common.springboot.utils.Random.password; +import static com.github.throyer.common.springboot.utils.Random.randomUser; +import static com.github.throyer.common.springboot.utils.TokenUtils.token; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasSize; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; @@ -17,7 +17,7 @@ import java.util.List; import java.util.Map; -import com.github.throyer.common.springboot.api.domain.repositories.UserRepository; +import com.github.throyer.common.springboot.domain.repositories.UserRepository; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; @@ -73,7 +73,7 @@ public void should_save_a_new_user() throws Exception { "password", password() )); - var request = post("/users") + var request = post("/api/users") .content(json) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); @@ -93,7 +93,7 @@ public void should_return_400_saving_user_without_required_fields() throws Excep "password", "123" )); - var request = post("/users") + var request = post("/api/users") .content(payload) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); @@ -110,7 +110,7 @@ public void should_list_users() throws Exception { repository.saveAll(List.of(randomUser(), randomUser(), randomUser(), randomUser())); - var request = get("/users") + var request = get("/api/users") .header(HttpHeaders.AUTHORIZATION, header) .queryParam("page", "0") .queryParam("size", "10"); @@ -127,7 +127,7 @@ public void should_delete_user() throws Exception { var user = repository.save(randomUser()); - var request = delete(String.format("/users/%s", user.getId())) + var request = delete(String.format("/api/users/%s", user.getId())) .header(HttpHeaders.AUTHORIZATION, header); api.perform(request).andDo(print()) @@ -139,13 +139,13 @@ public void should_delete_user() throws Exception { public void should_return_404_after_delete_user() throws Exception { var user = repository.save(randomUser()); - var fist = delete(String.format("/users/%s", user.getId())) + var fist = delete(String.format("/api/users/%s", user.getId())) .header(HttpHeaders.AUTHORIZATION, header); api.perform(fist).andDo(print()) .andExpect(status().isNoContent()); - var second = delete(String.format("/users/%s", user.getId())) + var second = delete(String.format("/api/users/%s", user.getId())) .header(HttpHeaders.AUTHORIZATION, header); api.perform(second).andDo(print()) @@ -162,7 +162,7 @@ public void should_return_400_after_save_same_email() throws Exception { "password", password() )); - var first = post("/users") + var first = post("/api/users") .content(json) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); @@ -172,7 +172,7 @@ public void should_return_400_after_save_same_email() throws Exception { .andExpect(jsonPath("$.id").exists()) .andExpect(jsonPath("$.id").isNotEmpty()); - var second = post("/users") + var second = post("/api/users") .content(json) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index 4e62042f..db603988 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -4,18 +4,21 @@ spring.datasource.url=jdbc:h2:mem:test;mode=MYSQL;DATABASE_TO_UPPER=false;DB_CLO spring.datasource.username=sa spring.datasource.password=sa spring.jpa.properties.javax.persistence.validation.mode=none +spring.jpa.open-in-view=false # logger spring.main.banner-mode=off logging.level.root=error spring.output.ansi.enabled=always +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.show-sql=${show-sql:true} # swagger springfox.documentation.open-api.v3.path=/documentation/schemas springfox.documentation.swagger-ui.base-url=/documentation springfox.documentation.swagger.v2.use-model-v3=false -# configurações do spring JPA. +# configura\u00c3\u00a7\u00c3\u00b5es do spring JPA. spring.jpa.hibernate.ddl-auto=none spring.datasource.initialization-mode=always