diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index ae947a3..587a2b2 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -18,11 +18,11 @@ jobs: uses: actions/setup-java@v5 with: distribution: temurin - java-version: 24 + java-version: 25 - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - name: Build on ${{ matrix.os }} - run: ./gradlew clean build test + run: ./gradlew clean build - name: Generate JaCoCo Coverage Report if: matrix.os == 'ubuntu-latest' run: ./gradlew jacocoTestReport diff --git a/build.gradle.kts b/build.gradle.kts index b69fb3f..9dee148 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,9 @@ plugins { alias(libs.plugins.micronaut.application) alias(libs.plugins.micronaut.aot) - alias(libs.plugins.micronaut.test.resources) +// alias(libs.plugins.micronaut.test.resources) // TODO: Needs be fixed, ref: https://github.com/micronaut-projects/micronaut-gradle-plugin/issues/1195 jacoco `maven-publish` - id("org.openapi.generator") version "7.14.0" alias(libs.plugins.cyclonedx) } @@ -37,7 +36,6 @@ dependencies { implementation(mn.micronaut.openapi) implementation(mn.validation) implementation(mn.swagger.core) - implementation(mn.micronaut.management) implementation(mn.micronaut.micrometer.core) implementation(mn.micronaut.micrometer.registry.prometheus) // External Dependencies @@ -105,93 +103,6 @@ tasks { csv.required.set(false) } } - this.openApiGenerate { - dependsOn("compileJava") - } - register("pushDartClient") { - dependsOn("openApiGenerate") - doLast { - val clientDir = file("$projectDir/build/generated/dart-client") - val version = project.version as String - - // Get GitHub credentials from environment variables - val githubToken = System.getenv("CLIENT_REPO_TOKEN") ?: System.getenv("GITHUB_TOKEN") ?: throw GradleException("CLIENT_REPO_TOKEN or GITHUB_TOKEN environment variable is required") - - // Create a temporary directory for the Git repository - val tempDir = file("$projectDir/build/temp/vulpes-client") - tempDir.mkdirs() - providers.exec { - workingDir = tempDir - commandLine("git", "clone", "https://${githubToken}@github.com/OneLiteFeatherNET/vulpes-backend-client-dart.git", ".") - }.result?.get() - - // Copy the generated client to the repository - copy { - from(clientDir) - into(tempDir) - } - -// providers.exec { -// workingDir = tempDir -// commandLine("flutter", "pub", "get") -// }.result?.get() - -// providers.exec { -// workingDir = tempDir -// commandLine("flutter", "pub", "run", "build_runner", "build", "--delete-conflicting-outputs") -// }.result?.get() - - providers.exec { - workingDir = tempDir - commandLine("git", "add", ".") - }.result?.get() - - providers.exec { - workingDir = tempDir - commandLine("git", "commit", "-m", "Update client to version $version") - }.result?.get() - - providers.exec { - workingDir = tempDir - commandLine("git", "tag", "-a", "v$version", "-m", "Version $version") - }.result?.get() - - providers.exec { - workingDir = tempDir - commandLine("git", "push", "origin") - }.result?.get() - - providers.exec { - workingDir = tempDir - commandLine("git", "push", "origin", "--tags") - }.result?.get() - } - } - named("publish") { - dependsOn("pushDartClient") - } -} - -// OpenAPI Generator configuration -openApiGenerate { - generatorName.set("dart-dio") - inputSpec.set("$projectDir/build/classes/java/main/META-INF/swagger/vulpes-backend-1.0.yml") - outputDir.set("$projectDir/build/generated/dart-client") - apiPackage.set("net.onelitefeather.vulpes.backend.client.api") - invokerPackage.set("net.onelitefeather.vulpes.backend.client.invoker") - modelPackage.set("net.onelitefeather.vulpes.backend.client.model") - configOptions.set(mapOf( - "pubName" to "vulpes_backend_client", - "pubVersion" to (project.version as String), - "pubDescription" to "Vulpes Backend API Client", - "pubAuthor" to "OneLiteFeatherNET", - "pubAuthorEmail" to "p.glanz@madfix.me", - "pubHomepage" to "https://github.com/OneLiteFeatherNET/vulpes-backend-client-dart", - "pubRepository" to "https://github.com/OneLiteFeatherNET/vulpes-backend-client-dart", - "pubPublishTo" to "https://github.com/OneLiteFeatherNET/vulpes-backend-client-dart", - "dateLibrary" to "core", - "enumUnknownDefaultCase" to "true" - )) } publishing { diff --git a/gradle.properties b/gradle.properties index 1c61192..af8a7f5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.parallel=true # org.gradle.warning.mode=all # org.gradle.logging.level=info org.gradle.jvmargs=-Xmx2G -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 -Dmicronaut.openapi.views.spec=redoc.enabled=true,rapidoc.enabled=true,openapi-explorer.enabled=true,swagger-ui.enabled=true,swagger-ui.theme=flattop -micronautVersion=4.10.1 +micronautVersion=4.10.2 # The version of the Vulpes API version=999.0.0-SNAPSHOT diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9bbc975..f8e1ee3 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2a84e18..bad7c24 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index faf9300..adff685 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019..e509b2d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle.kts b/settings.gradle.kts index aa48760..e674ebe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,7 +33,7 @@ dependencyResolutionManagement { versionCatalogs { create("libs") { version("micronaut", "4.6.1") - version("vulpes.model", "1.6.0-beta.11") + version("vulpes.model", "1.6.0-beta.14") version("uuid.creator", "6.1.1") version("datafaker", "2.4.2") version("jetbrains.annotation", "26.0.2") diff --git a/src/main/java/net/onelitefeather/vulpes/backend/controller/AttributeController.java b/src/main/java/net/onelitefeather/vulpes/backend/controller/AttributeController.java index 6cc8230..ebe727f 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/controller/AttributeController.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/controller/AttributeController.java @@ -144,7 +144,7 @@ public HttpResponse delete(@PathVariable UUID id) { schema = @Schema(implementation = AttributeModelResponseDTO.AttributeModelDTO.class) ) ) - @Delete("/delete/all") + @Delete("/delete") public HttpResponse> deleteAll() { List result = attributeService.deleteAllAttributes(); return HttpResponse.ok(result); @@ -173,7 +173,7 @@ public HttpResponse> deleteAll() { ) ) @Produces(MediaType.APPLICATION_JSON) - @Get(uris = {"/all"}) + @Get(uris = {"/"}) public HttpResponse> getAll(Pageable pageable) { Page models = attributeService.getAllAttributes(pageable); return HttpResponse.ok(models); diff --git a/src/main/java/net/onelitefeather/vulpes/backend/controller/FontController.java b/src/main/java/net/onelitefeather/vulpes/backend/controller/FontController.java index 89db7bf..9cde84c 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/controller/FontController.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/controller/FontController.java @@ -11,6 +11,7 @@ import io.micronaut.http.annotation.PathVariable; import io.micronaut.http.annotation.Post; import io.micronaut.http.annotation.Produces; +import io.micronaut.http.annotation.Put; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; @@ -21,6 +22,8 @@ import net.onelitefeather.vulpes.api.model.FontEntity; import net.onelitefeather.vulpes.backend.domain.font.FontModelDTO; import net.onelitefeather.vulpes.backend.domain.font.FontModelResponseDTO; +import net.onelitefeather.vulpes.backend.domain.font.FontStringDTO; +import net.onelitefeather.vulpes.backend.domain.font.FontStringResponseDTO; import net.onelitefeather.vulpes.backend.service.FontService; import java.util.List; @@ -105,62 +108,7 @@ public HttpResponse getById(@PathVariable UUID id) { } - @Operation( - summary = "Get characters by font ID", - operationId = "getCharsById", - description = "Gets the characters of a font by its ID from the database.", - tags = {"Font"} - ) - @ApiResponse( - responseCode = "200", - description = "The characters of the font were successfully retrieved from the database.", - content = @Content( - mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = FontModelCharsResponseDTO.class) - ) - ) - @ApiResponse( - responseCode = "404", - description = "The font was not found in the database.", - content = @Content( - mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = FontModelErrorDTO.class) - ) - ) - @Get("/chars/{id}") - @Produces(MediaType.APPLICATION_JSON) - public HttpResponse getCharsById(@PathVariable UUID id) { - List model = fontService.findCharsByFontId(id); - if (model == null) { - return HttpResponse.notFound(new FontModelErrorDTO("Font not found")); - } - FontModelCharsResponseDTO dto = FontModelCharsResponseDTO.createDTO(id, model); - return HttpResponse.ok(dto); - } - @Operation( - summary = "Update characters of a font", - operationId = "updateChars", - description = "Updates the characters of a font in the database.", - tags = {"Font"} - ) - @ApiResponse( - responseCode = "200", - description = "The characters of the font were successfully updated in the database.", - content = @Content( - mediaType = MediaType.APPLICATION_JSON, - array = @ArraySchema( - schema = @Schema(implementation = FontModelCharsResponseDTO.class) - ) - ) - ) - @Post("/chars/{id}") - @Produces(MediaType.APPLICATION_JSON) - public HttpResponse updateChars(@PathVariable UUID id,@Body List chars) { - List model = fontService.updateCharsByFontId(id, chars); - FontModelCharsResponseDTO dto = FontModelCharsResponseDTO.createDTO(id, model); - return HttpResponse.ok(dto); - } @Operation( summary = "Remove a font by ID", @@ -211,7 +159,7 @@ public HttpResponse remove(@PathVariable UUID id) { ) ) ) - @Get(uris = {"/all"}) + @Get(uris = {"/"}) @Produces(MediaType.APPLICATION_JSON) public HttpResponse> getAll(Pageable pageable) { Page models = fontService.getAllFonts(pageable); @@ -232,7 +180,7 @@ public HttpResponse> getAll(Pageable pag schema = @Schema(implementation = FontModelResponseDTO.FontModelDTO.class) ) ) - @Delete("delete/all") + @Delete("delete") @Produces(MediaType.APPLICATION_JSON) public HttpResponse> deleteAll() { List result = fontService.deleteAllFonts(); @@ -272,4 +220,133 @@ public HttpResponse update( } return HttpResponse.ok(result); } + + @Operation( + summary = "Create character of a font", + operationId = "createChar", + description = "Create the character of a font in the database.", + tags = {"Font"} + ) + @ApiResponse( + responseCode = "200", + description = "The characters of the font were successfully updated in the database.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FontStringResponseDTO.class) + ) + ) + @Put("/chars/{id}") + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse createChar(@PathVariable UUID id, @Body FontStringDTO charModel) { + FontStringResponseDTO model = fontService.createCharByFontId(id, charModel); + return HttpResponse.ok(model); + } + + @Operation( + summary = "Get characters by font ID", + operationId = "getCharsById", + description = "Gets the characters of a font by its ID from the database.", + tags = {"Font"} + ) + @ApiResponse( + responseCode = "200", + description = "The characters of the font were successfully retrieved from the database.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FontStringResponseDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "The font was not found in the database.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FontModelErrorDTO.class) + ) + ) + @Get("/chars/{id}") + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse> readCharsById(@PathVariable UUID id, Pageable pageable) { + Page models = fontService.findCharsByFontId(id, pageable); + return HttpResponse.ok(models); + } + + @Operation( + summary = "Update character of a font", + operationId = "updateChar", + description = "Updates the character of a font in the database.", + tags = {"Font"} + ) + @ApiResponse( + responseCode = "200", + description = "The characters of the font were successfully updated in the database.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + array = @ArraySchema( + schema = @Schema(implementation = FontStringResponseDTO.class) + ) + ) + ) + @Post("/chars/{id}") + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse updateChar(@PathVariable UUID id, @Body FontStringDTO charModel) { + FontStringResponseDTO model = fontService.updateCharByFontId(id, charModel); + return HttpResponse.ok(model); + } + + + @Operation( + summary = "Delete character of a font", + operationId = "deleteChar", + description = "Delete the character of a font in the database.", + tags = {"Font"} + ) + @ApiResponse( + responseCode = "200", + description = "The characters of the font were successfully updated in the database.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FontStringResponseDTO.FontStringDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "The character was not found in the database.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = FontStringResponseDTO.FontStringErrorDTO.class) + ) + ) + @Delete("/chars/{fontId}/{charId}") + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse deleteChar(@PathVariable UUID fontId, @PathVariable UUID charId) { + FontStringResponseDTO model = fontService.deleteCharByFontId(fontId, charId); + if (model instanceof FontStringResponseDTO.FontStringErrorDTO) { + return HttpResponse.notFound(model); + } + return HttpResponse.ok(model); + } + + @Operation( + summary = "Delete character of a font", + operationId = "deleteChar", + description = "Delete the character of a font in the database.", + tags = {"Font"} + ) + @ApiResponse( + responseCode = "200", + description = "The characters of the font were successfully deleted in the database.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + array = @ArraySchema( + schema = @Schema(implementation = FontStringResponseDTO.class) + ) + ) + ) + @Delete("/chars/{fontId}/") + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse> deleteAllChars(@PathVariable UUID fontId) { + List model = fontService.deleteAllCharByFontId(fontId); + return HttpResponse.ok(model); + } } diff --git a/src/main/java/net/onelitefeather/vulpes/backend/controller/ItemController.java b/src/main/java/net/onelitefeather/vulpes/backend/controller/ItemController.java index 0053332..6cda19e 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/controller/ItemController.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/controller/ItemController.java @@ -11,6 +11,7 @@ import io.micronaut.http.annotation.PathVariable; import io.micronaut.http.annotation.Post; import io.micronaut.http.annotation.Produces; +import io.micronaut.http.annotation.Put; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; @@ -19,22 +20,23 @@ import jakarta.inject.Inject; import jakarta.validation.Valid; import net.onelitefeather.vulpes.api.model.ItemEntity; +import net.onelitefeather.vulpes.backend.domain.item.ItemEnchantmentDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemEnchantmentResponseDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemFlagDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemFlagResponseDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemLoreDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemLoreResponseDTO; import net.onelitefeather.vulpes.backend.domain.item.ItemModelDTO; import net.onelitefeather.vulpes.backend.domain.item.ItemModelResponseDTO; import net.onelitefeather.vulpes.backend.service.ItemService; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.UUID; -import static net.onelitefeather.vulpes.backend.domain.item.ItemModelResponseDTO.ItemModelEnchantmentResponseDTO; -import static net.onelitefeather.vulpes.backend.domain.item.ItemModelResponseDTO.ItemModelErrorDTO; - /** - * @author theEvilReaper - * @version 1.0.0 - * @since 1.0.0 + * REST controller for item resources. + * Provides CRUD operations and nested resource management (enchantments, lore, flags). */ @Controller("/item") public class ItemController { @@ -47,45 +49,45 @@ public ItemController(ItemService itemService) { } @Operation( - summary = "Add a new item", + summary = "Create a new item", operationId = "addItem", - description = "Adds a new item to the database. The item is created with the given properties.", + description = "Creates a new item with the provided properties and stores it in the database.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The item was successfully added to the database.", + description = "Item successfully created.", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = ItemModelDTO.class) + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class) ) ) @ApiResponse( responseCode = "500", - description = "The item could not be added to the database.", + description = "Item could not be created due to an internal error.", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = ItemModelErrorDTO.class) + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelErrorDTO.class) ) ) @Post @Produces(MediaType.APPLICATION_JSON) public HttpResponse add( - @Valid @Body ItemModelDTO itemModelDto + @Valid @Body ItemModelDTO itemModel ) { - ItemModelResponseDTO.ItemModelDTO result = itemService.createItem(itemModelDto); - return HttpResponse.ok(result); + ItemModelResponseDTO.ItemModelDTO createdItem = itemService.createItem(itemModel); + return HttpResponse.ok(createdItem); } @Operation( summary = "Get an item by ID", operationId = "getItemById", - description = "Retrieves an item from the database by its ID.", + description = "Retrieves a single item from the database by its unique ID (itemId).", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The item was successfully retrieved from the database.", + description = "Item successfully retrieved.", content = @Content( mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class) @@ -93,34 +95,34 @@ public HttpResponse add( ) @ApiResponse( responseCode = "404", - description = "The item was not found in the database.", + description = "Item with the given ID was not found.", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = ItemModelErrorDTO.class) + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelErrorDTO.class) ) ) - @Get("/{id}") + @Get("/{itemId}") @Produces(MediaType.APPLICATION_JSON) public HttpResponse getById( - @Valid @PathVariable UUID id + @Valid @PathVariable("itemId") UUID itemId ) { - Optional model = itemService.findItemById(id); - if (model.isPresent()) { - var itemModel = model.get(); - return HttpResponse.ok(ItemModelResponseDTO.ItemModelDTO.createDTO(itemModel)); + Optional foundItemOpt = itemService.findItemById(itemId); + if (foundItemOpt.isPresent()) { + var foundItem = foundItemOpt.get(); + return HttpResponse.ok(ItemModelResponseDTO.ItemModelDTO.createDTO(foundItem)); } - return HttpResponse.notFound(new ItemModelErrorDTO("Item not found")); + return HttpResponse.notFound(new ItemModelResponseDTO.ItemModelErrorDTO("Item not found")); } @Operation( summary = "Remove an item by ID", operationId = "removeItemById", - description = "Removes an item from the database by its ID.", + description = "Deletes an item from the database by its unique ID (itemId).", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The item was successfully removed from the database.", + description = "Item successfully deleted.", content = @Content( mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class) @@ -128,250 +130,586 @@ public HttpResponse getById( ) @ApiResponse( responseCode = "404", - description = "The item was not found in the database.", + description = "Item with the given ID was not found.", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = ItemModelErrorDTO.class) + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelErrorDTO.class) ) ) - @Delete("/delete/{id}") + @Delete("/delete/{itemId}") @Produces(MediaType.APPLICATION_JSON) - public HttpResponse remove(@PathVariable UUID id) { - ItemModelResponseDTO result = itemService.deleteItem(id); - if (result instanceof ItemModelResponseDTO.ItemModelErrorDTO) { - return HttpResponse.notFound(result); + public HttpResponse remove(@PathVariable("itemId") UUID itemId) { + ItemModelResponseDTO deleteResult = itemService.deleteItem(itemId); + if (deleteResult instanceof ItemModelResponseDTO.ItemModelErrorDTO) { + return HttpResponse.notFound(deleteResult); } - return HttpResponse.ok(result); + return HttpResponse.ok(deleteResult); } @Operation( - summary = "Get enchantments of an item", - description = "Retrieves the enchantments of an item by its ID.", + summary = "Get all items", + operationId = "getAllItems", + description = "Retrieves a pageable list of all items. Supports standard Micronaut pagination (page, size, sort).", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The enchantments of the item were successfully retrieved.", + description = "Items successfully retrieved.", content = @Content( mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema( - schema = @Schema(implementation = ItemModelEnchantmentResponseDTO.class), + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class), arraySchema = @Schema(implementation = Page.class) ) ) ) - @Get(uris = { - "/enchantments/{id}", - "/{id}/enchantments" - }) + @Get @Produces(MediaType.APPLICATION_JSON) - public HttpResponse> getEnchantmentsById(@PathVariable UUID id, Pageable pageable) { - Map enchantments = itemService.findEnchantmentsById(id, pageable); - return HttpResponse.ok(Page.of(enchantments.entrySet().stream().map(ItemModelResponseDTO.ItemModelEnchantmentResponseDTO::createDTO).toList(), pageable, (long) enchantments.size())); + public HttpResponse> getAll(Pageable pageable) { + Page itemsPage = itemService.getAllItems(pageable); + return HttpResponse.ok(itemsPage); } @Operation( - summary = "Update enchantments of an item", - description = "Updates the enchantments of an item by its ID.", + summary = "Delete all items", + description = "Deletes all items from the database.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The enchantments of the item were successfully updated.", + description = "All items were successfully deleted.", content = @Content( mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema( - schema = @Schema(implementation = ItemModelEnchantmentResponseDTO.class), - arraySchema = @Schema(implementation = List.class) + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class) ) ) ) - @Post(uris = { - "/enchantments/{id}", - "/{id}/enchantments" - }) - public HttpResponse> updateEnchantments(@PathVariable UUID id, @Body Map enchantments) { - var enchantmentResult = itemService.updateEnchantmentsById(id, enchantments); - return HttpResponse.ok(enchantmentResult.entrySet().stream().map(ItemModelResponseDTO.ItemModelEnchantmentResponseDTO::createDTO).toList()); + @Delete("/deleteAll") + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse> deleteAll() { + List deleteResults = itemService.deleteAllItems(); + return HttpResponse.ok(deleteResults); } @Operation( - summary = "Get all flags of an item", - description = "Retrieves all flags of an item by its ID.", + summary = "Update an item", + operationId = "updateItem", + description = "Updates an existing item in the database.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The flags of the item were successfully retrieved.", + description = "Item successfully updated.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item was not found and could not be updated.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemModelResponseDTO.ItemModelErrorDTO.class) + ) + ) + @Post("/update") + @Produces(MediaType.APPLICATION_JSON) + public HttpResponse update( + @Valid @Body ItemModelDTO itemModel + ) { + ItemModelResponseDTO updateResult = itemService.updateItem(itemModel); + if (updateResult instanceof ItemModelResponseDTO.ItemModelErrorDTO) { + return HttpResponse.notFound(updateResult); + } + return HttpResponse.ok(updateResult); + } + + @Operation( + summary = "Get enchantments of an item", + operationId = "getEnchantments", + description = "Retrieves a pageable list of enchantments for the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "Enchantments successfully retrieved.", content = @Content( mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema( - schema = @Schema(implementation = String.class), + schema = @Schema(implementation = ItemEnchantmentResponseDTO.class), arraySchema = @Schema(implementation = Page.class) ) ) ) @Get(uris = { - "/flags/{id}", - "/{id}/flags" + "/enchantments/{itemId}", + "/{itemId}/enchantments" }) @Produces(MediaType.APPLICATION_JSON) - public HttpResponse> getFlagsById(@PathVariable UUID id, Pageable pageable) { - List flags = itemService.findFlagsById(id, pageable); - return HttpResponse.ok(Page.of(flags, pageable, (long) flags.size())); + public HttpResponse> getEnchantmentsById(@PathVariable("itemId") UUID itemId, Pageable pageable) { + Page enchantmentsPage = itemService.findEnchantmentsById(itemId, pageable); + return HttpResponse.ok(enchantmentsPage); } @Operation( - summary = "Update flags of an item", - description = "Updates the flags of an item by its ID.", + summary = "Update an enchantment of an item", + operationId = "updateEnchantment", + description = "Updates a specific enchantment of the item identified by itemId.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The flags of the item were successfully updated.", + description = "Enchantment successfully updated.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO.class) + ) + ) + @Post(uris = { + "/enchantment/{itemId}", + "/{itemId}/enchantment" + }) + public HttpResponse updateEnchantment(@PathVariable("itemId") UUID itemId, @Body ItemEnchantmentDTO enchantment) { + var updateResult = itemService.updateEnchantmentById(itemId, enchantment); + if (updateResult instanceof ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO) { + return HttpResponse.notFound(updateResult); + } + return HttpResponse.ok(updateResult); + } + + @Operation( + summary = "Create an enchantment for an item", + operationId = "createEnchantment", + description = "Creates a new enchantment entry for the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "Enchantment successfully created.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO.class) + ) + ) + @Put(uris = { + "/enchantment/{itemId}", + "/{itemId}/enchantment" + }) + public HttpResponse createEnchantment(@PathVariable("itemId") UUID itemId, @Body ItemEnchantmentDTO enchantment) { + var createResult = itemService.createEnchantmentById(itemId, enchantment); + return HttpResponse.ok(createResult); + } + + @Operation( + summary = "Delete an enchantment of an item", + operationId = "deleteEnchantment", + description = "Deletes a specific enchantment (enchantmentId) of the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "Enchantment successfully deleted.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO.class) + ) + ) + @Delete(uris = { + "/enchantment/{itemId}/{enchantmentId}", + "/{itemId}/enchantment/{enchantmentId}" + }) + public HttpResponse deleteEnchantment(@PathVariable("itemId") UUID itemId, @PathVariable("enchantmentId") UUID enchantmentId) { + var deleteResult = itemService.deleteEnchantmentById(itemId, enchantmentId); + if (deleteResult instanceof ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO) { + return HttpResponse.notFound(deleteResult); + } + return HttpResponse.ok(deleteResult); + } + + @Operation( + summary = "Delete all enchantments of an item", + operationId = "deleteEnchantments", + description = "Deletes all enchantments of the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "Enchantments successfully deleted.", content = @Content( mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema( - schema = @Schema(implementation = String.class), - arraySchema = @Schema(implementation = List.class) + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentDTO.class) ) ) ) - @Post(uris = { - "/flags/{id}", - "/{id}/flags" + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO.class) + ) + ) + @Delete(uris = { + "/enchantment/{itemId}/", + "/{itemId}/enchantment/" }) - public HttpResponse> updateFlags(@PathVariable UUID id,@Body List flags) { - List result = itemService.updateFlagsById(id, flags); - return HttpResponse.ok(result); + public HttpResponse> deleteEnchantments(@PathVariable("itemId") UUID itemId) { + var deletedEnchantments = itemService.deleteAllEnchantmentsById(itemId); + return HttpResponse.ok(deletedEnchantments); } @Operation( summary = "Get all lore of an item", - description = "Retrieves all lore of an item by its ID.", + operationId = "getLore", + description = "Retrieves a pageable list of lore entries for the item identified by itemId.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The lore of the item was successfully retrieved.", + description = "Lore successfully retrieved.", content = @Content( mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema( - schema = @Schema(implementation = String.class), + schema = @Schema(implementation = ItemLoreResponseDTO.class), arraySchema = @Schema(implementation = Page.class) ) ) ) @Get(uris = { - "/lore/{id}", - "/{id}/lore" + "/lore/{itemId}", + "/{itemId}/lore" }) @Produces(MediaType.APPLICATION_JSON) - public HttpResponse> getLoreById(@PathVariable UUID id, Pageable pageable) { - List lore = itemService.findLoreById(id, pageable); - return HttpResponse.ok(Page.of(lore, pageable, (long) lore.size())); + public HttpResponse> getLoreById(@PathVariable("itemId") UUID itemId, Pageable pageable) { + Page lorePage = itemService.findLoreById(itemId, pageable); + return HttpResponse.ok(lorePage); } @Operation( summary = "Update lore of an item", - description = "Updates the lore of an item by its ID.", + operationId = "updateLore", + description = "Updates a specific lore entry of the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "Lore successfully updated.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreErrorDTO.class) + ) + ) + @Post(uris = { + "/lore/{itemId}", + "/{itemId}/lore" + }) + public HttpResponse updateLore(@PathVariable("itemId") UUID itemId, @Body ItemLoreDTO lore) { + ItemLoreResponseDTO updateResult = itemService.updateLoreById(itemId, lore); + if (updateResult instanceof ItemLoreResponseDTO.ItemLoreErrorDTO) { + return HttpResponse.notFound(updateResult); + } + return HttpResponse.ok(updateResult); + } + + @Operation( + summary = "Create lore of an item", + operationId = "createLore", + description = "Creates a new lore entry for the item identified by itemId.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The lore of the item was successfully updated.", + description = "Lore successfully created.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreErrorDTO.class) + ) + ) + @Put(uris = { + "/lore/{itemId}", + "/{itemId}/lore" + }) + public HttpResponse createLore(@PathVariable("itemId") UUID itemId, @Body ItemLoreDTO lore) { + ItemLoreResponseDTO createResult = itemService.createLoreById(itemId, lore); + if (createResult instanceof ItemLoreResponseDTO.ItemLoreErrorDTO) { + return HttpResponse.notFound(createResult); + } + return HttpResponse.ok(createResult); + } + + + @Operation( + summary = "Delete lore of an item", + operationId = "deleteLore", + description = "Deletes a specific lore entry (loreId) of the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "Lore successfully deleted.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreErrorDTO.class) + ) + ) + @Delete(uris = { + "/lore/{itemId}/{loreId}", + "/{itemId}/lore/{loreId}" + }) + public HttpResponse deleteLore(@PathVariable("itemId") UUID itemId, @PathVariable("loreId") UUID loreId) { + var deleteResult = itemService.deleteLoreById(itemId, loreId); + if (deleteResult instanceof ItemLoreResponseDTO.ItemLoreErrorDTO) { + return HttpResponse.notFound(deleteResult); + } + return HttpResponse.ok(deleteResult); + } + + @Operation( + summary = "Delete all lore of an item", + operationId = "deleteAllLore", + description = "Deletes all lore entries of the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "All lore entries were successfully deleted.", content = @Content( mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema( - schema = @Schema(implementation = String.class), - arraySchema = @Schema(implementation = List.class) + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreDTO.class) ) ) ) - @Post(uris = { - "/lore/{id}", - "/{id}/lore" + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemLoreResponseDTO.ItemLoreErrorDTO.class) + ) + ) + @Delete(uris = { + "/lore/{itemId}/", + "/{itemId}/lore/" }) - public HttpResponse> updateLore(@PathVariable UUID id,@Body List lore) { - List result = itemService.updateLoreById(id, lore); - return HttpResponse.ok(result); + public HttpResponse> deleteLores(@PathVariable("itemId") UUID itemId) { + var deletedLores = itemService.deleteAllLoreById(itemId); + return HttpResponse.ok(deletedLores); } @Operation( - summary = "Get all items", - operationId = "getAllItems", - description = "Retrieves all items from the database.", + summary = "Get all flags of an item", + operationId = "getFlags", + description = "Retrieves a pageable list of flags for the item identified by itemId.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "All items were successfully retrieved from the database.", + description = "Flags successfully retrieved.", content = @Content( mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema( - schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class), + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagDTO.class), arraySchema = @Schema(implementation = Page.class) ) ) ) - @Get(uris = {"/all"}) + @Get(uris = { + "/flags/{itemId}", + "/{itemId}/flags" + }) @Produces(MediaType.APPLICATION_JSON) - public HttpResponse> getAll(Pageable pageable) { - Page list = itemService.getAllItems(pageable); - return HttpResponse.ok(list); + public HttpResponse> getFlagsById(@PathVariable("itemId") UUID itemId, Pageable pageable) { + Page flagsPage = itemService.findFlagsById(itemId, pageable); + return HttpResponse.ok(flagsPage); } @Operation( - summary = "Delete all items", - description = "Deletes all items from the database.", + summary = "Update flag of an item", + operationId = "updateFlag", + description = "Updates a specific flag of the item identified by itemId.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "All items were successfully deleted from the database.", + description = "Flag successfully updated.", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class) + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagDTO.class) ) ) - @Delete("/deleteAll") - @Produces(MediaType.APPLICATION_JSON) - public HttpResponse> deleteAll() { - List result = itemService.deleteAllItems(); - return HttpResponse.ok(result); + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagErrorDTO.class) + ) + ) + @Post(uris = { + "/flag/{itemId}", + "/{itemId}/flag" + }) + public HttpResponse updateFlags(@PathVariable("itemId") UUID itemId, @Body ItemFlagDTO flag) { + ItemFlagResponseDTO updateResult = itemService.updateFlagById(itemId, flag); + if (updateResult instanceof ItemFlagResponseDTO.ItemFlagErrorDTO) { + return HttpResponse.notFound(updateResult); + } + return HttpResponse.ok(updateResult); } @Operation( - summary = "Update an item", - description = "Updates an item in the database.", + summary = "Create flag of an item", + operationId = "createFlag", + description = "Creates a new flag entry for the item identified by itemId.", tags = {"Item"} ) @ApiResponse( responseCode = "200", - description = "The item was successfully updated in the database.", + description = "Flag successfully created.", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = ItemModelResponseDTO.ItemModelDTO.class) + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagDTO.class) ) ) @ApiResponse( responseCode = "404", - description = "The item was not found in the database.", + description = "Item for the given ID was not found.", content = @Content( mediaType = MediaType.APPLICATION_JSON, - schema = @Schema(implementation = ItemModelErrorDTO.class) + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagErrorDTO.class) ) ) - @Post("/update") - @Produces(MediaType.APPLICATION_JSON) - public HttpResponse update( - @Valid @Body ItemModelDTO model - ) { - ItemModelResponseDTO result = itemService.updateItem(model); - if (result instanceof ItemModelResponseDTO.ItemModelErrorDTO) { - return HttpResponse.notFound(result); + @Put(uris = { + "/flag/{itemId}", + "/{itemId}/flag" + }) + public HttpResponse createFlag(@PathVariable("itemId") UUID itemId, @Body ItemFlagDTO flag) { + ItemFlagResponseDTO createResult = itemService.createFlagById(itemId, flag); + if (createResult instanceof ItemFlagResponseDTO.ItemFlagErrorDTO) { + return HttpResponse.notFound(createResult); + } + return HttpResponse.ok(createResult); + } + + + @Operation( + summary = "Delete flag of an item", + operationId = "deleteFlag", + description = "Deletes a specific flag (flagId) of the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "Flag successfully deleted.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagDTO.class) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagErrorDTO.class) + ) + ) + @Delete(uris = { + "/flag/{itemId}/{flagId}", + "/{itemId}/flag/{flagId}" + }) + public HttpResponse deleteFlag(@PathVariable("itemId") UUID itemId, @PathVariable("flagId") UUID flagId) { + var deleteResult = itemService.deleteFlagById(itemId, flagId); + if (deleteResult instanceof ItemFlagResponseDTO.ItemFlagErrorDTO) { + return HttpResponse.notFound(deleteResult); } - return HttpResponse.ok(result); + return HttpResponse.ok(deleteResult); + } + + @Operation( + summary = "Delete all flags of an item", + operationId = "deleteFlags", + description = "Deletes all flags of the item identified by itemId.", + tags = {"Item"} + ) + @ApiResponse( + responseCode = "200", + description = "All flags were successfully deleted.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + array = @ArraySchema( + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagDTO.class) + ) + ) + ) + @ApiResponse( + responseCode = "404", + description = "Item for the given ID was not found.", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + schema = @Schema(implementation = ItemFlagResponseDTO.ItemFlagErrorDTO.class) + ) + ) + @Delete(uris = { + "/flag/{itemId}/", + "/{itemId}/flag/" + }) + public HttpResponse> deleteFlags(@PathVariable("itemId") UUID itemId) { + var deletedFlags = itemService.deleteAllFlagsById(itemId); + return HttpResponse.ok(deletedFlags); } + } diff --git a/src/main/java/net/onelitefeather/vulpes/backend/controller/NotificationController.java b/src/main/java/net/onelitefeather/vulpes/backend/controller/NotificationController.java index b9a04f5..ddb905c 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/controller/NotificationController.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/controller/NotificationController.java @@ -182,7 +182,7 @@ public HttpResponse remove(@PathVariable UUID id) schema = @Schema(implementation = NotificationModelResponseDTO.NotificationModelErrorDTO.class) ) ) - @Get(uris = {"/all"}) + @Get(uris = {"/"}) @Produces(MediaType.APPLICATION_JSON) public HttpResponse> getAll(Pageable pageable) { Page list = notificationService.getAllNotifications(pageable); @@ -208,7 +208,7 @@ public HttpResponse> get schema = @Schema(implementation = NotificationModelResponseDTO.NotificationModelDTO.class) ) ) - @Delete("/delete/all") + @Delete("/delete/") @Produces(MediaType.APPLICATION_JSON) public HttpResponse> deleteAll() { List result = notificationService.deleteAllNotifications(); diff --git a/src/main/java/net/onelitefeather/vulpes/backend/controller/SoundController.java b/src/main/java/net/onelitefeather/vulpes/backend/controller/SoundController.java index b17c7f1..7d11e70 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/controller/SoundController.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/controller/SoundController.java @@ -175,7 +175,7 @@ public HttpResponse remove(@PathVariable UUID id) { schema = @Schema(implementation = SoundResponseDTO.SoundErrorDTO.class) ) ) - @Get("/all") + @Get("/") @Produces(MediaType.APPLICATION_JSON) public HttpResponse> getAll(Pageable pageable) { Page returnValues = soundService.getAllSoundEvents(pageable); @@ -196,7 +196,7 @@ public HttpResponse> getAll(Pageable pageab schema = @Schema(implementation = SoundResponseDTO.SoundModelDTO.class) ) ) - @Delete("/delete/all") + @Delete("/delete/") @Produces(MediaType.APPLICATION_JSON) public HttpResponse> deleteAll() { List results = soundService.deleteAllSoundEvents(); diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelDTO.java index 4cae114..586270e 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelDTO.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelDTO.java @@ -41,7 +41,7 @@ public record FontModelDTO( comment, height, ascent, - chars + List.of() ); } } diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelResponseDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelResponseDTO.java index dd7f581..bf8d772 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelResponseDTO.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontModelResponseDTO.java @@ -50,7 +50,6 @@ record FontModelCharsResponseDTO( * @param comment an example comment for the font model * @param ascent the ascent value of the font model * @param height the height of the font model - * @param chars an optional list of characters in the font model */ @Schema(name = "ResponseFontModelDTO", description = "Font model data") @Serdeable @@ -63,8 +62,7 @@ record FontModelDTO( @Schema(description = "Example comment", requiredMode = Schema.RequiredMode.REQUIRED) String texturePath, @Schema(description = "Example comment", requiredMode = Schema.RequiredMode.REQUIRED) String comment, @Schema(description = "Example comment", requiredMode = Schema.RequiredMode.REQUIRED) int ascent, - @Schema(description = "Example comment", requiredMode = Schema.RequiredMode.REQUIRED) int height, - @Schema(description = "Example comment", requiredMode = Schema.RequiredMode.NOT_REQUIRED) List chars + @Schema(description = "Example comment", requiredMode = Schema.RequiredMode.REQUIRED) int height ) implements FontModelResponseDTO { /** @@ -83,8 +81,7 @@ public static FontModelDTO createDTO(FontEntity fontModel) { fontModel.getTexturePath(), fontModel.getComment(), fontModel.getAscent(), - fontModel.getHeight(), - Collections.emptyList() + fontModel.getHeight() ); } @@ -104,8 +101,7 @@ public static FontModelDTO createDTOWithChars(FontEntity fontModel) { fontModel.getTexturePath(), fontModel.getComment(), fontModel.getAscent(), - fontModel.getHeight(), - fontModel.getChars() + fontModel.getHeight() ); } } diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontStringDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontStringDTO.java new file mode 100644 index 0000000..cce4d04 --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontStringDTO.java @@ -0,0 +1,33 @@ +package net.onelitefeather.vulpes.backend.domain.font; + +import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import net.onelitefeather.vulpes.api.model.font.FontStringEntity; + +import java.util.UUID; + +@Schema( + requiredProperties = { + "id", + "line", + "orderIndex" + } +) +@Introspected +@Serdeable +public record FontStringDTO( + UUID id, + String line, + int orderIndex +) { + + public FontStringEntity toEntity() { + FontStringEntity entity = new FontStringEntity(); + entity.setId(this.id); + entity.setLine(this.line); + entity.setOrderIndex(this.orderIndex); + return entity; + } + +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontStringResponseDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontStringResponseDTO.java new file mode 100644 index 0000000..aefa288 --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/font/FontStringResponseDTO.java @@ -0,0 +1,53 @@ +package net.onelitefeather.vulpes.backend.domain.font; + +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import net.onelitefeather.vulpes.api.model.font.FontStringEntity; +import net.onelitefeather.vulpes.backend.domain.error.ErrorResponse; + +import java.util.UUID; + +@Schema(description = "Response DTO for Font String Model") +@Serdeable +public interface FontStringResponseDTO { + + /** + * Represents a response DTO for font string id. + * + * @param id the unique identifier of the font string id + * @param line the line of the font string + * @param orderIndex the order index of the font string + */ + @Schema( + name = "ResponseFontStringDTO", + description = "Font String DTO" + ) + @Serdeable + record FontStringDTO( + @Schema(description = "Font String ID") UUID id, + @Schema(description = "Font String Line") String line, + @Schema(description = "Font String order index") int orderIndex + ) implements FontStringResponseDTO { + + public static FontStringResponseDTO createDTO(FontStringEntity entity) { + return new FontStringDTO(entity.getId(), entity.getLine(), entity.getOrderIndex()); + } + + } + + /** + * The {@link FontStringResponseDTO.FontStringErrorDTO} is used to represent an error response for Enchantment events. + * + * @param errorMessage the error message describing the issue + */ + @Schema( + name = "ResponseFontStringErrorDTO", + description = "Error message for Font String model" + ) + @Serdeable + record FontStringErrorDTO( + @Schema(description = "Error message") String errorMessage + ) implements FontStringResponseDTO, ErrorResponse { + } + +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemEnchantmentDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemEnchantmentDTO.java new file mode 100644 index 0000000..aced55e --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemEnchantmentDTO.java @@ -0,0 +1,36 @@ +package net.onelitefeather.vulpes.backend.domain.item; + +import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Positive; +import net.onelitefeather.vulpes.api.model.item.ItemEnchantmentEntity; + +import java.util.UUID; + +@Schema(requiredProperties = { + "id", + "name", + "level", + "unsafe", +}) +@Introspected +@Serdeable +public record ItemEnchantmentDTO( + @Schema(description = "ID of the Model", requiredMode = Schema.RequiredMode.NOT_REQUIRED) UUID id, + @Schema(description = "Name of the enchantment", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String name, + @Schema(description = "Level of the enchantment", requiredMode = Schema.RequiredMode.REQUIRED) @Positive short level, + @Schema(description = "If the enchantment is unsafe", requiredMode = Schema.RequiredMode.REQUIRED) boolean unsafe +) { + + + public ItemEnchantmentEntity toEntity() { + ItemEnchantmentEntity entity = new ItemEnchantmentEntity(); + entity.setId(this.id); + entity.setName(this.name); + entity.setLevel(this.level); + entity.setUnsafe(this.unsafe); + return entity; + } +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemEnchantmentResponseDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemEnchantmentResponseDTO.java new file mode 100644 index 0000000..7886f46 --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemEnchantmentResponseDTO.java @@ -0,0 +1,71 @@ +package net.onelitefeather.vulpes.backend.domain.item; + +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import net.onelitefeather.vulpes.api.model.item.ItemEnchantmentEntity; +import net.onelitefeather.vulpes.backend.domain.error.ErrorResponse; + +import java.util.UUID; + +@Schema(description = "Response DTO for Item Enchantment Model") +@Serdeable +public interface ItemEnchantmentResponseDTO { + + /** + * Represents a response DTO for item enchantments. + * + * @param id the unique identifier of the enchantment + * @param name the name of the enchantment + * @param level the level of the enchantment + */ + @Schema( + name = "ResponseItemEnchantmentDTO", + description = "Item Enchantment DTO" + ) + @Serdeable + record ItemEnchantmentDTO( + @Schema(description = "Enchantment ID") UUID id, + @Schema(description = "Enchantment Name") String name, + @Schema(description = "Enchantment Level") short level, + @Schema(description = "The unsafe option of the enchantment") boolean unsafe + ) implements ItemEnchantmentResponseDTO { + + /** + * Creates a new instance of ItemEnchantmentDTO. + * + * @param id the unique identifier of the enchantment + * @param name the name of the enchantment + * @param level the level of the enchantment + * @param unsafe the unsafe option of the enchantment + * @return a new ItemEnchantmentDTO instance + */ + public static ItemEnchantmentDTO createDTO(UUID id, String name, short level, boolean unsafe) { + return new ItemEnchantmentDTO(id, name, level, unsafe); + } + + /** + * Creates a new instance of ItemEnchantmentDTO from an {@link ItemEnchantmentEntity}. + * + * @param entity the entity to convert + * @return a new ItemEnchantmentDTO instance + */ + public static ItemEnchantmentResponseDTO createDTO(ItemEnchantmentEntity entity) { + return new ItemEnchantmentDTO(entity.getId(), entity.getName(), entity.getLevel(), entity.isUnsafe()); + } + } + + /** + * The {@link ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO} is used to represent an error response for Enchantment events. + * + * @param errorMessage the error message describing the issue + */ + @Schema( + name = "ResponseItemEnchantmentErrorDTO", + description = "Error message for Enchantment model" + ) + @Serdeable + record ItemEnchantmentErrorDTO( + @Schema(description = "Error message") String errorMessage + ) implements ItemEnchantmentResponseDTO, ErrorResponse { + } +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemFlagDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemFlagDTO.java new file mode 100644 index 0000000..74b0028 --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemFlagDTO.java @@ -0,0 +1,25 @@ +package net.onelitefeather.vulpes.backend.domain.item; + +import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import net.onelitefeather.vulpes.api.model.item.ItemFlagEntity; + +import java.util.UUID; + +@Schema() +@Introspected +@Serdeable +public record ItemFlagDTO( + @Schema(description = "ID of the Model", requiredMode = Schema.RequiredMode.NOT_REQUIRED) UUID id, + @Schema(description = "Flag of the Model", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String flag +) { + + public ItemFlagEntity toEntity() { + ItemFlagEntity entity = new ItemFlagEntity(); + entity.setId(this.id); + entity.setFlag(this.flag); + return entity; + } +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemFlagResponseDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemFlagResponseDTO.java new file mode 100644 index 0000000..804af12 --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemFlagResponseDTO.java @@ -0,0 +1,51 @@ +package net.onelitefeather.vulpes.backend.domain.item; + +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import net.onelitefeather.vulpes.api.model.item.ItemFlagEntity; +import net.onelitefeather.vulpes.backend.domain.error.ErrorResponse; + +import java.util.UUID; + +@Schema(description = "Response DTO for Item Flag Model") +@Serdeable +public interface ItemFlagResponseDTO { + + /** + * Represents a response DTO for item flag. + * + * @param id the unique identifier of the flag + * @param flag the flag of the flag + */ + @Schema( + name = "ResponseItemFlagDTO", + description = "Item Flag DTO" + ) + @Serdeable + record ItemFlagDTO( + @Schema(description = "Flag ID") UUID id, + @Schema(description = "Flag Text") String flag + ) implements ItemFlagResponseDTO { + + public static ItemFlagResponseDTO createDTO(ItemFlagEntity entity) { + return new ItemFlagDTO(entity.getId(), entity.getFlag()); + } + + } + + /** + * The {@link ItemFlagResponseDTO.ItemFlagErrorDTO} is used to represent an error response for flag entry. + * + * @param errorMessage the error message describing the issue + */ + @Schema( + name = "ResponseItemFlagErrorDTO", + description = "Error message for flag model" + ) + @Serdeable + record ItemFlagErrorDTO( + @Schema(description = "Error message") String errorMessage + ) implements ItemFlagResponseDTO, ErrorResponse { + } + +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemLoreDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemLoreDTO.java new file mode 100644 index 0000000..cc7d5ed --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemLoreDTO.java @@ -0,0 +1,29 @@ +package net.onelitefeather.vulpes.backend.domain.item; + +import io.micronaut.core.annotation.Introspected; +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Positive; +import net.onelitefeather.vulpes.api.model.item.ItemLoreEntity; + +import java.util.UUID; + +@Schema() +@Introspected +@Serdeable +public record ItemLoreDTO( + @Schema(description = "ID of the Model", requiredMode = Schema.RequiredMode.NOT_REQUIRED) UUID id, + @Schema(description = "Text of the lore", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String text, + @Schema(description = "Order index of the lore", requiredMode = Schema.RequiredMode.REQUIRED) @Positive int orderIndex +) { + + + public ItemLoreEntity toEntity() { + ItemLoreEntity entity = new ItemLoreEntity(); + entity.setId(this.id); + entity.setText(this.text); + entity.setOrderIndex(this.orderIndex); + return entity; + } +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemLoreResponseDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemLoreResponseDTO.java new file mode 100644 index 0000000..cf1e316 --- /dev/null +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemLoreResponseDTO.java @@ -0,0 +1,51 @@ +package net.onelitefeather.vulpes.backend.domain.item; + +import io.micronaut.serde.annotation.Serdeable; +import io.swagger.v3.oas.annotations.media.Schema; +import net.onelitefeather.vulpes.api.model.item.ItemLoreEntity; +import net.onelitefeather.vulpes.backend.domain.error.ErrorResponse; + +import java.util.UUID; + +@Schema(description = "Response DTO for Item Lore Model") +@Serdeable +public interface ItemLoreResponseDTO { + /** + * Represents a response DTO for item lore. + * + * @param id the unique identifier of the lore + * @param text the text of the lore + * @param orderIndex the orderIndex of the lore + */ + @Schema( + name = "ResponseItemLoreDTO", + description = "Item Lore DTO" + ) + @Serdeable + record ItemLoreDTO( + @Schema(description = "Lore ID") UUID id, + @Schema(description = "Lore Text") String text, + @Schema(description = "Lore Sort Index") int orderIndex + ) implements ItemLoreResponseDTO { + + public static ItemLoreResponseDTO createDTO(ItemLoreEntity entity) { + return new ItemLoreDTO(entity.getId(), entity.getText(), entity.getOrderIndex()); + } + + } + + /** + * The {@link ItemLoreResponseDTO.ItemLoreErrorDTO} is used to represent an error response for lore entry. + * + * @param errorMessage the error message describing the issue + */ + @Schema( + name = "ResponseItemLoreErrorDTO", + description = "Error message for lore model" + ) + @Serdeable + record ItemLoreErrorDTO( + @Schema(description = "Error message") String errorMessage + ) implements ItemLoreResponseDTO, ErrorResponse { + } +} diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelDTO.java index d84c4c2..7435a21 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelDTO.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelDTO.java @@ -10,7 +10,6 @@ import net.onelitefeather.vulpes.api.model.ItemEntity; import java.util.List; -import java.util.Map; import java.util.UUID; @Schema( @@ -34,12 +33,9 @@ public record ItemModelDTO( @Schema(description = "Internal description of the item", requiredMode = Schema.RequiredMode.REQUIRED) String comment, @Schema(description = "The display name of the item", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String displayName, @Schema(description = "The material from the item", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String material, - @Schema(description = "The group to identify their basic usage", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String group, + @Schema(description = "The group to identify their basic usage", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String groupName, @Schema(description = "Integer which refers to the customModelData index", requiredMode = Schema.RequiredMode.REQUIRED) @PositiveOrZero int customModelData, - @Schema(description = "The amount of the item", requiredMode = Schema.RequiredMode.REQUIRED) @Positive int amount, - @Schema(description = "The given enchantments", requiredMode = Schema.RequiredMode.NOT_REQUIRED) Map enchantments, - @Schema(description = "The given lore from the item", requiredMode = Schema.RequiredMode.NOT_REQUIRED) List lore, - @Schema(description = "The flags which the item should have", requiredMode = Schema.RequiredMode.NOT_REQUIRED) List flags + @Schema(description = "The amount of the item", requiredMode = Schema.RequiredMode.REQUIRED) @Positive int amount ) { /** @@ -55,12 +51,12 @@ public record ItemModelDTO( comment, displayName, material, - group, + groupName, customModelData, amount, - enchantments, - lore, - flags + List.of(), + List.of(), + List.of() ); } } diff --git a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelResponseDTO.java b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelResponseDTO.java index ed1423d..06e70fc 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelResponseDTO.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/domain/item/ItemModelResponseDTO.java @@ -15,31 +15,6 @@ @Serdeable public sealed interface ItemModelResponseDTO { - /** - * Represents a response DTO for item models that includes enchantments. - * @param name the name of the enchantment - * @param level the level of the enchantment - */ - @Schema( - name = "ResponseEnchantmentDTO", - description = "Item model with enchantments" - ) - @Serdeable - record ItemModelEnchantmentResponseDTO( - @Schema(description = "Enchantment name") String name, - @Schema(description = "Enchantment level") Short level - ) implements ItemModelResponseDTO { - - /** - * Creates a new instance of ItemModelEnchantmentResponseDTO. - * @param entry the map entry containing the enchantment name and level - * @return a new ItemModelEnchantmentResponseDTO instance - */ - public static ItemModelEnchantmentResponseDTO createDTO(Map.Entry entry) { - return new ItemModelEnchantmentResponseDTO(entry.getKey(), entry.getValue()); - } - } - /** diff --git a/src/main/java/net/onelitefeather/vulpes/backend/service/FontService.java b/src/main/java/net/onelitefeather/vulpes/backend/service/FontService.java index 4edae33..f3fe392 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/service/FontService.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/service/FontService.java @@ -5,6 +5,8 @@ import net.onelitefeather.vulpes.api.model.FontEntity; import net.onelitefeather.vulpes.backend.domain.font.FontModelDTO; import net.onelitefeather.vulpes.backend.domain.font.FontModelResponseDTO; +import net.onelitefeather.vulpes.backend.domain.font.FontStringDTO; +import net.onelitefeather.vulpes.backend.domain.font.FontStringResponseDTO; import java.util.List; import java.util.Optional; @@ -66,15 +68,40 @@ public interface FontService { * Gets the characters of a font by its ID. * * @param id the ID of the font + * @param pageable pagination information * @return a list of characters */ - List findCharsByFontId(UUID id); + Page findCharsByFontId(UUID id, Pageable pageable); + + /** + * Updates the character of a font by its ID. + * @param id the ID of the font + * @param charModel the new character to set + * @return the updated character + */ + FontStringResponseDTO updateCharByFontId(UUID id, FontStringDTO charModel); /** - * Updates the characters of a font by its ID. + * Create the character of a font by its ID. * @param id the ID of the font - * @param chars the new characters to set - * @return the updated characters + * @param charModel the new character to set + * @return the updated character + */ + FontStringResponseDTO createCharByFontId(UUID id, FontStringDTO charModel); + + /** + * Deletes the character of a font by its ID. + * @param fontId the ID of the font + * @param charId the id of the character to delete + * @return the deleted character + */ + FontStringResponseDTO deleteCharByFontId(UUID fontId, UUID charId); + + + /** + * Deletes all characters of a font by its ID. + * @param fontId the ID of the font + * @return the list of deleted characters */ - List updateCharsByFontId(UUID id, List chars); + List deleteAllCharByFontId(UUID fontId); } \ No newline at end of file diff --git a/src/main/java/net/onelitefeather/vulpes/backend/service/ItemService.java b/src/main/java/net/onelitefeather/vulpes/backend/service/ItemService.java index fe6fac2..d9713c7 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/service/ItemService.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/service/ItemService.java @@ -3,11 +3,16 @@ import io.micronaut.data.model.Page; import io.micronaut.data.model.Pageable; import net.onelitefeather.vulpes.api.model.ItemEntity; +import net.onelitefeather.vulpes.backend.domain.item.ItemEnchantmentDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemEnchantmentResponseDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemFlagDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemFlagResponseDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemLoreDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemLoreResponseDTO; import net.onelitefeather.vulpes.backend.domain.item.ItemModelDTO; import net.onelitefeather.vulpes.backend.domain.item.ItemModelResponseDTO; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -64,22 +69,84 @@ public interface ItemService { Optional findItemById(UUID id); /** - * Gets the enchantments of an item by its ID. + * Gets the flags of an item by its ID. * * @param id the ID of the item * @param pageable pagination information - * @return a map of enchantment names to levels + * @return a list of flags */ - Map findEnchantmentsById(UUID id, Pageable pageable); + Page findFlagsById(UUID id, Pageable pageable); /** - * Gets the flags of an item by its ID. + * Creates the flag of an item by its ID. + * @param id the ID of the item to update the flag of + * @param itemFlagDTO the flag to create + * @return the created flag + */ + ItemFlagResponseDTO createFlagById(UUID id, ItemFlagDTO itemFlagDTO); + + /** + * Delete the flag of an item by its ID. + * @param id the ID of the item to update the flag of + * @param flagId the flag to delete + * @return the deleted flag + */ + ItemFlagResponseDTO deleteFlagById(UUID id, UUID flagId); + + /** + * Delete the flags of an item by its ID. + * @param id the ID of the item to update the flags of + * @return the deleted flags + */ + List deleteAllFlagsById(UUID id); + + /** + * Updates the flag of an item by its ID. + * @param id the ID of the item to update the flag of + * @param flag the new flag to set + * @return the updated flag + */ + ItemFlagResponseDTO updateFlagById(UUID id, ItemFlagDTO flag); + + /** + * Gets the enchantments of an item by its ID. * * @param id the ID of the item * @param pageable pagination information - * @return a list of flags + * @return a map of enchantment names to levels + */ + Page findEnchantmentsById(UUID id, Pageable pageable); + + /** + * Updates the enchantments of an item by its ID. + * @param id the ID of the item to update the enchantments of + * @param enchantment the enchantments to update + * @return the updated enchantments */ - List findFlagsById(UUID id, Pageable pageable); + ItemEnchantmentResponseDTO updateEnchantmentById(UUID id, ItemEnchantmentDTO enchantment); + + /** + * Creates the enchantments of an item by its ID. + * @param id the ID of the item to update the enchantments of + * @param enchantment the enchantments to create + * @return the created enchantment + */ + ItemEnchantmentResponseDTO createEnchantmentById(UUID id, ItemEnchantmentDTO enchantment); + + /** + * Delete the enchantment of an item by its ID. + * @param id the ID of the item to update the enchantments of + * @param enchantment the enchantment to delete + * @return the deleted enchantment + */ + ItemEnchantmentResponseDTO deleteEnchantmentById(UUID id, UUID enchantment); + + /** + * Delete the enchantments of an item by its ID. + * @param id the ID of the item to update the enchantments of + * @return the deleted enchantment + */ + List deleteAllEnchantmentsById(UUID id); /** * Gets the lore of an item by its ID. @@ -88,29 +155,36 @@ public interface ItemService { * @param pageable pagination information * @return a list of lore lines */ - List findLoreById(UUID id, Pageable pageable); + Page findLoreById(UUID id, Pageable pageable); /** - * Updates the flags of an item by its ID. - * @param id the ID of the item to update the flags of - * @param flags the new flags to set - * @return the updated flags + * Updates the lore of an item by its ID. + * @param id the ID of the item to update the lore of + * @param loreDto the lore to update + * @return the updated lore */ - List updateFlagsById(UUID id, List flags); + ItemLoreResponseDTO updateLoreById(UUID id, ItemLoreDTO loreDto); /** - * Updates the enchantments of an item by its ID. + * Creates the lore of an item by its ID. + * @param id the ID of the item to update the lore of item + * @param loreDto the lore to create + * @return the created lore + */ + ItemLoreResponseDTO createLoreById(UUID id, ItemLoreDTO loreDto); + + /** + * Delete the enchantment of an item by its ID. * @param id the ID of the item to update the enchantments of - * @param enchantments the new enchantments to set - * @return the updated enchantments + * @param loreId the enchantment to delete + * @return the deleted enchantment */ - Map updateEnchantmentsById(UUID id, Map enchantments); + ItemLoreResponseDTO deleteLoreById(UUID id, UUID loreId); /** - * Updates the lore of an item by its ID. + * Delete the lore of an item by its ID. * @param id the ID of the item to update the lore of - * @param lore the new lore to set - * @return the updated lore + * @return the deleted lore */ - List updateLoreById(UUID id, List lore); + List deleteAllLoreById(UUID id); } \ No newline at end of file diff --git a/src/main/java/net/onelitefeather/vulpes/backend/service/impl/FontServiceImpl.java b/src/main/java/net/onelitefeather/vulpes/backend/service/impl/FontServiceImpl.java index cb41cf6..7f914c4 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/service/impl/FontServiceImpl.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/service/impl/FontServiceImpl.java @@ -4,10 +4,14 @@ import io.micronaut.data.model.Pageable; import jakarta.inject.Inject; import jakarta.inject.Singleton; +import jakarta.transaction.Transactional; import net.onelitefeather.vulpes.api.model.FontEntity; import net.onelitefeather.vulpes.api.repository.FontRepository; +import net.onelitefeather.vulpes.api.repository.font.FontStringRepository; import net.onelitefeather.vulpes.backend.domain.font.FontModelDTO; import net.onelitefeather.vulpes.backend.domain.font.FontModelResponseDTO; +import net.onelitefeather.vulpes.backend.domain.font.FontStringDTO; +import net.onelitefeather.vulpes.backend.domain.font.FontStringResponseDTO; import net.onelitefeather.vulpes.backend.service.FontService; import java.util.List; @@ -21,10 +25,12 @@ public class FontServiceImpl implements FontService { private final FontRepository fontRepository; + private final FontStringRepository fontStringRepository; @Inject - public FontServiceImpl(FontRepository fontRepository) { + public FontServiceImpl(FontRepository fontRepository, FontStringRepository fontStringRepository) { this.fontRepository = fontRepository; + this.fontStringRepository = fontStringRepository; } @Override @@ -73,19 +79,70 @@ public Optional findFontById(UUID id) { } @Override - public List findCharsByFontId(UUID id) { - return fontRepository.findCharsByFontId(id, Pageable.UNPAGED); + public Page findCharsByFontId(UUID id, Pageable pageable) { + return this.fontStringRepository.findCharsByFontId(id, pageable).map(FontStringResponseDTO.FontStringDTO::createDTO); } + @Transactional @Override - public List updateCharsByFontId(UUID id, List chars) { + public FontStringResponseDTO updateCharByFontId(UUID id, FontStringDTO charModel) { var byId = this.fontRepository.findById(id); + if (byId.isEmpty()) { + return new FontStringResponseDTO.FontStringErrorDTO("Font not found"); + } + var fontEntity = byId.get(); + var charEntity = charModel.toEntity(); + charEntity.setFont(fontEntity); + var updatedChar = this.fontStringRepository.update(charEntity); + return FontStringResponseDTO.FontStringDTO.createDTO(updatedChar); + } + + @Transactional + @Override + public FontStringResponseDTO createCharByFontId(UUID id, FontStringDTO charModel) { + var byId = this.fontRepository.findById(id); + if (byId.isEmpty()) { + return new FontStringResponseDTO.FontStringErrorDTO("Font not found"); + } + var fontEntity = byId.get(); + var charEntity = charModel.toEntity(); + charEntity.setFont(fontEntity); + var savedChar = this.fontStringRepository.save(charEntity); + return FontStringResponseDTO.FontStringDTO.createDTO(savedChar); + } + + @Override + public FontStringResponseDTO deleteCharByFontId(UUID fontId, UUID charId) { + var byId = this.fontRepository.findById(fontId); + if (byId.isEmpty()) { + return new FontStringResponseDTO.FontStringErrorDTO("Font not found"); + } + var charById = this.fontStringRepository.findById(charId); + if (charById.isEmpty()) { + return new FontStringResponseDTO.FontStringErrorDTO("Font character not found"); + } + var fontEntity = byId.get(); + var charEntity = charById.get(); + if (!fontEntity.getId().equals(charEntity.getFont().getId())) { + return new FontStringResponseDTO.FontStringErrorDTO("Font character not found"); + } + this.fontStringRepository.deleteById(charId); + return FontStringResponseDTO.FontStringDTO.createDTO(charEntity); + } + + @Override + public List deleteAllCharByFontId(UUID fontId) { + var byId = this.fontRepository.findById(fontId); if (byId.isEmpty()) { return List.of(); } - var font = byId.get(); - font.setChars(chars); - var updated = this.fontRepository.update(font); - return updated.getChars(); + var fontEntity = byId.get(); + var charEntities = this.fontStringRepository.findAll() + .stream() + .filter(charEntity -> charEntity.getFont().getId().equals(fontEntity.getId())).toList(); + this.fontStringRepository.deleteAll(charEntities); + return charEntities.stream() + .map(FontStringResponseDTO.FontStringDTO::createDTO) + .toList(); } } \ No newline at end of file diff --git a/src/main/java/net/onelitefeather/vulpes/backend/service/impl/ItemServiceImpl.java b/src/main/java/net/onelitefeather/vulpes/backend/service/impl/ItemServiceImpl.java index ea768fb..9740b0d 100644 --- a/src/main/java/net/onelitefeather/vulpes/backend/service/impl/ItemServiceImpl.java +++ b/src/main/java/net/onelitefeather/vulpes/backend/service/impl/ItemServiceImpl.java @@ -5,13 +5,23 @@ import jakarta.inject.Inject; import jakarta.inject.Singleton; import net.onelitefeather.vulpes.api.model.ItemEntity; +import net.onelitefeather.vulpes.api.model.item.ItemEnchantmentEntity; +import net.onelitefeather.vulpes.api.model.item.ItemLoreEntity; import net.onelitefeather.vulpes.api.repository.ItemRepository; +import net.onelitefeather.vulpes.api.repository.item.ItemEnchantmentRepository; +import net.onelitefeather.vulpes.api.repository.item.ItemFlagRepository; +import net.onelitefeather.vulpes.api.repository.item.ItemLoreRepository; +import net.onelitefeather.vulpes.backend.domain.item.ItemEnchantmentDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemEnchantmentResponseDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemFlagDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemFlagResponseDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemLoreDTO; +import net.onelitefeather.vulpes.backend.domain.item.ItemLoreResponseDTO; import net.onelitefeather.vulpes.backend.domain.item.ItemModelDTO; import net.onelitefeather.vulpes.backend.domain.item.ItemModelResponseDTO; import net.onelitefeather.vulpes.backend.service.ItemService; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -21,11 +31,21 @@ @Singleton public class ItemServiceImpl implements ItemService { + private static final String GENERIC_ERROR = "Item not found"; private final ItemRepository itemRepository; + private final ItemEnchantmentRepository itemEnchantmentRepository; + private final ItemLoreRepository itemLoreRepository; + private final ItemFlagRepository itemFlagRepository; @Inject - public ItemServiceImpl(ItemRepository itemRepository) { + public ItemServiceImpl(ItemRepository itemRepository, + ItemEnchantmentRepository itemEnchantmentRepository, + ItemLoreRepository itemLoreRepository, + ItemFlagRepository itemFlagRepository) { this.itemRepository = itemRepository; + this.itemEnchantmentRepository = itemEnchantmentRepository; + this.itemLoreRepository = itemLoreRepository; + this.itemFlagRepository = itemFlagRepository; } @Override @@ -73,53 +93,194 @@ public Optional findItemById(UUID id) { } @Override - public Map findEnchantmentsById(UUID id,Pageable pageable) { - return itemRepository.findEnchantmentsById(id, pageable); + public Page findEnchantmentsById(UUID id, Pageable pageable) { + return this.itemEnchantmentRepository.findEnchantmentsById(id, pageable).map(ItemEnchantmentResponseDTO.ItemEnchantmentDTO::createDTO); } @Override - public List findFlagsById(UUID id, Pageable pageable) { - return itemRepository.findFlagsById(id, pageable); + public Page findFlagsById(UUID id, Pageable pageable) { + return this.itemFlagRepository.findFlagsById(id, pageable).map(ItemFlagResponseDTO.ItemFlagDTO::createDTO); } @Override - public List findLoreById(UUID id, Pageable pageable) { - return itemRepository.findLoreById(id, pageable); + public ItemFlagResponseDTO createFlagById(UUID id, ItemFlagDTO itemFlagDTO) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemFlagResponseDTO.ItemFlagErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + var entity = itemFlagDTO.toEntity(); + entity.setItem(item); + var saved = this.itemFlagRepository.save(entity); + return ItemFlagResponseDTO.ItemFlagDTO.createDTO(saved); + } + + @Override + public ItemFlagResponseDTO deleteFlagById(UUID id, UUID flagId) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemFlagResponseDTO.ItemFlagErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + var entity = this.itemFlagRepository.findById(flagId); + if (entity.isEmpty()) { + return new ItemFlagResponseDTO.ItemFlagErrorDTO(GENERIC_ERROR); + } + var resolvedEntity = entity.get(); + if (!resolvedEntity.getItem().getId().equals(item.getId())) { + return new ItemFlagResponseDTO.ItemFlagErrorDTO(GENERIC_ERROR); + } + this.itemFlagRepository.deleteById(resolvedEntity.getId()); + return ItemFlagResponseDTO.ItemFlagDTO.createDTO(resolvedEntity); + } + + @Override + public List deleteAllFlagsById(UUID id) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return List.of(); + } + var item = byId.get(); + var flags = this.itemFlagRepository.findAll().stream().filter(e -> e.getItem().getId().equals(item.getId())).toList(); + this.itemFlagRepository.deleteAll(flags); + return flags.stream() + .map(ItemFlagResponseDTO.ItemFlagDTO::createDTO) + .toList(); + } + + @Override + public Page findLoreById(UUID id, Pageable pageable) { + return this.itemLoreRepository.findLoreById(id, pageable).map(ItemLoreResponseDTO.ItemLoreDTO::createDTO); + } + + @Override + public ItemLoreResponseDTO updateLoreById(UUID id, ItemLoreDTO lore) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemLoreResponseDTO.ItemLoreErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + var entity = lore.toEntity(); + entity.setItem(item); + var saved = this.itemLoreRepository.update(entity); + return ItemLoreResponseDTO.ItemLoreDTO.createDTO(saved); + } + + @Override + public ItemLoreResponseDTO createLoreById(UUID id, ItemLoreDTO loreDto) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemLoreResponseDTO.ItemLoreErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + var entity = loreDto.toEntity(); + entity.setItem(item); + var saved = this.itemLoreRepository.save(entity); + return ItemLoreResponseDTO.ItemLoreDTO.createDTO(saved); + } + + @Override + public ItemLoreResponseDTO deleteLoreById(UUID id, UUID loreId) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemLoreResponseDTO.ItemLoreErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + var entity = this.itemLoreRepository.findById(loreId); + if (entity.isEmpty()) { + return new ItemLoreResponseDTO.ItemLoreErrorDTO(GENERIC_ERROR); + } + var resolvedEntity = entity.get(); + if (!resolvedEntity.getItem().getId().equals(item.getId())) { + return new ItemLoreResponseDTO.ItemLoreErrorDTO(GENERIC_ERROR); + } + this.itemLoreRepository.deleteById(resolvedEntity.getId()); + return ItemLoreResponseDTO.ItemLoreDTO.createDTO(resolvedEntity); } @Override - public List updateLoreById(UUID id, List lore) { + public List deleteAllLoreById(UUID id) { var byId = this.itemRepository.findById(id); if (byId.isEmpty()) { return List.of(); } var item = byId.get(); - item.setLore(lore); - var updated = this.itemRepository.update(item); - return updated.getLore(); + var lores = this.itemLoreRepository.findAll().stream().filter(e -> e.getItem().getId().equals(item.getId())).toList(); + this.itemLoreRepository.deleteAll(lores); + return lores.stream() + .map(ItemLoreResponseDTO.ItemLoreDTO::createDTO) + .toList(); } @Override - public Map updateEnchantmentsById(UUID id, Map enchantments) { + public ItemEnchantmentResponseDTO updateEnchantmentById(UUID id, ItemEnchantmentDTO enchantment) { var byId = this.itemRepository.findById(id); if (byId.isEmpty()) { - return Map.of(); + return new ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO(GENERIC_ERROR); } var item = byId.get(); - item.setEnchantments(enchantments); - var updated = this.itemRepository.update(item); - return updated.getEnchantments(); + ItemEnchantmentEntity entity = enchantment.toEntity(); + entity.setItem(item); + var saved = this.itemEnchantmentRepository.update(entity); + return ItemEnchantmentResponseDTO.ItemEnchantmentDTO.createDTO(saved); } @Override - public List updateFlagsById(UUID id, List flags) { + public ItemEnchantmentResponseDTO createEnchantmentById(UUID id, ItemEnchantmentDTO enchantment) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + ItemEnchantmentEntity entity = enchantment.toEntity(); + entity.setItem(item); + var saved = this.itemEnchantmentRepository.save(entity); + return ItemEnchantmentResponseDTO.ItemEnchantmentDTO.createDTO(saved); + } + + @Override + public ItemEnchantmentResponseDTO deleteEnchantmentById(UUID id, UUID enchantment) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + var entity = this.itemEnchantmentRepository.findById(enchantment); + if (entity.isEmpty()) { + return new ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO(GENERIC_ERROR); + } + var resolvedEntity = entity.get(); + if (!resolvedEntity.getItem().getId().equals(item.getId())) { + return new ItemEnchantmentResponseDTO.ItemEnchantmentErrorDTO(GENERIC_ERROR); + } + this.itemEnchantmentRepository.deleteById(resolvedEntity.getId()); + return ItemEnchantmentResponseDTO.ItemEnchantmentDTO.createDTO(resolvedEntity); + } + + @Override + public List deleteAllEnchantmentsById(UUID id) { var byId = this.itemRepository.findById(id); if (byId.isEmpty()) { return List.of(); } var item = byId.get(); - item.setFlags(flags); - var updated = this.itemRepository.update(item); - return updated.getFlags(); + var enchantments = this.itemEnchantmentRepository.findAll().stream().filter(e -> e.getItem().getId().equals(item.getId())).toList(); + this.itemEnchantmentRepository.deleteAll(enchantments); + return enchantments.stream() + .map(ItemEnchantmentResponseDTO.ItemEnchantmentDTO::createDTO) + .toList(); + } + + @Override + public ItemFlagResponseDTO updateFlagById(UUID id, ItemFlagDTO flag) { + var byId = this.itemRepository.findById(id); + if (byId.isEmpty()) { + return new ItemFlagResponseDTO.ItemFlagErrorDTO(GENERIC_ERROR); + } + var item = byId.get(); + var entity = flag.toEntity(); + entity.setItem(item); + var saved = this.itemFlagRepository.update(entity); + return ItemFlagResponseDTO.ItemFlagDTO.createDTO(saved); } } \ No newline at end of file diff --git a/src/test/java/net/onelitefeather/vulpes/backend/controller/SoundControllerIntegrationTest.java b/src/test/java/net/onelitefeather/vulpes/backend/controller/SoundControllerIntegrationTest.java index 328e71c..bab0535 100644 --- a/src/test/java/net/onelitefeather/vulpes/backend/controller/SoundControllerIntegrationTest.java +++ b/src/test/java/net/onelitefeather/vulpes/backend/controller/SoundControllerIntegrationTest.java @@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +@Disabled @MicronautTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) @DisplayName("Integration tests for SoundController endpoints with Testcontainers") diff --git a/src/test/java/net/onelitefeather/vulpes/backend/domain/item/validation/ItemModelDTOValidationTest.java b/src/test/java/net/onelitefeather/vulpes/backend/domain/item/validation/ItemModelDTOValidationTest.java index 94819ef..20eae57 100644 --- a/src/test/java/net/onelitefeather/vulpes/backend/domain/item/validation/ItemModelDTOValidationTest.java +++ b/src/test/java/net/onelitefeather/vulpes/backend/domain/item/validation/ItemModelDTOValidationTest.java @@ -21,10 +21,7 @@ void testBlankUiNameValidationFail() { "minecraft:gold_shovel", "weapon", 1, - 1, - Map.of(), - List.of(), - List.of() + 1 ); assertViolation(dto, "uiName"); @@ -41,10 +38,7 @@ void testBlankVariableNameValidationFail() { "minecraft:dirt", "misc", 1, - 1, - Map.of(), - List.of(), - List.of() + 1 ); assertViolation(dto, "variableName"); @@ -61,10 +55,7 @@ void testBlankCommentValidationFail() { "minecraft:bucket", "misc", 1, - 1, - Map.of(), - List.of(), - List.of() + 1 ); assertNoViolation(dto, "comment"); } @@ -80,10 +71,7 @@ void testBlankDisplayNameValidationFail() { "minecraft:dirt", "misc", 1, - 1, - Map.of(), - List.of(), - List.of() + 1 ); assertViolation(dto, "displayName"); @@ -100,10 +88,7 @@ void testBlankMaterialValidationFail() { "", // invalid "weapon", 1, - 1, - Map.of(), - List.of(), - List.of() + 1 ); assertViolation(dto, "material"); @@ -120,13 +105,10 @@ void testBlankGroupValidationFail() { "minecraft:stone", "", // invalid 1, - 1, - Map.of(), - List.of(), - List.of() + 1 ); - assertViolation(dto, "group"); + assertViolation(dto, "groupName"); } @Test @@ -140,10 +122,7 @@ void testNegativeCustomModelDataValidationFail() { "material:wool", "misc", -1, // invalid - 1, - Map.of(), - List.of(), - List.of() + 1 ); assertViolation(dto, "customModelData"); @@ -160,10 +139,7 @@ void testNegativeAmountValidationFail() { "minecraft:dirt", "tools", 1, - -1, // invalid - Map.of(), - List.of(), - List.of() + -1 ); assertViolation(dto, "amount");