From b2602408303674781451bbde5659c78a9b2278bb Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Sat, 30 Dec 2023 15:13:20 +0100 Subject: [PATCH] slightly better exception handling --- server/build.gradle | 1 + .../tjv/y/server/OpenAPIConfiguration.java | 48 +++++++++++++++++++ .../controller/ApiExceptionHandler.java | 34 ++++++++++++- .../y/server/controller/PersonController.java | 30 ++++++------ .../y/server/controller/TokenController.java | 2 + .../y/server/security/WebSecurityConfig.java | 2 + .../tjv/y/server/service/ChatServiceImpl.java | 24 +++++----- .../y/server/service/MessageServiceImpl.java | 7 ++- .../y/server/service/PersonServiceImpl.java | 34 +++++++------ .../tjv/y/server/service/PostServiceImpl.java | 9 ++-- .../service/exceptions/BadInputException.java | 7 +++ .../service/exceptions/ConflictException.java | 7 +++ .../service/exceptions/NotFoundException.java | 11 +++++ .../UserAlreadyExistsException.java | 11 ----- .../exceptions/UserNotFoundException.java | 15 ------ 15 files changed, 165 insertions(+), 77 deletions(-) create mode 100644 server/src/main/java/com/usatiuk/tjv/y/server/OpenAPIConfiguration.java create mode 100644 server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/BadInputException.java create mode 100644 server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/ConflictException.java create mode 100644 server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/NotFoundException.java delete mode 100644 server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserAlreadyExistsException.java delete mode 100644 server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserNotFoundException.java diff --git a/server/build.gradle b/server/build.gradle index 3caf017..0b483da 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -37,6 +37,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' // For TestRestTemplate as default client can't handle UNAUTHORIZED response testImplementation 'org.apache.httpcomponents.client5:httpclient5:5.3' + implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.2.0' implementation 'io.jsonwebtoken:jjwt-api:0.12.3' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3' diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/OpenAPIConfiguration.java b/server/src/main/java/com/usatiuk/tjv/y/server/OpenAPIConfiguration.java new file mode 100644 index 0000000..9f301ff --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/OpenAPIConfiguration.java @@ -0,0 +1,48 @@ +package com.usatiuk.tjv.y.server; + +import com.usatiuk.tjv.y.server.dto.ErrorTo; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverters; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.responses.ApiResponse; +import org.springdoc.core.customizers.OpenApiCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@OpenAPIDefinition(info = @Info(title = "Y API", version = "v1"), security = {@SecurityRequirement(name = "bearerAuth")}) +@SecurityScheme( + name = "bearerAuth", + type = SecuritySchemeType.HTTP, + bearerFormat = "JWT", + scheme = "bearer" +) +public class OpenAPIConfiguration { + private ApiResponse createApiResponse(String message, Schema schema) { + MediaType mediaType = new MediaType(); + mediaType.schema(schema); + return new ApiResponse().description(message) + .content(new Content().addMediaType(org.springframework.http.MediaType.APPLICATION_JSON_VALUE, mediaType)); + } + + @Bean + public OpenApiCustomizer customizer() { + return openApi -> { + Schema errorResponseSchema = ModelConverters.getInstance() + .resolveAsResolvedSchema(new AnnotatedType(ErrorTo.class)).schema; + openApi.getPaths().values().forEach(pathItem -> pathItem.readOperations().forEach(operation -> { + var apiResponses = operation.getResponses(); + apiResponses.addApiResponse("500", createApiResponse("Server Error", errorResponseSchema)); + })); + }; + + + } +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/controller/ApiExceptionHandler.java b/server/src/main/java/com/usatiuk/tjv/y/server/controller/ApiExceptionHandler.java index 18c88e0..b6b9fd5 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/controller/ApiExceptionHandler.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/controller/ApiExceptionHandler.java @@ -1,6 +1,10 @@ package com.usatiuk.tjv.y.server.controller; import com.usatiuk.tjv.y.server.dto.ErrorTo; +import com.usatiuk.tjv.y.server.service.exceptions.BadInputException; +import com.usatiuk.tjv.y.server.service.exceptions.ConflictException; +import com.usatiuk.tjv.y.server.service.exceptions.NotFoundException; +import jakarta.persistence.EntityNotFoundException; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import org.springframework.http.HttpHeaders; @@ -39,7 +43,6 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { } } - @ExceptionHandler(AuthenticationException.class) protected ResponseEntity handleAuthenticationException(AuthenticationException ex, WebRequest request) { return handleExceptionInternal(ex, @@ -61,6 +64,35 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler { new HttpHeaders(), HttpStatus.UNAUTHORIZED, request); } + @ExceptionHandler(BadInputException.class) + protected ResponseEntity handleBadInputException(BadInputException ex, WebRequest request) { + return handleExceptionInternal(ex, + new ErrorTo(List.of(ex.getMessage()), HttpStatus.BAD_REQUEST.value()), + new HttpHeaders(), HttpStatus.BAD_REQUEST, request); + } + + @ExceptionHandler(ConflictException.class) + protected ResponseEntity handleConflictException(ConflictException ex, WebRequest request) { + return handleExceptionInternal(ex, + new ErrorTo(List.of(ex.getMessage()), HttpStatus.CONFLICT.value()), + new HttpHeaders(), HttpStatus.CONFLICT, request); + } + + @ExceptionHandler(NotFoundException.class) + protected ResponseEntity handleNotFoundException(NotFoundException ex, WebRequest request) { + return handleExceptionInternal(ex, + new ErrorTo(List.of(ex.getMessage()), HttpStatus.NOT_FOUND.value()), + new HttpHeaders(), HttpStatus.NOT_FOUND, request); + } + + @ExceptionHandler(EntityNotFoundException.class) + protected ResponseEntity handleEntityNotFoundException(EntityNotFoundException ex, WebRequest request) { + return handleExceptionInternal(ex, + new ErrorTo(List.of(ex.getMessage()), HttpStatus.NOT_FOUND.value()), + new HttpHeaders(), HttpStatus.NOT_FOUND, request); + } + + @ExceptionHandler(ResponseStatusException.class) protected ResponseEntity handleResponseStatusException(ResponseStatusException ex, WebRequest request) { return handleExceptionInternal(ex, diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java b/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java index 96497eb..a7ddec2 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/controller/PersonController.java @@ -3,8 +3,9 @@ package com.usatiuk.tjv.y.server.controller; import com.usatiuk.tjv.y.server.dto.PersonCreateTo; import com.usatiuk.tjv.y.server.dto.PersonTo; import com.usatiuk.tjv.y.server.service.PersonService; -import com.usatiuk.tjv.y.server.service.exceptions.UserAlreadyExistsException; -import com.usatiuk.tjv.y.server.service.exceptions.UserNotFoundException; +import com.usatiuk.tjv.y.server.service.exceptions.ConflictException; +import com.usatiuk.tjv.y.server.service.exceptions.NotFoundException; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; @@ -22,22 +23,23 @@ public class PersonController { } @PostMapping - public PersonTo signup(@RequestBody PersonCreateTo signupRequest) throws UserAlreadyExistsException { + @SecurityRequirements(value = {}) + public PersonTo signup(@RequestBody PersonCreateTo signupRequest) throws ConflictException { return personService.signup(signupRequest); } @GetMapping(path = "/by-username/{username}") - public PersonTo getByUsername(@PathVariable String username) throws UserNotFoundException { + public PersonTo getByUsername(@PathVariable String username) throws NotFoundException { return personService.readByUsername(username); } @GetMapping(path = "/by-uuid/{uuid}") - public PersonTo getByUuid(@PathVariable String uuid) throws UserNotFoundException { + public PersonTo getByUuid(@PathVariable String uuid) throws NotFoundException { return personService.readByUuid(uuid); } @GetMapping(path = "/self") - public PersonTo getSelf(Authentication authentication) throws UserNotFoundException { + public PersonTo getSelf(Authentication authentication) throws NotFoundException { return personService.readSelf(authentication); } @@ -54,23 +56,23 @@ public class PersonController { @DeleteMapping(path = "/by-uuid/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) - public void deleteByUuid(@PathVariable String uuid) throws UserNotFoundException { + public void deleteByUuid(@PathVariable String uuid) throws NotFoundException { personService.deleteByUuid(uuid); } @GetMapping - public Collection getAll() throws UserNotFoundException { + public Collection getAll() throws NotFoundException { return personService.readAll(); } @GetMapping(path = "/followers") - public Collection getFollowers(Authentication authentication) throws UserNotFoundException { + public Collection getFollowers(Authentication authentication) throws NotFoundException { return personService.getFollowers(authentication); } @GetMapping(path = "/following") - public Collection getFollowing(Authentication authentication) throws UserNotFoundException { + public Collection getFollowing(Authentication authentication) throws NotFoundException { return personService.getFollowing(authentication); } @@ -81,25 +83,25 @@ public class PersonController { @PutMapping(path = "/admins/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) - public void addAdmin(@PathVariable String uuid) throws UserNotFoundException { + public void addAdmin(@PathVariable String uuid) throws NotFoundException { personService.addAdmin(uuid); } @DeleteMapping(path = "/admins/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) - public void deleteAdmin(@PathVariable String uuid) throws UserNotFoundException { + public void deleteAdmin(@PathVariable String uuid) throws NotFoundException { personService.removeAdmin(uuid); } @PutMapping(path = "/following/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) - public void addFollowing(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException { + public void addFollowing(Authentication authentication, @PathVariable String uuid) throws NotFoundException { personService.addFollower(authentication, uuid); } @DeleteMapping(path = "/following/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) - public void deleteFollowing(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException { + public void deleteFollowing(Authentication authentication, @PathVariable String uuid) throws NotFoundException { personService.removeFollower(authentication, uuid); } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/controller/TokenController.java b/server/src/main/java/com/usatiuk/tjv/y/server/controller/TokenController.java index 1e220f9..d371b33 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/controller/TokenController.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/controller/TokenController.java @@ -3,6 +3,7 @@ package com.usatiuk.tjv.y.server.controller; import com.usatiuk.tjv.y.server.dto.TokenRequestTo; import com.usatiuk.tjv.y.server.dto.TokenResponseTo; import com.usatiuk.tjv.y.server.service.LoginTokenService; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -19,6 +20,7 @@ public class TokenController { } @PostMapping + @SecurityRequirements(value = {}) public TokenResponseTo request(@RequestBody TokenRequestTo tokenRequestTo) { return loginTokenService.login(tokenRequestTo); } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java index a735e7e..89c90d9 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/WebSecurityConfig.java @@ -59,6 +59,8 @@ public class WebSecurityConfig { .authorizeHttpRequests((authorize) -> authorize .requestMatchers(mvc.pattern(HttpMethod.POST, "/person")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.POST, "/token")).permitAll() + .requestMatchers(mvc.pattern("/swagger-ui*/**")).permitAll() + .requestMatchers(mvc.pattern("/v3/**")).permitAll() .requestMatchers(mvc.pattern("/error")).permitAll() .anyRequest().hasAuthority(UserRoles.ROLE_USER.name())) .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatServiceImpl.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatServiceImpl.java index 08fde29..9074e32 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatServiceImpl.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatServiceImpl.java @@ -8,11 +8,11 @@ import com.usatiuk.tjv.y.server.dto.converters.PersonMapper; import com.usatiuk.tjv.y.server.entity.Chat; import com.usatiuk.tjv.y.server.entity.Person; import com.usatiuk.tjv.y.server.repository.ChatRepository; +import com.usatiuk.tjv.y.server.service.exceptions.BadInputException; +import com.usatiuk.tjv.y.server.service.exceptions.NotFoundException; import jakarta.persistence.EntityManager; -import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; import java.util.ArrayList; import java.util.Arrays; @@ -39,10 +39,10 @@ public class ChatServiceImpl implements ChatService { var chat = new Chat(); if (Arrays.stream(chatCreateTo.memberUuids()).noneMatch(n -> Objects.equals(n, authentication.getName()))) - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Creator of chat must be its member"); + throw new BadInputException("Creator of chat must be its member"); if (chatCreateTo.memberUuids().length == 1) - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Chat must have members other than its creator"); + throw new BadInputException("Chat must have members other than its creator"); chat.setCreator(entityManager.getReference(Person.class, authentication.getName())); chat.setMembers(Arrays.stream(chatCreateTo.memberUuids()).map( @@ -56,13 +56,13 @@ public class ChatServiceImpl implements ChatService { @Override public ChatTo update(Authentication authentication, Long id, ChatCreateTo chatCreateTo) { - var chat = chatRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var chat = chatRepository.findById(id).orElseThrow(() -> new NotFoundException("Chat not found")); if (Arrays.stream(chatCreateTo.memberUuids()).noneMatch(n -> Objects.equals(n, authentication.getName()))) - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Creator of chat must be its member"); + throw new BadInputException("Creator of chat must be its member"); if (chatCreateTo.memberUuids().length <= 1) - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Chat must have members other than its creator"); + throw new BadInputException("Chat must have members other than its creator"); chat.setMembers(new ArrayList<>(Arrays.stream(chatCreateTo.memberUuids()).map( p -> entityManager.getReference(Person.class, p) @@ -80,32 +80,32 @@ public class ChatServiceImpl implements ChatService { @Override public ChatTo getById(Long id) { - var chat = chatRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var chat = chatRepository.findById(id).orElseThrow(() -> new NotFoundException("Chat not found")); return chatMapper.makeDto(chat); } @Override public void deleteById(Long id) { - var chat = chatRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var chat = chatRepository.findById(id).orElseThrow(() -> new NotFoundException("Chat not found")); chatRepository.delete(chat); } @Override public Collection getMembers(Long id) { - var chat = chatRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var chat = chatRepository.findById(id).orElseThrow(() -> new NotFoundException("Chat not found")); return chat.getMembers().stream().map(personMapper::makeDto).toList(); } @Override public boolean isMemberOf(String personUuid, Long chatId) { - var chat = chatRepository.findById(chatId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var chat = chatRepository.findById(chatId).orElseThrow(() -> new NotFoundException("Chat not found")); var userRef = entityManager.getReference(Person.class, personUuid); return chat.getMembers().contains(userRef); } @Override public boolean isCreatorOf(String personUuid, Long chatId) { - var chat = chatRepository.findById(chatId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var chat = chatRepository.findById(chatId).orElseThrow(() -> new NotFoundException("Chat not found")); return Objects.equals(chat.getCreator().getUuid(), personUuid); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageServiceImpl.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageServiceImpl.java index c9eb49e..79339f7 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageServiceImpl.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageServiceImpl.java @@ -7,11 +7,10 @@ import com.usatiuk.tjv.y.server.entity.Chat; import com.usatiuk.tjv.y.server.entity.Message; import com.usatiuk.tjv.y.server.entity.Person; import com.usatiuk.tjv.y.server.repository.MessageRepository; +import com.usatiuk.tjv.y.server.service.exceptions.NotFoundException; import jakarta.persistence.EntityManager; -import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; import java.util.Collection; import java.util.Objects; @@ -47,7 +46,7 @@ public class MessageServiceImpl implements MessageService { @Override public MessageTo update(Long id, MessageCreateTo msg) { - var message = messageRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + var message = messageRepository.findById(id).orElseThrow(NotFoundException::new); message.setContents(msg.contents()); messageRepository.save(message); return messageMapper.makeDto(message); @@ -67,7 +66,7 @@ public class MessageServiceImpl implements MessageService { @Override public boolean isAuthorOf(String userUuid, Long messageId) { - var msg = messageRepository.findById(messageId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var msg = messageRepository.findById(messageId).orElseThrow(() -> new NotFoundException("Chat not found")); return Objects.equals(msg.getAuthor().getUuid(), userUuid); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonServiceImpl.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonServiceImpl.java index d778e98..e129271 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonServiceImpl.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonServiceImpl.java @@ -6,17 +6,16 @@ import com.usatiuk.tjv.y.server.dto.converters.PersonMapper; import com.usatiuk.tjv.y.server.entity.Chat; import com.usatiuk.tjv.y.server.entity.Person; import com.usatiuk.tjv.y.server.repository.PersonRepository; -import com.usatiuk.tjv.y.server.service.exceptions.UserAlreadyExistsException; -import com.usatiuk.tjv.y.server.service.exceptions.UserNotFoundException; +import com.usatiuk.tjv.y.server.service.exceptions.ConflictException; +import com.usatiuk.tjv.y.server.service.exceptions.NotFoundException; import jakarta.persistence.EntityManager; import jakarta.transaction.Transactional; -import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; import java.util.Collection; +import java.util.Objects; import java.util.Optional; import java.util.stream.StreamSupport; @@ -38,7 +37,7 @@ public class PersonServiceImpl implements PersonService { @Override public PersonTo signup(PersonCreateTo signupRequest) { if (personRepository.existsByUsername(signupRequest.username())) - throw new UserAlreadyExistsException(); + throw new ConflictException("User already exists with this username"); Person toCreate = new Person(); @@ -64,12 +63,12 @@ public class PersonServiceImpl implements PersonService { @Override public PersonTo readByUsername(String username) { - return personMapper.makeDto(personRepository.findByUsername(username).orElseThrow(UserNotFoundException::new)); + return personMapper.makeDto(personRepository.findByUsername(username).orElseThrow(NotFoundException::new)); } @Override public PersonTo readByUuid(String uuid) { - return personMapper.makeDto(personRepository.findById(uuid).orElseThrow(UserNotFoundException::new)); + return personMapper.makeDto(personRepository.findById(uuid).orElseThrow(NotFoundException::new)); } @Override @@ -78,8 +77,13 @@ public class PersonServiceImpl implements PersonService { } @Override + @Transactional public PersonTo update(Authentication authentication, PersonCreateTo person) { - var found = personRepository.findById(authentication.getName()).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + var found = personRepository.findById(authentication.getName()).orElseThrow(NotFoundException::new); + + if (!Objects.equals(found.getUsername(), person.username()) && personRepository.existsByUsername(person.username())) + throw new ConflictException("User already exists with this username"); + found.setUsername(person.username()) .setFullName(person.fullName()); if (!person.password().isEmpty()) found.setPassword(passwordEncoder.encode(person.password())); @@ -89,7 +93,7 @@ public class PersonServiceImpl implements PersonService { @Transactional public void deleteByUuid(String uuid) { - var person = personRepository.findById(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + var person = personRepository.findById(uuid).orElseThrow(NotFoundException::new); for (Chat c : person.getChats()) { c.getMembers().remove(person); } @@ -114,40 +118,40 @@ public class PersonServiceImpl implements PersonService { @Override public Collection getFollowers(Authentication authentication) { - return personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new) + return personRepository.findById(authentication.getName()).orElseThrow(NotFoundException::new) .getFollowers().stream().map(personMapper::makeDto).toList(); } @Override public Collection getFollowing(Authentication authentication) { - return personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new) + return personRepository.findById(authentication.getName()).orElseThrow(NotFoundException::new) .getFollowing().stream().map(personMapper::makeDto).toList(); } @Override public void addFollower(Authentication authentication, String followee) { - var person = personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new); + var person = personRepository.findById(authentication.getName()).orElseThrow(NotFoundException::new); person.getFollowing().add(entityManager.getReference(Person.class, followee)); personRepository.save(person); } @Override public void removeFollower(Authentication authentication, String followee) { - var person = personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new); + var person = personRepository.findById(authentication.getName()).orElseThrow(NotFoundException::new); person.getFollowing().remove(entityManager.getReference(Person.class, followee)); personRepository.save(person); } @Override public void addAdmin(String uuid) { - var person = personRepository.findById(uuid).orElseThrow(UserNotFoundException::new); + var person = personRepository.findById(uuid).orElseThrow(NotFoundException::new); person.setAdmin(true); personRepository.save(person); } @Override public void removeAdmin(String uuid) { - var person = personRepository.findById(uuid).orElseThrow(UserNotFoundException::new); + var person = personRepository.findById(uuid).orElseThrow(NotFoundException::new); person.setAdmin(false); personRepository.save(person); } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/PostServiceImpl.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/PostServiceImpl.java index 2077b19..7c276be 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/PostServiceImpl.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/PostServiceImpl.java @@ -6,11 +6,10 @@ import com.usatiuk.tjv.y.server.dto.converters.PostMapper; import com.usatiuk.tjv.y.server.entity.Person; import com.usatiuk.tjv.y.server.entity.Post; import com.usatiuk.tjv.y.server.repository.PostRepository; +import com.usatiuk.tjv.y.server.service.exceptions.NotFoundException; import jakarta.persistence.EntityManager; -import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; import java.util.Collection; import java.util.Objects; @@ -39,7 +38,7 @@ public class PostServiceImpl implements PostService { @Override public PostTo readById(Long id) { return postMapper.makeDto(postRepository.findById(id) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Post not found"))); + .orElseThrow(() -> new NotFoundException("Post not found"))); } @Override @@ -59,7 +58,7 @@ public class PostServiceImpl implements PostService { @Override public PostTo updatePost(Long id, PostCreateTo postCreateTo) { - var post = postRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + var post = postRepository.findById(id).orElseThrow(NotFoundException::new); post.setText(postCreateTo.text()); postRepository.save(post); return postMapper.makeDto(post); @@ -79,7 +78,7 @@ public class PostServiceImpl implements PostService { @Override public boolean isAuthorOf(String userUuid, Long postId) { - var p = postRepository.findById(postId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var p = postRepository.findById(postId).orElseThrow(() -> new NotFoundException("Chat not found")); return Objects.equals(p.getAuthor().getUuid(), userUuid); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/BadInputException.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/BadInputException.java new file mode 100644 index 0000000..9633045 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/BadInputException.java @@ -0,0 +1,7 @@ +package com.usatiuk.tjv.y.server.service.exceptions; + +public class BadInputException extends RuntimeException { + public BadInputException(String message) { + super(message); + } +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/ConflictException.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/ConflictException.java new file mode 100644 index 0000000..7df1d44 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/ConflictException.java @@ -0,0 +1,7 @@ +package com.usatiuk.tjv.y.server.service.exceptions; + +public class ConflictException extends RuntimeException { + public ConflictException(String message) { + super(message); + } +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/NotFoundException.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/NotFoundException.java new file mode 100644 index 0000000..51dc872 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/NotFoundException.java @@ -0,0 +1,11 @@ +package com.usatiuk.tjv.y.server.service.exceptions; + +public class NotFoundException extends RuntimeException { + public NotFoundException() { + super("Requested data not found"); + } + + public NotFoundException(String message) { + super(message); + } +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserAlreadyExistsException.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserAlreadyExistsException.java deleted file mode 100644 index 689e24d..0000000 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserAlreadyExistsException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.usatiuk.tjv.y.server.service.exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.CONFLICT) -public class UserAlreadyExistsException extends RuntimeException { - public UserAlreadyExistsException() { - super(); - } -} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserNotFoundException.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserNotFoundException.java deleted file mode 100644 index b877d72..0000000 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/exceptions/UserNotFoundException.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.usatiuk.tjv.y.server.service.exceptions; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -@ResponseStatus(HttpStatus.NOT_FOUND) -public class UserNotFoundException extends RuntimeException { - public UserNotFoundException() { - super(); - } - - public UserNotFoundException(String message) { - super(message); - } -}