Skip to content

Commit f3b6a62

Browse files
committed
chore: improve user repositories
1 parent 0b644c8 commit f3b6a62

40 files changed

+851
-516
lines changed

src/main/java/com/github/throyer/common/springboot/Application.java

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
56

67
@SpringBootApplication
78
public class Application {

src/main/java/com/github/throyer/common/springboot/configurations/SpringSecurityConfiguration.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,11 @@ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
5353

5454
@Override
5555
protected void configure(HttpSecurity http) throws Exception {
56+
PUBLIC_API_ROUTES.configure(http);
57+
5658
http
5759
.antMatcher("/api/**")
5860
.authorizeRequests()
59-
.antMatchers(GET, "/api", "/api/documentation/**")
60-
.permitAll()
61-
.antMatchers(POST, "/api/users", "/api/sessions/**", "/api/recoveries/**", "/api/documentation/**")
62-
.permitAll()
6361
.anyRequest()
6462
.authenticated()
6563
.and()

src/main/java/com/github/throyer/common/springboot/controllers/api/UsersController.java

+23-31
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,29 @@
11
package com.github.throyer.common.springboot.controllers.api;
22

3-
import static org.springframework.http.HttpStatus.CREATED;
4-
import static org.springframework.http.HttpStatus.NO_CONTENT;
5-
6-
import static com.github.throyer.common.springboot.utils.Responses.created;
7-
import static com.github.throyer.common.springboot.utils.Responses.ok;
8-
93
import com.github.throyer.common.springboot.domain.pagination.model.Page;
10-
import com.github.throyer.common.springboot.domain.user.service.FindUserService;
11-
import com.github.throyer.common.springboot.domain.user.service.RemoveUserService;
4+
import com.github.throyer.common.springboot.domain.pagination.service.Pagination;
125
import com.github.throyer.common.springboot.domain.user.form.CreateUserProps;
13-
import com.github.throyer.common.springboot.domain.user.service.CreateUserService;
146
import com.github.throyer.common.springboot.domain.user.form.UpdateUserProps;
7+
import com.github.throyer.common.springboot.domain.user.model.UserDetails;
8+
import com.github.throyer.common.springboot.domain.user.repository.UserRepository;
9+
import com.github.throyer.common.springboot.domain.user.service.CreateUserService;
1510
import com.github.throyer.common.springboot.domain.user.service.FindUserByIdService;
11+
import com.github.throyer.common.springboot.domain.user.service.RemoveUserService;
1612
import com.github.throyer.common.springboot.domain.user.service.UpdateUserService;
17-
import com.github.throyer.common.springboot.domain.user.model.UserDetails;
18-
1913
import io.swagger.v3.oas.annotations.Operation;
2014
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
21-
22-
import java.util.Optional;
23-
2415
import io.swagger.v3.oas.annotations.tags.Tag;
2516
import org.springframework.beans.factory.annotation.Autowired;
2617
import org.springframework.http.ResponseEntity;
2718
import org.springframework.security.access.prepost.PreAuthorize;
2819
import org.springframework.validation.annotation.Validated;
29-
import org.springframework.web.bind.annotation.DeleteMapping;
30-
import org.springframework.web.bind.annotation.GetMapping;
31-
import org.springframework.web.bind.annotation.PathVariable;
32-
import org.springframework.web.bind.annotation.PostMapping;
33-
import org.springframework.web.bind.annotation.PutMapping;
34-
import org.springframework.web.bind.annotation.RequestBody;
35-
import org.springframework.web.bind.annotation.RequestMapping;
36-
import org.springframework.web.bind.annotation.ResponseStatus;
37-
import org.springframework.web.bind.annotation.RestController;
20+
import org.springframework.web.bind.annotation.*;
21+
22+
import java.util.Optional;
23+
24+
import static com.github.throyer.common.springboot.utils.Responses.*;
25+
import static org.springframework.http.HttpStatus.CREATED;
26+
import static org.springframework.http.HttpStatus.NO_CONTENT;
3827

3928
@RestController
4029
@Tag(name = "Users")
@@ -44,22 +33,23 @@ public class UsersController {
4433
private final CreateUserService createService;
4534
private final UpdateUserService updateService;
4635
private final RemoveUserService removeService;
47-
private final FindUserService findService;
4836
private final FindUserByIdService findByIdService;
4937

38+
private final UserRepository repository;
39+
5040
@Autowired
5141
public UsersController(
5242
CreateUserService createService,
5343
UpdateUserService updateService,
5444
RemoveUserService removeService,
55-
FindUserService findService,
56-
FindUserByIdService findByIdService
45+
FindUserByIdService findByIdService,
46+
UserRepository repository
5747
) {
5848
this.createService = createService;
5949
this.updateService = updateService;
6050
this.removeService = removeService;
61-
this.findService = findService;
6251
this.findByIdService = findByIdService;
52+
this.repository = repository;
6353
}
6454

6555
@GetMapping
@@ -70,17 +60,19 @@ public ResponseEntity<Page<UserDetails>> index(
7060
Optional<Integer> page,
7161
Optional<Integer> size
7262
) {
73-
var content = findService.findAll(page, size);
74-
return ok(content);
63+
var pageable = Pagination.of(page, size);
64+
var content = repository.findAll(pageable);
65+
return ok(content.map(UserDetails::new));
7566
}
7667

7768
@GetMapping("/{id}")
7869
@SecurityRequirement(name = "token")
7970
@PreAuthorize("hasAnyAuthority('ADM', 'USER')")
8071
@Operation(summary = "Show user info")
8172
public ResponseEntity<UserDetails> show(@PathVariable Long id) {
82-
var user = findByIdService.find(id);
83-
return ok(user);
73+
var user = repository.findById(id)
74+
.orElseThrow(() -> notFound("user not found"));
75+
return ok(new UserDetails(user));
8476
}
8577

8678
@PostMapping

src/main/java/com/github/throyer/common/springboot/controllers/app/UserController.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.github.throyer.common.springboot.controllers.app;
22

3+
import com.github.throyer.common.springboot.domain.pagination.service.Pagination;
34
import com.github.throyer.common.springboot.domain.toast.Type;
4-
import com.github.throyer.common.springboot.domain.user.service.FindUserService;
5+
import com.github.throyer.common.springboot.domain.user.repository.UserRepository;
6+
import com.github.throyer.common.springboot.domain.user.repository.custom.NativeQueryUserRepository;
57
import com.github.throyer.common.springboot.domain.user.service.RemoveUserService;
68
import com.github.throyer.common.springboot.domain.toast.Toasts;
79
import java.util.Optional;
@@ -21,7 +23,7 @@
2123
public class UserController {
2224

2325
@Autowired
24-
private FindUserService findService;
26+
private UserRepository repository;
2527

2628
@Autowired
2729
private RemoveUserService removeService;
@@ -32,10 +34,10 @@ public String index(
3234
Optional<Integer> page,
3335
Optional<Integer> size
3436
) {
37+
var pageable = Pagination.of(page, size);
38+
var content = repository.findAll(pageable);
3539

36-
var result = findService.findAll(page, size);
37-
38-
model.addAttribute("page", result);
40+
model.addAttribute("page", content);
3941

4042
return "app/users/index";
4143
}

src/main/java/com/github/throyer/common/springboot/domain/management/repository/SoftDeleteRepository.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import org.springframework.transaction.annotation.Transactional;
1313

1414
@NoRepositoryBean
15-
public interface SoftDeleteRepository <T extends Auditable> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> {
15+
public interface SoftDeleteRepository <T extends Auditable> extends JpaRepository<T, Long> {
1616

1717
@Override
1818
@Modifying

src/main/java/com/github/throyer/common/springboot/domain/pagination/model/Page.java

+12-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
import io.swagger.v3.oas.annotations.media.Schema;
44
import lombok.Getter;
55

6-
import static com.github.throyer.common.springboot.utils.JsonUtils.toJson;
76
import java.util.Collection;
87
import java.util.List;
8+
import java.util.function.Function;
9+
10+
import static com.github.throyer.common.springboot.utils.JSON.stringify;
911

1012
@Getter
1113
@Schema(requiredProperties = {"content", "page", "size", "totalPages", "totalElements"})
1214
public class Page<T> {
13-
private final Collection<T> content;
15+
private final Collection<? extends T> content;
1416
private final Integer page;
1517
private final Integer size;
1618
private final Integer totalPages;
@@ -24,7 +26,7 @@ public Page(org.springframework.data.domain.Page<T> page) {
2426
this.totalElements = page.getTotalElements();
2527
}
2628

27-
public Page(Collection<T> content, Integer page, Integer size, Long count) {
29+
public Page(Collection<? extends T> content, Integer page, Integer size, Long count) {
2830
this.content = content;
2931
this.page = page;
3032
this.size = size;
@@ -37,7 +39,12 @@ public static <T> Page<T> of(org.springframework.data.domain.Page<T> page) {
3739
}
3840

3941
public static <T> Page<T> of(Collection<T> content, Integer page, Integer size, Long count) {
40-
return new Page<>(content, page, size, count);
42+
return new Page<T>(content, page, size, count);
43+
}
44+
45+
public <U> Page<U> map(Function<? super T, ? extends U> converter) {
46+
var content = this.content.stream().map(converter).toList();
47+
return new Page<U>(content, this.page, this.size, this.totalElements);
4148
}
4249

4350
public static <T> Page<T> empty() {
@@ -46,6 +53,6 @@ public static <T> Page<T> empty() {
4653

4754
@Override
4855
public String toString() {
49-
return toJson(this);
56+
return stringify(this);
5057
}
5158
}

src/main/java/com/github/throyer/common/springboot/domain/recovery/service/RecoveryConfirmService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class RecoveryConfirmService {
1717
private RecoveryRepository recoveryRepository;
1818

1919
public void confirm(String email, String code) {
20-
var user = users.findOptionalByEmail(email)
20+
var user = users.findByEmail(email)
2121
.orElseThrow(() -> new ResponseStatusException(HttpStatus.FORBIDDEN));
2222

2323
var recovery = recoveryRepository

src/main/java/com/github/throyer/common/springboot/domain/recovery/service/RecoveryService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public RecoveryService(
3737

3838
public void recovery(String email) {
3939

40-
var user = users.findOptionalByEmail(email);
40+
var user = users.findByEmail(email);
4141

4242
if (user.isEmpty()) {
4343
return;

src/main/java/com/github/throyer/common/springboot/domain/recovery/service/RecoveryUpdateService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class RecoveryUpdateService {
1717
private RecoveryRepository recoveries;
1818

1919
public void update(String email, String code, String password) {
20-
var user = users.findOptionalByEmail(email)
20+
var user = users.findByEmail(email)
2121
.orElseThrow(() -> new ResponseStatusException(HttpStatus.FORBIDDEN));
2222

2323
var recovery = recoveries

src/main/java/com/github/throyer/common/springboot/domain/session/service/CreateTokenService.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ public CreateTokenService(
3333
}
3434

3535
public TokenResponse create(TokenRequest request) {
36-
var user = userRepository.findOptionalByEmailFetchRoles(request.getEmail())
37-
.filter(session -> session.validatePassword(request.getPassword()))
36+
var session = userRepository.findByEmail(request.getEmail())
37+
.filter(user -> user.validatePassword(request.getPassword()))
3838
.orElseThrow(() -> forbidden(message(CREATE_SESSION_ERROR_MESSAGE)));
39-
return create(new UserDetails(user));
39+
return create(new UserDetails(session));
4040
}
4141

4242
public TokenResponse create(UserDetails user) {

src/main/java/com/github/throyer/common/springboot/domain/session/service/SessionService.java

+30-18
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
package com.github.throyer.common.springboot.domain.session.service;
22

3-
import com.github.throyer.common.springboot.domain.user.repository.UserRepository;
43
import com.github.throyer.common.springboot.domain.session.model.Authorized;
4+
import com.github.throyer.common.springboot.domain.user.repository.UserRepository;
5+
import com.github.throyer.common.springboot.utils.Authorization;
6+
import org.springframework.security.core.context.SecurityContextHolder;
7+
import org.springframework.security.core.userdetails.UserDetails;
8+
import org.springframework.security.core.userdetails.UserDetailsService;
9+
import org.springframework.security.core.userdetails.UsernameNotFoundException;
10+
import org.springframework.stereotype.Service;
11+
12+
import javax.servlet.http.HttpServletRequest;
13+
import javax.servlet.http.HttpServletResponse;
14+
import java.util.Optional;
515

616
import static com.github.throyer.common.springboot.utils.Constants.MESSAGES.INVALID_USERNAME;
7-
import static com.github.throyer.common.springboot.utils.Constants.MESSAGES.TOKEN_EXPIRED_OR_INVALID;
817
import static com.github.throyer.common.springboot.utils.Constants.SECURITY.*;
918
import static com.github.throyer.common.springboot.utils.Messages.message;
19+
import static com.github.throyer.common.springboot.utils.Responses.expired;
20+
import static java.util.Objects.isNull;
1021
import static java.util.Objects.nonNull;
11-
import java.util.Optional;
1222
import static java.util.Optional.empty;
1323
import static java.util.Optional.of;
14-
import static java.util.logging.Level.WARNING;
15-
16-
import java.util.logging.Logger;
17-
18-
import org.springframework.beans.factory.annotation.Value;
19-
import org.springframework.security.core.context.SecurityContextHolder;
20-
import org.springframework.security.core.userdetails.UserDetails;
21-
import org.springframework.security.core.userdetails.UserDetailsService;
22-
import org.springframework.security.core.userdetails.UsernameNotFoundException;
23-
import org.springframework.stereotype.Service;
2424

2525
@Service
2626
public class SessionService implements UserDetailsService {
27-
private static final Logger LOGGER = Logger.getLogger(SessionService.class.getName());
2827

2928
private final UserRepository repository;
3029

@@ -34,20 +33,33 @@ public SessionService(UserRepository repository) {
3433

3534
@Override
3635
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
37-
var user = repository.findOptionalByEmailFetchRoles(email)
36+
var user = repository.findByEmail(email)
3837
.orElseThrow(() -> new UsernameNotFoundException(message(INVALID_USERNAME)));
3938

4039
return new Authorized(user);
4140
}
4241

43-
public static void authorize(String token) {
42+
public static void authorize(
43+
HttpServletRequest request,
44+
HttpServletResponse response
45+
) {
46+
if (PUBLIC_API_ROUTES.anyMatch(request)) {
47+
return;
48+
}
49+
50+
var token = Authorization.extract(request);
51+
52+
if (isNull(token)) {
53+
return;
54+
}
55+
4456
try {
4557
var authorized = JWT.decode(token, TOKEN_SECRET);
46-
SecurityContextHolder
58+
SecurityContextHolder
4759
.getContext()
4860
.setAuthentication(authorized.getAuthentication());
4961
} catch (Exception exception) {
50-
LOGGER.log(WARNING, message(TOKEN_EXPIRED_OR_INVALID));
62+
expired(response);
5163
}
5264
}
5365

0 commit comments

Comments
 (0)