diff --git a/modules/funixbot/client/src/main/java/fr/funixgaming/api/funixbot/client/clients/FunixBotAutoMessagesClient.java b/modules/funixbot/client/src/main/java/fr/funixgaming/api/funixbot/client/clients/FunixBotAutoMessagesClient.java new file mode 100644 index 0000000..8ffea22 --- /dev/null +++ b/modules/funixbot/client/src/main/java/fr/funixgaming/api/funixbot/client/clients/FunixBotAutoMessagesClient.java @@ -0,0 +1,9 @@ +package fr.funixgaming.api.funixbot.client.clients; + +import com.funixproductions.core.crud.clients.CrudClient; +import fr.funixgaming.api.funixbot.client.dtos.FunixBotAutoMessageDTO; +import org.springframework.cloud.openfeign.FeignClient; + +@FeignClient(name = "FunixBotAutoMessagesClient", url = "${funixgaming.api.funixbot.app-domain-url}", path = "/funixbot/automessages/") +public interface FunixBotAutoMessagesClient extends CrudClient { +} diff --git a/modules/funixbot/client/src/main/java/fr/funixgaming/api/funixbot/client/dtos/FunixBotAutoMessageDTO.java b/modules/funixbot/client/src/main/java/fr/funixgaming/api/funixbot/client/dtos/FunixBotAutoMessageDTO.java new file mode 100644 index 0000000..bc60848 --- /dev/null +++ b/modules/funixbot/client/src/main/java/fr/funixgaming/api/funixbot/client/dtos/FunixBotAutoMessageDTO.java @@ -0,0 +1,38 @@ +package fr.funixgaming.api.funixbot.client.dtos; + +import com.funixproductions.core.crud.dtos.ApiDTO; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.annotation.Nullable; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class FunixBotAutoMessageDTO extends ApiDTO { + + /** + * The message to send. + */ + @NotBlank(message = "Le message ne peut pas être vide.") + private String message; + + /** + * The game name to send the message to. + * Null if you can send it anytime + */ + @Nullable + private String gameName; + + /** + * If the message is announced or not in the twitch chat. + */ + @NotNull(message = "Le message doit être annoncé ou non.") + private Boolean isAnnounced = Boolean.FALSE; + +} diff --git a/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/entities/FunixBotAutoMessage.java b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/entities/FunixBotAutoMessage.java new file mode 100644 index 0000000..baf6b25 --- /dev/null +++ b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/entities/FunixBotAutoMessage.java @@ -0,0 +1,37 @@ +package fr.funixgaming.api.funixbot.service.entities; + +import com.funixproductions.core.crud.entities.ApiEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity(name = "funixbot_automessages") +public class FunixBotAutoMessage extends ApiEntity { + + /** + * The message to send. + */ + @Column(nullable = false, length = 500) + private String message; + + /** + * The game name to send the message to. + * Null if you can send it anytime + */ + @Column(name = "game_name", length = 100) + private String gameName; + + /** + * If the message is announced or not in the twitch chat. + */ + @Column(nullable = false, name = "is_announced", columnDefinition = "boolean default false") + private Boolean isAnnounced = Boolean.FALSE; + +} diff --git a/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/mappers/FunixBotAutoMessagesMapper.java b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/mappers/FunixBotAutoMessagesMapper.java new file mode 100644 index 0000000..267a90e --- /dev/null +++ b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/mappers/FunixBotAutoMessagesMapper.java @@ -0,0 +1,10 @@ +package fr.funixgaming.api.funixbot.service.mappers; + +import com.funixproductions.core.crud.mappers.ApiMapper; +import fr.funixgaming.api.funixbot.client.dtos.FunixBotAutoMessageDTO; +import fr.funixgaming.api.funixbot.service.entities.FunixBotAutoMessage; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface FunixBotAutoMessagesMapper extends ApiMapper { +} diff --git a/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/repositories/FunixBotAutoMessagesRepository.java b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/repositories/FunixBotAutoMessagesRepository.java new file mode 100644 index 0000000..ac65991 --- /dev/null +++ b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/repositories/FunixBotAutoMessagesRepository.java @@ -0,0 +1,9 @@ +package fr.funixgaming.api.funixbot.service.repositories; + +import com.funixproductions.core.crud.repositories.ApiRepository; +import fr.funixgaming.api.funixbot.service.entities.FunixBotAutoMessage; +import org.springframework.stereotype.Repository; + +@Repository +public interface FunixBotAutoMessagesRepository extends ApiRepository { +} diff --git a/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/resources/FunixBotAutoMessagesResource.java b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/resources/FunixBotAutoMessagesResource.java new file mode 100644 index 0000000..3836854 --- /dev/null +++ b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/resources/FunixBotAutoMessagesResource.java @@ -0,0 +1,18 @@ +package fr.funixgaming.api.funixbot.service.resources; + +import com.funixproductions.core.crud.resources.ApiResource; +import fr.funixgaming.api.funixbot.client.clients.FunixBotAutoMessagesClient; +import fr.funixgaming.api.funixbot.client.dtos.FunixBotAutoMessageDTO; +import fr.funixgaming.api.funixbot.service.services.FunixBotAutoMessagesService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/funixbot/automessages") +public class FunixBotAutoMessagesResource extends ApiResource implements FunixBotAutoMessagesClient { + + public FunixBotAutoMessagesResource(FunixBotAutoMessagesService service) { + super(service); + } + +} diff --git a/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/security/WebSecurity.java b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/security/WebSecurity.java index ffad243..e407d99 100644 --- a/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/security/WebSecurity.java +++ b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/security/WebSecurity.java @@ -18,8 +18,7 @@ public class WebSecurity extends ApiWebSecurity { public Customizer.AuthorizationManagerRequestMatcherRegistry> getUrlsMatchers() { return ex -> ex .requestMatchers("/actuator/**").permitAll() - .requestMatchers(HttpMethod.GET, "/funixbot/user/**").permitAll() - .requestMatchers(HttpMethod.GET, "/funixbot/command/**").permitAll() + .requestMatchers(HttpMethod.GET, "/funixbot/**").permitAll() .anyRequest().hasAuthority(UserRole.MODERATOR.getRole()); } } diff --git a/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/services/FunixBotAutoMessagesService.java b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/services/FunixBotAutoMessagesService.java new file mode 100644 index 0000000..604972e --- /dev/null +++ b/modules/funixbot/service/src/main/java/fr/funixgaming/api/funixbot/service/services/FunixBotAutoMessagesService.java @@ -0,0 +1,17 @@ +package fr.funixgaming.api.funixbot.service.services; + +import com.funixproductions.core.crud.services.ApiService; +import fr.funixgaming.api.funixbot.client.dtos.FunixBotAutoMessageDTO; +import fr.funixgaming.api.funixbot.service.entities.FunixBotAutoMessage; +import fr.funixgaming.api.funixbot.service.mappers.FunixBotAutoMessagesMapper; +import fr.funixgaming.api.funixbot.service.repositories.FunixBotAutoMessagesRepository; +import org.springframework.stereotype.Service; + +@Service +public class FunixBotAutoMessagesService extends ApiService { + + public FunixBotAutoMessagesService(FunixBotAutoMessagesRepository repository, FunixBotAutoMessagesMapper mapper) { + super(repository, mapper); + } + +} diff --git a/modules/funixbot/service/src/main/resources/db/migration/V4__funixbot_automessages.sql b/modules/funixbot/service/src/main/resources/db/migration/V4__funixbot_automessages.sql new file mode 100644 index 0000000..417f949 --- /dev/null +++ b/modules/funixbot/service/src/main/resources/db/migration/V4__funixbot_automessages.sql @@ -0,0 +1,10 @@ +create table if not exists funixbot_automessages +( + id bigint generated by default as identity primary key, + created_at timestamp not null, + updated_at timestamp, + uuid varchar(255) not null constraint UK_fbot_user_public_id unique, + message varchar(500) not null, + game_name varchar(100), + is_announced boolean default false not null +); diff --git a/modules/funixbot/service/src/test/java/fr/funixgaming/api/funixbot/service/resources/FunixBotAutoMessagesResourceTest.java b/modules/funixbot/service/src/test/java/fr/funixgaming/api/funixbot/service/resources/FunixBotAutoMessagesResourceTest.java new file mode 100644 index 0000000..cdc2461 --- /dev/null +++ b/modules/funixbot/service/src/test/java/fr/funixgaming/api/funixbot/service/resources/FunixBotAutoMessagesResourceTest.java @@ -0,0 +1,114 @@ +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.FunixBotAutoMessageDTO; +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 java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +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 +@AutoConfigureMockMvc +class FunixBotAutoMessagesResourceTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private JsonHelper jsonHelper; + + @MockBean + private UserAuthClient userAuthClient; + + @Test + void testAccessMessages() throws Exception { + mockMvc.perform(get("/funixbot/automessages")) + .andExpect(status().isOk()); + } + + @Test + void testCreateAndPatch() 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/automessages")) + .andExpect(status().isUnauthorized()); + + final FunixBotAutoMessageDTO funixBotAutoMessageDTO = new FunixBotAutoMessageDTO("testMessage", "Minecraft", false); + MvcResult mvcResult = mockMvc.perform(post("/funixbot/automessages") + .header("Authorization", "Bearer " + UUID.randomUUID()) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonHelper.toJson(funixBotAutoMessageDTO)) + ).andExpect(status().isOk()).andReturn(); + + final FunixBotAutoMessageDTO created = jsonHelper.fromJson(mvcResult.getResponse().getContentAsString(), FunixBotAutoMessageDTO.class); + assertEquals(funixBotAutoMessageDTO.getMessage(), created.getMessage()); + created.setMessage("testMessage2"); + created.setGameName(null); + + mvcResult = mockMvc.perform(put("/funixbot/automessages") + .header("Authorization", "Bearer " + UUID.randomUUID()) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonHelper.toJson(created)) + ).andExpect(status().isOk()).andReturn(); + final FunixBotAutoMessageDTO updated = jsonHelper.fromJson(mvcResult.getResponse().getContentAsString(), FunixBotAutoMessageDTO.class); + assertEquals(created.getMessage(), updated.getMessage()); + assertNull(updated.getGameName()); + } + + @Test + void testCreateMessageWithNoMessage() 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/automessages") + .header("Authorization", "Bearer " + UUID.randomUUID()) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonHelper.toJson(new FunixBotAutoMessageDTO())) + ).andExpect(status().isBadRequest()); + } + + @Test + void testCreateMessageWithNoAccess() 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/automessages") + .header("Authorization", "Bearer " + UUID.randomUUID()) + .contentType(MediaType.APPLICATION_JSON) + .content(jsonHelper.toJson(new FunixBotAutoMessageDTO())) + ).andExpect(status().isForbidden()); + } + +} diff --git a/pom.xml b/pom.xml index 973b8c2..a0a8758 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ com.funixproductions.api funixproductions-api - 1.2.2.0 + 1.2.2.1