diff --git a/api/src/main/java/com/javadiscord/jdi/core/api/DiscordResponseParser.java b/api/src/main/java/com/javadiscord/jdi/core/api/DiscordResponseParser.java index b727fa38..7f188669 100644 --- a/api/src/main/java/com/javadiscord/jdi/core/api/DiscordResponseParser.java +++ b/api/src/main/java/com/javadiscord/jdi/core/api/DiscordResponseParser.java @@ -100,7 +100,10 @@ private void success( ) { if (isSuccessfulResponse(response)) { try { - T result = OBJECT_MAPPER.readValue(response.body(), type); + T result = null; + if (!response.body().isEmpty()) { + result = OBJECT_MAPPER.readValue(response.body(), type); + } asyncResponse.setResult(result); } catch (JsonProcessingException e) { asyncResponse.setException(e); diff --git a/api/src/main/java/com/javadiscord/jdi/core/api/StickerRequest.java b/api/src/main/java/com/javadiscord/jdi/core/api/StickerRequest.java index 8d488058..e1220c98 100644 --- a/api/src/main/java/com/javadiscord/jdi/core/api/StickerRequest.java +++ b/api/src/main/java/com/javadiscord/jdi/core/api/StickerRequest.java @@ -18,7 +18,6 @@ public StickerRequest(DiscordResponseParser responseParser, long guildId) { } public AsyncResponse createGuildSticker( - long guildId, String name, String description, String tags, @@ -30,9 +29,9 @@ public AsyncResponse createGuildSticker( ); } - public AsyncResponse deleteGuildSticker(long stickerId) { + public AsyncResponse deleteGuildSticker(long stickerId) { return responseParser.callAndParse( - Sticker.class, new DeleteGuildStickerRequest(guildId, stickerId) + Void.class, new DeleteGuildStickerRequest(guildId, stickerId) ); } diff --git a/api/src/main/java/com/javadiscord/jdi/core/api/utils/DiscordImageUtil.java b/api/src/main/java/com/javadiscord/jdi/core/api/utils/DiscordImageUtil.java index de1a9cd8..971052ef 100644 --- a/api/src/main/java/com/javadiscord/jdi/core/api/utils/DiscordImageUtil.java +++ b/api/src/main/java/com/javadiscord/jdi/core/api/utils/DiscordImageUtil.java @@ -26,7 +26,7 @@ public static boolean isNotImage(Path path) { return !IMAGE_EXTENSIONS.contains(getExtension(path)); } - private static String getExtension(Path path) { + public static String getExtension(Path path) { String fileName = path.getFileName().toString().toLowerCase(); return fileName.substring(fileName.lastIndexOf('.') + 1); } diff --git a/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestBuilder.java b/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestBuilder.java index b17f82cd..ab3359e2 100644 --- a/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestBuilder.java +++ b/api/src/main/java/com/javadiscord/jdi/internal/api/DiscordRequestBuilder.java @@ -57,7 +57,7 @@ public DiscordRequestBuilder body(HttpRequest.BodyPublisher body) { public DiscordRequestBuilder multipartBody(MultipartBodyPublisher body) { this.body = body; - this.headers.put("Content-Type", "multipart/form-data"); + this.headers.put("Content-Type", "multipart/form-data; boundary=" + body.boundary()); return this; } diff --git a/api/src/main/java/com/javadiscord/jdi/internal/api/sticker/CreateGuildStickerRequest.java b/api/src/main/java/com/javadiscord/jdi/internal/api/sticker/CreateGuildStickerRequest.java index 15b4e33e..cd9cd8a3 100644 --- a/api/src/main/java/com/javadiscord/jdi/internal/api/sticker/CreateGuildStickerRequest.java +++ b/api/src/main/java/com/javadiscord/jdi/internal/api/sticker/CreateGuildStickerRequest.java @@ -1,12 +1,13 @@ package com.javadiscord.jdi.internal.api.sticker; import java.io.FileNotFoundException; -import java.net.http.HttpRequest; import java.nio.file.Path; +import com.javadiscord.jdi.core.api.utils.DiscordImageUtil; import com.javadiscord.jdi.internal.api.DiscordRequest; import com.javadiscord.jdi.internal.api.DiscordRequestBuilder; +import com.github.mizosoft.methanol.MediaType; import com.github.mizosoft.methanol.MultipartBodyPublisher; public record CreateGuildStickerRequest( @@ -19,21 +20,29 @@ public record CreateGuildStickerRequest( @Override public DiscordRequestBuilder create() { - HttpRequest.BodyPublisher body; + try { - body = + MultipartBodyPublisher.Builder body = MultipartBodyPublisher.newBuilder() .textPart("name", name) .textPart("description", description) - .textPart("tags", tags) - .filePart("file", filePath) - .build(); + .textPart("tags", tags); + + String extension = DiscordImageUtil.getExtension(filePath); + + switch (extension) { + case "png" -> body.filePart("file", filePath, MediaType.IMAGE_PNG); + case "jpg", "jpeg" -> body.filePart("file", filePath, MediaType.IMAGE_JPEG); + case "gif" -> body.filePart("file", filePath, MediaType.IMAGE_GIF); + } + + return new DiscordRequestBuilder() + .post() + .path("/guilds/%s/stickers".formatted(guildId)) + .multipartBody(body.build()); + } catch (FileNotFoundException e) { throw new RuntimeException(e); } - return new DiscordRequestBuilder() - .post() - .path("/guilds/%s/stickers".formatted(guildId)) - .body(body); } } diff --git a/api/src/test/integration/com/javadiscord/jdi/core/api/StickerRequestTest.java b/api/src/test/integration/com/javadiscord/jdi/core/api/StickerRequestTest.java new file mode 100644 index 00000000..2f86d8dd --- /dev/null +++ b/api/src/test/integration/com/javadiscord/jdi/core/api/StickerRequestTest.java @@ -0,0 +1,131 @@ +package com.javadiscord.jdi.core.api; + +import com.javadiscord.jdi.core.Guild; +import com.javadiscord.jdi.core.api.builders.ModifyGuildStickerBuilder; +import com.javadiscord.jdi.core.models.message.Sticker; +import com.javadiscord.jdi.core.models.message.StickerFormatType; +import com.javadiscord.jdi.core.models.message.StickerType; +import helpers.LiveDiscordHelper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.*; + +class StickerRequestTest { + private static Guild guild; + + @BeforeAll + public static void setup() throws InterruptedException { + guild = new LiveDiscordHelper().getGuild(); + } + + @Test + void testCreateGuildStickerThenGetAndDelete() throws InterruptedException, URISyntaxException { + CountDownLatch latch = new CountDownLatch(1); + + String stickerName = "sticker-" + ThreadLocalRandom.current().nextInt(1,10); + String description = "d-" + ThreadLocalRandom.current().nextInt(1,10); + String tags = "tag-" + ThreadLocalRandom.current().nextInt(1,10); + + URL url = StickerRequestTest.class.getResource("/test-sticker.png"); + + if (url == null) { + fail("/test-sticker.png not found"); + return; + } + + AsyncResponse asyncResponse = guild + .sticker() + .createGuildSticker(stickerName, description, tags, Paths.get(url.toURI())); + + AtomicReference stickerId = new AtomicReference<>(); + + asyncResponse.onSuccess(res -> { + assertEquals(stickerName, res.name()); + assertEquals(description, res.description()); + assertEquals(tags, res.tags()); + assertEquals(StickerType.GUILD, res.type()); + assertEquals(StickerFormatType.PNG, res.formatType()); + stickerId.set(res.id()); + latch.countDown(); + }); + + asyncResponse.onError(Assertions::fail); + + assertTrue(latch.await(30, TimeUnit.SECONDS)); + + if(stickerId.get() != null) { + guild.sticker().deleteGuildSticker(stickerId.get()) + .onError(Assertions::fail); + } else { + fail(); + } + } + + @Test + void testModifySticker() throws InterruptedException, URISyntaxException { + CountDownLatch createLatch = new CountDownLatch(1); + + URL testSticker = StickerRequestTest.class.getResource("/test-sticker.png"); + URL testSticker2 = StickerRequestTest.class.getResource("/test-sticker-2.png"); + + if (testSticker == null) { + fail("/test-sticker.png not found"); + return; + } + if (testSticker2 == null) { + fail("/test-sticker-2.png not found"); + return; + } + + AtomicReference stickerId = new AtomicReference<>(); + + guild.sticker() + .createGuildSticker("test-sticker", "description", "tags", Paths.get(testSticker.toURI())) + .onSuccess(res -> { + stickerId.set(res.id()); + createLatch.countDown(); + }) + .onError(Assertions::fail); + + assertTrue(createLatch.await(30, TimeUnit.SECONDS)); + + CountDownLatch modifyLatch = new CountDownLatch(1); + + guild.sticker() + .modifyGuildSticker(new ModifyGuildStickerBuilder(stickerId.get()) + .description("new description") + .name("new name") + .tags("new tags")) + .onSuccess(res -> { + assertEquals("new name", res.name()); + assertEquals("new description", res.description()); + assertEquals("new tags", res.tags()); + modifyLatch.countDown(); + }) + .onError(err -> { + System.err.println("error: " + err.getMessage()); + }); + + assertTrue(modifyLatch.await(30, TimeUnit.SECONDS)); + + CountDownLatch deleteLatch = new CountDownLatch(1); + + AsyncResponse delete = guild.sticker() + .deleteGuildSticker(stickerId.get()); + + delete.onSuccess(res -> deleteLatch.countDown()); + delete.onError(Assertions::fail); + + assertTrue(deleteLatch.await(30, TimeUnit.SECONDS)); + } +} diff --git a/api/src/test/resources/test-sticker-2.png b/api/src/test/resources/test-sticker-2.png new file mode 100644 index 00000000..3e8e1eca Binary files /dev/null and b/api/src/test/resources/test-sticker-2.png differ diff --git a/api/src/test/resources/test-sticker.png b/api/src/test/resources/test-sticker.png new file mode 100644 index 00000000..4685213b Binary files /dev/null and b/api/src/test/resources/test-sticker.png differ