Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@
import com.videogamescatalogue.backend.dto.internal.GameSearchParameters;
import com.videogamescatalogue.backend.dto.internal.game.GameDto;
import com.videogamescatalogue.backend.dto.internal.game.GameWithStatusDto;
import com.videogamescatalogue.backend.model.Genre;
import com.videogamescatalogue.backend.model.Platform;
import com.videogamescatalogue.backend.model.User;
import com.videogamescatalogue.backend.service.game.GameService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -130,7 +126,6 @@ public Page<GameDto> search(
@PageableDefault(size = DEFAULT_PAGE_SIZE)
Pageable pageable
) {
validateSearchParams(searchParameters);
return gameService.search(searchParameters, pageable);
}

Expand All @@ -149,31 +144,4 @@ public Page<GameDto> apiSearch(
) {
return gameService.apiSearch(searchParams);
}

private void validateSearchParams(GameSearchParameters searchParameters) {
if (searchParameters.platforms() != null) {
try {
searchParameters.platforms()
.forEach(
p -> Platform.GeneralName.valueOf(p.toUpperCase())
);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
"Invalid platforms provided. Valid platforms: "
+ Arrays.stream(Platform.GeneralName.values())
.map(Enum::toString)
.collect(Collectors.joining(", ")), e);
}
}
if (searchParameters.genres() != null) {
try {
searchParameters.genres().forEach(g -> Genre.Name.valueOf(g.toUpperCase()));
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid genres provided. Valid genres: "
+ Arrays.stream(Genre.Name.values())
.map(Enum::toString)
.collect(Collectors.joining(", ")), e);
}
}
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/videogamescatalogue/backend/model/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.SQLDelete;
Expand All @@ -39,6 +40,7 @@ public class Game {

private String backgroundImage;

@EqualsAndHashCode.Exclude
@ManyToMany
@JoinTable(
name = "games_platforms",
Expand All @@ -48,6 +50,7 @@ public class Game {
)
private Set<Platform> platforms = new HashSet<>();

@EqualsAndHashCode.Exclude
@ManyToMany
@JoinTable(
name = "games_genres",
Expand All @@ -57,6 +60,7 @@ public class Game {
)
private Set<Genre> genres = new HashSet<>();

@EqualsAndHashCode.Exclude
@ManyToMany
@JoinTable(
name = "games_developers",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
import com.videogamescatalogue.backend.model.Game;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface GameRepository extends JpaRepository<Game, Long>, JpaSpecificationExecutor<Game> {
@EntityGraph(attributePaths = {
"platforms", "genres", "developers"
})
Optional<Game> findByApiId(Long apiId);

@EntityGraph(attributePaths = {
"platforms", "genres", "developers"
})
List<Game> findAllByApiIdIn(List<Long> apiIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ public boolean isValidToken(String token) {
}
}

private Jws<Claims> getAllClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(secret)
.build()
.parseClaimsJws(token);
}

public String getUsername(String token) {
return getSpecificClaim(token, Claims::getSubject);
}
Expand All @@ -56,4 +49,11 @@ private <T> T getSpecificClaim(String token, Function<Claims, T> claimsResolver)
Jws<Claims> allClaims = getAllClaims(token);
return claimsResolver.apply(allClaims.getBody());
}

private Jws<Claims> getAllClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(secret)
.build()
.parseClaimsJws(token);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public class RawgApiClient {
private static final String DATES_BETWEEN_URL_PART = "&dates=" + LocalDate.now()
+ "%2C" + LocalDate.now().minusMonths(12);
private static final String METACRITIC_URL_PART = "metacritic=80%2C100";
private static final int NUMBER_OF_DOWNLOAD_PORTIONS = 11;
private static final String REQUEST_HEADER_NAME = "User-Agent";
private static final String REQUEST_HEADER_VALUE = "VideoGamesCatalogue";

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

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

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

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

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

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Service
Expand All @@ -31,6 +32,7 @@ public class CommentServiceImpl implements CommentService {
private final GameMapper gameMapper;
private final CommentRepository commentRepository;

@Transactional
@Override
public CommentDto create(Long gameApiId, CreateCommentRequestDto requestDto, User user) {
Comment comment = commentMapper.toModel(requestDto);
Expand Down Expand Up @@ -61,11 +63,6 @@ public Page<CommentDto> getUserComments(
return findCommentsByUserId(userId, pageable);
}

private Page<CommentDto> findCommentsByUserId(Long userId, Pageable pageable) {
Page<Comment> userComments = commentRepository.findAllByUserId(userId, pageable);
return userComments.map(commentMapper::toDto);
}

@Override
public CommentDto update(Long commentId, UpdateCommentRequestDto requestDto, Long userId) {
Comment comment = commentRepository.findById(commentId)
Expand Down Expand Up @@ -94,6 +91,11 @@ public void delete(Long commentId, Long userId) {
commentRepository.deleteById(commentId);
}

private Page<CommentDto> findCommentsByUserId(Long userId, Pageable pageable) {
Page<Comment> userComments = commentRepository.findAllByUserId(userId, pageable);
return userComments.map(commentMapper::toDto);
}

private void existsByIdAndUserId(Long commentId, Long userId) {
if (!commentRepository.existsByIdAndUserId(commentId, userId)) {
throw new AccessNotAllowedException("User with id: " + userId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import com.videogamescatalogue.backend.dto.internal.game.GameDto;
import com.videogamescatalogue.backend.dto.internal.game.GameWithStatusDto;
import com.videogamescatalogue.backend.mapper.developer.DeveloperMapper;
import com.videogamescatalogue.backend.mapper.developer.DeveloperProvider;
import com.videogamescatalogue.backend.mapper.game.GameMapper;
import com.videogamescatalogue.backend.model.Developer;
import com.videogamescatalogue.backend.model.Game;
import com.videogamescatalogue.backend.model.Genre;
import com.videogamescatalogue.backend.model.Platform;
import com.videogamescatalogue.backend.model.User;
import com.videogamescatalogue.backend.model.UserGame;
import com.videogamescatalogue.backend.repository.DeveloperRepository;
Expand All @@ -18,6 +21,7 @@
import com.videogamescatalogue.backend.service.RawgApiClient;
import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -42,6 +46,7 @@ public class GameServiceImpl implements GameService {
private final SpecificationBuilder<Game, GameSearchParameters> specificationBuilder;
private final UserGameRepository userGameRepository;
private final DeveloperRepository developerRepository;
private final DeveloperProvider developerProvider;

@Override
public void fetchBestGames() {
Expand Down Expand Up @@ -108,6 +113,7 @@ public Page<GameDto> getAllGamesFromApi(Pageable pageable) {

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

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

private Game findOrUpdate(Long apiId) {
Optional<Game> gameOptional = gameRepository.findByApiId(apiId);
if (gameOptional.isPresent()
&& gameOptional.get().getDescription() != null
&& !gameOptional.get().getDevelopers().isEmpty()) {
return gameOptional.get();
}
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
if (gameOptional.isEmpty()) {
return findFromApi(apiId);
return gameMapper.toModel(apiGame);
}
Game game = gameOptional.get();
updateGameInfo(game, apiGame);
return game;
}

private void updateGameInfo(Game game, ApiResponseFullGameDto apiGame) {
if (game.getDescription() == null) {
updateGameDescription(apiId, game);
game.setDescription(apiGame.description());
}
if (game.getDevelopers().isEmpty()) {
updateGameDevelopers(apiId, game);
Set<Developer> developersSet = developerProvider.toDevelopersSet(apiGame.developers());
developerRepository.saveAll(developersSet);
game.setDevelopers(developersSet);
}
return game;
}

private void updateGameDescription(Long apiId, Game game) {
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
game.setDescription(apiGame.description());
gameRepository.save(game);
}

private void updateGameDevelopers(Long apiId, Game game) {
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
Set<Developer> developers = developerMapper.toModelSet(apiGame.developers());
developerRepository.saveAll(developers);
game.setDevelopers(developers);
gameRepository.save(game);
}

private Game findFromApi(Long apiId) {
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
return gameMapper.toModel(apiGame);
private void validateSearchParams(GameSearchParameters searchParameters) {
if (searchParameters.platforms() != null) {
try {
searchParameters.platforms()
.forEach(
p -> Platform.GeneralName.valueOf(p.toUpperCase())
);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
"Invalid platforms provided. Valid platforms: "
+ Arrays.stream(Platform.GeneralName.values())
.map(Enum::toString)
.collect(Collectors.joining(", ")), e);
}
}
if (searchParameters.genres() != null) {
try {
searchParameters.genres().forEach(g -> Genre.Name.valueOf(g.toUpperCase()));
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid genres provided. Valid genres: "
+ Arrays.stream(Genre.Name.values())
.map(Enum::toString)
.collect(Collectors.joining(", ")), e);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.videogamescatalogue.backend.dto.internal.user.UserRegistrationRequestDto;
import com.videogamescatalogue.backend.dto.internal.user.UserRegistrationResponseDto;
import com.videogamescatalogue.backend.dto.internal.user.UserResponseDto;
import com.videogamescatalogue.backend.exception.AccessNotAllowedException;
import com.videogamescatalogue.backend.exception.AuthenticationRequiredException;
import com.videogamescatalogue.backend.exception.EntityNotFoundException;
import com.videogamescatalogue.backend.exception.InvalidInputException;
Expand Down Expand Up @@ -78,6 +79,14 @@ public UserResponseDto getUserInfo(Long userId, User authenticatedUser) {

@Override
public UserResponseDto updateUserInfo(UpdateUserRequestDto requestDto, User authenticatedUser) {
if (authenticatedUser == null) {
throw new AccessNotAllowedException(
"You are not allowed to modify this user info. Please log in."
);
}
if (requestDto.profileName() != null) {
checkProfileNameAlreadyExists(requestDto.profileName());
}
User updatedUser = userMapper.updateProfileInfo(authenticatedUser, requestDto);
User savedUser = userRepository.save(updatedUser);

Expand All @@ -90,6 +99,11 @@ public UserResponseDto updateUserInfo(UpdateUserRequestDto requestDto, User auth
public UserResponseDto changePassword(
ChangePasswordRequestDto requestDto, User authenticatedUser
) {
if (authenticatedUser == null) {
throw new AccessNotAllowedException(
"You are not allowed to modify this user info. Please log in."
);
}
validateCurrentPassword(requestDto, authenticatedUser);
checkPasswordsMatch(requestDto);

Expand Down Expand Up @@ -127,8 +141,8 @@ private void checkUserAlreadyExistsByEmail(String email) {

private void checkProfileNameAlreadyExists(String profileName) {
if (userRepository.existsByProfileNameIgnoreCase(profileName)) {
throw new RegistrationException("Can't register user with profileName "
+ profileName + ". This profileName is already in use.");
throw new RegistrationException("Profile Name "
+ profileName + " is already in use.");
}
}

Expand Down