diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/config/SecurityConfig.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/config/SecurityConfig.java index e8d6a703..c0e37205 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/config/SecurityConfig.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/config/SecurityConfig.java @@ -50,7 +50,6 @@ protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.cors().disable() .csrf().disable() .authorizeRequests() - // désactive l'authentification pour les requêtes dont l'url commence par /api/auth/ .antMatchers(AUTH_WHITELIST) .permitAll() .anyRequest() diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/RelationController.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/RelationController.java index c6cc522e..69ce567e 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/RelationController.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/RelationController.java @@ -8,8 +8,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @AllArgsConstructor @@ -26,12 +24,6 @@ public ResponseEntity requestRelation(@PathVariable("receiverId") return ResponseEntity.ok(relationsDto); } - @GetMapping(value = "/list/{userId}") - public ResponseEntity> getAllForUserId(@PathVariable("userId") Long userId) { - List relations = relationService.getAllForUserId(userId); - return ResponseEntity.ok(relations); - } - @SuppressWarnings("rawtypes") @DeleteMapping(value = "/{senderId}/decline") public ResponseEntity deleteRelationBySender(@PathVariable("senderId") Long senderId) { diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/UserController.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/UserController.java index d6889221..af5a100f 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/UserController.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/controller/UserController.java @@ -30,7 +30,7 @@ public ResponseEntity> getAll( @RequestParam(value = "size", defaultValue = "10") int size ) { Pageable pageable = PageRequest.of(page, size); - Page users = userService.getAll(pageable); + Page users = userService.getAll(pageable, true); return ResponseEntity.ok(users); } @@ -47,7 +47,7 @@ public ResponseEntity> getAllFriends( @PathVariable("userId") Long userId ) { Pageable pageable = PageRequest.of(page, size); - Page userDtos = relationService.getAllFriendsByUserId(pageable, userId); + Page userDtos = relationService.getAllFriendsByUserId(userId, pageable); return ResponseEntity.ok(userDtos); } @@ -69,7 +69,7 @@ public ResponseEntity> getReceivedFriendRequest( ) { Pageable pageable = PageRequest.of(page, size); Long userId = authService.getCurrentUser().getId(); - Page usersDto = relationService.getReceivedFriendRequest(userId ,pageable); + Page usersDto = relationService.getReceivedFriendRequest(userId, pageable); return ResponseEntity.ok(usersDto); } } diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/dto/RelationTypeEnum.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/dto/RelationTypeEnum.java new file mode 100644 index 00000000..a2829e83 --- /dev/null +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/dto/RelationTypeEnum.java @@ -0,0 +1,5 @@ +package com.dynonuggets.refonteimplicaction.dto; + +public enum RelationTypeEnum { + FRIEND, RECEIVER, SENDER, NONE +} diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/dto/UserDto.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/dto/UserDto.java index 1d620191..d02ffe7d 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/dto/UserDto.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/dto/UserDto.java @@ -33,5 +33,5 @@ public class UserDto { private String contribution; private String firstName; private String lastName; - + private RelationTypeEnum relationTypeOfCurrentUser; } diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/repository/RelationRepository.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/repository/RelationRepository.java index e9d03773..30c7fb79 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/repository/RelationRepository.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/repository/RelationRepository.java @@ -38,4 +38,14 @@ public interface RelationRepository extends JpaRepository { "from Relation r " + "where (r.sender.id = ?1 and r.receiver.id = ?2) or (r.sender.id = ?2 and r.receiver.id = ?1)") Optional findRelationBetween(Long userId1, Long userId2); + + @Query("select r " + + "from Relation r " + + "where r.sender.id in ?1 or r.receiver.id in ?1") + List findAllByUserIdIn(List userIds); + + @Query("select r " + + "from Relation r " + + "where (r.sender.id in ?2 and r.receiver.id = ?1) or (r.receiver.id in ?2 and r.sender.id = ?1)") + List findAllRelatedToUserByUserIdIn(Long userId, List userIds); } diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/AuthService.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/AuthService.java index cc78f645..daa1c7db 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/AuthService.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/AuthService.java @@ -27,7 +27,6 @@ public class AuthService { private final PasswordEncoder passwordEncoder; private final UserRepository userRepository; - private final UserService userService; private final SignUpRepository signUpRepository; private final MailService mailService; private final AuthenticationManager authenticationManager; @@ -78,7 +77,8 @@ public AuthenticationResponseDto login(LoginRequestDto loginRequestDto) throws I Instant expiresAt = Instant.now().plusMillis(jwtProvider.getJwtExpirationInMillis()); String refreshToken = refreshTokenService.generateRefreshToken().getToken(); - final UserDto user = userService.getUserByUsername(username); + final User user = userRepository.findByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException("Username " + username + " not found.")); return AuthenticationResponseDto.builder() .authenticationToken(token) @@ -100,7 +100,8 @@ public UserDto getCurrentUser() { public AuthenticationResponseDto refreshToken(RefreshTokenRequestDto refreshTokenRequestDto) throws ImplicactionException { final String username = refreshTokenRequestDto.getUsername(); - final UserDto user = userService.getUserByUsername(username); + final User user = userRepository.findByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException("Username " + username + " not found.")); refreshTokenService.validateRefreshToken(refreshTokenRequestDto.getRefreshToken()); String token = jwtProvider.generateTokenWithUsername(username); diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/RelationService.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/RelationService.java index 674121a2..a777687e 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/RelationService.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/RelationService.java @@ -17,9 +17,8 @@ import org.springframework.stereotype.Service; import java.time.Instant; -import java.util.List; -import static java.util.stream.Collectors.toList; +import static com.dynonuggets.refonteimplicaction.dto.RelationTypeEnum.*; @Service @AllArgsConstructor @@ -29,8 +28,14 @@ public class RelationService { private final RelationRepository relationRepository; private final RelationAdapter relationAdapter; private final UserAdapter userAdapter; - private final UserService userService; + /** + * Crée une nouvelle relation entre le senderId et le receiverId + * + * @return la nouvelle relation créée avec confirmedAt à null + * @throws UserNotFoundException si l'un des deux utilisateurs au moins n'existe pas + * @throws ImplicactionException si sender et receiver correspondent au même utilisateur + */ public RelationsDto requestRelation(Long senderId, Long receiverId) { // TODO: gérer avec une exception plus appropriée if (senderId.equals(receiverId)) { @@ -55,15 +60,10 @@ public RelationsDto requestRelation(Long senderId, Long receiverId) { return relationAdapter.toDto(save); } - public List getAllForUserId(Long userId) { - final List relations = relationRepository.findAllByUserId(userId); - return relations.stream() - .map(relationAdapter::toDto) - .collect(toList()); - } - /** * Supprime la relation entre le sender et le receiver dont les ids sont passé en paramètres + * + * @throws NotFoundException si l'un des deux utilisateurs au moins n'existe pas */ public void deleteRelation(Long senderId, Long receiverId) { Relation relation = relationRepository.findBySender_IdAndReceiver_Id(senderId, receiverId) @@ -74,6 +74,8 @@ public void deleteRelation(Long senderId, Long receiverId) { /** * Supprime la relation entre les utilisateurs dont les ids sont passés en paramètres, sans tenir compte de la notion * de sender / receiver + * + * @throws NotFoundException si l'un des deux utilisateurs au moins n'existe pas */ public void cancelRelation(Long userId1, Long userId2) { Relation relation = relationRepository.findRelationBetween(userId1, userId2) @@ -82,8 +84,10 @@ public void cancelRelation(Long userId1, Long userId2) { } /** - * Confirme la relation entre les utilisateurs dont les ids sont passés en paramètres, en tenant compte de la notion - * de sender / receiver + * Confirme la relation entre les utilisateurs dont les ids sont passés en paramètres + * + * @return la relation entre senderId et receiverId + * @throws NotFoundException si l'un des deux utilisateurs au moins n'existe pas */ public RelationsDto confirmRelation(Long senderId, Long receiverId) { Relation relation = relationRepository.findBySender_IdAndReceiver_Id(senderId, receiverId) @@ -94,28 +98,39 @@ public RelationsDto confirmRelation(Long senderId, Long receiverId) { } /** - * Renvoie tous les utilisateurs qui sont amis avec l'utilisateur en paramètres + * @return tous les utilisateurs qui sont amis avec userId */ - public Page getAllFriendsByUserId(Pageable pageable, Long userId) { - // renvoie une exception si l'utilisateur n'existe pas - userService.getUserById(userId); + public Page getAllFriendsByUserId(Long userId, Pageable pageable) { Page relations = relationRepository.findAllFriendsByUserId(userId, pageable); - return relations.map(relation -> { - if (relation.getSender().getId().equals(userId)) { - return userAdapter.toDto(relation.getReceiver()); - } - return userAdapter.toDto(relation.getSender()); + final User friend = userId.equals(relation.getReceiver().getId()) ? relation.getSender() : relation.getReceiver(); + final UserDto userDto = userAdapter.toDto(friend); + userDto.setRelationTypeOfCurrentUser(FRIEND); + return userDto; }); } + /** + * @return tous les utilisateurs à qui userId a envoyé une demande d'ami qui n'a pas encore été confirmée + */ public Page getSentFriendRequest(Long userId, Pageable pageable) { Page relations = relationRepository.findAllBySender_IdAndConfirmedAtIsNull(userId, pageable); - return relations.map(relation -> userAdapter.toDto(relation.getReceiver())); + return relations.map(relation -> { + final UserDto userDto = userAdapter.toDto(relation.getReceiver()); + userDto.setRelationTypeOfCurrentUser(SENDER); + return userDto; + }); } + /** + * @return tous les utilisateurs qui ont envoyé une demande d'ami à userId + */ public Page getReceivedFriendRequest(Long userId, Pageable pageable) { Page relations = relationRepository.findAllByReceiver_IdAndConfirmedAtIsNull(userId, pageable); - return relations.map(relation -> userAdapter.toDto(relation.getSender())); + return relations.map(relation -> { + final UserDto userDto = userAdapter.toDto(relation.getSender()); + userDto.setRelationTypeOfCurrentUser(RECEIVER); + return userDto; + }); } } diff --git a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/UserService.java b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/UserService.java index f4ca7605..628c2849 100644 --- a/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/UserService.java +++ b/backend-implicaction/src/main/java/com/dynonuggets/refonteimplicaction/service/UserService.java @@ -1,9 +1,12 @@ package com.dynonuggets.refonteimplicaction.service; import com.dynonuggets.refonteimplicaction.adapter.UserAdapter; +import com.dynonuggets.refonteimplicaction.dto.RelationTypeEnum; import com.dynonuggets.refonteimplicaction.dto.UserDto; import com.dynonuggets.refonteimplicaction.exception.UserNotFoundException; +import com.dynonuggets.refonteimplicaction.model.Relation; import com.dynonuggets.refonteimplicaction.model.User; +import com.dynonuggets.refonteimplicaction.repository.RelationRepository; import com.dynonuggets.refonteimplicaction.repository.UserRepository; import lombok.AllArgsConstructor; import org.springframework.data.domain.Page; @@ -11,17 +14,42 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.stream.Collectors; + @Service @AllArgsConstructor public class UserService { private final UserRepository userRepository; + private final RelationRepository relationRepository; + private final AuthService authService; private final UserAdapter userAdapter; + /** + * @param isCurrentUserRelation recherche les relations avec l'utilisateur courant + * @return la liste paginée de tous les utilisateurs + */ @Transactional(readOnly = true) - public Page getAll(Pageable pageable) { - return userRepository.findAll(pageable) + public Page getAll(Pageable pageable, boolean isCurrentUserRelation) { + final Long currentUserId = authService.getCurrentUser().getId(); + + final Page users = userRepository.findAll(pageable) .map(userAdapter::toDto); + + if (isCurrentUserRelation) { + final List userIds = users.map(UserDto::getId) + .get() + .collect(Collectors.toList()); + // on recherche les relations de tous les utilisateurs remontés avec l'utilisateur courant ... + List relations = relationRepository.findAllRelatedToUserByUserIdIn(currentUserId, userIds); + // ... et on associe chaque relation avec un statut + relations.forEach(relation -> users.stream() + .filter(user -> isSenderOrReceiver(relation, user.getId()) && !currentUserId.equals(user.getId())) + .findFirst() + .ifPresent(user -> user.setRelationTypeOfCurrentUser(getRelationType(relation, currentUserId)))); + } + return users; } public UserDto getUserById(Long userId) { @@ -30,9 +58,20 @@ public UserDto getUserById(Long userId) { return userAdapter.toDto(user); } - public UserDto getUserByUsername(String username) { - final User user = userRepository.findByUsername(username) - .orElseThrow(() -> new UserNotFoundException("No user found with username " + username)); - return userAdapter.toDto(user); + private boolean isSenderOrReceiver(Relation relation, Long userId) { + return userId.equals(relation.getReceiver().getId()) || userId.equals(relation.getSender().getId()); + } + + private RelationTypeEnum getRelationType(Relation relation, Long userId) { + if (relation.getConfirmedAt() != null) { + return RelationTypeEnum.FRIEND; + } + if (userId.equals(relation.getReceiver().getId())) { + return RelationTypeEnum.RECEIVER; + } + if (userId.equals(relation.getSender().getId())) { + return RelationTypeEnum.SENDER; + } + return RelationTypeEnum.NONE; } } diff --git a/frontend-implicaction/src/app/shared/models/user.ts b/frontend-implicaction/src/app/shared/models/user.ts index c8905e73..52cded7e 100644 --- a/frontend-implicaction/src/app/shared/models/user.ts +++ b/frontend-implicaction/src/app/shared/models/user.ts @@ -1,5 +1,6 @@ import {WorkExperience} from './work-experience'; import {Training} from './training'; +import {RelationType} from '../../user/models/relation-type.enum'; export interface User { id?: string; @@ -21,4 +22,5 @@ export interface User { rank?: string; experiences?: WorkExperience[]; trainings?: Training[]; + relationTypeOfCurrentUser?: RelationType; } diff --git a/frontend-implicaction/src/app/user/components/user-list/user-list.component.html b/frontend-implicaction/src/app/user/components/user-list/user-list.component.html index 0af2eaa4..2671da4c 100644 --- a/frontend-implicaction/src/app/user/components/user-list/user-list.component.html +++ b/frontend-implicaction/src/app/user/components/user-list/user-list.component.html @@ -38,7 +38,7 @@
- +
user.relationTypeOfCurrentUser === RelationType.FRIEND; + + private static isSender = (user: User): boolean => user.relationTypeOfCurrentUser === RelationType.SENDER; + + private static isReceiver = (user: User): boolean => user.relationTypeOfCurrentUser === RelationType.RECEIVER; + ngOnInit(): void { - this.userId = this.authService.getUserId(); + this.currentUserId = this.authService.getUserId(); + // chargement des données this.paginate({ first: 0, rows: this.pageable.size, }); } - isFriend = (user: User): boolean => this.listType === USER_LIST_TYPE.FRIENDS || this.friends.find(u => user.id === u.id) !== undefined; - - // tslint:disable-next-line:max-line-length - isSender = (user: User): boolean => this.listType === USER_LIST_TYPE.FRIENDS_SENT || this.friendAsSenders.find(u => user.id === u.id) !== undefined; - - // tslint:disable-next-line:max-line-length - isReceiver = (user: User): boolean => this.listType === USER_LIST_TYPE.FRIENDS_RECEIVED || this.friendAsReceivers.find(u => user.id === u.id) !== undefined; - paginate({first, rows}): void { this.pageable.page = first / rows; this.pageable.size = rows; let user$: Observable; - // on détermine quel observable à écouter en fonction dy type d'utilisateurs à afficher - if (this.listType === USER_LIST_TYPE.ALL_USERS) { + // on détermine quel est l'observable auquel s'abonner en fonction du type d'utilisateurs à afficher + if (this.listType === UserListType.ALL_USERS) { user$ = this.userService.getAll(this.pageable); - this.getAllFriends(); - } else if (this.listType === USER_LIST_TYPE.FRIENDS) { - user$ = this.userService.getUserFriends(this.userId, this.pageable); - } else if (this.listType === USER_LIST_TYPE.FRIENDS_RECEIVED) { + } else if (this.listType === UserListType.FRIENDS) { + user$ = this.userService.getUserFriends(this.currentUserId, this.pageable); + } else if (this.listType === UserListType.FRIENDS_RECEIVED) { user$ = this.userService.getUserFriendRequestReceived(this.pageable); - } else if (this.listType === USER_LIST_TYPE.FRIENDS_SENT) { + } else if (this.listType === UserListType.FRIENDS_SENT) { user$ = this.userService.getUserFriendRequestSent(this.pageable); } @@ -103,7 +101,7 @@ export class UserListComponent implements OnInit { this.relationService .requestFriend(user.id) .subscribe( - relation => this.friendAsSenders.push(relation.receiver), + () => user.relationTypeOfCurrentUser = RelationType.SENDER, () => this.toastService.error('Oops', 'Une erreur est survenue'), () => this.toastService.success('Demande effectuée', `Votre demande a bien été envoyée à ${user.nicename}`) ); @@ -113,9 +111,9 @@ export class UserListComponent implements OnInit { this.userService .confirmUserAsFriend(sender.id) .subscribe( - relation => { - if (this.listType === USER_LIST_TYPE.ALL_USERS) { - this.friends.push(relation.sender); + () => { + if (this.listType === UserListType.ALL_USERS) { + sender.relationTypeOfCurrentUser = RelationType.FRIEND; } else { const first = this.pageable.page * this.pageable.size; const rows = this.pageable.size; @@ -136,24 +134,16 @@ export class UserListComponent implements OnInit { .removeUserFromFriends(user.id) .subscribe( () => { - if (this.isFriend(user)) { - if (this.listType === USER_LIST_TYPE.ALL_USERS) { - this.friends = this.friends.filter(u => u.id !== user.id); - } + if (UserListComponent.isFriend(user)) { message = `L'utilisateur ${user.nicename} a bien été supprimé de vos amis`; - } else if (this.isSender(user)) { - if (this.listType === USER_LIST_TYPE.ALL_USERS) { - this.friendAsSenders = this.friendAsSenders.filter(u => u.id !== user.id); - } + } else if (UserListComponent.isSender(user)) { message = `Vous avez annulé la demande d'ami avec ${user.nicename}`; - } else if (this.isReceiver(user)) { - if (this.listType === USER_LIST_TYPE.ALL_USERS) { - this.friendAsReceivers = this.friendAsReceivers.filter(u => u.id !== user.id); - } + } else if (UserListComponent.isReceiver(user)) { message = `Vous avez refusé la demande d'ami de ${user.nicename}`; } + user.relationTypeOfCurrentUser = RelationType.NONE; // il faut relancer la pagination dans le cas de l'affichage des amis / demandes - if (this.listType !== USER_LIST_TYPE.ALL_USERS) { + if (this.listType !== UserListType.ALL_USERS) { const first = this.pageable.page * this.pageable.size; const rows = this.pageable.size; this.paginate({first, rows}); @@ -163,23 +153,4 @@ export class UserListComponent implements OnInit { () => this.toastService.success('Succès', message) ); } - - private getAllFriends(): void { - this.relationService - // TODO: peut être optimisé en ne recherchant que les relations avec les utilisateurs affichés - .getAllByUserId(this.userId) - .subscribe( - relations => { - relations.forEach(relation => { - if (relation.confirmedAt) { - this.friends.push(relation.sender.id !== this.userId ? relation.sender : relation.receiver); - } else if (relation.sender.id === this.userId) { - this.friendAsSenders.push(relation.receiver); - } else { - this.friendAsReceivers.push(relation.sender); - } - }, - () => this.toastService.error('Oops', 'Une erreur est survenue lors du chargement de la liste des utilisateurs.')); - }); - } } diff --git a/frontend-implicaction/src/app/user/models/relation-type.enum.ts b/frontend-implicaction/src/app/user/models/relation-type.enum.ts new file mode 100644 index 00000000..83efaaa4 --- /dev/null +++ b/frontend-implicaction/src/app/user/models/relation-type.enum.ts @@ -0,0 +1,6 @@ +export enum RelationType { + FRIEND = 'FRIEND', + RECEIVER = 'RECEIVER', + SENDER = 'SENDER', + NONE = 'NONE' +}