Skip to content

Commit dc703c8

Browse files
authored
corrected duplicate developers save (#59)
* corrected duplicate developers save * ran mvn clean package
1 parent a0f4de6 commit dc703c8

File tree

8 files changed

+96
-71
lines changed

8 files changed

+96
-71
lines changed

src/main/java/com/videogamescatalogue/backend/controller/GameController.java

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,14 @@
33
import com.videogamescatalogue.backend.dto.internal.GameSearchParameters;
44
import com.videogamescatalogue.backend.dto.internal.game.GameDto;
55
import com.videogamescatalogue.backend.dto.internal.game.GameWithStatusDto;
6-
import com.videogamescatalogue.backend.model.Genre;
7-
import com.videogamescatalogue.backend.model.Platform;
86
import com.videogamescatalogue.backend.model.User;
97
import com.videogamescatalogue.backend.service.game.GameService;
108
import io.swagger.v3.oas.annotations.Operation;
119
import io.swagger.v3.oas.annotations.media.Content;
1210
import io.swagger.v3.oas.annotations.media.Schema;
1311
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1412
import io.swagger.v3.oas.annotations.tags.Tag;
15-
import java.util.Arrays;
1613
import java.util.Map;
17-
import java.util.stream.Collectors;
1814
import lombok.RequiredArgsConstructor;
1915
import org.springframework.data.domain.Page;
2016
import org.springframework.data.domain.Pageable;
@@ -130,7 +126,6 @@ public Page<GameDto> search(
130126
@PageableDefault(size = DEFAULT_PAGE_SIZE)
131127
Pageable pageable
132128
) {
133-
validateSearchParams(searchParameters);
134129
return gameService.search(searchParameters, pageable);
135130
}
136131

@@ -149,31 +144,4 @@ public Page<GameDto> apiSearch(
149144
) {
150145
return gameService.apiSearch(searchParams);
151146
}
152-
153-
private void validateSearchParams(GameSearchParameters searchParameters) {
154-
if (searchParameters.platforms() != null) {
155-
try {
156-
searchParameters.platforms()
157-
.forEach(
158-
p -> Platform.GeneralName.valueOf(p.toUpperCase())
159-
);
160-
} catch (IllegalArgumentException e) {
161-
throw new IllegalArgumentException(
162-
"Invalid platforms provided. Valid platforms: "
163-
+ Arrays.stream(Platform.GeneralName.values())
164-
.map(Enum::toString)
165-
.collect(Collectors.joining(", ")), e);
166-
}
167-
}
168-
if (searchParameters.genres() != null) {
169-
try {
170-
searchParameters.genres().forEach(g -> Genre.Name.valueOf(g.toUpperCase()));
171-
} catch (IllegalArgumentException e) {
172-
throw new IllegalArgumentException("Invalid genres provided. Valid genres: "
173-
+ Arrays.stream(Genre.Name.values())
174-
.map(Enum::toString)
175-
.collect(Collectors.joining(", ")), e);
176-
}
177-
}
178-
}
179147
}

