Skip to content

Commit

Permalink
Merge pull request #211 from Arquisoft/admin-view
Browse files Browse the repository at this point in the history
Admin view
  • Loading branch information
Pelayori authored Apr 26, 2024
2 parents eec984f + 35ecb0f commit 8d6c06e
Show file tree
Hide file tree
Showing 46 changed files with 1,143 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class QuestionGeneratorV2 implements QuestionGenerator{

Expand All @@ -27,6 +29,8 @@ public class QuestionGeneratorV2 implements QuestionGenerator{
private String answer_placeholder;
private String language;

private Random random = new SecureRandom();

public QuestionGeneratorV2(JsonNode jsonNode) {
this.jsonNode = jsonNode;
this.language_placeholder = jsonNode.get("language_placeholder").textValue();
Expand Down Expand Up @@ -103,8 +107,8 @@ private List<Answer> generateOptions(JsonNode results, String correctAnswer, Str
int size = results.size();
int tries = 0;

while (options.size() < 3 && tries < 10){
int random = (int) (Math.random() * size);
while (options.size() < 3 && tries < 10) {
int random = (int) (this.random.nextFloat() * size);
String option = results.get(random).path(answerLabel).path("value").asText();
if (!option.equals(correctAnswer) && !usedOptions.contains(option) ) {
usedOptions.add(option);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/uniovi/configuration/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.requestMatchers("/api/**").permitAll()
.requestMatchers("/game/**").authenticated()
.requestMatchers("/ranking/playerRanking").authenticated()
.requestMatchers("/player/admin/**").hasAuthority("ROLE_ADMIN")
.requestMatchers("/**").permitAll()
).formLogin(
form -> form
Expand Down
11 changes: 1 addition & 10 deletions src/main/java/com/uniovi/controllers/GameController.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,23 @@ public String getCheckResult(@PathVariable Long idQuestion, @PathVariable Long i

if(idAnswer == -1
|| getRemainingTime(gameSession) <= 0) {
//model.addAttribute("correctAnswer", gameSession.getCurrentQuestion().getCorrectAnswer());
//model.addAttribute("messageKey", "timeRunOut.result");
//model.addAttribute("logoImage", "/images/logo_incorrect.svg");
gameSession.addAnsweredQuestion(gameSession.getCurrentQuestion());
gameSession.addQuestion(false, 0);
}
else if(questionService.checkAnswer(idQuestion, idAnswer)) {
//model.addAttribute("messageKey", "correctAnswer.result");
//model.addAttribute("logoImage", "/images/logo_correct.svg");

if (!gameSession.isAnswered(gameSession.getCurrentQuestion())) {
gameSession.addQuestion(true, getRemainingTime(gameSession));
gameSession.addAnsweredQuestion(gameSession.getCurrentQuestion());
}

} else {
//model.addAttribute("correctAnswer", gameSession.getCurrentQuestion().getCorrectAnswer());
//model.addAttribute("messageKey", "failedAnswer.result");
//model.addAttribute("logoImage", "/images/logo_incorrect.svg");
gameSession.addAnsweredQuestion(gameSession.getCurrentQuestion());
gameSession.addQuestion(false, 0);
}

session.setAttribute("hasJustAnswered", true);
gameSession.getNextQuestion();
//return "game/fragments/questionResult";

return updateGame(model, session);
}

Expand Down
178 changes: 171 additions & 7 deletions src/main/java/com/uniovi/controllers/PlayersController.java
Original file line number Diff line number Diff line change
@@ -1,42 +1,56 @@
package com.uniovi.controllers;

import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.uniovi.configuration.SecurityConfig;
import com.uniovi.dto.RoleDto;
import com.uniovi.entities.Associations;
import com.uniovi.entities.GameSession;
import com.uniovi.entities.Player;
import com.uniovi.services.GameSessionService;
import com.uniovi.services.PlayerService;
import com.uniovi.entities.Role;
import com.uniovi.services.*;
import com.uniovi.validators.SignUpValidator;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.*;
import com.uniovi.dto.PlayerDto;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Principal;
import java.util.Optional;
import java.util.List;

@Controller
public class PlayersController {
private final PlayerService playerService;
private final RoleService roleService;
private QuestionService questionService;
private final SignUpValidator signUpValidator;

private final GameSessionService gameSessionService;

@Autowired
public PlayersController(PlayerService playerService, SignUpValidator signUpValidator, GameSessionService gameSessionService) {
public PlayersController(PlayerService playerService, SignUpValidator signUpValidator, GameSessionService gameSessionService,
RoleService roleService, QuestionService questionService) {
this.playerService = playerService;
this.signUpValidator = signUpValidator;
this.gameSessionService = gameSessionService;
this.roleService = roleService;
}

@GetMapping("/signup")
Expand Down Expand Up @@ -122,4 +136,154 @@ public String showPlayerRanking(Pageable pageable, Model model, Principal princi

return "ranking/playerRanking";
}

// ----- Admin endpoints -----

@GetMapping("/player/admin")
public String showAdminPanel(Model model) {
return "player/admin/admin";
}

@GetMapping("/player/admin/userManagement")
public String showUserManagementFragment(Model model, Pageable pageable) {
model.addAttribute("endpoint", "/player/admin/userManagement");
Page<Player> users = playerService.getPlayersPage(pageable);
model.addAttribute("page", users);
model.addAttribute("users", users.getContent());

return "player/admin/userManagement";
}

@GetMapping("/player/admin/deleteUser")
@ResponseBody
public String deleteUser(HttpServletResponse response, @RequestParam String username, Principal principal) {
Player player = playerService.getUserByUsername(username).orElse(null);
if (player == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return "User not found";
}

if (principal.getName().equals(player.getUsername())) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return "You can't delete yourself";
}

playerService.deletePlayer(player.getId());
return "User deleted";
}

@GetMapping("/player/admin/changePassword")
@ResponseBody
public String changePassword(HttpServletResponse response, @RequestParam String username, @RequestParam String password) {
Player player = playerService.getUserByUsername(username).orElse(null);
if (player == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return "User not found";
}

playerService.updatePassword(player, password);
return "User password changed";
}

@GetMapping("/player/admin/getRoles")
@ResponseBody
public String getRoles(@RequestParam String username) {
List<Role> roles = roleService.getAllRoles();
Player player = playerService.getUserByUsername(username).orElse(null);

roles.remove(roleService.getRole("ROLE_USER"));

if (player == null) {
return "{}";
}

ObjectMapper mapper = new ObjectMapper();
ObjectNode rolesJson = mapper.createObjectNode();
for (Role role : roles) {
boolean hasRole = player.getRoles().contains(role);
rolesJson.put(role.getName(), hasRole);
}

return rolesJson.toString();
}

@GetMapping("/player/admin/changeRoles")
@ResponseBody
public String changeRoles(HttpServletResponse response, @RequestParam String username, @RequestParam String roles) {
Player player = playerService.getUserByUsername(username).orElse(null);
if (player == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return "User not found";
}

JsonNode rolesJson;
try {
rolesJson = new ObjectMapper().readTree(roles);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return "Invalid roles";
}

rolesJson.fieldNames().forEachRemaining(roleName -> {
boolean hasRole = rolesJson.get(roleName).asBoolean();

Role role = roleService.getRole(roleName);
if (role == null && !hasRole) {
return;
} else if (role == null) {
role = roleService.addRole(new RoleDto(roleName));
}

if (hasRole) {
Associations.PlayerRole.addRole(player, role);
} else {
Associations.PlayerRole.removeRole(player, role);
}
});

playerService.savePlayer(player);
return "User roles changed";
}

@GetMapping("/player/admin/questionManagement")
public String showQuestionManagementFragment(Model model) throws IOException {
File jsonFile = new File(QuestionGeneratorService.jsonFilePath);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode json = objectMapper.readTree(jsonFile);
model.addAttribute("jsonContent", json.toString());

return "player/admin/questionManagement";
}

@GetMapping("/player/admin/deleteAllQuestions")
@ResponseBody
public String deleteAllQuestions() {
questionService.deleteAllQuestions();
return "Questions deleted";
}

@GetMapping("/player/admin/saveQuestions")
@ResponseBody
public String saveQuestions(HttpServletResponse response, @RequestParam String json) throws IOException {
try {
JsonNode node = new ObjectMapper().readTree(json);
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter();
printer.indentObjectsWith(indenter); // Indent JSON objects
printer.indentArraysWith(indenter); // Indent JSON arrays

ObjectMapper mapper = new ObjectMapper();
mapper.writer(printer).writeValue(new FileOutputStream(QuestionGeneratorService.jsonFilePath), node);
return "Questions saved";
}
catch (Exception e) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return "Invalid JSON";
}
}

@GetMapping("/player/admin/monitoring")
public String showMonitoring(Model model) {
return "player/admin/monitoring";
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/uniovi/entities/Role.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ public class Role {
public Role(String name) {
this.name = name;
}

@Override
public String toString() {
return name;
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/uniovi/repositories/PlayerRepository.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.uniovi.repositories;

import com.uniovi.entities.Player;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;

public interface PlayerRepository extends CrudRepository<Player, Long> {
Player findByEmail(String email);
Player findByUsername(String nickname);

Page<Player> findAll(Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,15 @@ public InsertSampleDataService(PlayerService playerService, QuestionService ques
@Transactional
@EventListener(ApplicationReadyEvent.class) // Uncomment this line to insert sample data on startup
public void insertSampleQuestions() throws InterruptedException, IOException {
if (!playerService.getUserByEmail("[email protected]").isPresent()) {
if (playerService.getUserByEmail("[email protected]").isEmpty()) {
PlayerDto player = new PlayerDto();
player.setEmail("[email protected]");
player.setUsername("test");
player.setPassword("test");
player.setRoles(new String[]{"ROLE_USER"});
if (Arrays.asList(environment.getActiveProfiles()).contains("test"))
player.setRoles(new String[]{"ROLE_USER", "ROLE_ADMIN"});
else
player.setRoles(new String[]{"ROLE_USER"});
playerService.generateApiKey(playerService.addNewPlayer(player));
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/uniovi/services/PlayerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.uniovi.entities.Player;
import com.uniovi.repositories.PlayerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;
Expand Down Expand Up @@ -72,4 +74,24 @@ public interface PlayerService {
* @param id The id of the player to delete
*/
void deletePlayer(Long id);

/**
* Get a page with all the players in the database
* @param pageable The page information
* @return A page with all the players
*/
Page<Player> getPlayersPage(Pageable pageable);

/**
* Update the password of a player
* @param player The player to update the password
* @param password The new password
*/
void updatePassword(Player player, String password);

/**
* Save a player in the database
* @param player The player to save
*/
void savePlayer(Player player);
}
Loading

0 comments on commit 8d6c06e

Please sign in to comment.