transloadit 3.0.2 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/transloadit.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  require "multi_json"
2
2
  require "date"
3
+ require "json"
4
+ require "openssl"
5
+ require "cgi"
6
+ require "uri"
3
7
 
4
8
  #
5
9
  # Implements the Transloadit REST API in Ruby. Check the {file:README.md README}
@@ -11,6 +15,7 @@ class Transloadit
11
15
  autoload :Exception, "transloadit/exception"
12
16
  autoload :Request, "transloadit/request"
13
17
  autoload :Response, "transloadit/response"
18
+ autoload :SmartCDN, "transloadit/smart_cdn"
14
19
  autoload :Step, "transloadit/step"
15
20
  autoload :Template, "transloadit/template"
16
21
  autoload :VERSION, "transloadit/version"
@@ -83,7 +88,7 @@ class Transloadit
83
88
  # Creates a Transloadit::Template instance ready to interact with its corresponding REST API.
84
89
  #
85
90
  # See the Transloadit {documentation}[https://transloadit.com/docs/api-docs/#template-api]
86
- # for futher information on Templates and available endpoints.
91
+ # for further information on Templates and available endpoints.
87
92
  #
88
93
  def template(options = {})
89
94
  Transloadit::Template.new(self, options)
@@ -130,6 +135,54 @@ class Transloadit
130
135
  MultiJson.dump(to_hash)
131
136
  end
132
137
 
138
+ # @param workspace [String] Workspace slug
139
+ # @param template [String] Template slug or template ID
140
+ # @param input [String] Input value that is provided as `${fields.input}` in the template
141
+ # @param url_params [Hash] Additional parameters for the URL query string (optional)
142
+ # @param expire_at_ms [Integer] Expiration time as Unix timestamp in milliseconds (optional)
143
+ # @return [String] Signed Smart CDN URL
144
+ def signed_smart_cdn_url(
145
+ workspace:,
146
+ template:,
147
+ input:,
148
+ expire_at_ms: nil,
149
+ url_params: {}
150
+ )
151
+ raise ArgumentError, "workspace is required" if workspace.nil? || workspace.empty?
152
+ raise ArgumentError, "template is required" if template.nil? || template.empty?
153
+ raise ArgumentError, "input is required" if input.nil?
154
+
155
+ workspace_slug = CGI.escape(workspace)
156
+ template_slug = CGI.escape(template)
157
+ input_field = CGI.escape(input)
158
+
159
+ expire_at = expire_at_ms || (Time.now.to_i * 1000 + 60 * 60 * 1000) # 1 hour default
160
+
161
+ query_params = {}
162
+ url_params.each do |key, value|
163
+ next if value.nil?
164
+ Array(value).each do |val|
165
+ next if val.nil?
166
+ (query_params[key.to_s] ||= []) << val.to_s
167
+ end
168
+ end
169
+
170
+ query_params["auth_key"] = [key]
171
+ query_params["exp"] = [expire_at.to_s]
172
+
173
+ # Sort parameters to ensure consistent ordering
174
+ sorted_params = query_params.sort.flat_map do |key, values|
175
+ values.map { |v| "#{CGI.escape(key)}=#{CGI.escape(v)}" }
176
+ end.join("&")
177
+
178
+ string_to_sign = "#{workspace_slug}/#{template_slug}/#{input_field}?#{sorted_params}"
179
+
180
+ signature = OpenSSL::HMAC.hexdigest("sha256", secret, string_to_sign)
181
+
182
+ final_params = "#{sorted_params}&sig=#{CGI.escape("sha256:#{signature}")}"
183
+ "https://#{workspace_slug}.tlcdn.com/#{template_slug}/#{input_field}?#{final_params}"
184
+ end
185
+
133
186
  private
134
187
 