src/main/java/com/videogamescatalogue/backend/model/Game.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.math.BigDecimal;
1414
import java.util.HashSet;
1515
import java.util.Set;
16+
import lombok.EqualsAndHashCode;
1617
import lombok.Getter;
1718
import lombok.Setter;
1819
import org.hibernate.annotations.SQLDelete;
@@ -39,6 +40,7 @@ public class Game {
3940

4041
private String backgroundImage;
4142

43+
@EqualsAndHashCode.Exclude
4244
@ManyToMany
4345
@JoinTable(
4446
name = "games_platforms",
@@ -48,6 +50,7 @@ public class Game {
4850
)
4951
private Set<Platform> platforms = new HashSet<>();
5052

53+
@EqualsAndHashCode.Exclude
5154
@ManyToMany
5255
@JoinTable(
5356
name = "games_genres",
@@ -57,6 +60,7 @@ public class Game {
5760
)
5861
private Set<Genre> genres = new HashSet<>();
5962

63+
@EqualsAndHashCode.Exclude
6064
@ManyToMany
6165
@JoinTable(
6266
name = "games_developers",

src/main/java/com/videogamescatalogue/backend/repository/GameRepository.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@
33
import com.videogamescatalogue.backend.model.Game;
44
import java.util.List;
55
import java.util.Optional;
6+
import org.springframework.data.jpa.repository.EntityGraph;
67
import org.springframework.data.jpa.repository.JpaRepository;
78
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
89

910
public interface GameRepository extends JpaRepository<Game, Long>, JpaSpecificationExecutor<Game> {
11+
@EntityGraph(attributePaths = {
12+
"platforms", "genres", "developers"
13+
})
1014
Optional<Game> findByApiId(Long apiId);
1115

16+
@EntityGraph(attributePaths = {
17+
"platforms", "genres", "developers"
18+
})
1219
List<Game> findAllByApiIdIn(List<Long> apiIds);
1320
}

src/main/java/com/videogamescatalogue/backend/security/JwtUtil.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,6 @@ public boolean isValidToken(String token) {
4141
}
4242
}
4343

44-
private Jws<Claims> getAllClaims(String token) {
45-
return Jwts.parserBuilder()
46-
.setSigningKey(secret)
47-
.build()
48-
.parseClaimsJws(token);
49-
}
50-
5144
public String getUsername(String token) {
5245
return getSpecificClaim(token, Claims::getSubject);
5346
}
@@ -56,4 +49,11 @@ private <T> T getSpecificClaim(String token, Function<Claims, T> claimsResolver)
5649
Jws<Claims> allClaims = getAllClaims(token);
5750
return claimsResolver.apply(allClaims.getBody());
5851
}
52+
53+
private Jws<Claims> getAllClaims(String token) {
54+
return Jwts.parserBuilder()
55+
.setSigningKey(secret)
56+
.build()
57+
.parseClaimsJws(token);
58+
}
5959
}

src/main/java/com/videogamescatalogue/backend/service/RawgApiClient.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ public class RawgApiClient {
4545
private static final String DATES_BETWEEN_URL_PART = "&dates=" + LocalDate.now()
4646
+ "%2C" + LocalDate.now().minusMonths(12);
4747
private static final String METACRITIC_URL_PART = "metacritic=80%2C100";
48+
private static final int NUMBER_OF_DOWNLOAD_PORTIONS = 11;
49+
private static final String REQUEST_HEADER_NAME = "User-Agent";
50+
private static final String REQUEST_HEADER_VALUE = "VideoGamesCatalogue";
4851

4952
@Value("${rawg.key}")
5053
private String apiKey;
@@ -56,7 +59,7 @@ public List<ApiResponseGameDto> getBestGames() {
5659

5760
ArrayList<ApiResponseGameDto> result = new ArrayList<>();
5861

59-
for (int i = 1; i < 11; i++) {
62+
for (int i = 1; i < NUMBER_OF_DOWNLOAD_PORTIONS; i++) {
6063
log.info("Create request for page {}", i);
6164

6265
String url = BASE_URL + GAME_URL_PART
@@ -70,7 +73,7 @@ public List<ApiResponseGameDto> getBestGames() {
7073
HttpRequest httpRequest = HttpRequest.newBuilder()
7174
.GET()
7275
.uri(URI.create(url))
73-
.header("User-Agent", "VideoGamesCatalogue")
76+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
7477
.build();
7578
ApiResponseGames responseObject = getResponseGamesList(httpRequest);
7679

@@ -95,7 +98,7 @@ public Page<ApiResponseGameDto> getAllGames(Pageable pageable) {
9598
HttpRequest httpRequest = HttpRequest.newBuilder()
9699
.GET()
97100
.uri(URI.create(url))
98-
.header("User-Agent", "VideoGamesCatalogue")
101+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
99102
.build();
100103
ApiResponseGames responseObject = getResponseGamesList(httpRequest);
101104

@@ -112,7 +115,7 @@ public ApiResponseFullGameDto getGameById(Long id) {
112115
HttpRequest httpRequest = HttpRequest.newBuilder()
113116
.GET()
114117
.uri(URI.create(url))
115-
.header("User-Agent", "VideoGamesCatalogue")
118+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
116119
.build();
117120
ApiResponseFullGameDto game = getIndividualGame(httpRequest);
118121

@@ -129,7 +132,7 @@ public Page<ApiResponseGameDto> search(Map<String, String> searchParams) {
129132
HttpRequest httpRequest = HttpRequest.newBuilder()
130133
.GET()
131134
.uri(URI.create(url.toString()))
132-
.header("User-Agent", "VideoGamesCatalogue")
135+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
133136
.build();
134137
ApiResponseGames responseObject = getResponseGamesList(httpRequest);
135138

src/main/java/com/videogamescatalogue/backend/service/comment/CommentServiceImpl.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.springframework.data.domain.Page;
2222
import org.springframework.data.domain.Pageable;
2323
import org.springframework.stereotype.Service;
24+
import org.springframework.transaction.annotation.Transactional;
2425

2526
@RequiredArgsConstructor
2627
@Service
@@ -31,6 +32,7 @@ public class CommentServiceImpl implements CommentService {
3132
private final GameMapper gameMapper;
3233
private final CommentRepository commentRepository;
3334

35+
@Transactional
3436
@Override
3537
public CommentDto create(Long gameApiId, CreateCommentRequestDto requestDto, User user) {
3638
Comment comment = commentMapper.toModel(requestDto);
@@ -61,11 +63,6 @@ public Page<CommentDto> getUserComments(
6163
return findCommentsByUserId(userId, pageable);
6264
}
6365

64-
private Page<CommentDto> findCommentsByUserId(Long userId, Pageable pageable) {
65-
Page<Comment> userComments = commentRepository.findAllByUserId(userId, pageable);
66-
return userComments.map(commentMapper::toDto);
67-
}
68-
6966
@Override
7067
public CommentDto update(Long commentId, UpdateCommentRequestDto requestDto, Long userId) {
7168
Comment comment = commentRepository.findById(commentId)
@@ -94,6 +91,11 @@ public void delete(Long commentId, Long userId) {
9491
commentRepository.deleteById(commentId);
9592
}
9693

94+
private Page<CommentDto> findCommentsByUserId(Long userId, Pageable pageable) {
95+
Page<Comment> userComments = commentRepository.findAllByUserId(userId, pageable);
96+
return userComments.map(commentMapper::toDto);
97+
}
98+
9799
private void existsByIdAndUserId(Long commentId, Long userId) {
98100
if (!commentRepository.existsByIdAndUserId(commentId, userId)) {
99101
throw new AccessNotAllowedException("User with id: " + userId

src/main/java/com/videogamescatalogue/backend/service/game/GameServiceImpl.java

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
import com.videogamescatalogue.backend.dto.internal.game.GameDto;
77
import com.videogamescatalogue.backend.dto.internal.game.GameWithStatusDto;
88
import com.videogamescatalogue.backend.mapper.developer.DeveloperMapper;
9+
import com.videogamescatalogue.backend.mapper.developer.DeveloperProvider;
910
import com.videogamescatalogue.backend.mapper.game.GameMapper;
1011
import com.videogamescatalogue.backend.model.Developer;
1112
import com.videogamescatalogue.backend.model.Game;
13+
import com.videogamescatalogue.backend.model.Genre;
14+
import com.videogamescatalogue.backend.model.Platform;
1215
import com.videogamescatalogue.backend.model.User;
1316
import com.videogamescatalogue.backend.model.UserGame;
1417
import com.videogamescatalogue.backend.repository.DeveloperRepository;
@@ -18,6 +21,7 @@
1821
import com.videogamescatalogue.backend.service.RawgApiClient;
1922
import jakarta.transaction.Transactional;
2023
import java.util.ArrayList;
24+
import java.util.Arrays;
2125
import java.util.List;
2226
import java.util.Map;
2327
import java.util.Optional;
@@ -42,6 +46,7 @@ public class GameServiceImpl implements GameService {
4246
private final SpecificationBuilder<Game, GameSearchParameters> specificationBuilder;
4347
private final UserGameRepository userGameRepository;
4448
private final DeveloperRepository developerRepository;
49+
private final DeveloperProvider developerProvider;
4550

4651
@Override
4752
public void fetchBestGames() {
@@ -108,6 +113,7 @@ public Page<GameDto> getAllGamesFromApi(Pageable pageable) {
108113

109114
@Override
110115
public Page<GameDto> search(GameSearchParameters searchParameters, Pageable pageable) {
116+
validateSearchParams(searchParameters);
111117
Specification<Game> specification = specificationBuilder.build(searchParameters);
112118

113119
return gameRepository.findAll(specification, pageable)
@@ -157,35 +163,56 @@ private UserGame.GameStatus getGameStatus(Long apiId, User user) {
157163

158164
private Game findOrUpdate(Long apiId) {
159165
Optional<Game> gameOptional = gameRepository.findByApiId(apiId);
166+
if (gameOptional.isPresent()
167+
&& gameOptional.get().getDescription() != null
168+
&& !gameOptional.get().getDevelopers().isEmpty()) {
169+
return gameOptional.get();
170+
}
171+
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
160172
if (gameOptional.isEmpty()) {
161-
return findFromApi(apiId);
173+
return gameMapper.toModel(apiGame);
162174
}
163175
Game game = gameOptional.get();
176+
updateGameInfo(game, apiGame);
177+
return game;
178+
}
179+
180+
private void updateGameInfo(Game game, ApiResponseFullGameDto apiGame) {
164181
if (game.getDescription() == null) {
165-
updateGameDescription(apiId, game);
182+
game.setDescription(apiGame.description());
166183
}
167184
if (game.getDevelopers().isEmpty()) {
168-
updateGameDevelopers(apiId, game);
185+
Set<Developer> developersSet = developerProvider.toDevelopersSet(apiGame.developers());
186+
developerRepository.saveAll(developersSet);
187+
game.setDevelopers(developersSet);
169188
}
170-
return game;
171-
}
172-
173-
private void updateGameDescription(Long apiId, Game game) {
174-
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
175-
game.setDescription(apiGame.description());
176189
gameRepository.save(game);
177190
}
178191

179-
private void updateGameDevelopers(Long apiId, Game game) {
180-
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
181-
Set<Developer> developers = developerMapper.toModelSet(apiGame.developers());
182-
developerRepository.saveAll(developers);
183-
game.setDevelopers(developers);
184-
gameRepository.save(game);
185-
}
186-
187-
private Game findFromApi(Long apiId) {
188-
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
189-
return gameMapper.toModel(apiGame);
192+
private void validateSearchParams(GameSearchParameters searchParameters) {
193+
if (searchParameters.platforms() != null) {
194+
try {
195+
searchParameters.platforms()
196+
.forEach(
197+
p -> Platform.GeneralName.valueOf(p.toUpperCase())
198+
);
199+
} catch (IllegalArgumentException e) {
200+
throw new IllegalArgumentException(
201+
"Invalid platforms provided. Valid platforms: "
202+
+ Arrays.stream(Platform.GeneralName.values())
203+
.map(Enum::toString)
204+
.collect(Collectors.joining(", ")), e);
205+
}
206+
}
207+
if (searchParameters.genres() != null) {
208+
try {
209+
searchParameters.genres().forEach(g -> Genre.Name.valueOf(g.toUpperCase()));
210+
} catch (IllegalArgumentException e) {
211+
throw new IllegalArgumentException("Invalid genres provided. Valid genres: "
212+
+ Arrays.stream(Genre.Name.values())
213+
.map(Enum::toString)
214+
.collect(Collectors.joining(", ")), e);
215+
}
216+
}
190217
}
191218
}

src/main/java/com/videogamescatalogue/backend/service/user/UserServiceImpl.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.videogamescatalogue.backend.dto.internal.user.UserRegistrationRequestDto;
88
import com.videogamescatalogue.backend.dto.internal.user.UserRegistrationResponseDto;
99
import com.videogamescatalogue.backend.dto.internal.user.UserResponseDto;
10+
import com.videogamescatalogue.backend.exception.AccessNotAllowedException;
1011
import com.videogamescatalogue.backend.exception.AuthenticationRequiredException;
1112
import com.videogamescatalogue.backend.exception.EntityNotFoundException;
1213
import com.videogamescatalogue.backend.exception.InvalidInputException;
@@ -78,6 +79,14 @@ public UserResponseDto getUserInfo(Long userId, User authenticatedUser) {
7879

7980
@Override
8081
public UserResponseDto updateUserInfo(UpdateUserRequestDto requestDto, User authenticatedUser) {
82+
if (authenticatedUser == null) {
83+
throw new AccessNotAllowedException(
84+
"You are not allowed to modify this user info. Please log in."
85+
);
86+
}
87+
if (requestDto.profileName() != null) {
88+
checkProfileNameAlreadyExists(requestDto.profileName());
89+
}
8190
User updatedUser = userMapper.updateProfileInfo(authenticatedUser, requestDto);
8291
User savedUser = userRepository.save(updatedUser);
8392

@@ -90,6 +99,11 @@ public UserResponseDto updateUserInfo(UpdateUserRequestDto requestDto, User auth
9099
public UserResponseDto changePassword(
91100
ChangePasswordRequestDto requestDto, User authenticatedUser
92101
) {
102+
if (authenticatedUser == null) {
103+
throw new AccessNotAllowedException(
104+
"You are not allowed to modify this user info. Please log in."
105+
);
106+
}
93107
validateCurrentPassword(requestDto, authenticatedUser);
94108
checkPasswordsMatch(requestDto);
95109

@@ -127,8 +141,8 @@ private void checkUserAlreadyExistsByEmail(String email) {
127141

128142
private void checkProfileNameAlreadyExists(String profileName) {
129143
if (userRepository.existsByProfileNameIgnoreCase(profileName)) {
130-
throw new RegistrationException("Can't register user with profileName "
131-
+ profileName + ". This profileName is already in use.");
144+
throw new RegistrationException("Profile Name "
145+
+ profileName + " is already in use.");
132146
}
133147
}
134148

0 commit comments

Comments
 (0)