pylon-api 1.1.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d98b4389f4182e2f3d62261c2a60d9f4a325c18a5376c09668cc17e1594219c
4
- data.tar.gz: ea1c690a74e4e8d2890098211d58909ae551af8deecaf757d3463e5de37f3cdc
3
+ metadata.gz: 4f54f7ed75e823866e06256d1a598bb3158e686131156932b7aad3d9a90da9c7
4
+ data.tar.gz: fe68e2c1be8128acadd4179b2baa2751fd9223fdbe1a5c66cb35d2d41c13fae0
5
5
  SHA512:
6
- metadata.gz: b3a1dcd703454b3efc5818292f01a00366a50ddfa5f06d6dbbdbfc865907b907b05ea35d0ca591e0eb93d5ffbec26e4ad90b85e47379aa029f61346b766e81f1
7
- data.tar.gz: aa703a9d4f20da2243ce49b31627548afd719835a3a591fab2ffafd5480ab84cbce02b3c88a54b25979a8138641b584c9e32054ae673f548ca4936daa2531e53
6
+ metadata.gz: 6282c28251d01ed1f7c196fbb421c3e895d37681da8e71e5941ed74db3ff88aff39e8e9c8604fe899d555e61aec5bc7b8824fcdf30e6e789c3b74086d25ae7ee
7
+ data.tar.gz: bf00a26818a96154c91a2a1f281d219372f0fd97b8b0075ddbb70fcebaa675c28b31e55a10bf218303fcc4e2b0ad15229a30950e2f2a5e41cd174995940c0a2a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.1] - 2025-04-18
4
+
5
+ ### Fixed
6
+ - Fixed URL-based file attachments by ensuring they use proper multipart form encoding
7
+
8
+ ## [1.1.0] - 2025-04-17
9
+
10
+ ### Added
11
+ - Support for URL-based file attachments
12
+ - Enhanced attachment handling for various file types
13
+ - Added MIME type detection for file uploads
14
+
3
15
  ## [1.0.0] - 2024-03-21
4
16
 
5
17
  ### Changed
data/lib/pylon/client.rb CHANGED
@@ -7,7 +7,22 @@ module Pylon
7
7
  # client = Pylon::Client.new(api_key: 'your_api_key')
8
8
  # issues = client.list_issues(start_time: '2024-03-01T00:00:00Z', end_time: '2024-03-31T23:59:59Z')
9
9
  # issues.each { |issue| puts issue.title }
10
+ # rubocop:disable Metrics/ClassLength
10
11
  class Client
12
+ # Common MIME types for file uploads
13
+ MIME_TYPES = {
14
+ ".jpg" => "image/jpeg",
15
+ ".jpeg" => "image/jpeg",
16
+ ".png" => "image/png",
17
+ ".gif" => "image/gif",
18
+ ".pdf" => "application/pdf",
19
+ ".doc" => "application/msword",
20
+ ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
21
+ ".xls" => "application/vnd.ms-excel",
22
+ ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
23
+ ".csv" => "text/csv",
24
+ ".txt" => "text/plain"
25
+ }
11
26
  # Base URL for the Pylon API
12
27
  BASE_URL = "https://api.usepylon.com"
13
28
 
@@ -45,10 +60,36 @@ module Pylon
45
60
 
46
61
  # Create a new attachment
47
62
  #
48
- # @param file [String] The file content to upload
63
+ # @param file [File, String, nil] The file to upload (File object or file content)
64
+ # @param description [String, nil] A text description of the file
65
+ # @param file_url [String, nil] A URL to fetch the file from if file is not provided
49
66
  # @return [Models::Attachment] Created attachment object
