Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into fix/webapp/game
Browse files Browse the repository at this point in the history
  • Loading branch information
jjgancfer committed Apr 19, 2024
2 parents aac5620 + 637ea18 commit be901da
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 78 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,32 @@ jobs:
DATABASE_PASSWORD
JWT_SECRET
SSL_PASSWORD
docker-push-prometheus:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
with:
name: arquisoft/wiq_en2b/prometheus
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: api/monitoring/prometheus
docker-push-grafana:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
with:
name: arquisoft/wiq_en2b/grafana
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: api/monitoring/grafana
docker-push-kiwiq:
runs-on: ubuntu-latest
needs: [ e2e-tests ]
Expand Down
14 changes: 14 additions & 0 deletions api/monitoring/grafana/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM grafana/grafana
LABEL authors="dario"
# Define the source and destination directories
COPY_SOURCE = ./provisioning
COPY_DESTINATION = /etc/grafana/provisioning

# Copy the configuration files
COPY ${COPY_SOURCE}/* ${COPY_DESTINATION}

# Expose the default Grafana port
EXPOSE 9091

# Run Grafana in the foreground
CMD ["grafana-server"]
14 changes: 14 additions & 0 deletions api/monitoring/prometheus/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM prom/prometheus
LABEL authors="dario"
# Define the source and destination directories
COPY_SOURCE = ./configuration
COPY_DESTINATION = /etc/prometheus

# Copy the configuration files
COPY ${COPY_SOURCE}/* ${COPY_DESTINATION}

# Expose the default Prometheus port
EXPOSE 9090

# Run Prometheus in the foreground
CMD ["prometheus"]
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ scrape_configs:
metrics_path: '/actuator/prometheus'
scrape_interval: 10s
static_configs:
- targets: ['host.docker.internal:8080']
- targets: ['host.docker.internal:8443']
labels:
application: 'WIQ API'
182 changes: 125 additions & 57 deletions api/src/main/java/lab/en2b/quizapi/commons/utils/GameModeUtils.java
Original file line number Diff line number Diff line change
@@ -1,57 +1,125 @@
package lab.en2b.quizapi.commons.utils;

import lab.en2b.quizapi.game.Game;
import lab.en2b.quizapi.game.GameMode;
import lab.en2b.quizapi.questions.question.QuestionCategory;

import java.util.List;

import static lab.en2b.quizapi.game.GameMode.KIWI_QUEST;

public class GameModeUtils {
public static List<QuestionCategory> getQuestionCategoriesForGamemode(GameMode gamemode, List<QuestionCategory> questionCategoriesForCustom){
if(gamemode == null){
gamemode = KIWI_QUEST;
}
return switch (gamemode) {
case KIWI_QUEST -> List.of(QuestionCategory.ART, QuestionCategory.MUSIC, QuestionCategory.GEOGRAPHY);
case FOOTBALL_SHOWDOWN -> List.of(QuestionCategory.SPORTS);
case GEO_GENIUS -> List.of(QuestionCategory.GEOGRAPHY);
case VIDEOGAME_ADVENTURE -> List.of(QuestionCategory.VIDEOGAMES);
case ANCIENT_ODYSSEY -> List.of(QuestionCategory.MUSIC,QuestionCategory.ART);
case RANDOM -> List.of(QuestionCategory.values());
case CUSTOM -> questionCategoriesForCustom;
};
}
public static void setGamemodeParams(Game game){
switch(game.getGamemode()){
case KIWI_QUEST:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case FOOTBALL_SHOWDOWN:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case GEO_GENIUS:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case VIDEOGAME_ADVENTURE:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case ANCIENT_ODYSSEY:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case RANDOM:
game.setRounds(9L);
game.setRoundDuration(30);
break;
default:
game.setRounds(9L);
game.setRoundDuration(30);
}
}
}
package lab.en2b.quizapi.commons.utils;

import lab.en2b.quizapi.game.Game;
import lab.en2b.quizapi.game.GameMode;
import lab.en2b.quizapi.questions.question.QuestionCategory;
import lab.en2b.quizapi.questions.question.dtos.QuestionCategoryDto;

import java.util.List;

import static lab.en2b.quizapi.game.GameMode.KIWI_QUEST;

public class GameModeUtils {
public static List<QuestionCategory> getQuestionCategoriesForGamemode(GameMode gamemode, List<QuestionCategory> questionCategoriesForCustom){
if(gamemode == null){
gamemode = KIWI_QUEST;
}
return switch (gamemode) {
case KIWI_QUEST -> List.of(QuestionCategory.ART, QuestionCategory.MUSIC, QuestionCategory.GEOGRAPHY);
case FOOTBALL_SHOWDOWN -> List.of(QuestionCategory.SPORTS);
case GEO_GENIUS -> List.of(QuestionCategory.GEOGRAPHY);
case VIDEOGAME_ADVENTURE -> List.of(QuestionCategory.VIDEOGAMES);
case ANCIENT_ODYSSEY -> List.of(QuestionCategory.MUSIC,QuestionCategory.ART);
case RANDOM -> List.of(QuestionCategory.values());
case CUSTOM -> questionCategoriesForCustom;
};
}
public static void setGamemodeParams(Game game){
switch(game.getGamemode()){
case KIWI_QUEST:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case FOOTBALL_SHOWDOWN:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case GEO_GENIUS:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case VIDEOGAME_ADVENTURE:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case ANCIENT_ODYSSEY:
game.setRounds(9L);
game.setRoundDuration(30);
break;
case RANDOM:
game.setRounds(9L);
game.setRoundDuration(30);
break;
default:
game.setRounds(9L);
game.setRoundDuration(30);
}
}

public static List<QuestionCategoryDto> getQuestionCategories(String lang) {
if(lang == null)
lang = "en";
if(lang.equals("en"))
return getQuestionCategoriesEn();
return getQuestionCategoriesEs();
}
private static List<QuestionCategoryDto> getQuestionCategoriesEn(){
return List.of(
QuestionCategoryDto.builder()
.name("Art")
.description("Are you an art expert? Prove it!")
.internalRepresentation(QuestionCategory.ART)
.build(),
QuestionCategoryDto.builder()
.name("Music")
.description("Are you a music lover? Prove it!")
.internalRepresentation(QuestionCategory.MUSIC)
.build(),
QuestionCategoryDto.builder()
.name("Geography")
.description("Are you a geography expert? Prove it!")
.internalRepresentation(QuestionCategory.GEOGRAPHY)
.build(),
QuestionCategoryDto.builder()
.name("Sports")
.description("Are you a sports fanatic? Prove it!")
.internalRepresentation(QuestionCategory.SPORTS)
.build(),
QuestionCategoryDto.builder()
.name("Video Games")
.description("Are you a gamer? Prove it!")
.internalRepresentation(QuestionCategory.VIDEOGAMES)
.build()
);
}

private static List<QuestionCategoryDto> getQuestionCategoriesEs(){
return List.of(
QuestionCategoryDto.builder()
.name("Arte")
.description("¿Eres un experto en arte? ¡Demuéstralo!")
.internalRepresentation(QuestionCategory.ART)
.build(),
QuestionCategoryDto.builder()
.name("Música")
.description("¿Eres un melómano? ¡Demuéstralo!")
.internalRepresentation(QuestionCategory.MUSIC)
.build(),
QuestionCategoryDto.builder()
.name("Geografía")
.description("¿Eres un experto en geografía? ¡Demuéstralo!")
.internalRepresentation(QuestionCategory.GEOGRAPHY)
.build(),
QuestionCategoryDto.builder()
.name("Deportes")
.description("¿Eres un fanático de los deportes? ¡Demuéstralo!")
.internalRepresentation(QuestionCategory.SPORTS)
.build(),
QuestionCategoryDto.builder()
.name("Videojuegos")
.description("¿Eres un gamer? ¡Demuéstralo!")
.internalRepresentation(QuestionCategory.VIDEOGAMES)
.build()
);
}
}
5 changes: 3 additions & 2 deletions api/src/main/java/lab/en2b/quizapi/game/GameController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import jakarta.validation.Valid;
import lab.en2b.quizapi.game.dtos.*;
import lab.en2b.quizapi.questions.question.QuestionCategory;
import lab.en2b.quizapi.questions.question.dtos.QuestionCategoryDto;
import lab.en2b.quizapi.questions.question.dtos.QuestionResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -133,8 +134,8 @@ public ResponseEntity<List<GameModeDto>> getQuestionGameModes(){
@ApiResponse(responseCode = "403", description = "You are not logged in", content = @io.swagger.v3.oas.annotations.media.Content)
})
@GetMapping("/question-categories")
public ResponseEntity<List<QuestionCategory>> getQuestionCategories(){
return ResponseEntity.ok(gameService.getQuestionCategories());
public ResponseEntity<List<QuestionCategoryDto>> getQuestionCategories(@RequestParam(required = false) String lang){
return ResponseEntity.ok(gameService.getQuestionCategories(lang));
}

}
6 changes: 4 additions & 2 deletions api/src/main/java/lab/en2b/quizapi/game/GameService.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package lab.en2b.quizapi.game;

import lab.en2b.quizapi.commons.user.UserService;
import lab.en2b.quizapi.commons.utils.GameModeUtils;
import lab.en2b.quizapi.game.dtos.*;
import lab.en2b.quizapi.game.mappers.GameResponseDtoMapper;
import lab.en2b.quizapi.questions.question.QuestionCategory;
import lab.en2b.quizapi.questions.question.QuestionService;
import lab.en2b.quizapi.questions.question.dtos.QuestionCategoryDto;
import lab.en2b.quizapi.questions.question.dtos.QuestionResponseDto;
import lab.en2b.quizapi.questions.question.mappers.QuestionResponseDtoMapper;
import lab.en2b.quizapi.statistics.Statistics;
Expand Down Expand Up @@ -151,8 +153,8 @@ public GameResponseDto getGameDetails(Long id, Authentication authentication) {
return gameResponseDtoMapper.apply(game);
}

public List<QuestionCategory> getQuestionCategories() {
return Arrays.asList(QuestionCategory.values());
public List<QuestionCategoryDto> getQuestionCategories(String lang) {
return GameModeUtils.getQuestionCategories(lang);
}

private boolean wasGameMeantToBeOver(Game game) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lab.en2b.quizapi.questions.question;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
Expand All @@ -12,6 +13,8 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/questions")
@RequiredArgsConstructor
Expand Down Expand Up @@ -47,4 +50,16 @@ private ResponseEntity<QuestionResponseDto> generateQuestion(@RequestParam(requi
private ResponseEntity<QuestionResponseDto> getQuestionById(@PathVariable @PositiveOrZero Long id){
return ResponseEntity.ok(questionService.getQuestionById(id));
}

@Operation(summary = "Gets a list of questions", description = "Gets a list of questions given a page number")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Successfully retrieved"),
@ApiResponse(responseCode = "404", description = "Not found - There are no questions", content = @io.swagger.v3.oas.annotations.media.Content),
@ApiResponse(responseCode = "400", description = "Bad request - The page number is invalid", content = @io.swagger.v3.oas.annotations.media.Content)
})
@Parameter(name = "page", description = "The page number. Cannot be lower or equal to 0.", required = true)
@GetMapping
private ResponseEntity<List<QuestionResponseDto>> getQuestions(@RequestParam Long page){
return ResponseEntity.ok(questionService.getQuestionsWithPage(page));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,33 @@ public QuestionResponseDto getQuestionById(Long id) {
return questionResponseDtoMapper.apply(q);
}

/**
* Get a list of questions with a page
* @param page The page number
* @return the list of questions
*/
public List<QuestionResponseDto> getQuestionsWithPage(Long page){
if (page < 1)
throw new IllegalArgumentException("Invalid page number");
List<QuestionResponseDto> result = questionRepository.findAll().stream()
.map(questionResponseDtoMapper).toList();
return getPage(result, page);
}

