Skip to content
This repository was archived by the owner on Aug 21, 2025. It is now read-only.
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
@@ -1,7 +1,9 @@
package fr.funixgaming.api.funixbot.client.dtos;

import com.funixproductions.core.crud.dtos.ApiDTO;
import fr.funixgaming.api.funixbot.client.enums.FunixBotCommandType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -11,6 +13,9 @@ public class FunixBotCommandDTO extends ApiDTO {
@NotBlank
private String command;

@NotNull
private FunixBotCommandType type;

@NotBlank
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package fr.funixgaming.api.funixbot.client.enums;

public enum FunixBotCommandType {
INFO,
VIEWER,
MODERATION,
FUN,
OTHER
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package fr.funixgaming.api.funixbot.service.entities;

import com.funixproductions.core.crud.entities.ApiEntity;
import fr.funixgaming.api.funixbot.client.enums.FunixBotCommandType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import lombok.Getter;
import lombok.Setter;

Expand All @@ -13,6 +16,10 @@ public class FunixBotCommand extends ApiEntity {
@Column(nullable = false, unique = true, length = 30)
private String command;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
@Column(nullable = false, columnDefinition = "varchar(200) DEFAULT 'OTHER'")
private FunixBotCommandType type;

@Column(nullable = false, length = 500)
private String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import fr.funixgaming.api.funixbot.service.entities.FunixBotCommand;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface FunixBotCommandRepository extends ApiRepository<FunixBotCommand> {
Optional<FunixBotCommand> findByCommand(String command);
boolean existsFunixBotCommandByCommandContainsIgnoreCase(String command);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,61 @@
package fr.funixgaming.api.funixbot.service.services;

import com.funixproductions.core.crud.services.ApiService;
import com.funixproductions.core.exceptions.ApiBadRequestException;
import fr.funixgaming.api.funixbot.client.dtos.FunixBotCommandDTO;
import fr.funixgaming.api.funixbot.service.entities.FunixBotCommand;
import fr.funixgaming.api.funixbot.service.mappers.FunixBotCommandMapper;
import fr.funixgaming.api.funixbot.service.repositories.FunixBotCommandRepository;
import lombok.NonNull;
import org.springframework.stereotype.Service;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class FunixBotCommandsService extends ApiService<FunixBotCommandDTO, FunixBotCommand, FunixBotCommandMapper, FunixBotCommandRepository> {

private static final int MAX_LEN_MESSAGE = 500;
private static final int MAX_LEN_COMMAND = 30;
private static final String ERROR_MESSAGE_COMMAND_MAX_LEN = String.format("La commande ne peut pas dépasser %d caractères.", MAX_LEN_COMMAND);
private static final String ERROR_MESSAGE_MAX_LEN = String.format("Le message de la commande ne peut pas dépasser %d caractères.", MAX_LEN_MESSAGE);
private static final String ERROR_MESSAGE_NOT_ALPHANUMERIC = "La commande ne peut contenir que des caractères alphanumériques.";
private final Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+$");

public FunixBotCommandsService(FunixBotCommandRepository repository,
FunixBotCommandMapper mapper) {
super(repository, mapper);
}

@Override
public void beforeMappingToEntity(@NonNull Iterable<FunixBotCommandDTO> request) {
for (FunixBotCommandDTO command : request) {
if (command.getMessage().length() > MAX_LEN_MESSAGE) {
throw new ApiBadRequestException(ERROR_MESSAGE_MAX_LEN);
}

if (command.getCommand().startsWith("!")) {
command.setCommand(command.getCommand().substring(1));
}
if (command.getCommand().length() > MAX_LEN_COMMAND) {
throw new ApiBadRequestException(ERROR_MESSAGE_COMMAND_MAX_LEN);
}

if (!isAlphanumeric(command.getCommand())) {
throw new ApiBadRequestException(ERROR_MESSAGE_NOT_ALPHANUMERIC);
}

if (super.getRepository().existsFunixBotCommandByCommandContainsIgnoreCase(command.getCommand())) {
throw new ApiBadRequestException(String.format("La commande '%s' existe déjà.", command.getCommand()));
}

command.setCommand(command.getCommand().toLowerCase());
}
}

private boolean isAlphanumeric(String input) {
Matcher matcher = pattern.matcher(input);
return matcher.matches();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE funixbot_commands ADD COLUMN type VARCHAR(200) DEFAULT 'OTHER' NOT NULL;

ALTER TABLE funixbot_commands ALTER COLUMN message TYPE VARCHAR(500);
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
package fr.funixgaming.api.funixbot.service.resources;

import com.funixproductions.api.user.client.clients.UserAuthClient;
import com.funixproductions.api.user.client.dtos.UserDTO;
import com.funixproductions.api.user.client.enums.UserRole;
import com.funixproductions.core.test.beans.JsonHelper;
import fr.funixgaming.api.funixbot.client.dtos.FunixBotCommandDTO;
import fr.funixgaming.api.funixbot.client.enums.FunixBotCommandType;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
Expand All @@ -16,10 +30,152 @@ class FunixBotCommandResourceTest {
@Autowired
private MockMvc mockMvc;

@Autowired
private JsonHelper jsonHelper;

@MockBean
private UserAuthClient userAuthClient;

@Test
void testGetCommands() throws Exception {
mockMvc.perform(get("/funixbot/command"))
.andExpect(status().isOk());
}

@Test
void testCreateCommandNoAccess() throws Exception {
final UserDTO userDTO = new UserDTO();
userDTO.setRole(UserRole.USER);
userDTO.setUsername(UUID.randomUUID().toString());
userDTO.setEmail(UUID.randomUUID().toString());
userDTO.setId(UUID.randomUUID());
userDTO.setValid(true);
when(userAuthClient.current(any())).thenReturn(userDTO);

mockMvc.perform(post("/funixbot/command"))
.andExpect(status().isUnauthorized());

mockMvc.perform(post("/funixbot/command")
.header("Authorization", "Bearer " + UUID.randomUUID()))
.andExpect(status().isForbidden());

mockMvc.perform(patch("/funixbot/command")
.header("Authorization", "Bearer " + UUID.randomUUID()))
.andExpect(status().isForbidden());
}

@Test
void testCreateAndEditCommand() throws Exception {
final UserDTO userDTO = new UserDTO();
userDTO.setRole(UserRole.MODERATOR);
userDTO.setUsername(UUID.randomUUID().toString());
userDTO.setEmail(UUID.randomUUID().toString());
userDTO.setId(UUID.randomUUID());
userDTO.setValid(true);
when(userAuthClient.current(any())).thenReturn(userDTO);

final String commandName = "tEst1";
final FunixBotCommandDTO commandDTO = new FunixBotCommandDTO();
commandDTO.setCommand("!" + commandName);
commandDTO.setMessage("testMessage");
commandDTO.setType(FunixBotCommandType.FUN);

MvcResult mvcResult = mockMvc.perform(post("/funixbot/command")
.header("Authorization", "Bearer " + UUID.randomUUID())
.contentType(MediaType.APPLICATION_JSON)
.content(jsonHelper.toJson(commandDTO)))
.andExpect(status().isOk()).andReturn();
final FunixBotCommandDTO createdCommand = jsonHelper.fromJson(mvcResult.getResponse().getContentAsString(), FunixBotCommandDTO.class);
assertEquals(commandName.toLowerCase(), createdCommand.getCommand());
createdCommand.setCommand("test2patched");

mvcResult = mockMvc.perform(patch("/funixbot/command")
.header("Authorization", "Bearer " + UUID.randomUUID())
.contentType(MediaType.APPLICATION_JSON)
.content(jsonHelper.toJson(createdCommand)))
.andExpect(status().isOk()).andReturn();
final FunixBotCommandDTO editedCommand = jsonHelper.fromJson(mvcResult.getResponse().getContentAsString(), FunixBotCommandDTO.class);
assertEquals(createdCommand.getCommand(), editedCommand.getCommand());
}

@Test
void testCreateCommandWithCommandTooLong() throws Exception {
final FunixBotCommandDTO commandDTO = new FunixBotCommandDTO();
commandDTO.setCommand("testdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdgh");
commandDTO.setMessage("testMessage");
commandDTO.setType(FunixBotCommandType.FUN);

handleBadRequest(commandDTO);
}

@Test
void testCreateCommandWithMessageTooLong() throws Exception {
final FunixBotCommandDTO commandDTO = new FunixBotCommandDTO();
commandDTO.setCommand("test");
commandDTO.setMessage("testdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdghtestdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdghtestdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdghtestdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdghtestdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdghtestdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdghtestdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdghtestdfgldfskghdflkghdflskgjhdfslkgjhdflkgjhdskflhfghdgfhdgfhdfghdfghfdghfdgh");
commandDTO.setType(FunixBotCommandType.FUN);

handleBadRequest(commandDTO);
}

@Test
void testCreateCommandNotAlphanumeric() throws Exception {
final FunixBotCommandDTO commandDTO = new FunixBotCommandDTO();
commandDTO.setCommand("test!");
commandDTO.setMessage("testMessage");
commandDTO.setType(FunixBotCommandType.FUN);

handleBadRequest(commandDTO);

commandDTO.setCommand("test@");
handleBadRequest(commandDTO);
commandDTO.setCommand("test#");
handleBadRequest(commandDTO);
}

@Test
void testCreateDuplicateCommands() throws Exception {
final FunixBotCommandDTO commandDTO = new FunixBotCommandDTO();
commandDTO.setCommand("testDupplicateCmd");
commandDTO.setMessage("testMessage");
commandDTO.setType(FunixBotCommandType.FUN);

final UserDTO userDTO = new UserDTO();
userDTO.setRole(UserRole.MODERATOR);
userDTO.setUsername(UUID.randomUUID().toString());
userDTO.setEmail(UUID.randomUUID().toString());
userDTO.setId(UUID.randomUUID());
userDTO.setValid(true);
when(userAuthClient.current(any())).thenReturn(userDTO);

mockMvc.perform(post("/funixbot/command")
.header("Authorization", "Bearer " + UUID.randomUUID())
.contentType(MediaType.APPLICATION_JSON)
.content(jsonHelper.toJson(commandDTO)))
.andExpect(status().isOk());

commandDTO.setId(null);
mockMvc.perform(post("/funixbot/command")
.header("Authorization", "Bearer " + UUID.randomUUID())
.contentType(MediaType.APPLICATION_JSON)
.content(jsonHelper.toJson(commandDTO)))
.andExpect(status().isBadRequest());
}

private void handleBadRequest(final FunixBotCommandDTO commandDTO) throws Exception {
final UserDTO userDTO = new UserDTO();
userDTO.setRole(UserRole.MODERATOR);
userDTO.setUsername(UUID.randomUUID().toString());
userDTO.setEmail(UUID.randomUUID().toString());
userDTO.setId(UUID.randomUUID());
userDTO.setValid(true);
when(userAuthClient.current(any())).thenReturn(userDTO);

mockMvc.perform(post("/funixbot/command")
.header("Authorization", "Bearer " + UUID.randomUUID())
.contentType(MediaType.APPLICATION_JSON)
.content(jsonHelper.toJson(commandDTO)))
.andExpect(status().isBadRequest());
}

}
Loading