135
188
  #
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ IMAGE_NAME=${IMAGE_NAME:-transloadit-ruby-sdk-dev}
5
+
6
+ err() {
7
+ echo "notify-registry: $*" >&2
8
+ }
9
+
10
+ if ! command -v docker >/dev/null 2>&1; then
11
+ err "Docker is required to publish the gem."
12
+ exit 1
13
+ fi
14
+
15
+ if [[ -z "${GEM_HOST_API_KEY:-}" ]]; then
16
+ err "GEM_HOST_API_KEY environment variable is not set. Generate a RubyGems API key with push permissions and export it before running this script."
17
+ exit 1
18
+ fi
19
+
20
+ if ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then
21
+ err "Docker image '$IMAGE_NAME' not found. Building it now..."
22
+ docker build -t "$IMAGE_NAME" -f Dockerfile .
23
+ fi
24
+
25
+ version=$(
26
+ docker run --rm \
27
+ -v "$PWD":/workspace \
28
+ -w /workspace \
29
+ "$IMAGE_NAME" \
30
+ ruby -Ilib -e 'require "transloadit/version"; puts Transloadit::VERSION'
31
+ )
32
+
33
+ gem_file="transloadit-${version}.gem"
34
+
35
+ err "Building ${gem_file}..."
36
+ docker run --rm \
37
+ --user "$(id -u):$(id -g)" \
38
+ -e HOME=/workspace \
39
+ -v "$PWD":/workspace \
40
+ -w /workspace \
41
+ "$IMAGE_NAME" \
42
+ bash -lc "set -euo pipefail; rm -f ${gem_file}; gem build transloadit.gemspec >/dev/null"
43
+
44
+ err "Pushing ${gem_file} to RubyGems..."
45
+ docker run --rm \
46
+ --user "$(id -u):$(id -g)" \
47
+ -e HOME=/workspace \
48
+ -e GEM_HOST_API_KEY="$GEM_HOST_API_KEY" \
49
+ -v "$PWD":/workspace \
50
+ -w /workspace \
51
+ "$IMAGE_NAME" \
52
+ bash -lc "set -euo pipefail; gem push ${gem_file}"
53
+
54
+ err "Removing local ${gem_file}..."
55
+ rm -f "${gem_file}"
56
+
57
+ echo "notify-registry: Successfully pushed ${gem_file} to RubyGems."
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ IMAGE_NAME=${IMAGE_NAME:-transloadit-ruby-sdk-dev}
5
+ CACHE_DIR=.docker-cache
6
+
7
+ ensure_docker() {
8
+ if ! command -v docker >/dev/null 2>&1; then
9
+ echo "Docker is required to run this script." >&2
10
+ exit 1
11
+ fi
12
+
13
+ if ! docker info >/dev/null 2>&1; then
14
+ if [[ -z "${DOCKER_HOST:-}" && -S "$HOME/.colima/default/docker.sock" ]]; then
15
+ export DOCKER_HOST="unix://$HOME/.colima/default/docker.sock"
16
+ fi
17
+ fi
18
+
19
+ if ! docker info >/dev/null 2>&1; then
20
+ echo "Docker daemon is not reachable. Start Docker (or Colima) and retry." >&2
21
+ exit 1
22
+ fi
23
+ }
24
+
25
+ configure_platform() {
26
+ if [[ -z "${DOCKER_PLATFORM:-}" ]]; then
27
+ local arch
28
+ arch=$(uname -m)
29
+ if [[ "$arch" == "arm64" || "$arch" == "aarch64" ]]; then
30
+ DOCKER_PLATFORM=linux/amd64
31
+ fi
32
+ fi
33
+ }
34
+
35
+ ensure_docker
36
+ configure_platform
37
+
38
+ if [[ $# -eq 0 ]]; then
39
+ RUN_CMD='set -e; bundle install --jobs 4 --retry 3; bundle exec rake test'
40
+ else
41
+ printf -v USER_CMD '%q ' "$@"
42
+ RUN_CMD="set -e; bundle install --jobs 4 --retry 3; ${USER_CMD}"
43
+ fi
44
+
45
+ mkdir -p "$CACHE_DIR/bundle" "$CACHE_DIR/npm-cache"
46
+
47
+ BUILD_ARGS=()
48
+ if [[ -n "${DOCKER_PLATFORM:-}" ]]; then
49
+ BUILD_ARGS+=(--platform "$DOCKER_PLATFORM")
50
+ fi
51
+ BUILD_ARGS+=(-t "$IMAGE_NAME" -f Dockerfile .)
52
+
53
+ docker build "${BUILD_ARGS[@]}"
54
+
55
+ DOCKER_ARGS=(
56
+ --rm
57
+ --user "$(id -u):$(id -g)"
58
+ -e HOME=/workspace
59
+ -e BUNDLE_PATH=/workspace/$CACHE_DIR/bundle
60
+ -e BUNDLE_APP_CONFIG=/workspace/$CACHE_DIR/bundle-config
61
+ -e BUNDLE_CACHE_PATH=/workspace/$CACHE_DIR/bundle-cache
62
+ -e npm_config_cache=/workspace/$CACHE_DIR/npm-cache
63
+ -e TEST_NODE_PARITY="${TEST_NODE_PARITY:-0}"
64
+ -e RUBY_SDK_E2E="${RUBY_SDK_E2E:-1}"
65
+ -v "$PWD":/workspace
66
+ -w /workspace
67
+ )
68
+
69
+ if [[ -n "${DOCKER_PLATFORM:-}" ]]; then
70
+ DOCKER_ARGS+=(--platform "$DOCKER_PLATFORM")
71
+ fi
72
+
73
+ if [[ -f .env ]]; then
74
+ DOCKER_ARGS+=(--env-file "$PWD/.env")
75
+ fi
76
+
77
+ PASSTHROUGH_ENV_VARS=(
78
+ TRANSLOADIT_KEY
79
+ TRANSLOADIT_SECRET
80
+ TRANSLOADIT_TEMPLATE_ID
81
+ )
82
+
83
+ for var in "${PASSTHROUGH_ENV_VARS[@]}"; do
84
+ if [[ -n "${!var:-}" ]]; then
85
+ DOCKER_ARGS+=(-e "$var=${!var}")
86
+ fi
87
+ done
88
+
89
+ exec docker run "${DOCKER_ARGS[@]}" "$IMAGE_NAME" bash -lc "$RUN_CMD"
@@ -0,0 +1,97 @@
1
+ require "test_helper"
2
+ require "webmock"
3
+
4
+ describe "Transloadit end-to-end upload" do
5
+ before do
6
+ skip "Set RUBY_SDK_E2E=1 to run live upload tests" unless e2e_enabled?
7
+
8
+ @key = ENV["TRANSLOADIT_KEY"]
9
+ @secret = ENV["TRANSLOADIT_SECRET"]
10
+ skip "TRANSLOADIT_KEY and TRANSLOADIT_SECRET must be set to run live upload tests" if blank?(@key) || blank?(@secret)
11
+
12
+ @fixture_path = File.expand_path("../../chameleon.jpg", __dir__)
13
+ skip "chameleon.jpg fixture missing; run tests from the repository root" unless File.file?(@fixture_path)
14
+ end
15
+
16
+ it "uploads and processes the chameleon image" do
17
+ with_live_http do
18
+ transloadit = Transloadit.new(key: @key, secret: @secret)
19
+
20
+ resize_step = transloadit.step(
21
+ "resize",
22
+ "/image/resize",
23
+ use: ":original",
24
+ width: 128,
25
+ height: 128,
26
+ resize_strategy: "fit",
27
+ format: "png"
28
+ )
29
+
30
+ response = File.open(@fixture_path, "rb") do |upload|
31
+ transloadit.assembly.create!(
32
+ upload,
33
+ wait: true,
34
+ steps: resize_step
35
+ )
36
+ end
37
+
38
+ response.reload_until_finished!(tries: 120) unless response.finished?
39
+
40
+ _(response.completed?).must_equal true, "Assembly did not complete successfully: #{response.body.inspect}"
41
+
42
+ uploads = response["uploads"] || []
43
+ refute_empty uploads, "Expected uploads in the assembly response"
44
+
45
+ upload_info = uploads.first
46
+ basename = upload_info["basename"]
47
+ _(basename).must_equal File.basename(@fixture_path, ".*") if basename
48
+
49
+ filename = upload_info["name"]
50
+ _(filename).must_equal File.basename(@fixture_path) if filename
51
+
52
+ results = (response["results"] || {})["resize"] || []
53
+ refute_empty results, "Expected resize results in assembly response"
54
+
55
+ first_result = results.first
56
+ ssl_url = first_result["ssl_url"]
57
+ refute_nil ssl_url, "Missing ssl_url in resize result: #{first_result.inspect}"
58
+ _(ssl_url).must_match(/\Ahttps:\/\//)
59
+
60
+ meta = first_result["meta"] || {}
61
+ width = integer_if_present(meta["width"])
62
+ height = integer_if_present(meta["height"])
63
+ refute_nil width, "Missing width metadata: #{meta.inspect}"
64
+ refute_nil height, "Missing height metadata: #{meta.inspect}"
65
+ assert width.positive? && width <= 128, "Unexpected width #{width.inspect}"
66
+ assert height.positive? && height <= 128, "Unexpected height #{height.inspect}"
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def with_live_http
73
+ VCR.turn_off!(ignore_cassettes: true)
74
+ WebMock.allow_net_connect!
75
+ yield
76
+ ensure
77
+ WebMock.disable_net_connect!(allow_localhost: true)
78
+ VCR.turn_on!
79
+ end
80
+
81
+ def e2e_enabled?
82
+ flag = ENV["RUBY_SDK_E2E"]
83
+ return false if blank?(flag)
84
+
85
+ %w[1 true yes on].include?(flag.to_s.strip.downcase)
86
+ end
87
+
88
+ def integer_if_present(value)
89
+ return nil if blank?(value)
90
+
91
+ value.to_i
92
+ end
93
+
94
+ def blank?(value)
95
+ value.respond_to?(:empty?) ? value.empty? : !value
96
+ end
97
+ end
data/test/test_helper.rb CHANGED
@@ -1,14 +1,22 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
  $:.unshift File.expand_path("../../lib", __FILE__)
3
3
 
4
- if ENV["COVERAGE"] != "false"
4
+ if ENV["COVERAGE"] != "0"
5
5
  require "simplecov"
6
- SimpleCov.start { add_filter "/test/" }
6
+ SimpleCov.start do
7
+ add_filter "/test/"
8
+ enable_coverage :branch
9
+ end
10
+
11
+ require "simplecov-cobertura"
12
+ SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
7
13
  end
8
14
 
9
15
  require "minitest/autorun"
10
16
  require "transloadit"
11
17
  require "vcr"
18
+ require "open3"
19
+ require "json"
12
20
 
13
21
  VCR.configure do |c|
14
22
  c.cassette_library_dir = "test/fixtures/cassettes"
@@ -19,3 +27,48 @@ end
19
27
  def values_from_post_body(body)
20
28
  Addressable::URI.parse("?" + CGI.unescape(body)).query_values
21
29
  end
30
+
31
+ module TransloaditCliHelpers
32
+ TRANSLOADIT_CLI_PACKAGE = ENV.fetch("TRANSLOADIT_CLI_PACKAGE", "transloadit@4.0.5")
33
+
34
+ def run_transloadit_cli(command, payload, key:, secret:, algorithm: nil)
35
+ return nil unless ENV["TEST_NODE_PARITY"] == "1"
36
+
37
+ env = {
38
+ "TRANSLOADIT_KEY" => key,
39
+ "TRANSLOADIT_SECRET" => secret,
40
+ "TRANSLOADIT_AUTH_KEY" => key,
41
+ "TRANSLOADIT_AUTH_SECRET" => secret
42
+ }
43
+
44
+ args = [
45
+ "npm", "exec", "--yes", "--package", TRANSLOADIT_CLI_PACKAGE, "--",
46
+ "transloadit", command
47
+ ]
48
+ args += ["--algorithm", algorithm] if algorithm
49
+
50
+ stdout, stderr, status = Open3.capture3(env, *args, stdin_data: JSON.dump(payload))
51
+ raise "transloadit CLI #{command} failed: #{stderr}" unless status.success?
52
+
53
+ stdout.strip
54
+ end
55
+
56
+ def run_transloadit_smart_sig(payload, key:, secret:)
57
+ cli_payload = {
58
+ workspace: payload.fetch(:workspace),
59
+ template: payload.fetch(:template),
60
+ input: payload.fetch(:input)
61
+ }
62
+ cli_payload[:url_params] = payload[:url_params] if payload.key?(:url_params)
63
+ cli_payload[:expire_at_ms] = payload[:expire_at_ms] if payload.key?(:expire_at_ms)
64
+
65
+ run_transloadit_cli("smart_sig", cli_payload, key: key, secret: secret)
66
+ end
67
+
68
+ def run_transloadit_sig(payload, key:, secret:, algorithm: nil)
69
+ output = run_transloadit_cli("sig", payload, key: key, secret: secret, algorithm: algorithm)
70
+ output && JSON.parse(output)
71
+ end
72
+ end
73
+
74
+ Minitest::Test.include(TransloaditCliHelpers)
@@ -108,7 +108,10 @@ describe Transloadit do
108
108
  end
109
109
 
110
110
  it "must produce Transloadit-compatible JSON output" do
111
- _(@transloadit.to_json).must_equal MultiJson.dump(@transloadit.to_hash)
111
+ fixed_time = Time.utc(2025, 10, 28, 0, 0, 0)
112
+ Time.stub :now, fixed_time do
113
+ _(@transloadit.to_json).must_equal MultiJson.dump(@transloadit.to_hash)
114
+ end
112
115
  end
113
116
  end
114
117
 
@@ -286,7 +286,7 @@ describe Transloadit::Assembly do
286
286
  end
287
287
 
288
288
  describe "when replaying assembly notification" do
289
- it "must replay notification of sepcified assembly" do
289
+ it "must replay notification of specified assembly" do
290
290
  VCR.use_cassette "replay_assembly_notification" do
291
291
  response = @assembly.replay_notification "2ea5d21063ad11e6bc93e53395ce4e7d"
292
292
 
@@ -1,4 +1,7 @@
1
1
  require "test_helper"
2
+ require "multi_json"
3
+ require "rbconfig"
4
+ require "tmpdir"
2
5
 
3
6
  describe Transloadit::Request do
4
7
  it "must allow initialization" do
@@ -75,4 +78,86 @@ describe Transloadit::Request do
75
78
  end
76
79
  end
77
80
  end
81
+
82
+ it "loads request when URI was not previously required" do
83
+ lib_path = File.expand_path("../../../lib", __dir__)
84
+
85
+ Dir.mktmpdir do |stub_dir|
86
+ File.write(File.join(stub_dir, "rest-client.rb"), <<~RUBY)
87
+ module RestClient
88
+ class Response; end
89
+
90
+ class Resource
91
+ def initialize(*); end
92
+ def [](*); self; end
93
+ def get(*); Response.new; end
94
+ def post(*); Response.new; end
95
+ def put(*); Response.new; end
96
+ def delete(*); Response.new; end
97
+ end
98
+
99
+ module Exceptions
100
+ class OpenTimeout < StandardError; end
101
+ end
102
+ end
103
+ RUBY
104
+
105
+ File.write(File.join(stub_dir, "multi_json.rb"), <<~RUBY)
106
+ require "json"
107
+
108
+ module MultiJson
109
+ def self.dump(value)
110
+ JSON.dump(value)
111
+ end
112
+
113
+ def self.load(json)
114
+ JSON.parse(json)
115
+ end
116
+ end
117
+ RUBY
118
+
119
+ script = <<~RUBY
120
+ $LOAD_PATH.unshift #{stub_dir.inspect}
121
+ $LOAD_PATH.unshift #{lib_path.inspect}
122
+
123
+ begin
124
+ require "transloadit/request"
125
+ Transloadit::Request.new("/")
126
+ rescue StandardError => e
127
+ warn e.full_message
128
+ exit 1
129
+ end
130
+ RUBY
131
+
132
+ stdout, stderr, status = Open3.capture3(RbConfig.ruby, "-e", script)
133
+ error_output = stderr.empty? ? stdout : stderr
134
+ assert status.success?, "Expected transloadit/request to load without NameError, got: #{error_output}"
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "signature parity" do
140
+ it "matches transloadit CLI sig output" do
141
+ skip "Parity testing not enabled" unless ENV["TEST_NODE_PARITY"] == "1"
142
+
143
+ expires = "2025-01-02T00:00:00.000Z"
144
+ params = {
145
+ auth: {key: "cli-key", expires: expires},
146
+ steps: {encode: {robot: "/video/encode"}}
147
+ }
148
+
149
+ cli_result = run_transloadit_sig(params, key: "cli-key", secret: "cli-secret", algorithm: "sha384")
150
+ refute_nil cli_result
151
+
152
+ cli_params_json = cli_result["params"]
153
+ request = Transloadit::Request.new("/", "cli-secret")
154
+ ruby_signature = request.send(:signature, cli_params_json)
155
+
156
+ assert_equal cli_result["signature"], ruby_signature
157
+
158
+ cli_params = JSON.parse(cli_params_json)
159
+ assert_equal "cli-key", cli_params.dig("auth", "key")
160
+ assert_equal expires, cli_params.dig("auth", "expires")
161
+ assert_equal "/video/encode", cli_params.dig("steps", "encode", "robot")
162
+ end
78
163
  end
@@ -0,0 +1,158 @@
1
+ require "test_helper"
2
+
3
+ describe Transloadit do
4
+ before do
5
+ @auth_key = "my-key"
6
+ @auth_secret = "my-secret"
7
+ @transloadit = Transloadit.new(key: @auth_key, secret: @auth_secret)
8
+ @workspace = "my-app"
9
+ @template = "test-smart-cdn"
10
+ @input = "inputs/prinsengracht.jpg"
11
+ @expire_at = 1732550672867
12
+ end
13
+
14
+ describe "#signed_smart_cdn_url" do
15
+ it "requires workspace" do
16
+ assert_raises ArgumentError, "workspace is required" do
17
+ @transloadit.signed_smart_cdn_url(
18
+ workspace: nil,
19
+ template: @template,
20
+ input: @input
21
+ )
22
+ end
23
+
24
+ assert_raises ArgumentError, "workspace is required" do
25
+ @transloadit.signed_smart_cdn_url(
26
+ workspace: "",
27
+ template: @template,
28
+ input: @input
29
+ )
30
+ end
31
+ end
32
+
33
+ it "requires template" do
34
+ assert_raises ArgumentError, "template is required" do
35
+ @transloadit.signed_smart_cdn_url(
36
+ workspace: @workspace,
37
+ template: nil,
38
+ input: @input
39
+ )
40
+ end
41
+
42
+ assert_raises ArgumentError, "template is required" do
43
+ @transloadit.signed_smart_cdn_url(
44
+ workspace: @workspace,
45
+ template: "",
46
+ input: @input
47
+ )
48
+ end
49
+ end
50
+
51
+ it "requires input" do
52
+ assert_raises ArgumentError, "input is required" do
53
+ @transloadit.signed_smart_cdn_url(
54
+ workspace: @workspace,
55
+ template: @template,
56
+ input: nil
57
+ )
58
+ end
59
+ end
60
+
61
+ it "allows empty input string" do
62
+ params = {
63
+ workspace: @workspace,
64
+ template: @template,
65
+ input: "",
66
+ expire_at_ms: @expire_at
67
+ }
68
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/?auth_key=my-key&exp=1732550672867&sig=sha256%3Ad5e13df4acde8d4aaa0f34534489e54098b5128c54392600ed96dd77669a533e"
69
+
70
+ url = @transloadit.signed_smart_cdn_url(**params)
71
+ assert_equal expected_url, url
72
+
73
+ if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
74
+ assert_equal expected_url, cli_url
75
+ end
76
+ end
77
+
78
+ it "uses instance credentials" do
79
+ params = {
80
+ workspace: @workspace,
81
+ template: @template,
82
+ input: @input,
83
+ expire_at_ms: @expire_at
84
+ }
85
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&sig=sha256%3A8620fc2a22aec6081cde730b7f3f29c0d8083f58a68f62739e642b3c03709139"
86
+
87
+ url = @transloadit.signed_smart_cdn_url(**params)
88
+ assert_equal expected_url, url
89
+
90
+ if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
91
+ assert_equal expected_url, cli_url
92
+ end
93
+ end
94
+
95
+ it "includes empty width parameter" do
96
+ params = {
97
+ workspace: @workspace,
98
+ template: @template,
99
+ input: @input,
100
+ expire_at_ms: @expire_at,
101
+ url_params: {
102
+ width: "",
103
+ height: 200
104
+ }
105
+ }
106
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&height=200&width=&sig=sha256%3Aebf562722c504839db97165e657583f74192ac4ab580f1a0dd67d3d868b4ced3"
107
+
108
+ url = @transloadit.signed_smart_cdn_url(**params)
109
+ assert_equal expected_url, url
110
+
111
+ if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
112
+ assert_equal expected_url, cli_url
113
+ end
114
+ end
115
+
116
+ it "handles nil values in parameters" do
117
+ params = {
118
+ workspace: @workspace,
119
+ template: @template,
120
+ input: @input,
121
+ expire_at_ms: @expire_at,
122
+ url_params: {
123
+ width: nil,
124
+ height: 200
125
+ }
126
+ }
127
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&height=200&sig=sha256%3Ad6897a0cb527a14eaab13c54b06f53527797c553d8b7e5d0b1a5df237212f083"
128
+
129
+ url = @transloadit.signed_smart_cdn_url(**params)
130
+ assert_equal expected_url, url
131
+
132
+ if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
133
+ assert_equal expected_url, cli_url
134
+ end
135
+ end
136
+
137
+ it "handles array values in parameters" do
138
+ params = {
139
+ workspace: @workspace,
140
+ template: @template,
141
+ input: @input,
142
+ expire_at_ms: @expire_at,
143
+ url_params: {
144
+ tags: ["landscape", "amsterdam", nil, ""],
145
+ height: 200
146
+ }
147
+ }
148
+ expected_url = "https://my-app.tlcdn.com/test-smart-cdn/inputs%2Fprinsengracht.jpg?auth_key=my-key&exp=1732550672867&height=200&tags=landscape&tags=amsterdam&tags=&sig=sha256%3Aff46eb0083d64b250b2e4510380e333f67da855b2401493dee7a706a47957d3f"
149
+
150
+ url = @transloadit.signed_smart_cdn_url(**params)
151
+ assert_equal expected_url, url
152
+
153
+ if (cli_url = run_transloadit_smart_sig(params, key: @auth_key, secret: @auth_secret))
154
+ assert_equal expected_url, cli_url
155
+ end
156
+ end
157
+ end
158
+ end
data/transloadit.gemspec CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |gem|
7
7
  gem.version = Transloadit::VERSION
8
8
  gem.platform = Gem::Platform::RUBY
9
9
 
10
- gem.authors = ["Stephen Touset", "Robin Mehner"]
11
- gem.email = %w[stephen@touset.org robin@coding-robin.de]
10
+ gem.authors = ["Stephen Touset", "Robin Mehner", "Kevin van Zonneveld"]
11
+ gem.email = %w[stephen@touset.org robin@coding-robin.de kevin@transloadit.com]
12
12
  gem.homepage = "https://github.com/transloadit/ruby-sdk/"
13
13
  gem.license = "MIT"
14
14