diff --git a/client/src/ProfileCard.scss b/client/src/ProfileCard.scss index 6098354..7b2da15 100644 --- a/client/src/ProfileCard.scss +++ b/client/src/ProfileCard.scss @@ -38,6 +38,17 @@ cursor: pointer; color: inherit; font-size: 0.8rem; + font-family: inherit; + } + + span { + background: none; + border: none; + padding: 0; + text-decoration: none; + color: inherit; + font-size: 0.8rem; + font-family: inherit; } } } \ No newline at end of file diff --git a/client/src/ProfileCard.tsx b/client/src/ProfileCard.tsx index a93f379..88e39ca 100644 --- a/client/src/ProfileCard.tsx +++ b/client/src/ProfileCard.tsx @@ -9,6 +9,7 @@ export function ProfileCard({ actions, alreadyFollowing, isAdmin, + isFollower, }: { username: string; fullName: string; @@ -16,6 +17,7 @@ export function ProfileCard({ actions: boolean; alreadyFollowing: boolean; isAdmin: boolean; + isFollower: boolean; }) { const homeContext = useHomeContext(); @@ -85,6 +87,7 @@ export function ProfileCard({ ))} + {isFollower && follows you} ); diff --git a/client/src/UserList.tsx b/client/src/UserList.tsx index 59d339c..5e86ca6 100644 --- a/client/src/UserList.tsx +++ b/client/src/UserList.tsx @@ -14,8 +14,8 @@ export function UserList() { return
Error
; } - const { people, following } = loaderData; - if (isError(following) || isError(people)) { + const { people, following, followers } = loaderData; + if (isError(following) || isError(people) || isError(followers)) { return
Error
; } return ( @@ -32,6 +32,7 @@ export function UserList() { alreadyFollowing={following.some( (f) => f.uuid == u.uuid, )} + isFollower={followers.some((f) => f.uuid == u.uuid)} /> ); })} diff --git a/client/src/api/Person.ts b/client/src/api/Person.ts index dd956f2..9481407 100644 --- a/client/src/api/Person.ts +++ b/client/src/api/Person.ts @@ -56,6 +56,10 @@ export async function getFollowing(): Promise { return fetchJSONAuth("/person/following", "GET", PersonToArrResp); } +export async function getFollowers(): Promise { + return fetchJSONAuth("/person/followers", "GET", PersonToArrResp); +} + export async function getPersonByUsername( username: string, ): Promise { diff --git a/client/src/api/Post.ts b/client/src/api/Post.ts index 0fd5d99..26c6a4c 100644 --- a/client/src/api/Post.ts +++ b/client/src/api/Post.ts @@ -31,7 +31,7 @@ export async function getPostsByAuthorUuid( author: string, ): Promise { return fetchJSONAuth( - `/post/by-author-uuid?author=${author}`, + `/post/by-author-uuid/${author}`, "GET", PostToArrResp, ); @@ -45,7 +45,7 @@ export async function getPostsByAuthorUsername( author: string, ): Promise { return fetchJSONAuth( - `/post/by-author-username?author=${author}`, + `/post/by-author-username/${author}`, "GET", PostToArrResp, ); diff --git a/client/src/loaders.ts b/client/src/loaders.ts index 398890f..fa60005 100644 --- a/client/src/loaders.ts +++ b/client/src/loaders.ts @@ -1,5 +1,6 @@ import { getAllPerson, + getFollowers, getFollowing, getPersonByUsername, getSelf, @@ -36,7 +37,11 @@ export async function homeLoader() { } export async function userListLoader() { - return { people: await getAllPerson(), following: await getFollowing() }; + return { + people: await getAllPerson(), + following: await getFollowing(), + followers: await getFollowers(), + }; } export async function profileLoader({ diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/controller/MessageController.java b/server/src/main/java/com/usatiuk/tjv/y/server/controller/MessageController.java index c538e08..2cb09e8 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/controller/MessageController.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/controller/MessageController.java @@ -3,22 +3,15 @@ package com.usatiuk.tjv.y.server.controller; import com.usatiuk.tjv.y.server.dto.MessageCreateTo; import com.usatiuk.tjv.y.server.dto.MessageTo; import com.usatiuk.tjv.y.server.dto.converters.MessageMapper; -import com.usatiuk.tjv.y.server.entity.Message; -import com.usatiuk.tjv.y.server.entity.Person; -import com.usatiuk.tjv.y.server.security.UserRoles; import com.usatiuk.tjv.y.server.service.ChatService; import com.usatiuk.tjv.y.server.service.MessageService; import jakarta.persistence.EntityManager; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; -import java.util.Objects; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; +import java.util.Collection; @RestController @RequestMapping(value = "/message", produces = MediaType.APPLICATION_JSON_VALUE) @@ -36,54 +29,29 @@ public class MessageController { } @GetMapping(path = "/by-chat/{chatTd}") - public Stream get(Authentication authentication, @PathVariable Long chatTd) { - var chat = chatService.readById(chatTd).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.getMessages().stream().map(messageMapper::makeDto); + public Collection get(Authentication authentication, @PathVariable Long chatTd) { + return messageService.getByChat(authentication, chatTd); } @PostMapping(path = "/by-chat/{chatId}") public MessageTo post(Authentication authentication, @PathVariable Long chatId, @RequestBody MessageCreateTo messageCreateTo) { - var chat = chatService.readById(chatId).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"); - - Message message = new Message().setChat(chat).setAuthor(userRef).setContents(messageCreateTo.contents()); - messageService.create(message); - return messageMapper.makeDto(message); + return messageService.addToChat(authentication, chatId, messageCreateTo); } @PatchMapping(path = "/by-id/{id}") public MessageTo update(Authentication authentication, @PathVariable long id, @RequestBody MessageCreateTo messageCreateTo) { - var message = messageService.readById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - if (!Objects.equals(message.getAuthor().getUuid(), authentication.getName())) - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - message.setContents(messageCreateTo.contents()); - messageService.update(message); - return messageMapper.makeDto(message); + return messageService.update(authentication, id, messageCreateTo); } @DeleteMapping(path = "/by-id/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) public void delete(Authentication authentication, @PathVariable long id) { - var read = messageService.readById(id); - if (read.isEmpty()) return; - if (!Objects.equals(read.get().getAuthor().getId(), authentication.getName())) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - } - messageService.deleteById(id); + messageService.delete(authentication, id); } @GetMapping - public Stream getAll(Authentication authentication) { - if (!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name()))) - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); - - return StreamSupport.stream(messageService.readAll().spliterator(), false).map(messageMapper::makeDto); + public Collection getAll(Authentication authentication) { + return messageService.readAll(authentication); } 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 186b994..7247ecd 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,9 +3,6 @@ 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.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.security.UserRoles; import com.usatiuk.tjv.y.server.service.ChatService; import com.usatiuk.tjv.y.server.service.PersonService; import com.usatiuk.tjv.y.server.service.exceptions.UserAlreadyExistsException; @@ -13,14 +10,10 @@ import com.usatiuk.tjv.y.server.service.exceptions.UserNotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; -import java.util.Optional; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; +import java.util.Collection; @RestController @RequestMapping(value = "/person", produces = MediaType.APPLICATION_JSON_VALUE) @@ -39,103 +32,60 @@ public class PersonController { @PostMapping public PersonTo signup(@RequestBody PersonCreateTo signupRequest) throws UserAlreadyExistsException { - Person toCreate = new Person(); - toCreate.setUsername(signupRequest.username()) - .setPassword(signupRequest.password()) - .setFullName(signupRequest.fullName()); - - Person created = personService.signup(toCreate); - - return personMapper.makeDto(created); + return personService.signup(signupRequest); } @GetMapping(path = "/by-username/{username}") public PersonTo getByUsername(@PathVariable String username) throws UserNotFoundException { - Optional found = personService.readByUsername(username); - - if (found.isEmpty()) throw new UserNotFoundException(); - - return personMapper.makeDto(found.get()); + return personService.readByUsername(username); } @GetMapping(path = "/by-uuid/{uuid}") public PersonTo getByUuid(@PathVariable String uuid) throws UserNotFoundException { - Optional found = personService.readById(uuid); - - if (found.isEmpty()) throw new UserNotFoundException(); - - return personMapper.makeDto(found.get()); + return personService.readByUuid(uuid); } - @GetMapping(path = "/self") public PersonTo getSelf(Authentication authentication) throws UserNotFoundException { - Optional found = personService.readById(authentication.getName()); - - if (found.isEmpty()) throw new UserNotFoundException(); - - return personMapper.makeDto(found.get()); + return personService.readSelf(authentication); } @PatchMapping(path = "/self") public PersonTo update(Authentication authentication, @RequestBody PersonCreateTo personCreateTo) { - var person = personService.readById(authentication.getName()).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - person.setUsername(personCreateTo.username()) - .setFullName(personCreateTo.fullName()); - if (!personCreateTo.password().isEmpty()) person.setPassword(passwordEncoder.encode(personCreateTo.password())); - personService.update(person); - return personMapper.makeDto(person); + return personService.update(authentication, personCreateTo); } @DeleteMapping(path = "/self") @ResponseStatus(HttpStatus.NO_CONTENT) public void delete(Authentication authentication) { - var person = personService.readById(authentication.getName()).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - for (Chat c : person.getChats()) { - c.getMembers().remove(person); - chatService.update(c); - } - personService.deleteById(authentication.getName()); + personService.deleteSelf(authentication); } @DeleteMapping(path = "/by-uuid/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteByUuid(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException { - if (!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name()))) - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); - - var person = personService.readById(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - for (Chat c : person.getChats()) { - c.getMembers().remove(person); - chatService.update(c); - } - for (Person p : person.getFollowers()) { - p.getFollowing().remove(person); - personService.update(p); - } - - personService.deleteById(person.getUuid()); + personService.deleteByUuid(authentication, uuid); } @GetMapping - public Stream getAll() throws UserNotFoundException { - return StreamSupport.stream(personService.readAll().spliterator(), false).map(personMapper::makeDto); + public Collection getAll() throws UserNotFoundException { + return personService.readAll(); } @GetMapping(path = "/followers") - public Stream getFollowers(Authentication authentication) throws UserNotFoundException { - return personService.getFollowers(authentication.getName()).stream().map(personMapper::makeDto); + public Collection getFollowers(Authentication authentication) throws UserNotFoundException { + return personService.getFollowers(authentication); } @GetMapping(path = "/following") - public Stream getFollowing(Authentication authentication) throws UserNotFoundException { - return personService.getFollowing(authentication.getName()).stream().map(personMapper::makeDto); + public Collection getFollowing(Authentication authentication) throws UserNotFoundException { + return personService.getFollowing(authentication); } @GetMapping(path = "/admins") - public Stream getAdmins() { - return personService.getAdmins().stream().map(personMapper::makeDto); + public Collection getAdmins() { + return personService.getAdmins(); } @PutMapping(path = "/admins/{uuid}") @@ -150,17 +100,16 @@ public class PersonController { personService.removeAdmin(authentication, uuid); } - @PutMapping(path = "/following/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) public void addFollowing(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException { - personService.addFollower(authentication.getName(), uuid); + personService.addFollower(authentication, uuid); } @DeleteMapping(path = "/following/{uuid}") @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteFollowing(Authentication authentication, @PathVariable String uuid) throws UserNotFoundException { - personService.removeFollower(authentication.getName(), uuid); + personService.removeFollower(authentication, uuid); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/controller/PostController.java b/server/src/main/java/com/usatiuk/tjv/y/server/controller/PostController.java index 33ed898..2dba43b 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/controller/PostController.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/controller/PostController.java @@ -3,99 +3,63 @@ package com.usatiuk.tjv.y.server.controller; import com.usatiuk.tjv.y.server.dto.PostCreateTo; import com.usatiuk.tjv.y.server.dto.PostTo; 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.security.UserRoles; import com.usatiuk.tjv.y.server.service.PostService; import jakarta.persistence.EntityManager; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; +import java.util.Collection; @RestController @RequestMapping(value = "/post", produces = MediaType.APPLICATION_JSON_VALUE) public class PostController { private final PostService postService; - private final PostMapper postMapper; - private final EntityManager entityManager; public PostController(PostService postService, PostMapper postMapper, EntityManager entityManager) { this.postService = postService; - this.postMapper = postMapper; - this.entityManager = entityManager; } @PostMapping public PostTo createPost(Authentication authentication, @RequestBody PostCreateTo postCreateTo) { - Post post = new Post(); - post.setAuthor(entityManager.getReference(Person.class, authentication.getName())); - post.setText(postCreateTo.text()); - return postMapper.makeDto(postService.create(post)); + return postService.createPost(authentication, postCreateTo); } - @GetMapping(path = "/by-author-uuid") - public Stream readAllByAuthorUuid(@RequestParam Optional author) { - if (author.isPresent()) - return postService.readByAuthorId(author.get()).stream().map(postMapper::makeDto); - else - throw new ResponseStatusException(HttpStatus.BAD_REQUEST); + @GetMapping(path = "/by-author-uuid/{uuid}") + public Collection readAllByAuthorUuid(@PathVariable String uuid) { + return postService.readByAuthorId(uuid); } - @GetMapping(path = "/by-author-username") - public Stream readAllByAuthorUsername(@RequestParam Optional author) { - if (author.isPresent()) - return postService.readByAuthorUsername(author.get()).stream().map(postMapper::makeDto); - else - throw new ResponseStatusException(HttpStatus.BAD_REQUEST); + @GetMapping(path = "/by-author-username/{username}") + public Collection readAllByAuthorUsername(@PathVariable String username) { + return postService.readByAuthorUsername(username); } @GetMapping(path = "/by-following") - public Stream readAllByFollowees(Authentication authentication) { - return postService.readByPersonFollowees(authentication.getName()).stream().map(postMapper::makeDto); + public Collection readAllByFollowees(Authentication authentication) { + return postService.readByPersonFollowees(authentication); } @GetMapping(path = "/{id}") public PostTo get(@PathVariable long id) { - var post = postService.readById(id); - if (post.isEmpty()) throw new ResponseStatusException(HttpStatus.NOT_FOUND); - return postMapper.makeDto(post.get()); + return postService.readById(id); } @PatchMapping(path = "/{id}") public PostTo update(Authentication authentication, @PathVariable long id, @RequestBody PostCreateTo postCreateTo) { - var post = postService.readById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); - if (!Objects.equals(post.getAuthor().getUuid(), authentication.getName())) - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - post.setText(postCreateTo.text()); - postService.update(post); - return postMapper.makeDto(post); + return postService.updatePost(authentication, id, postCreateTo); } @DeleteMapping(path = "/{id}") @ResponseStatus(HttpStatus.NO_CONTENT) public void delete(Authentication authentication, @PathVariable long id) { - var read = postService.readById(id); - if (read.isEmpty()) return; - if (!Objects.equals(read.get().getAuthor().getId(), authentication.getName())) { - throw new ResponseStatusException(HttpStatus.FORBIDDEN); - } - postService.deleteById(id); + postService.deletePost(authentication, id); } @GetMapping - public Stream getAll(Authentication authentication) { - if (!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name()))) - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); - - return StreamSupport.stream(postService.readAll().spliterator(), false).map(postMapper::makeDto); + public Collection getAll(Authentication authentication) { + return postService.readAll(authentication); } } 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 69e677e..0c49b8b 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 @@ -2,35 +2,28 @@ 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.entity.Person; +import com.usatiuk.tjv.y.server.service.LoginTokenService; import com.usatiuk.tjv.y.server.service.PersonService; -import com.usatiuk.tjv.y.server.service.TokenService; -import com.usatiuk.tjv.y.server.service.exceptions.UserNotFoundException; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; - -import java.util.Optional; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/token", produces = MediaType.APPLICATION_JSON_VALUE) public class TokenController { private final PersonService personService; - private final TokenService tokenService; + private final LoginTokenService loginTokenService; - public TokenController(PersonService personService, TokenService tokenService) { + public TokenController(PersonService personService, LoginTokenService loginTokenService) { this.personService = personService; - this.tokenService = tokenService; + this.loginTokenService = loginTokenService; } @PostMapping - public TokenResponseTo request(@RequestBody TokenRequestTo tokenRequestTo) throws UserNotFoundException { - Optional found = personService.login(tokenRequestTo.username(), tokenRequestTo.password()); - - if (found.isEmpty()) throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Couldn't find user"); - - return new TokenResponseTo(tokenService.generateToken(found.get().getId())); + public TokenResponseTo request(@RequestBody TokenRequestTo tokenRequestTo) { + return loginTokenService.login(tokenRequestTo); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/repository/MessageRepository.java b/server/src/main/java/com/usatiuk/tjv/y/server/repository/MessageRepository.java index 6406692..d129f12 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/repository/MessageRepository.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/repository/MessageRepository.java @@ -3,5 +3,8 @@ package com.usatiuk.tjv.y.server.repository; import com.usatiuk.tjv.y.server.entity.Message; import org.springframework.data.repository.CrudRepository; +import java.util.Collection; + public interface MessageRepository extends CrudRepository { + Collection findByChat_Id(Long chatId); } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/repository/PersonRepository.java b/server/src/main/java/com/usatiuk/tjv/y/server/repository/PersonRepository.java index 176210c..c7e2e02 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/repository/PersonRepository.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/repository/PersonRepository.java @@ -1,6 +1,7 @@ package com.usatiuk.tjv.y.server.repository; import com.usatiuk.tjv.y.server.entity.Person; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import java.util.Collection; @@ -9,6 +10,9 @@ import java.util.Optional; public interface PersonRepository extends CrudRepository { Optional findByUsername(String username); + @Query(value = "SELECT p from Person p where p.uuid = :usernameOrId or p.username = :usernameOrId") + Optional findByUsernameOrId(String usernameOrId); + boolean existsByUsername(String username); Collection findByAdminIsTrue(); diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/AuthenticationManagerConfig.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/AuthenticationManagerConfig.java new file mode 100644 index 0000000..c1f8ef3 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/AuthenticationManagerConfig.java @@ -0,0 +1,20 @@ +package com.usatiuk.tjv.y.server.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; + +@Configuration +public class AuthenticationManagerConfig { + + @Bean + public AuthenticationManager authManager(HttpSecurity http, DaoAuthenticationProvider daoAuthenticationProvider) throws Exception { + AuthenticationManagerBuilder authenticationManagerBuilder = + http.getSharedObject(AuthenticationManagerBuilder.class); + authenticationManagerBuilder.authenticationProvider(daoAuthenticationProvider); + return authenticationManagerBuilder.build(); + } +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/DaoAuthenticationProviderConf.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/DaoAuthenticationProviderConf.java new file mode 100644 index 0000000..18bcf0d --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/DaoAuthenticationProviderConf.java @@ -0,0 +1,20 @@ +package com.usatiuk.tjv.y.server.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class DaoAuthenticationProviderConf { + + @Bean + public DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { + DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); + authProvider.setUserDetailsService(userDetailsService); + authProvider.setPasswordEncoder(passwordEncoder); + return authProvider; + } + +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtRequestFilter.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtRequestFilter.java index 33c9aae..3a264a8 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtRequestFilter.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtRequestFilter.java @@ -1,6 +1,5 @@ package com.usatiuk.tjv.y.server.security; -import com.usatiuk.tjv.y.server.service.TokenService; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -18,12 +17,12 @@ import java.util.Optional; @Component public class JwtRequestFilter extends OncePerRequestFilter { - private final TokenService tokenService; - private final JwtUserDetailsService jwtUserDetailsService; + private final JwtTokenService jwtTokenService; + private final UserDetailsService userDetailsService; - public JwtRequestFilter(TokenService tokenService, JwtUserDetailsService jwtUserDetailsService) { - this.tokenService = tokenService; - this.jwtUserDetailsService = jwtUserDetailsService; + public JwtRequestFilter(JwtTokenService jwtTokenService, UserDetailsService userDetailsService) { + this.jwtTokenService = jwtTokenService; + this.userDetailsService = userDetailsService; } @Override @@ -36,13 +35,13 @@ public class JwtRequestFilter extends OncePerRequestFilter { } String token = header.substring(7); - Optional userUuid = tokenService.parseToken(token); + Optional userUuid = jwtTokenService.getPersonUuidFromToken(token); if (userUuid.isEmpty()) { filterChain.doFilter(request, response); return; } - UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(userUuid.get()); + UserDetails userDetails = userDetailsService.loadUserByUsername(userUuid.get()); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/TokenServiceImpl.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtTokenService.java similarity index 69% rename from server/src/main/java/com/usatiuk/tjv/y/server/service/TokenServiceImpl.java rename to server/src/main/java/com/usatiuk/tjv/y/server/security/JwtTokenService.java index c8e73d6..77cf062 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/TokenServiceImpl.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtTokenService.java @@ -1,10 +1,8 @@ -package com.usatiuk.tjv.y.server.service; +package com.usatiuk.tjv.y.server.security; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.io.Encoders; import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -16,28 +14,25 @@ import java.util.Date; import java.util.Optional; @Service -public class TokenServiceImpl implements TokenService { - private static final Duration JWT_EXPIRY = Duration.ofMinutes(20); - +public class JwtTokenService { private final SecretKey key; + private final Duration jwtExpiry; - public TokenServiceImpl(@Value("${jwt.secret}") String secret) { - // FIXME: + public JwtTokenService(@Value("${jwt.secret}") String secret, @Value("${jwt.expiryMinutes}") Long expiry) { this.key = Keys.hmacShaKeyFor(secret.getBytes()); + this.jwtExpiry = Duration.ofMinutes(expiry); } - @Override public String generateToken(String personUuid) { Instant now = Instant.now(); return Jwts.builder() .subject(personUuid) - .expiration(Date.from(now.plus(JWT_EXPIRY))) + .expiration(Date.from(now.plus(jwtExpiry))) .signWith(key, Jwts.SIG.HS512) .compact(); } - @Override - public Optional parseToken(String token) { + public Optional getPersonUuidFromToken(String token) { try { Claims claims = Jwts.parser().verifyWith(key).build().parseSignedClaims(token).getPayload(); if (claims.getExpiration().before(new Date())) return Optional.empty(); @@ -46,4 +41,5 @@ public class TokenServiceImpl implements TokenService { return Optional.empty(); } } + } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtUser.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtUser.java deleted file mode 100644 index 2bea894..0000000 --- a/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtUser.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.usatiuk.tjv.y.server.security; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.User; - -import java.util.Collection; - -public class JwtUser extends User { - - public JwtUser(String uuid, String hash, - Collection authorities) { - super(uuid, hash, authorities); - } -} \ No newline at end of file diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtUserDetailsService.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtUserDetailsService.java deleted file mode 100644 index 76205b5..0000000 --- a/server/src/main/java/com/usatiuk/tjv/y/server/security/JwtUserDetailsService.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.usatiuk.tjv.y.server.security; - -import com.usatiuk.tjv.y.server.entity.Person; -import com.usatiuk.tjv.y.server.service.PersonService; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -@Service -public class JwtUserDetailsService implements UserDetailsService { - private final PersonService personService; - - public JwtUserDetailsService(PersonService personService) { - this.personService = personService; - } - - @Override - public UserDetails loadUserByUsername(String uuid) { - Optional person = personService.readById(uuid); - if (!person.isPresent()) throw new UsernameNotFoundException("User with UUID " + uuid + " not found"); - ArrayList roles = - new ArrayList<>(List.of(new SimpleGrantedAuthority(UserRoles.ROLE_USER.name()))); - if (person.get().isAdmin()) roles.add(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name())); - return new JwtUser(uuid, person.get().getPassword(), roles); - } - -} \ No newline at end of file diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/User.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/User.java new file mode 100644 index 0000000..d63d8f0 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/User.java @@ -0,0 +1,13 @@ +package com.usatiuk.tjv.y.server.security; + +import org.springframework.security.core.GrantedAuthority; + +import java.util.Collection; + +public class User extends org.springframework.security.core.userdetails.User { + + public User(String uuid, String hash, + Collection authorities) { + super(uuid, hash, authorities); + } +} \ No newline at end of file diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/security/UserDetailsService.java b/server/src/main/java/com/usatiuk/tjv/y/server/security/UserDetailsService.java new file mode 100644 index 0000000..10b5528 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/security/UserDetailsService.java @@ -0,0 +1,30 @@ +package com.usatiuk.tjv.y.server.security; + +import com.usatiuk.tjv.y.server.entity.Person; +import com.usatiuk.tjv.y.server.repository.PersonRepository; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService { + private final PersonRepository personRepository; + + public UserDetailsService(PersonRepository personRepository) { + this.personRepository = personRepository; + } + + @Override + public UserDetails loadUserByUsername(String usernameOrUuid) { + Person person = personRepository.findByUsernameOrId(usernameOrUuid).orElseThrow(() -> new UsernameNotFoundException("Username not found")); + ArrayList roles = + new ArrayList<>(List.of(new SimpleGrantedAuthority(UserRoles.ROLE_USER.name()))); + if (person.isAdmin()) roles.add(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name())); + return new User(person.getUuid(), person.getPassword(), roles); + } + +} \ No newline at end of file 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 5da35d2..96c8c29 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 @@ -60,7 +60,7 @@ public class WebSecurityConfig { return http.cors(Customizer.withDefaults()) .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests((authorize) -> authorize - .requestMatchers(mvc.pattern(HttpMethod.GET, "/post/*")).permitAll() + .requestMatchers(mvc.pattern(HttpMethod.GET, "/post/**")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.GET, "/post*")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.POST, "/person")).permitAll() .requestMatchers(mvc.pattern(HttpMethod.GET, "/person")).permitAll() @@ -75,7 +75,6 @@ public class WebSecurityConfig { .build(); } - @Bean CorsConfigurationSource corsConfigurationSource() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatService.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatService.java index edd90d4..a71690c 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatService.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/ChatService.java @@ -3,12 +3,11 @@ 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 com.usatiuk.tjv.y.server.entity.Chat; import org.springframework.security.core.Authentication; import java.util.Collection; -public interface ChatService extends CrudService { +public interface ChatService { ChatTo create(Authentication authentication, ChatCreateTo chatCreateTo); ChatTo update(Authentication authentication, Long id, ChatCreateTo chatCreateTo); @@ -18,4 +17,6 @@ public interface ChatService extends CrudService { void deleteById(Authentication authentication, Long id); Collection getMembers(Authentication authentication, Long id); + + boolean isMemberOf(String personUuid, Long chatId); } 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 31eb4a3..91f6759 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 @@ -9,7 +9,6 @@ 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 jakarta.persistence.EntityManager; -import org.springframework.data.repository.CrudRepository; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; @@ -21,7 +20,7 @@ import java.util.Collection; import java.util.Objects; @Service -public class ChatServiceImpl extends CrudServiceImpl implements ChatService { +public class ChatServiceImpl implements ChatService { private final ChatRepository chatRepository; private final ChatMapper chatMapper; @@ -35,12 +34,6 @@ public class ChatServiceImpl extends CrudServiceImpl implements Chat this.entityManager = entityManager; } - @Override - protected CrudRepository getRepository() { - return chatRepository; - } - - @Override public ChatTo create(Authentication authentication, ChatCreateTo chatCreateTo) { var chat = new Chat(); @@ -63,7 +56,7 @@ public class ChatServiceImpl extends CrudServiceImpl implements Chat @Override public ChatTo update(Authentication authentication, Long id, ChatCreateTo chatCreateTo) { - var chat = readById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + 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"); @@ -89,7 +82,7 @@ public class ChatServiceImpl extends CrudServiceImpl implements Chat @Override public ChatTo getById(Authentication authentication, Long id) { - var chat = readById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + 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"); @@ -99,18 +92,25 @@ public class ChatServiceImpl extends CrudServiceImpl implements Chat @Override public void deleteById(Authentication authentication, Long id) { - var chat = readById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + 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"); - deleteById(id); + chatRepository.delete(chat); } @Override public Collection getMembers(Authentication authentication, Long id) { - var chat = readById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + 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(); } + + @Override + public boolean isMemberOf(String personUuid, Long chatId) { + var chat = chatRepository.findById(chatId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Chat not found")); + var userRef = entityManager.getReference(Person.class, personUuid); + return chat.getMembers().contains(userRef); + } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/CrudService.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/CrudService.java deleted file mode 100644 index 208e6c4..0000000 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/CrudService.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.usatiuk.tjv.y.server.service; - -import com.usatiuk.tjv.y.server.entity.EntityWithId; - -import java.io.Serializable; -import java.util.Optional; - -public interface CrudService, ID extends Serializable> { - T create(T e); - - Optional readById(ID id); - - Iterable readAll(); - - void update(T e); - - void deleteById(ID id); -} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/CrudServiceImpl.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/CrudServiceImpl.java deleted file mode 100644 index 623d35b..0000000 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/CrudServiceImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.usatiuk.tjv.y.server.service; - -import com.usatiuk.tjv.y.server.entity.EntityWithId; -import org.springframework.data.repository.CrudRepository; - -import java.io.Serializable; -import java.util.Optional; - -public abstract class CrudServiceImpl, ID extends Serializable> - implements CrudService { - @Override - public T create(T e) { - if (e == null || (e.getId() != null && getRepository().existsById(e.getId()))) - throw new IllegalArgumentException(); - - return getRepository().save(e); - } - - @Override - public Optional readById(ID id) { - return getRepository().findById(id); - } - - @Override - public Iterable readAll() { - return getRepository().findAll(); - } - - @Override - public void update(T e) { - getRepository().save(e); - } - - @Override - public void deleteById(ID id) { - getRepository().deleteById(id); - } - - protected abstract CrudRepository getRepository(); -} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/LoginTokenService.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/LoginTokenService.java new file mode 100644 index 0000000..2bc0170 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/LoginTokenService.java @@ -0,0 +1,8 @@ +package com.usatiuk.tjv.y.server.service; + +import com.usatiuk.tjv.y.server.dto.TokenRequestTo; +import com.usatiuk.tjv.y.server.dto.TokenResponseTo; + +public interface LoginTokenService { + TokenResponseTo login(TokenRequestTo tokenRequestTo); +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/LoginTokenServiceImpl.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/LoginTokenServiceImpl.java new file mode 100644 index 0000000..febd9d4 --- /dev/null +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/LoginTokenServiceImpl.java @@ -0,0 +1,29 @@ +package com.usatiuk.tjv.y.server.service; + +import com.usatiuk.tjv.y.server.dto.TokenRequestTo; +import com.usatiuk.tjv.y.server.dto.TokenResponseTo; +import com.usatiuk.tjv.y.server.security.JwtTokenService; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +@Service +public class LoginTokenServiceImpl implements LoginTokenService { + private final AuthenticationManager authenticationManager; + private final JwtTokenService jwtTokenService; + + public LoginTokenServiceImpl(AuthenticationManager authenticationManager, JwtTokenService jwtTokenService) { + this.authenticationManager = authenticationManager; + this.jwtTokenService = jwtTokenService; + } + + @Override + public TokenResponseTo login(TokenRequestTo tokenRequestTo) { + Authentication authentication = + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(tokenRequestTo.username(), tokenRequestTo.password())); + String uuid = authentication.getName(); + String token = jwtTokenService.generateToken(uuid); + return new TokenResponseTo(token); + } +} diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageService.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageService.java index 9e5d1fc..5ad91b1 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageService.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/MessageService.java @@ -1,6 +1,17 @@ package com.usatiuk.tjv.y.server.service; -import com.usatiuk.tjv.y.server.entity.Message; +import com.usatiuk.tjv.y.server.dto.MessageCreateTo; +import com.usatiuk.tjv.y.server.dto.MessageTo; +import org.springframework.security.core.Authentication; -public interface MessageService extends CrudService { +import java.util.Collection; + +public interface MessageService { + Collection getByChat(Authentication authentication, Long chatId); + MessageTo addToChat(Authentication authentication, Long chatId, MessageCreateTo messageCreateTo); + + MessageTo update(Authentication authentication, Long id, MessageCreateTo msg); + void delete(Authentication authentication, Long id); + + Collection readAll(Authentication authentication); } 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 364776b..1865478 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 @@ -1,21 +1,85 @@ package com.usatiuk.tjv.y.server.service; +import com.usatiuk.tjv.y.server.dto.MessageCreateTo; +import com.usatiuk.tjv.y.server.dto.MessageTo; +import com.usatiuk.tjv.y.server.dto.converters.MessageMapper; +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 org.springframework.data.repository.CrudRepository; +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; + +import java.util.Collection; +import java.util.Objects; +import java.util.stream.StreamSupport; @Service -public class MessageServiceImpl extends CrudServiceImpl implements 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) { + public MessageServiceImpl(MessageRepository messageRepository, MessageMapper messageMapper, ChatService chatService, EntityManager entityManager) { this.messageRepository = messageRepository; + this.messageMapper = messageMapper; + this.chatService = chatService; + this.entityManager = entityManager; } @Override - protected CrudRepository getRepository() { - return messageRepository; + public Collection getByChat(Authentication authentication, Long chatId) { + if (!chatService.isMemberOf(authentication.getName(), chatId)) + throw new ResponseStatusException(HttpStatus.FORBIDDEN, "User isn't member of the chat"); + + 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()); + + messageRepository.save(message); + return messageMapper.makeDto(message); + } + + @Override + public MessageTo update(Authentication authentication, 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) { + 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 readAll(Authentication authentication) { + if (!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name()))) + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); + + return StreamSupport.stream(messageRepository.findAll().spliterator(), false).map(messageMapper::makeDto).toList(); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonService.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonService.java index fab0878..153fe9c 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonService.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/PersonService.java @@ -1,28 +1,37 @@ 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 com.usatiuk.tjv.y.server.service.exceptions.UserAlreadyExistsException; -import com.usatiuk.tjv.y.server.service.exceptions.UserNotFoundException; import org.springframework.security.core.Authentication; import java.util.Collection; import java.util.Optional; -public interface PersonService extends CrudService { - Person signup(Person person) throws UserAlreadyExistsException; +public interface PersonService { + PersonTo signup(PersonCreateTo person); Optional login(String username, String password); - Optional readByUsername(String username); + PersonTo readByUsername(String username); + PersonTo readByUuid(String uuid); + PersonTo readSelf(Authentication authentication); - Collection getFollowers(String uuid) throws UserNotFoundException; - Collection getFollowing(String uuid) throws UserNotFoundException; + PersonTo update(Authentication authentication, PersonCreateTo person); - void addFollower(String follower, String followee) throws UserNotFoundException; - void removeFollower(String follower, String followee) throws UserNotFoundException; + void deleteSelf(Authentication authentication); + void deleteByUuid(Authentication authentication, String uuid); - Collection getAdmins(); - void addAdmin(Authentication caller, String uuid) throws UserNotFoundException; - void removeAdmin(Authentication caller, String uuid) throws UserNotFoundException; + Collection readAll(); + + Collection getFollowers(Authentication authentication); + Collection getFollowing(Authentication authentication); + + void addFollower(Authentication authentication, String followee); + void removeFollower(Authentication authentication, String followee); + + Collection getAdmins(); + void addAdmin(Authentication caller, String uuid); + void removeAdmin(Authentication caller, String uuid); } 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 6cae073..ba32c57 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 @@ -1,12 +1,15 @@ 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.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 org.springframework.data.repository.CrudRepository; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -15,36 +18,41 @@ 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; @Service -public class PersonServiceImpl extends CrudServiceImpl implements PersonService { +public class PersonServiceImpl implements PersonService { private final PersonRepository personRepository; private final PasswordEncoder passwordEncoder; private final EntityManager entityManager; + private final PersonMapper personMapper; public PersonServiceImpl(PersonRepository personRepository, - PasswordEncoder passwordEncoder, EntityManager entityManager) { + PasswordEncoder passwordEncoder, EntityManager entityManager, PersonMapper personMapper) { this.personRepository = personRepository; this.passwordEncoder = passwordEncoder; this.entityManager = entityManager; + this.personMapper = personMapper; } @Override - protected CrudRepository getRepository() { - return personRepository; - } - - @Override - public Person signup(Person person) throws UserAlreadyExistsException { - if (personRepository.existsByUsername(person.getUsername())) + public PersonTo signup(PersonCreateTo signupRequest) { + if (personRepository.existsByUsername(signupRequest.username())) throw new UserAlreadyExistsException(); - person.setPassword(passwordEncoder.encode(person.getPassword())); + Person toCreate = new Person(); - if (personRepository.findByAdminIsTrue().isEmpty()) person.setAdmin(true); + toCreate.setUsername(signupRequest.username()) + .setPassword(signupRequest.password()) + .setFullName(signupRequest.fullName()); - return create(person); + toCreate.setPassword(passwordEncoder.encode(signupRequest.password())); + + if (personRepository.findByAdminIsTrue().isEmpty()) toCreate.setAdmin(true); + + return personMapper.makeDto(personRepository.save(toCreate)); } @Override @@ -57,36 +65,90 @@ public class PersonServiceImpl extends CrudServiceImpl implement } @Override - public Optional readByUsername(String username) { - return personRepository.findByUsername(username); + public PersonTo readByUsername(String username) { + return personMapper.makeDto(personRepository.findByUsername(username).orElseThrow(UserNotFoundException::new)); } @Override - public Collection getFollowers(String uuid) throws UserNotFoundException { - return personRepository.findById(uuid).orElseThrow(UserNotFoundException::new).getFollowers(); + public PersonTo readByUuid(String uuid) { + return personMapper.makeDto(personRepository.findById(uuid).orElseThrow(UserNotFoundException::new)); } @Override - public Collection getFollowing(String uuid) throws UserNotFoundException { - return personRepository.findById(uuid).orElseThrow(UserNotFoundException::new).getFollowing(); + public PersonTo readSelf(Authentication authentication) { + return readByUuid(authentication.getName()); } @Override - public void addFollower(String follower, String followee) throws UserNotFoundException { - var person = personRepository.findById(follower).orElseThrow(UserNotFoundException::new); + public PersonTo update(Authentication authentication, PersonCreateTo person) { + var found = personRepository.findById(authentication.getName()).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + found.setUsername(person.username()) + .setFullName(person.fullName()); + if (!person.password().isEmpty()) found.setPassword(passwordEncoder.encode(person.password())); + personRepository.save(found); + return personMapper.makeDto(found); + } + + private 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 + 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 readAll() { + return StreamSupport.stream(personRepository.findAll().spliterator(), false).map(personMapper::makeDto).toList(); + } + + @Override + public Collection getFollowers(Authentication authentication) { + return personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new) + .getFollowers().stream().map(personMapper::makeDto).toList(); + } + + @Override + public Collection getFollowing(Authentication authentication) { + return personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new) + .getFollowing().stream().map(personMapper::makeDto).toList(); + } + + @Override + public void addFollower(Authentication authentication, String followee) { + var person = personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new); person.getFollowing().add(entityManager.getReference(Person.class, followee)); personRepository.save(person); } @Override - public void removeFollower(String follower, String followee) throws UserNotFoundException { - var person = personRepository.findById(follower).orElseThrow(UserNotFoundException::new); + public void removeFollower(Authentication authentication, String followee) { + var person = personRepository.findById(authentication.getName()).orElseThrow(UserNotFoundException::new); person.getFollowing().remove(entityManager.getReference(Person.class, followee)); personRepository.save(person); } @Override - public void addAdmin(Authentication caller, String uuid) throws UserNotFoundException { + public void addAdmin(Authentication caller, String uuid) { if (!caller.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name()))) throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); @@ -96,7 +158,7 @@ public class PersonServiceImpl extends CrudServiceImpl implement } @Override - public void removeAdmin(Authentication caller, String uuid) throws UserNotFoundException { + public void removeAdmin(Authentication caller, String uuid) { if (!caller.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name()))) throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); @@ -109,7 +171,7 @@ public class PersonServiceImpl extends CrudServiceImpl implement } @Override - public Collection getAdmins() { - return personRepository.findByAdminIsTrue(); + public Collection getAdmins() { + return personRepository.findByAdminIsTrue().stream().map(personMapper::makeDto).toList(); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/PostService.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/PostService.java index 0074b90..8390356 100644 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/PostService.java +++ b/server/src/main/java/com/usatiuk/tjv/y/server/service/PostService.java @@ -1,13 +1,22 @@ package com.usatiuk.tjv.y.server.service; -import com.usatiuk.tjv.y.server.entity.Post; +import com.usatiuk.tjv.y.server.dto.PostCreateTo; +import com.usatiuk.tjv.y.server.dto.PostTo; +import org.springframework.security.core.Authentication; import java.util.Collection; -public interface PostService extends CrudService { - Collection readByAuthorId(String authorUuid); +public interface PostService { + PostTo createPost(Authentication authentication, PostCreateTo postCreateTo); + PostTo updatePost(Authentication authentication, Long id, PostCreateTo postCreateTo); + void deletePost(Authentication authentication, Long id); - Collection readByAuthorUsername(String authorUsername); + PostTo readById(Long id); - Collection readByPersonFollowees(String personUuid); + Collection readByAuthorId(String authorUuid); + Collection readByAuthorUsername(String authorUsername); + + Collection readByPersonFollowees(Authentication authentication); + + Collection readAll(Authentication authentication); } 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 7062eab..d7f63db 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 @@ -1,37 +1,89 @@ package com.usatiuk.tjv.y.server.service; +import com.usatiuk.tjv.y.server.dto.PostCreateTo; +import com.usatiuk.tjv.y.server.dto.PostTo; +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 org.springframework.data.repository.CrudRepository; +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; import java.util.Collection; +import java.util.Objects; +import java.util.stream.StreamSupport; @Service -public class PostServiceImpl extends CrudServiceImpl implements PostService { +public class PostServiceImpl implements PostService { private final PostRepository postRepository; + private final PostMapper postMapper; + private final EntityManager entityManager; - public PostServiceImpl(PostRepository postRepository) { + public PostServiceImpl(PostRepository postRepository, PostMapper postMapper, EntityManager entityManager) { this.postRepository = postRepository; + this.postMapper = postMapper; + this.entityManager = entityManager; } @Override - protected CrudRepository getRepository() { - return postRepository; + public PostTo createPost(Authentication authentication, PostCreateTo postCreateTo) { + Post post = new Post(); + post.setAuthor(entityManager.getReference(Person.class, authentication.getName())); + post.setText(postCreateTo.text()); + return postMapper.makeDto(postRepository.save(post)); } @Override - public Collection readByAuthorId(String authorId) { - return postRepository.findByAuthorUuid(authorId); + public PostTo readById(Long id) { + return postMapper.makeDto(postRepository.findById(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Post not found"))); } @Override - public Collection readByAuthorUsername(String authorUsername) { - return postRepository.findByAuthorUsername(authorUsername); + public Collection readByAuthorId(String authorId) { + return postRepository.findByAuthorUuid(authorId).stream().map(postMapper::makeDto).toList(); } @Override - public Collection readByPersonFollowees(String personUuid) { - return postRepository.findByPersonFollowees(personUuid); + public Collection readByAuthorUsername(String authorUsername) { + return postRepository.findByAuthorUsername(authorUsername).stream().map(postMapper::makeDto).toList(); + } + + @Override + public Collection readByPersonFollowees(Authentication authentication) { + return postRepository.findByPersonFollowees(authentication.getName()).stream().map(postMapper::makeDto).toList(); + } + + @Override + public PostTo updatePost(Authentication authentication, 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) { + 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 readAll(Authentication authentication) { + if (!authentication.getAuthorities().contains(new SimpleGrantedAuthority(UserRoles.ROLE_ADMIN.name()))) + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); + + return StreamSupport.stream(postRepository.findAll().spliterator(), false).map(postMapper::makeDto).toList(); } } diff --git a/server/src/main/java/com/usatiuk/tjv/y/server/service/TokenService.java b/server/src/main/java/com/usatiuk/tjv/y/server/service/TokenService.java deleted file mode 100644 index ed927f7..0000000 --- a/server/src/main/java/com/usatiuk/tjv/y/server/service/TokenService.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.usatiuk.tjv.y.server.service; - -import java.util.Optional; - -public interface TokenService { - String generateToken(String personUuid); - - Optional parseToken(String token); -} 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 index c1f0235..689e24d 100644 --- 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 @@ -4,7 +4,7 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.CONFLICT) -public class UserAlreadyExistsException extends Exception { +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 index 2a57f56..b877d72 100644 --- 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 @@ -4,11 +4,11 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.NOT_FOUND) -public class UserNotFoundException extends Exception { +public class UserNotFoundException extends RuntimeException { public UserNotFoundException() { super(); } - + public UserNotFoundException(String message) { super(message); } diff --git a/server/src/main/resources/application.properties b/server/src/main/resources/application.properties index 17ff2a3..44dc159 100644 --- a/server/src/main/resources/application.properties +++ b/server/src/main/resources/application.properties @@ -1,4 +1,5 @@ jwt.secret=JKLASJKLASJKLJHKLDFAHJKFDSHJKFJHKDSHJKFHJKSDFJHKSDJHKFJHKS98346783467899782345jkhgsdoigh938g +jwt.expiryMinutes=20 logging.level.root=DEBUG logging.level.org.springframework.security=DEBUG spring.datasource.url=jdbc:h2:file:~/tjvserver.h2 diff --git a/server/src/test/java/com/usatiuk/tjv/y/server/controller/ChatControllerTest.java b/server/src/test/java/com/usatiuk/tjv/y/server/controller/ChatControllerTest.java index 2e02486..dc9011a 100644 --- a/server/src/test/java/com/usatiuk/tjv/y/server/controller/ChatControllerTest.java +++ b/server/src/test/java/com/usatiuk/tjv/y/server/controller/ChatControllerTest.java @@ -109,7 +109,7 @@ public class ChatControllerTest extends DemoDataDbTest { @Test - void shouldNotChatUnauthorized() { + void shouldNotGetChatUnauthorized() { var response = restTemplate.exchange(addr + "/chat/by-id/" + chat1.getId(), HttpMethod.GET, new HttpEntity<>(createAuthHeaders(person3Auth)), ErrorTo.class); diff --git a/server/src/test/java/com/usatiuk/tjv/y/server/controller/DemoDataDbTest.java b/server/src/test/java/com/usatiuk/tjv/y/server/controller/DemoDataDbTest.java index 3483f93..f24c3d0 100644 --- a/server/src/test/java/com/usatiuk/tjv/y/server/controller/DemoDataDbTest.java +++ b/server/src/test/java/com/usatiuk/tjv/y/server/controller/DemoDataDbTest.java @@ -2,12 +2,14 @@ package com.usatiuk.tjv.y.server.controller; import com.usatiuk.tjv.y.server.dto.TokenResponseTo; 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.entity.Post; import com.usatiuk.tjv.y.server.repository.ChatRepository; +import com.usatiuk.tjv.y.server.repository.MessageRepository; import com.usatiuk.tjv.y.server.repository.PersonRepository; import com.usatiuk.tjv.y.server.repository.PostRepository; -import com.usatiuk.tjv.y.server.service.TokenService; +import com.usatiuk.tjv.y.server.security.JwtTokenService; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -35,13 +37,15 @@ public abstract class DemoDataDbTest { @Autowired private PasswordEncoder passwordEncoder; @Autowired - private TokenService tokenService; + private JwtTokenService jwtTokenService; @Autowired private PersonRepository personRepository; @Autowired private PostRepository postRepository; @Autowired private ChatRepository chatRepository; + @Autowired + private MessageRepository messageRepository; protected static final String person1Password = "p1p"; protected Person person1; @@ -59,6 +63,11 @@ public abstract class DemoDataDbTest { protected Chat chat1; protected Chat chat2; + protected Message message1; + protected Message message2; + protected Message message3; + protected Message message4; + protected HttpHeaders createAuthHeaders(TokenResponseTo personAuth) { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); @@ -74,20 +83,20 @@ public abstract class DemoDataDbTest { .setUsername("person1") .setFullName("Person 1") .setPassword(passwordEncoder.encode(person1Password))); - person1Auth = new TokenResponseTo(tokenService.generateToken(person1.getUuid())); + person1Auth = new TokenResponseTo(jwtTokenService.generateToken(person1.getUuid())); person2 = personRepository.save( new Person() .setUsername("person2") .setFullName("Person 2") .setPassword(passwordEncoder.encode(person2Password)).setFollowing(List.of(person1))); - person2Auth = new TokenResponseTo(tokenService.generateToken(person2.getUuid())); + person2Auth = new TokenResponseTo(jwtTokenService.generateToken(person2.getUuid())); person3 = personRepository.save( new Person() .setUsername("person3") .setFullName("Person 3") .setPassword(passwordEncoder.encode(person3Password)) .setFollowing(List.of(person2, person1))); - person3Auth = new TokenResponseTo(tokenService.generateToken(person3.getUuid())); + person3Auth = new TokenResponseTo(jwtTokenService.generateToken(person3.getUuid())); post1 = postRepository.save(new Post().setAuthor(person1).setText("post 1")); post2 = postRepository.save(new Post().setAuthor(person2).setText("post 2")); @@ -102,12 +111,17 @@ public abstract class DemoDataDbTest { .setCreator(person3) .setMembers(List.of(person2, person3)) .setName("Chat 1")); + + message1 = messageRepository.save(new Message().setAuthor(person1).setChat(chat1).setContents("message 1")); + message2 = messageRepository.save(new Message().setAuthor(person2).setChat(chat1).setContents("message2")); + message3 = messageRepository.save(new Message().setAuthor(person2).setChat(chat2).setContents("message 3")); + message4 = messageRepository.save(new Message().setAuthor(person3).setChat(chat2).setContents("message 4")); } @AfterEach void erase() { assert !TestTransaction.isActive(); - JdbcTestUtils.deleteFromTables(jdbcTemplate, "person_follows", "chat_person", "post", "chat", "message", "person"); + JdbcTestUtils.deleteFromTables(jdbcTemplate, "person_follows", "chat_person", "post", "message", "chat", "person"); } } diff --git a/server/src/test/java/com/usatiuk/tjv/y/server/controller/PostControllerTest.java b/server/src/test/java/com/usatiuk/tjv/y/server/controller/PostControllerTest.java index 3b4ac59..cc71556 100644 --- a/server/src/test/java/com/usatiuk/tjv/y/server/controller/PostControllerTest.java +++ b/server/src/test/java/com/usatiuk/tjv/y/server/controller/PostControllerTest.java @@ -63,7 +63,7 @@ public class PostControllerTest extends DemoDataDbTest { @Test void shouldGetByAuthor() { - var response = restTemplate.exchange(addr + "/post/by-author-uuid?author=" + person1.getUuid(), HttpMethod.GET, + var response = restTemplate.exchange(addr + "/post/by-author-uuid/" + person1.getUuid(), HttpMethod.GET, HttpEntity.EMPTY, PostTo[].class); Assertions.assertEquals(HttpStatus.OK, response.getStatusCode()); diff --git a/server/src/test/java/com/usatiuk/tjv/y/server/controller/TokenControllerTest.java b/server/src/test/java/com/usatiuk/tjv/y/server/controller/TokenControllerTest.java index c546f82..2393e92 100644 --- a/server/src/test/java/com/usatiuk/tjv/y/server/controller/TokenControllerTest.java +++ b/server/src/test/java/com/usatiuk/tjv/y/server/controller/TokenControllerTest.java @@ -2,7 +2,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.TokenService; +import com.usatiuk.tjv.y.server.security.JwtTokenService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,7 +13,7 @@ import org.springframework.http.HttpStatus; public class TokenControllerTest extends DemoDataDbTest { @Autowired - private TokenService tokenService; + private JwtTokenService jwtTokenService; @Test void shouldLogin() { @@ -26,7 +26,7 @@ public class TokenControllerTest extends DemoDataDbTest { TokenResponseTo parsedResponse = response.getBody(); Assertions.assertNotNull(parsedResponse); - Assertions.assertTrue(tokenService.parseToken(parsedResponse.token()).isPresent()); + Assertions.assertTrue(jwtTokenService.getPersonUuidFromToken(parsedResponse.token()).isPresent()); } diff --git a/server/src/test/resources/application.properties b/server/src/test/resources/application.properties index ed4e31f..69e9c26 100644 --- a/server/src/test/resources/application.properties +++ b/server/src/test/resources/application.properties @@ -1,3 +1,4 @@ jwt.secret=FLJKDSDKLJFJKLISDAHJKFHOUIJOHUIJFHUOI$UIHGOUIOFG$#UIOYFOUYIG#$UIOHDUGHIOHUGIHJFHJLKDFHJLKDHJLKFSJDHKFHJKLSH +jwt.expiryMinutes=20 logging.level.root=DEBUG logging.level.org.springframework.security=DEBUG \ No newline at end of file