50
- def create_attachment(file)
51
- post("/attachments", body: { file: file }, model_class: Models::Attachment)
67
+ # @raise [ArgumentError] If neither file nor file_url is provided
68
+ def create_attachment(file = nil, description: nil, file_url: nil)
69
+ if file.nil? && file_url.nil?
70
+ raise ArgumentError, "Either file or file_url must be provided"
71
+ end
72
+
73
+ params = {}
74
+ params[:description] = description if description
75
+ params[:file_url] = file_url if file_url
76
+
77
+ if file
78
+ if file.is_a?(::File) || (file.respond_to?(:path) && file.respond_to?(:read))
79
+ # For File objects or IO-like objects
80
+ params[:file] = Faraday::UploadIO.new(file, mime_type_for_file(file), File.basename(file.path))
81
+ else
82
+ # For raw content as string, create a temp file
83
+ temp_file = Tempfile.new(["upload", ".bin"])
84
+ temp_file.binmode
85
+ temp_file.write(file)
86
+ temp_file.rewind
87
+ params[:file] = Faraday::UploadIO.new(temp_file, "application/octet-stream")
88
+ end
89
+ end
90
+
91
+ # Always use multipart for attachments, whether file or file_url
92
+ post_multipart("/attachments", params, model_class: Models::Attachment)
52
93
  end
53
94
 
54
95
  # Get details for a specific attachment
@@ -324,6 +365,17 @@ module Pylon
324
365
  end
325
366
  end
326
367
 
368
+ # Determine MIME type for file
369
+ #
370
+ # @param file [File] The file to determine MIME type for
371
+ # @return [String] The MIME type
372
+ def mime_type_for_file(file)
373
+ return "application/octet-stream" unless file.respond_to?(:path)
374
+
375
+ ext = File.extname(file.path).downcase
376
+ MIME_TYPES[ext] || "application/octet-stream"
377
+ end
378
+
327
379
  # Handle API response and raise appropriate errors
328
380
  #
329
381
  # @param response [Faraday::Response] The API response
@@ -427,6 +479,34 @@ module Pylon
427
479
  handle_response(connection.post(path, body.to_json), model_class, collection)
428
480
  end
429
481
 
482
+ # Make a multipart POST request for file uploads
483
+ #
484
+ # @param path [String] The API endpoint path
485
+ # @param params [Hash] Request parameters including file uploads
486
+ # @param model_class [Class] The model class to use for wrapping the response
487
+ # @param collection [Boolean] Whether the response is a collection of items
488
+ # @return [Models::Base, Models::Collection, Array] Model, Collection, or response data array
489
+ def post_multipart(path, params = {}, model_class: nil, collection: false)
490
+ # Create a connection without the default JSON content type for multipart uploads
491
+ multipart_conn = Faraday.new(@base_url) do |f|
492
+ f.request :multipart
493
+ # Only force multipart for file_url uploads, omit url_encoded middleware
494
+ f.response :json, content_type: /\bjson$/
495
+ f.response :logger if @debug
496
+ f.adapter Faraday.default_adapter
497
+ f.headers["Authorization"] = "Bearer #{api_key}"
498
+ f.headers["Accept"] = "application/json"
499
+ end
500
+
501
+ # If we have a file_url but no actual file, create a dummy file part to force multipart encoding
502
+ if params[:file_url] && !params[:file]
503
+ # Create an empty file part to force multipart encoding
504
+ params[:_dummy] = Faraday::FilePart.new(StringIO.new(""), "application/octet-stream", "dummy")
505
+ end
506
+
507
+ handle_response(multipart_conn.post(path, params), model_class, collection)
508
+ end
509
+
430
510
  # Make a PATCH request
431
511
  #
432
512
  # @param path [String] The API endpoint path
data/lib/pylon/version.rb CHANGED
@@ -6,7 +6,7 @@ module Pylon
6
6
  # Minor version for new features
7
7
  MINOR = 1
8
8
  # Patch version for bug fixes
9
- PATCH = 0
9
+ PATCH = 1
10
10
  # Pre-release version (optional)
11
11
  PRE = nil
12
12
 
data/lib/pylon.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "faraday"
4
4
  require "faraday/multipart"
5
5
  require "json"
6
+ require "tempfile"
6
7
 
7
8
  require_relative "pylon/version"
8
9
  require_relative "pylon/models/base"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pylon-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Odom
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-17 00:00:00.000000000 Z
11
+ date: 2025-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday