diff --git a/gleam.toml b/gleam.toml index 1f47e9c..3fa498d 100644 --- a/gleam.toml +++ b/gleam.toml @@ -8,9 +8,9 @@ repository = { type = "github", user = "folospior", repo = "flybycord"} gleam_stdlib = ">= 0.44.0 and < 2.0.0" gleam_httpc = ">= 4.1.0 and < 5.0.0" gleam_http = ">= 4.0.0 and < 5.0.0" -gleam_json = ">= 2.3.0 and < 3.0.0" +gleam_json = ">= 3.0.1 and < 4.0.0" gleam_time = ">= 1.1.0 and < 2.0.0" -multipart_form = ">= 1.0.0 and < 2.0.0" +multipart_form = ">= 1.1.0 and < 2.0.0" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index e147ba9..63bb677 100644 --- a/manifest.toml +++ b/manifest.toml @@ -4,19 +4,19 @@ packages = [ { name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" }, { name = "gleam_http", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "0A62451FC85B98062E0907659D92E6A89F5F3C0FBE4AB8046C99936BF6F91DBC" }, - { name = "gleam_httpc", version = "4.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "1A38507AF26CACA145248733688703EADCB734EA971D4E34FB97B7613DECF132" }, - { name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" }, - { name = "gleam_stdlib", version = "0.59.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "F8FEE9B35797301994B81AF75508CF87C328FE1585558B0FFD188DC2B32EAA95" }, - { name = "gleam_time", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "CBAA68E215BEA961B40F3B1BA7B88741B1EB49572EF5E1154E357A5D152A2A2C" }, - { name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" }, - { name = "multipart_form", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "multipart_form", source = "hex", outer_checksum = "700FEC9E7C82DB2EA3B048AC6C2869095560AB68EBDC97BF207E8DAD9BB3C022" }, + { name = "gleam_httpc", version = "4.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C670EBD46FC1472AD5F1F74F1D3938D1D0AC1C7531895ED1D4DDCB6F07279F43" }, + { name = "gleam_json", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "5BA154440B22D9800955B1AB854282FA37B97F30F409D76B0824D0A60C934188" }, + { name = "gleam_stdlib", version = "0.60.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "621D600BB134BC239CB2537630899817B1A42E60A1D46C5E9F3FAE39F88C800B" }, + { name = "gleam_time", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "D71F1AFF7FEB534FF55E5DC58E534E9201BA75A444619788A2E4DEA4EBD87D16" }, + { name = "gleeunit", version = "1.3.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "A7DD6C07B7DA49A6E28796058AA89E651D233B357D5607006D70619CD89DAAAB" }, + { name = "multipart_form", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "multipart_form", source = "hex", outer_checksum = "082C77A0C3BB1128FCD55491665E9B72BC943E849B67D02B08CFA6808AD8E47C" }, ] [requirements] gleam_http = { version = ">= 4.0.0 and < 5.0.0" } gleam_httpc = { version = ">= 4.1.0 and < 5.0.0" } -gleam_json = { version = ">= 2.3.0 and < 3.0.0" } +gleam_json = { version = ">= 3.0.1 and < 4.0.0" } gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } gleam_time = { version = ">= 1.1.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } -multipart_form = { version = ">= 1.0.0 and < 2.0.0" } +multipart_form = { version = ">= 1.1.0 and < 2.0.0" } diff --git a/src/flybycord/file.gleam b/src/flybycord/file.gleam new file mode 100644 index 0000000..ddb357c --- /dev/null +++ b/src/flybycord/file.gleam @@ -0,0 +1,3 @@ +pub type File { + File(name: String, content_type: String, content: BitArray) +} diff --git a/src/flybycord/internal/rest.gleam b/src/flybycord/internal/rest.gleam index 83e9a5e..dc47781 100644 --- a/src/flybycord/internal/rest.gleam +++ b/src/flybycord/internal/rest.gleam @@ -1,11 +1,16 @@ import flybycord/client.{type Client} import flybycord/error +import flybycord/file.{type File} import gleam/http import gleam/http/request.{type Request} import gleam/http/response.{type Response} import gleam/httpc +import gleam/int +import gleam/list import gleam/option.{type Option, None, Some} import gleam/result +import multipart_form +import multipart_form/field // CONSTANTS ------------------------------------------------------------------- @@ -40,7 +45,7 @@ pub fn new_request( |> request.set_host(discord_url) |> request.set_path(discord_api_path <> path) |> request.set_method(method) - |> request.prepend_header("authorization", "Bot" <> client.token) + |> request.prepend_header("authorization", "Bot " <> client.token) |> request.prepend_header( "user-agent", "DiscordBot (https://github.com/folospior/flybycord, " @@ -50,6 +55,38 @@ pub fn new_request( |> request.prepend_header("content-type", "application/json") } +@internal +pub fn new_multipart_request( + client: Client, + method: http.Method, + path: String, + payload_json: String, + files: List(File), +) { + let #(_, file_parts) = + files + |> list.map_fold(0, fn(acc, file) { + #(acc + 1, #( + "files[" <> acc |> int.to_string <> "]", + field.File(file.name, file.content_type, file.content), + )) + }) + + new_request(client, method, path) + |> multipart_form.to_request( + [ + [ + #( + "payload_json", + field.StringWithType(payload_json, "application/json"), + ), + ], + file_parts, + ] + |> list.flatten, + ) +} + @internal pub fn with_reason(request: Request(a), reason: Option(String)) -> Request(a) { case reason { diff --git a/test/flybycord_test.gleam b/test/flybycord_test.gleam index 2397582..012c0ee 100644 --- a/test/flybycord_test.gleam +++ b/test/flybycord_test.gleam @@ -1,4 +1,9 @@ +import flybycord/client +import flybycord/file.{File} +import flybycord/internal/rest import flybycord/user/current_user +import gleam/http +import gleam/http/request import gleam/json import gleeunit import gleeunit/should @@ -7,12 +12,6 @@ pub fn main() { gleeunit.main() } -// gleeunit test functions end in `_test` -pub fn hello_world_test() { - 1 - |> should.equal(1) -} - pub fn encode_modify_current_test() { current_user.new_modify() |> current_user.modify_username("fo1o") @@ -20,3 +19,33 @@ pub fn encode_modify_current_test() { |> json.to_string |> should.equal("{\"username\":\"fo1o\"}") } + +pub fn multipart_request_test() { + let expected = + rest.new_request(client.Client("token"), http.Post, "/") + |> request.set_body(<< + "--gleam_multipart_form\r\n":utf8, + "Content-Disposition: form-data; name=\"payload_json\"\r\n":utf8, + "Content-Type: application/json\r\n\r\n":utf8, "{}\r\n":utf8, + "--gleam_multipart_form\r\n":utf8, + "Content-Disposition: form-data; name=\"files[0]\"; filename=\"name\"\r\n":utf8, + "Content-Type: image/png\r\n\r\n":utf8, "test\r\n":utf8, + "--gleam_multipart_form\r\n":utf8, + "Content-Disposition: form-data; name=\"files[1]\"; filename=\"name2\"\r\n":utf8, + "Content-Type: image/jpeg\r\n\r\n":utf8, "jpeg\r\n":utf8, + "--gleam_multipart_form--":utf8, + >>) + |> request.set_header( + "content-type", + "multipart/form-data; boundary=gleam_multipart_form", + ) + + let result = + rest.new_multipart_request(client.Client("token"), http.Post, "/", "{}", [ + File("name", "image/png", <<"test":utf8>>), + File("name2", "image/jpeg", <<"jpeg":utf8>>), + ]) + + result + |> should.equal(expected) +}