private List<QuestionResponseDto> getPage(List<QuestionResponseDto> result, Long page) {
try{
int QUESTION_PAGE_SIZE = 100;
int startIndex = Math.toIntExact((page-1)* QUESTION_PAGE_SIZE);
if(startIndex > result.size())
throw new IllegalArgumentException("Invalid page number, maximum page is "+(result.size()/ QUESTION_PAGE_SIZE +1) + " and you requested page "+page);
if (result.size() < page* QUESTION_PAGE_SIZE)
return result.subList(startIndex,result.size());
return result.subList(startIndex, Math.toIntExact(page* QUESTION_PAGE_SIZE));
} catch (ArithmeticException e) {
throw new IllegalArgumentException("Invalid page number");
}

}

/**
* Load the answers for a question (The distractors and the correct one)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package lab.en2b.quizapi.questions.question.dtos;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lab.en2b.quizapi.questions.question.QuestionCategory;
import lombok.*;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Setter
public class QuestionCategoryDto {
@Schema(description = "Beautified name of the question category",example = "Sports")
private String name;
@Schema(description = "Description of the question category",example = "Test description of the question category")
private String description;
@JsonProperty("internal_representation")
@Schema(description = "Internal code used for describing the question category",example = "SPORTS")
private QuestionCategory internalRepresentation;
}
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ public void getGameDetailsInvalidId(){

@Test
public void testGetQuestionCategories(){
assertEquals(Arrays.asList(QuestionCategory.values()), gameService.getQuestionCategories());
assertEquals(QuestionCategory.values().length, gameService.getQuestionCategories(null).size());
}

@Test
Expand Down
Loading

0 comments on commit be901da

Please sign in to comment.