use spring security more

This commit is contained in:
Stepan Usatiuk
2023-12-30 14:02:58 +01:00
parent d31ded94b2
commit d83bed9edd
22 changed files with 177 additions and 135 deletions

View File

@@ -6,6 +6,7 @@ import jakarta.validation.ConstraintViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.ControllerAdvice;
@@ -33,6 +34,13 @@ public class ApiExceptionHandler extends ResponseEntityExceptionHandler {
new HttpHeaders(), HttpStatus.UNAUTHORIZED, request);
}
@ExceptionHandler(AccessDeniedException.class)
protected ResponseEntity<Object> handleAccessDeniedException(AccessDeniedException ex, WebRequest request) {
return handleExceptionInternal(ex,
new ErrorTo(List.of(ex.getMessage()), HttpStatus.FORBIDDEN.value()),
new HttpHeaders(), HttpStatus.FORBIDDEN, request);
}
@ExceptionHandler(UsernameNotFoundException.class)
protected ResponseEntity<Object> handleUsernameNotFoundException(UsernameNotFoundException ex, WebRequest request) {
return handleExceptionInternal(ex,

View File

@@ -26,29 +26,29 @@ public class ChatController {
}
@GetMapping(path = "/by-id/{id}")
public ChatTo get(Authentication authentication, @PathVariable Long id) {
return chatService.getById(authentication, id);
public ChatTo get(@PathVariable Long id) {
return chatService.getById(id);
}
@DeleteMapping(path = "/by-id/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(Authentication authentication, @PathVariable Long id) {
chatService.deleteById(authentication, id);
public void delete(@PathVariable Long id) {
chatService.deleteById(id);
}
@PatchMapping(path = "/by-id/{id}")
public ChatTo update(Authentication authentication, @PathVariable Long id, @RequestBody ChatCreateTo chatCreateTo) {
return chatService.update(authentication, id, chatCreateTo);
}
@GetMapping(path = "/my")
public Collection<ChatTo> getMy(Authentication authentication) {
return chatService.getMy(authentication);
}
@GetMapping(path = "/by-id/{id}/members")
public Collection<PersonTo> getMembers(Authentication authentication, @PathVariable Long id) {
return chatService.getMembers(authentication, id);
public Collection<PersonTo> getMembers(@PathVariable Long id) {
return chatService.getMembers(id);
}

View File

@@ -21,7 +21,7 @@ public class MessageController {
@GetMapping(path = "/by-chat/{chatTd}")
public Collection<MessageTo> get(Authentication authentication, @PathVariable Long chatTd) {
return messageService.getByChat(authentication, chatTd);
return messageService.getByChat(chatTd);
}
@PostMapping(path = "/by-chat/{chatId}")
@@ -30,19 +30,19 @@ public class MessageController {
}
@PatchMapping(path = "/by-id/{id}")
public MessageTo update(Authentication authentication, @PathVariable long id, @RequestBody MessageCreateTo messageCreateTo) {
return messageService.update(authentication, id, messageCreateTo);
public MessageTo update(@PathVariable long id, @RequestBody MessageCreateTo messageCreateTo) {
return messageService.update(id, messageCreateTo);
}
@DeleteMapping(path = "/by-id/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(Authentication authentication, @PathVariable long id) {
messageService.delete(authentication, id);
public void delete(@PathVariable long id) {
messageService.delete(id);
}
@GetMapping
public Collection<MessageTo> getAll(Authentication authentication) {
return messageService.readAll(authentication);
public Collection<MessageTo> getAll() {
return messageService.readAll();
}

View File

@@ -54,8 +54,8 @@ public class PersonController {
@DeleteMapping(path = "/by-uuid/{uuid}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteByUuid(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException {
personService.deleteByUuid(authentication, uuid);
public void deleteByUuid(@PathVariable String uuid) throws UserNotFoundException {
personService.deleteByUuid(uuid);
}
@@ -81,14 +81,14 @@ public class PersonController {
@PutMapping(path = "/admins/{uuid}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void addAdmin(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException {
personService.addAdmin(authentication, uuid);
public void addAdmin(@PathVariable String uuid) throws UserNotFoundException {
personService.addAdmin(uuid);
}
@DeleteMapping(path = "/admins/{uuid}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteAdmin(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException {
personService.removeAdmin(authentication, uuid);
public void deleteAdmin(@PathVariable String uuid) throws UserNotFoundException {
personService.removeAdmin(uuid);
}
@PutMapping(path = "/following/{uuid}")

View File

@@ -47,19 +47,19 @@ public class PostController {
}
@PatchMapping(path = "/{id}")
public PostTo update(Authentication authentication, @PathVariable long id, @RequestBody PostCreateTo postCreateTo) {
return postService.updatePost(authentication, id, postCreateTo);
public PostTo update(@PathVariable long id, @RequestBody PostCreateTo postCreateTo) {
return postService.updatePost(id, postCreateTo);
}
@DeleteMapping(path = "/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(Authentication authentication, @PathVariable long id) {
postService.deletePost(authentication, id);
public void delete(@PathVariable long id) {
postService.deletePost(id);
}
@GetMapping
public Collection<PostTo> getAll(Authentication authentication) {
return postService.readAll(authentication);
public Collection<PostTo> getAll() {
return postService.readAll();
}
}

View File

@@ -17,7 +17,7 @@ import java.util.Collection;
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class Chat implements EntityWithId<Long> {
public class Chat {
@Id
@GeneratedValue
private Long id;

View File

@@ -1,5 +0,0 @@
package com.usatiuk.tjv.y.server.entity;
public interface EntityWithId<ID> {
ID getId();
}

View File

@@ -17,7 +17,7 @@ import java.time.Instant;
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class Message implements EntityWithId<Long> {
public class Message {
@Id
@GeneratedValue
private Long id;

View File

@@ -18,7 +18,7 @@ import java.util.Collection;
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class Person implements EntityWithId<String> {
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String uuid;
@@ -57,8 +57,4 @@ public class Person implements EntityWithId<String> {
@ManyToMany(mappedBy = "members")
private Collection<Chat> chats;
@Override
public String getId() {
return uuid;
}
}

View File

@@ -17,7 +17,7 @@ import java.time.Instant;
@NoArgsConstructor
@ToString
@Accessors(chain = true)
public class Post implements EntityWithId<Long> {
public class Post {
@Id
@GeneratedValue
private Long id;
@@ -31,9 +31,4 @@ public class Post implements EntityWithId<Long> {
@CreationTimestamp
private Instant createdAt;
@Override
public Long getId() {
return id;
}
}

View File

@@ -10,6 +10,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
@@ -31,6 +32,7 @@ import java.util.List;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig {
private final JwtRequestFilter jwtRequestFilter;

View File

@@ -3,20 +3,27 @@ package com.usatiuk.tjv.y.server.service;
import com.usatiuk.tjv.y.server.dto.ChatCreateTo;
import com.usatiuk.tjv.y.server.dto.ChatTo;
import com.usatiuk.tjv.y.server.dto.PersonTo;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import java.util.Collection;
public interface ChatService {
ChatTo create(Authentication authentication, ChatCreateTo chatCreateTo);
@PreAuthorize("@chatService.isCreatorOf(authentication.principal.username, #id)")
ChatTo update(Authentication authentication, Long id, ChatCreateTo chatCreateTo);
Collection<ChatTo> getMy(Authentication authentication);
ChatTo getById(Authentication authentication, Long id);
void deleteById(Authentication authentication, Long id);
@PreAuthorize("@chatService.isMemberOf(authentication.principal.username, #id)")
ChatTo getById(Long id);
@PreAuthorize("@chatService.isMemberOf(authentication.principal.username, #id)")
void deleteById(Long id);
Collection<PersonTo> getMembers(Authentication authentication, Long id);
@PreAuthorize("@chatService.isMemberOf(authentication.principal.username, #id)")
Collection<PersonTo> getMembers(Long id);
boolean isMemberOf(String personUuid, Long chatId);
boolean isCreatorOf(String personUuid, Long chatId);
}

View File

@@ -19,7 +19,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
@Service
@Service("chatService")
public class ChatServiceImpl implements ChatService {
private final ChatRepository chatRepository;
@@ -57,8 +57,6 @@ 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"));
if (!Objects.equals(chat.getCreator().getUuid(), authentication.getName()))
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User isn't creator of the 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");
@@ -81,29 +79,20 @@ public class ChatServiceImpl implements ChatService {
}
@Override
public ChatTo getById(Authentication authentication, Long id) {
public ChatTo getById(Long id) {
var chat = chatRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found"));
var userRef = entityManager.getReference(Person.class, authentication.getName());
if (!chat.getMembers().contains(userRef))
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User isn't member of the chat");
return chatMapper.makeDto(chat);
}
@Override
public void deleteById(Authentication authentication, Long id) {
public void deleteById(Long id) {
var chat = chatRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found"));
if (!Objects.equals(chat.getCreator().getUuid(), authentication.getName()))
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User isn't creator of the chat");
chatRepository.delete(chat);
}
@Override
public Collection<PersonTo> getMembers(Authentication authentication, Long id) {
public Collection<PersonTo> getMembers(Long id) {
var chat = chatRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found"));
var userRef = entityManager.getReference(Person.class, authentication.getName());
if (!chat.getMembers().contains(userRef))
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User isn't member of the chat");
return chat.getMembers().stream().map(personMapper::makeDto).toList();
}
@@ -113,4 +102,10 @@ public class ChatServiceImpl implements ChatService {
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"));
return Objects.equals(chat.getCreator().getUuid(), personUuid);
}
}

View File

@@ -2,16 +2,25 @@ package com.usatiuk.tjv.y.server.service;
import com.usatiuk.tjv.y.server.dto.MessageCreateTo;
import com.usatiuk.tjv.y.server.dto.MessageTo;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import java.util.Collection;
public interface MessageService {
Collection<MessageTo> getByChat(Authentication authentication, Long chatId);
@PreAuthorize("@chatService.isMemberOf(authentication.principal.username, #chatId)")
Collection<MessageTo> getByChat(Long chatId);
@PreAuthorize("@chatService.isMemberOf(authentication.principal.username, #chatId)")
MessageTo addToChat(Authentication authentication, Long chatId, MessageCreateTo messageCreateTo);
MessageTo update(Authentication authentication, Long id, MessageCreateTo msg);
void delete(Authentication authentication, Long id);
@PreAuthorize("@messageService.isAuthorOf(authentication.principal.username, #id)")
MessageTo update(Long id, MessageCreateTo msg);
@PreAuthorize("@messageService.isAuthorOf(authentication.principal.username, #id)")
void delete(Long id);
Collection<MessageTo> readAll(Authentication authentication);
@Secured({"ROLE_ADMIN"})
Collection<MessageTo> readAll();
boolean isAuthorOf(String userUuid, Long messageId);
}

View File

@@ -7,11 +7,9 @@ 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.security.UserRoles;
import jakarta.persistence.EntityManager;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
@@ -19,34 +17,26 @@ import java.util.Collection;
import java.util.Objects;
import java.util.stream.StreamSupport;
@Service
@Service("messageService")
public class MessageServiceImpl implements MessageService {
private final MessageRepository messageRepository;
private final MessageMapper messageMapper;
private final ChatService chatService;
private final EntityManager entityManager;
public MessageServiceImpl(MessageRepository messageRepository, MessageMapper messageMapper, ChatService chatService, EntityManager entityManager) {
public MessageServiceImpl(MessageRepository messageRepository, MessageMapper messageMapper, EntityManager entityManager) {
this.messageRepository = messageRepository;
this.messageMapper = messageMapper;
this.chatService = chatService;
this.entityManager = entityManager;
}
@Override
public Collection<MessageTo> getByChat(Authentication authentication, Long chatId) {
if (!chatService.isMemberOf(authentication.getName(), chatId))
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User isn't member of the chat");
public Collection<MessageTo> getByChat(Long chatId) {
return messageRepository.findByChat_Id(chatId).stream().map(messageMapper::makeDto).toList();
}
@Override
public MessageTo addToChat(Authentication authentication, Long chatId, MessageCreateTo messageCreateTo) {
if (!chatService.isMemberOf(authentication.getName(), chatId))
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User isn't member of the chat");
Message message = new Message().setChat(entityManager.getReference(Chat.class, chatId))
.setAuthor(entityManager.getReference(Person.class, authentication.getName()))
.setContents(messageCreateTo.contents());
@@ -56,30 +46,28 @@ public class MessageServiceImpl implements MessageService {
}
@Override
public MessageTo update(Authentication authentication, Long id, MessageCreateTo msg) {
public MessageTo update(Long id, MessageCreateTo msg) {
var message = messageRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
if (!Objects.equals(message.getAuthor().getUuid(), authentication.getName()))
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
message.setContents(msg.contents());
messageRepository.save(message);
return messageMapper.makeDto(message);
}
@Override
public void delete(Authentication authentication, Long id) {
public void delete(Long id) {
var read = messageRepository.findById(id);
if (read.isEmpty()) return;
if (!Objects.equals(read.get().getAuthor().getId(), authentication.getName())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
messageRepository.delete(read.get());
}
@Override
public Collection<MessageTo> readAll(Authentication authentication) {
if (!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name())))
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
public Collection<MessageTo> readAll() {
return StreamSupport.stream(messageRepository.findAll().spliterator(), false).map(messageMapper::makeDto).toList();
}
@Override
public boolean isAuthorOf(String userUuid, Long messageId) {
var msg = messageRepository.findById(messageId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found"));
return Objects.equals(msg.getAuthor().getUuid(), userUuid);
}
}

View File

@@ -3,6 +3,7 @@ package com.usatiuk.tjv.y.server.service;
import com.usatiuk.tjv.y.server.dto.PersonCreateTo;
import com.usatiuk.tjv.y.server.dto.PersonTo;
import com.usatiuk.tjv.y.server.entity.Person;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import java.util.Collection;
@@ -20,7 +21,8 @@ public interface PersonService {
PersonTo update(Authentication authentication, PersonCreateTo person);
void deleteSelf(Authentication authentication);
void deleteByUuid(Authentication authentication, String uuid);
@PreAuthorize("hasRole('ROLE_ADMIN') or authentication.principal.username == #uuid")
void deleteByUuid(String uuid);
Collection<PersonTo> readAll();
@@ -31,7 +33,9 @@ public interface PersonService {
void removeFollower(Authentication authentication, String followee);
Collection<PersonTo> getAdmins();
void addAdmin(Authentication caller, String uuid);
void removeAdmin(Authentication caller, String uuid);
@PreAuthorize("hasRole('ROLE_ADMIN') ")
void addAdmin(String uuid);
@PreAuthorize("hasRole('ROLE_ADMIN') ")
void removeAdmin(String uuid);
}

View File

@@ -6,19 +6,17 @@ 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.security.UserRoles;
import com.usatiuk.tjv.y.server.service.exceptions.UserAlreadyExistsException;
import com.usatiuk.tjv.y.server.service.exceptions.UserNotFoundException;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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;
@@ -89,32 +87,25 @@ public class PersonServiceImpl implements PersonService {
return personMapper.makeDto(found);
}
private void deleteByUuid(String uuid) {
@Transactional
public void deleteByUuid(String uuid) {
var person = personRepository.findById(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
for (Chat c : person.getChats()) {
c.getMembers().remove(person);
}
for (Person p : person.getFollowers()) {
p.getFollowing().remove(person);
personRepository.save(p);
}
personRepository.delete(person);
}
@Override
@Transactional
public void deleteSelf(Authentication authentication) {
deleteByUuid(authentication.getName());
}
@Override
public void deleteByUuid(Authentication authentication, String uuid) {
if ((!Objects.equals(authentication.getName(), uuid)) &&
!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name())))
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
deleteByUuid(uuid);
}
@Override
public Collection<PersonTo> readAll() {
@@ -148,24 +139,15 @@ public class PersonServiceImpl implements PersonService {
}
@Override
public void addAdmin(Authentication caller, String uuid) {
if (!caller.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name())))
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
public void addAdmin(String uuid) {
var person = personRepository.findById(uuid).orElseThrow(UserNotFoundException::new);
person.setAdmin(true);
personRepository.save(person);
}
@Override
public void removeAdmin(Authentication caller, String uuid) {
if (!caller.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name())))
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
public void removeAdmin(String uuid) {
var person = personRepository.findById(uuid).orElseThrow(UserNotFoundException::new);
// TODO
if (personRepository.findByAdminIsTrue().size() == 1) return;
person.setAdmin(false);
personRepository.save(person);
}

View File

@@ -2,14 +2,18 @@ package com.usatiuk.tjv.y.server.service;
import com.usatiuk.tjv.y.server.dto.PostCreateTo;
import com.usatiuk.tjv.y.server.dto.PostTo;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import java.util.Collection;
public interface PostService {
PostTo createPost(Authentication authentication, PostCreateTo postCreateTo);
PostTo updatePost(Authentication authentication, Long id, PostCreateTo postCreateTo);
void deletePost(Authentication authentication, Long id);
@PreAuthorize("@postService.isAuthorOf(authentication.principal.username, #id)")
PostTo updatePost(Long id, PostCreateTo postCreateTo);
@PreAuthorize("@postService.isAuthorOf(authentication.principal.username, #id)")
void deletePost(Long id);
PostTo readById(Long id);
@@ -18,5 +22,8 @@ public interface PostService {
Collection<PostTo> readByPersonFollowees(Authentication authentication);
Collection<PostTo> readAll(Authentication authentication);
@Secured({"ROLE_ADMIN"})
Collection<PostTo> readAll();
boolean isAuthorOf(String userUuid, Long postId);
}

View File

@@ -6,11 +6,9 @@ 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.security.UserRoles;
import jakarta.persistence.EntityManager;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
@@ -18,7 +16,7 @@ import java.util.Collection;
import java.util.Objects;
import java.util.stream.StreamSupport;
@Service
@Service("postService")
public class PostServiceImpl implements PostService {
private final PostRepository postRepository;
private final PostMapper postMapper;
@@ -60,30 +58,28 @@ public class PostServiceImpl implements PostService {
}
@Override
public PostTo updatePost(Authentication authentication, Long id, PostCreateTo postCreateTo) {
public PostTo updatePost(Long id, PostCreateTo postCreateTo) {
var post = postRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
if (!Objects.equals(post.getAuthor().getUuid(), authentication.getName()))
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
post.setText(postCreateTo.text());
postRepository.save(post);
return postMapper.makeDto(post);
}
@Override
public void deletePost(Authentication authentication, Long id) {
public void deletePost(Long id) {
var read = postRepository.findById(id);
if (read.isEmpty()) return;
if (!Objects.equals(read.get().getAuthor().getId(), authentication.getName())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN);
}
postRepository.delete(read.get());
}
@Override
public Collection<PostTo> readAll(Authentication authentication) {
if (!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name())))
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
public Collection<PostTo> readAll() {
return StreamSupport.stream(postRepository.findAll().spliterator(), false).map(postMapper::makeDto).toList();
}
@Override
public boolean isAuthorOf(String userUuid, Long postId) {
var p = postRepository.findById(postId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found"));
return Objects.equals(p.getAuthor().getUuid(), userUuid);
}
}

View File

@@ -82,7 +82,7 @@ public abstract class DemoDataDbTest {
new Person()
.setUsername("person1")
.setFullName("Person 1")
.setPassword(passwordEncoder.encode(person1Password)));
.setPassword(passwordEncoder.encode(person1Password)).setAdmin(true));
person1Auth = new TokenResponseTo(jwtTokenService.generateToken(person1.getUuid()));
person2 = personRepository.save(
new Person()

View File

@@ -0,0 +1,47 @@
package com.usatiuk.tjv.y.server.controller;
import com.usatiuk.tjv.y.server.dto.ErrorTo;
import com.usatiuk.tjv.y.server.dto.MessageTo;
import com.usatiuk.tjv.y.server.repository.MessageRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
public class MessageControllerTest extends DemoDataDbTest {
@Autowired
MessageRepository messageRepository;
@Test
void shouldGetMessagesIfAdmin() {
var response = restTemplate.exchange(addr + "/message", HttpMethod.GET,
new HttpEntity<>(createAuthHeaders(person1Auth)),
MessageTo[].class);
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.OK, response.getStatusCode());
var toResponse = response.getBody();
Assertions.assertNotNull(toResponse);
Assertions.assertEquals(toResponse.length, messageRepository.findAll().spliterator().estimateSize());
}
@Test
void shouldNotGetMessagesIfNotAdmin() {
var response = restTemplate.exchange(addr + "/message", HttpMethod.GET,
new HttpEntity<>(createAuthHeaders(person2Auth)),
ErrorTo.class);
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
var toResponse = response.getBody();
Assertions.assertNotNull(toResponse);
Assertions.assertEquals(toResponse.code(), HttpStatus.FORBIDDEN.value());
}
}

View File

@@ -68,6 +68,17 @@ public class PersonControllerTest extends DemoDataDbTest {
Assertions.assertEquals(personToResponse.fullName(), person1.getFullName());
}
@Test
void shouldDeleteSelf() {
var response = restTemplate.exchange(addr + "/person/self",
HttpMethod.DELETE, new HttpEntity<>(createAuthHeaders(person2Auth)), Object.class);
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode());
Assertions.assertFalse(personRepository.existsById(person2.getUuid()));
}
@Test
void shouldGetFollowers() {
var response = restTemplate.exchange(addr + "/person/followers",