gotenberg-ruby 1.0.4 → 1.0.6

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: 2fa54cb50c0f1acb75b9f60323e2609a58e0dfd9dc24598ea329dfeec6903e26
4
- data.tar.gz: 473d60ac2f1f4b70d8c53b59032df0fafae5d86ece2d4c5fca7a1e538e93954c
3
+ metadata.gz: 6d5bca5c31fb41596a72235309e9ac5156d156290a8d8f961b626e49e41a896a
4
+ data.tar.gz: 1d2562aaef002bafbafdc1f31da3341de73271b2cb09a95f9eede6f36b76c38d
5
5
  SHA512:
6
- metadata.gz: 71c2f2768d00baad5f44238fb893b721dfe768f399396a6e750f343af49339a76619095d32471a827f21ed31b5fffbbe99d79fd8b536db9bd73185c64096bf23
7
- data.tar.gz: c6facaf037d8ee62c8deb870565c39a70a5897b64241cdc868147eb117715bd54b20e91b17665fb7f4424de6bf986b9e42681bccbb779e77874e8a12fd5d0911
6
+ metadata.gz: 4fa4fa88a317bc10f35fc9f01bcae87b14501f3fc5aeca9e67a70d3c1e433c863cfdd61fc19af4797a0a6aa16b3438542450eed7ca9a7d685f78e275ec102884
7
+ data.tar.gz: 88fe62bc6fbc1e8f2db20cd4a797bfca471c01e45feb6636299e427d35dd8b55cb6900677386dacb6c9c2e8221b4c628431063d7de0621ee8b36d0856036af89
data/README.md CHANGED
@@ -22,6 +22,9 @@ gem "gotenberg-ruby"
22
22
 
23
23
  * [Send a request to the API](#send-a-request-to-the-api)
24
24
  * [Chromium](#chromium)
25
+ * [LibreOffice](#libreOffice)
26
+ * [PDF Engines](#pdf-engines)
27
+ * [Webhook](#webhook)
25
28
 
26
29
  ### Run Gotenberg
27
30
 
@@ -125,7 +128,12 @@ gotenberg_javascript_tag 'application.js', inline: true
125
128
  gotenberg_stylesheet_tag 'application.css', inline: true
126
129
  ```
127
130
 
128
- ⚠️ Warning! Nested resources for CSS is not supported yet.
131
+ ⚠️ Gem also supported extracting CSS nested resources defined with url() in experimentally mode.
132
+
133
+ ```ruby
134
+ # skip nested resources auto extracting
135
+ gotenberg_stylesheet_tag 'application.css', inline: true, skip_analyze: true
136
+ ```
129
137
 
130
138
  #### Convert an HTML document to PDF
131
139
 
@@ -414,10 +422,7 @@ You may add HTTP headers that Chromium will send when loading the HTML document:
414
422
  ```ruby
415
423
  document = Gotenberg::Chromium.call(ENV['GOTENBERG_URL']) do |doc|
416
424
  doc.url 'https://my.url'
417
- doc.extra_http_headers [
418
- 'My-Header-1' => 'My value',
419
- 'My-Header-2' => 'My value'
420
- ]
425
+ doc.extra_http_headers({'My-Header-1' => 'My value', 'My-Header-2' => 'My value'})
421
426
  end
422
427
  ```
423
428
 
@@ -456,3 +461,182 @@ document = Gotenberg::Chromium.call(ENV['GOTENBERG_URL']) do |doc|
456
461
  doc.pdf_format 'PDF/A-1a'
457
462
  end
458
463
  ```
464
+
465
+ ### LibreOffice
466
+
467
+ The [LibreOffice module](https://gotenberg.dev/docs/modules/libreoffice) interacts with [LibreOffice](https://www.libreoffice.org/)
468
+ to convert documents to PDF, thanks to [unoconv](https://github.com/unoconv/unoconv).
469
+
470
+ #### Convert documents to PDF
471
+
472
+ See https://gotenberg.dev/docs/modules/libreoffice#route.
473
+
474
+ Converting a document to PDF is as simple as:
475
+
476
+ ```ruby
477
+ document = Gotenberg::Libreoffice.call(ENV['GOTENBERG_URL']) do |doc|
478
+ doc.convert '/path/to/my.docx'
479
+ end
480
+ ```
481
+
482
+ If you send many documents, Gotenberg will return a ZIP archive with the PDFs:
483
+
484
+ ```ruby
485
+ document = Gotenberg::Libreoffice.call(ENV['GOTENBERG_URL']) do |doc|
486
+ doc.convert '/path/to/my.docx', '/path/to/my.xlsx'
487
+ end
488
+
489
+ # will return binary data with zip archive content
490
+ File.open('archive.zip', 'wb') do |file|
491
+ file << document.to_binary
492
+ end
493
+ ```
494
+
495
+ You may also merge them into one unique PDF:
496
+
497
+ ```ruby
498
+ document = Gotenberg::Libreoffice.call(ENV['GOTENBERG_URL']) do |doc|
499
+ doc.merge
500
+ doc.convert '/path/to/my.docx', '/path/to/my.xlsx'
501
+ end
502
+ ```
503
+
504
+ Please note that the merging order is determined by the order of the arguments.
505
+
506
+ #### Landscape orientation
507
+
508
+ You may override the default portrait orientation with:
509
+
510
+ ```ruby
511
+ document = Gotenberg::Libreoffice.call(ENV['GOTENBERG_URL']) do |doc|
512
+ doc.landscape
513
+ doc.convert '/path/to/my.docx'
514
+ end
515
+ ```
516
+
517
+ #### Page ranges
518
+
519
+ You may set the page ranges to print, e.g., `1-4`. Empty means all pages.
520
+
521
+ ```ruby
522
+ document = Gotenberg::Libreoffice.call(ENV['GOTENBERG_URL']) do |doc|
523
+ doc.native_page_ranges '1-2'
524
+ doc.convert '/path/to/my.docx'
525
+ end
526
+ ```
527
+
528
+ ⚠️ The page ranges are applied to all files independently.
529
+
530
+ #### PDF format
531
+
532
+ See https://gotenberg.dev/docs/modules/pdf-engines#engines.
533
+
534
+ You may set the PDF format of the resulting PDF(s) with:
535
+
536
+ ```ruby
537
+ document = Gotenberg::Libreoffice.call(ENV['GOTENBERG_URL']) do |doc|
538
+ doc.pdf_format 'PDF/A-1a'
539
+ doc.convert '/path/to/my.docx'
540
+ end
541
+ ```
542
+
543
+ You may also explicitly tell Gotenberg to use [unoconv](https://github.com/unoconv/unoconv) to convert the resulting PDF(s) to a PDF format:
544
+
545
+ ```ruby
546
+ document = Gotenberg::Libreoffice.call(ENV['GOTENBERG_URL']) do |doc|
547
+ doc.native_pdf_format 'PDF/A-1a'
548
+ doc.convert '/path/to/my.docx'
549
+ end
550
+ ```
551
+
552
+ ⚠️ You cannot set both property, otherwise Gotenberg will return `400 Bad Request` response.
553
+
554
+
555
+ ### PDF Engines
556
+
557
+ The [PDF Engines module](https://gotenberg.dev/docs/modules/pdf-engines) gathers all engines that can manipulate PDF files.
558
+
559
+ #### Merge PDFs
560
+
561
+ See https://gotenberg.dev/docs/modules/pdf-engines#merge.
562
+
563
+ Merging PDFs is as simple as:
564
+
565
+ ```ruby
566
+ document = Gotenberg::PdfEngines.call(ENV['GOTENBERG_URL']) do |doc|
567
+ doc.merge '/path/to/my.pdf', '/path/to/my2.pdf'
568
+ end
569
+ ```
570
+
571
+ Please note that the merging order is determined by the order of the arguments.
572
+
573
+ You may also set the PDF format of the resulting PDF(s) with:
574
+
575
+ ```ruby
576
+ document = Gotenberg::PdfEngines.call(ENV['GOTENBERG_URL']) do |doc|
577
+ doc.pdf_format 'PDF/A-1a'
578
+ doc.merge '/path/to/my.pdf', '/path/to/my2.pdf', '/path/to/my3.pdf'
579
+ end
580
+ ```
581
+
582
+ #### Convert to a specific PDF format
583
+
584
+ See https://gotenberg.dev/docs/modules/pdf-engines#convert.
585
+
586
+ You may convert a PDF to a specific PDF format with:
587
+
588
+ ```ruby
589
+ document = Gotenberg::PdfEngines.call(ENV['GOTENBERG_URL']) do |doc|
590
+ doc.convert 'PDF/A-1a', '/path/to/my.pdf'
591
+ end
592
+ ```
593
+
594
+ If you send many PDFs, Gotenberg will return a ZIP archive with the PDFs:
595
+
596
+ ```ruby
597
+ document = Gotenberg::PdfEngines.call(ENV['GOTENBERG_URL']) do |doc|
598
+ doc.convert 'PDF/A-1a', '/path/to/my.pdf', '/path/to/my2.pdf', '/path/to/my3.pdf'
599
+ end
600
+
601
+ # will return binary data with zip archive content
602
+ File.open('archive.zip', 'wb') do |file|
603
+ file << document.to_binary
604
+ end
605
+ ```
606
+
607
+ ### Webhook
608
+
609
+ The [Webhook module](https://gotenberg.dev/docs/modules/webhook) is a Gotenberg middleware that sends the API
610
+ responses to callbacks.
611
+
612
+ ⚠️ You cannot use the `document.to_binary` method if you're using the webhook feature.
613
+
614
+ For instance:
615
+
616
+ ```ruby
617
+ document = Gotenberg::Chromium.call(ENV['GOTENBERG_URL']) do |doc|
618
+ doc.url 'https://my.url'
619
+ doc.webhook 'https://my.webhook.url', 'https://my.webhook.error.url'
620
+ end
621
+ ```
622
+
623
+ You may also override the default HTTP method (`POST`) that Gotenberg will use to call the webhooks:
624
+
625
+ ```ruby
626
+ document = Gotenberg::Chromium.call(ENV['GOTENBERG_URL']) do |doc|
627
+ doc.url 'https://my.url'
628
+ doc.webhook_method('PATCH')
629
+ doc.webhook_error_method('PUT')
630
+ doc.webhook 'https://my.webhook.url', 'https://my.webhook.error.url'
631
+ end
632
+ ```
633
+
634
+ You may also tell Gotenberg to add extra HTTP headers that it will send alongside the request to the webhooks:
635
+
636
+ ```ruby
637
+ document = Gotenberg::Chromium.call(ENV['GOTENBERG_URL']) do |doc|
638
+ doc.url 'https://my.url'
639
+ doc.webhook_extra_http_headers({'My-Header-1' => 'My value', 'My-Header-2' => 'My value'})
640
+ doc.webhook 'https://my.webhook.url', 'https://my.webhook.error.url'
641
+ end
642
+ ```
@@ -1,5 +1,6 @@
1
- require 'faraday'
2
1
  require 'base64'
2
+ require 'net/http'
3
+ require 'uri'
3
4
  require 'gotenberg/exceptions'
4
5
 
5
6
  module Gotenberg
@@ -13,6 +14,10 @@ module Gotenberg
13
14
  @resource = resource
14
15
  end
15
16
 
17
+ def call
18
+ self
19
+ end
20
+
16
21
  def assets
17
22
  [binary, filename]
18
23
  end
@@ -20,25 +25,11 @@ module Gotenberg
20
25
  private
21
26
 
22
27
  def binary
23
- @binary ||= remote? ? remote_source : local_source
24
- end
25
-
26
- def remote_source
27
- Faraday.get(src).body
28
- rescue StandardError => e
29
- raise RemoteSourceError.new('Unable to load remote source. %s' % e.message)
30
- end
31
-
32
- def local_source
33
- IO.binread(src)
34
- end
35
-
36
- def extension
37
- @extension ||= File.extname(filename).strip.downcase[1..-1]
28
+ @binary ||= remote? ? remote_source(src) : local_source(src)
38
29
  end
39
30
 
40
31
  def filename
41
- @filename ||= File.basename(src)
32
+ @filename ||= URI(File.basename(src)).path
42
33
  end
43
34
 
44
35
  def remote?
@@ -48,6 +39,16 @@ module Gotenberg
48
39
  def src
49
40
  resource[:src]
50
41
  end
42
+
43
+ def local_source path
44
+ IO.binread(path)
45
+ end
46
+
47
+ def remote_source url
48
+ Net::HTTP.get_response(URI(url)).body
49
+ rescue StandardError => e
50
+ raise RemoteSourceError.new('Unable to load remote source. %s' % e.message)
51
+ end
51
52
  end
52
53
  end
53
54
  end
@@ -1,10 +1,17 @@
1
- require 'faraday'
2
- require 'base64'
3
1
  require 'gotenberg/analyzers/base'
2
+ require 'gotenberg/analyzers/resource'
4
3
 
5
4
  module Gotenberg
6
5
  module Analyzers
7
6
  class Css < Base
7
+ ASSETS_REGEX = /url\((?!['"]?(?:data|https?):)['"]?([^'"\)]*)['"]?\)/
8
+
9
+ def call
10
+ analyze_binary unless resource[:skip_analyze]
11
+
12
+ self
13
+ end
14
+
8
15
  def tag
9
16
  if resource[:inline]
10
17
  '<style type="text/css">%s</style>' % binary
@@ -12,6 +19,25 @@ module Gotenberg
12
19
  '<link rel="stylesheet" href="%s" />' % filename
13
20
  end
14
21
  end
22
+
23
+ def assets
24
+ @assets ||= [[binary, filename]]
25
+ end
26
+
27
+ private
28
+
29
+ def analyze_binary
30
+ binary.gsub!(ASSETS_REGEX) do
31
+ resource_src = File.join(resource[:base_path], $1)
32
+
33
+ analyzer =
34
+ Analyzers::Resource.new(resource.merge(src: resource_src)).call
35
+
36
+ assets << analyzer.assets
37
+
38
+ analyzer.tag
39
+ end
40
+ end
15
41
  end
16
42
  end
17
43
  end
@@ -1,23 +1,9 @@
1
- require 'faraday'
2
- require 'base64'
3
1
  require 'gotenberg/analyzers/base'
2
+ require 'gotenberg/utilities/inline_resource'
4
3
 
5
4
  module Gotenberg
6
5
  module Analyzers
7
6
  class Image < Base
8
- MIME_TYPES = {
9
- 'bmp' => 'image/bmp',
10
- 'gif' => 'image/gif',
11
- 'jpe' => 'image/jpeg',
12
- 'jpeg' => 'image/jpeg',
13
- 'jpg' => 'image/jpeg',
14
- 'jfif' => 'image/pipeg',
15
- 'svg' => 'image/svg+xml',
16
- 'tif' => 'image/tiff',
17
- 'tiff' => 'image/tiff',
18
- 'ico' => 'image/x-icon'
19
- }.freeze
20
-
21
7
  def tag
22
8
  '<img src="%s" alt="%s" />' % [src_value, filename]
23
9
  end
@@ -26,15 +12,11 @@ module Gotenberg
26
12
 
27
13
  def src_value
28
14
  if resource[:inline]
29
- 'data:%s;base64,%s' % [mimetype, Base64.strict_encode64(binary)]
15
+ Gotenberg::Utilities::InlineResource.new(filename, binary).call
30
16
  else
31
17
  filename
32
18
  end
33
19
  end
34
-
35
- def mimetype
36
- MIME_TYPES[extension] || 'application/octet-stream'
37
- end
38
20
  end
39
21
  end
40
22
  end
@@ -1,4 +1,3 @@
1
- require 'faraday'
2
1
  require 'base64'
3
2
  require 'gotenberg/analyzers/base'
4
3
 
@@ -0,0 +1,22 @@
1
+ require 'gotenberg/analyzers/base'
2
+ require 'gotenberg/utilities/inline_resource'
3
+
4
+ module Gotenberg
5
+ module Analyzers
6
+ class Resource < Base
7
+ def tag
8
+ 'url(%s)' % src_value
9
+ end
10
+
11
+ private
12
+
13
+ def src_value
14
+ if resource[:inline]
15
+ Gotenberg::Utilities::InlineResource.new(filename, binary).call
16
+ else
17
+ filename
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -11,6 +11,8 @@ module Gotenberg
11
11
  compiler = Compiler.new(header)
12
12
 
13
13
  files << multipart_file(compiler.body, 'header.html', 'text/html')
14
+
15
+ self
14
16
  end
15
17
 
16
18
  # Adds a footer to each page.
@@ -19,6 +21,8 @@ module Gotenberg
19
21
  compiler = Compiler.new(footer)
20
22
 
21
23
  files << multipart_file(compiler.body, 'footer.html', 'text/html')
24
+
25
+ self
22
26
  end
23
27
 
24
28
  # Converts an HTML document to PDF.
@@ -70,12 +74,12 @@ module Gotenberg
70
74
  self
71
75
  end
72
76
 
77
+ private
78
+
73
79
  def files
74
80
  @files ||= []
75
81
  end
76
82
 
77
- private
78
-
79
83
  def multipart_file body, filename, content_type = 'application/octet-stream'
80
84
  Faraday::Multipart::FilePart.new(StringIO.new(body), content_type, filename)
81
85
  end
@@ -133,6 +133,8 @@ module Gotenberg
133
133
 
134
134
  self
135
135
  end
136
+
137
+ private
136
138
 
137
139
  def properties
138
140
  @properties ||= {}
@@ -1,7 +1,7 @@
1
1
  require 'gotenberg/chromium/properties'
2
2
  require 'gotenberg/chromium/files'
3
- require 'gotenberg/chromium/headers'
4
- require 'gotenberg/chromium/metadata'
3
+ require 'gotenberg/headers'
4
+ require 'gotenberg/metadata'
5
5
  require 'gotenberg/client'
6
6
  require 'gotenberg/exiftools'
7
7
  require 'gotenberg/extractors'
@@ -30,10 +30,7 @@ module Gotenberg
30
30
  def call
31
31
  backtrace if html_debug?
32
32
  transform
33
-
34
- if success? && metadata_available?
35
- modify_metadata
36
- end
33
+ modify_metadata if modify_metadata?
37
34
 
38
35
  self
39
36
  end
@@ -46,12 +43,19 @@ module Gotenberg
46
43
  response || raise(exception)
47
44
  end
48
45
 
46
+
47
+ private
48
+
49
+ def modify_metadata?
50
+ return false if webhook_request?
51
+
52
+ success? && metadata_available?
53
+ end
54
+
49
55
  def html_debug?
50
56
  Gotenberg.configuration.html_debug == true
51
57
  end
52
58
 
53
- private
54
-
55
59
  def backtrace
56
60
  Backtrace.new(files).call
57
61
  end
@@ -30,26 +30,16 @@ module Gotenberg
30
30
  analyzer =
31
31
  case resource[:tag]
32
32
  when 'image'
33
- Analyzers::Image.new(resource)
33
+ Analyzers::Image.new(resource).call
34
34
  when 'js'
35
- Analyzers::Js.new(resource)
35
+ Analyzers::Js.new(resource).call
36
36
  when 'css'
37
- Analyzers::Css.new(resource)
37
+ Analyzers::Css.new(resource).call
38
38
  end
39
39
 
40
- assets << analyzer.assets
40
+ assets.push(*analyzer.assets)
41
41
 
42
42
  analyzer.tag
43
-
44
- #css -
45
- # 1) read to io (http or file)
46
- # 2) scan for url tags -
47
- # if data - skip
48
- # if relative (read to io http or file )
49
- # replace url tags
50
- # 3) check if inline then stylesheet tag
51
- # 4) if not inline add to assets
52
- # 5) replace tag
53
43
  end
54
44
  end
55
45
  end
@@ -0,0 +1,54 @@
1
+ require 'json'
2
+
3
+ module Gotenberg
4
+ module Headers
5
+ # Sets the callback and error callback that Gotenberg will use to send
6
+ # respectively the output file and the error response.
7
+ def webhook url, error_url
8
+ headers['Gotenberg-Webhook-Url'] = url
9
+ headers['Gotenberg-Webhook-Error-Url'] = error_url
10
+
11
+ self
12
+ end
13
+
14
+ # Overrides the default HTTP method that Gotenberg will use to call the webhook.
15
+ # Either "POST", "PATCH", or "PUT" - default "POST".
16
+ def webhook_method method
17
+ headers['Gotenberg-Webhook-Method'] = method
18
+
19
+ self
20
+ end
21
+
22
+ # Overrides the default HTTP method that Gotenberg will use to call the error webhook.
23
+ # Either "POST", "PATCH", or "PUT" - default "POST".
24
+ def webhook_error_method method
25
+ headers['Gotenberg-Webhook-Error-Method'] = method
26
+
27
+ self
28
+ end
29
+
30
+ # Sets the extra HTTP headers that Gotenberg will send alongside the request to the webhook and error webhook.
31
+ def webhook_extra_http_headers headers
32
+ headers['Gotenberg-Webhook-Extra-Http-Headers'] = headers.to_json
33
+
34
+ self
35
+ end
36
+
37
+ # Overrides the default UUID trace, or request ID, that identifies a request in Gotenberg's logs.
38
+ def trace trace, header = 'Gotenberg-Trace'
39
+ headers[header] = trace
40
+
41
+ self
42
+ end
43
+
44
+ private
45
+
46
+ def webhook_request?
47
+ headers.keys.include?('Gotenberg-Webhook-Url')
48
+ end
49
+
50
+ def headers
51
+ @headers ||= {}
52
+ end
53
+ end
54
+ end
@@ -2,36 +2,68 @@ module Gotenberg
2
2
  module Helpers
3
3
  module ActionView
4
4
  def gotenberg_image_tag source, options = {}
5
- gootenberg_source_tag(source, options.merge(tag: 'image'))
5
+ options[:tag] = 'image'
6
+ options[:src] = gotenberg_source_location(source, options)
7
+
8
+ gotenberg_context_tag(options)
6
9
  end
7
10
 
8
11
  def gotenberg_javascript_tag source, options = {}
9
- gootenberg_source_tag(source, options.merge(tag: 'js'))
12
+ options[:tag] = 'js'
13
+ options[:src] = gotenberg_source_location(source, options)
14
+
15
+ gotenberg_context_tag(options)
10
16
  end
11
17
 
12
18
  def gotenberg_stylesheet_tag source, options = {}
13
- gootenberg_source_tag(source, options.merge(tag: 'css'))
19
+ options[:tag] = 'css'
20
+ options[:src] = gotenberg_source_location(source, options)
21
+
22
+ options[:base_path] =
23
+ case gotenberg_source_type(options)
24
+ when :absolute
25
+ Rails.root
26
+ when :proxy
27
+ compute_asset_host(source, protocol: :request)
28
+ when :static
29
+ Rails.public_path
30
+ end
31
+
32
+ options[:skip_analyze] ||= false
33
+
34
+ gotenberg_context_tag(options)
14
35
  end
15
36
 
16
37
  private
17
38
 
18
- def gootenberg_source_tag source, options = {}
19
- src = if options[:absolute_path]
20
- File.join(Rails.root, source)
21
- elsif Rails.env.development?
22
- gootenberg_asset_location(source, :url)
23
- else
24
- File.join(Rails.public_path, gootenberg_asset_location(source, :path))
39
+ def gotenberg_source_type options = {}
40
+ return :absolute if options[:absolute_path]
41
+
42
+ if Rails.application.config.asset_host || Rails.application.config.action_controller.asset_host
43
+ raise <<-EOF.squish
44
+ You can not use Gotenberg tag helpers for assets with "asset_host" option. Use standard rails assets tag helpers.
45
+ EOF
25
46
  end
26
47
 
27
- gootenberg_context_tag(src: src, **options)
48
+ Rails.env.development? ? :proxy : :static
49
+ end
50
+
51
+ def gotenberg_source_location source, options = {}
52
+ case gotenberg_source_type(options)
53
+ when :absolute
54
+ File.join(Rails.root, source)
55
+ when :proxy
56
+ gotenberg_asset_location(source, :url)
57
+ when :static
58
+ File.join(Rails.public_path, gotenberg_asset_location(source, :path))
59
+ end
28
60
  end
29
61
 
30
- def gootenberg_context_tag attributes
62
+ def gotenberg_context_tag attributes
31
63
  ('<!-- GOTENBERG-CONTEXT-TAG %s -->' % attributes.to_json).html_safe
32
64
  end
33
65
 
34
- def gootenberg_asset_location source, type
66
+ def gotenberg_asset_location source, type
35
67
  webpacker = Module.const_defined?(:Webpacker)
36
68
 
37
69
  case type
@@ -0,0 +1,42 @@
1
+ require 'faraday'
2
+ require 'faraday/multipart'
3
+ require 'gotenberg/utilities/index'
4
+
5
+ module Gotenberg
6
+ class Libreoffice
7
+ module Files
8
+
9
+ # Converts the given document(s) to PDF(s).
10
+ # Gotenberg will return either a unique PDF if you request a merge or a ZIP archive with the PDFs.
11
+ # Note: if you requested a merge, the merging order is determined by the order of the arguments.
12
+ # See https://gotenberg.dev/docs/modules/libreoffice#route.
13
+ def convert *sources
14
+ sources.each.with_index(1) do |source, index|
15
+ files << multipart_file(IO.binread(source), merge_prefix(index) + File.basename(source))
16
+ end
17
+
18
+ @endpoint = '/forms/libreoffice/convert'
19
+
20
+ self
21
+ end
22
+
23
+ private
24
+
25
+ def files
26
+ @files ||= []
27
+ end
28
+
29
+ def zip_mode?
30
+ properties['merge'] != true && files.size > 1
31
+ end
32
+
33
+ def merge_prefix number
34
+ properties['merge'] ? Gotenberg::Utilities::Index::to_alpha(number) + '_' : ''
35
+ end
36
+
37
+ def multipart_file body, filename, content_type = 'application/octet-stream'
38
+ Faraday::Multipart::FilePart.new(StringIO.new(body), content_type, filename)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,49 @@
1
+ module Gotenberg
2
+ class Libreoffice
3
+ module Properties
4
+
5
+ # Sets the paper orientation to landscape.
6
+ def landscape
7
+ properties['landscape'] = true
8
+
9
+ self
10
+ end
11
+
12
+ # Set the page ranges to print, e.g., "1-5, 8, 11-13". Empty means all pages.
13
+ # Note: the page ranges are applied to all files independently.
14
+ def native_page_ranges ranges
15
+ properties['nativePageRanges'] = ranges
16
+
17
+ self
18
+ end
19
+
20
+ # Tells Gotenberg to use unoconv for converting the resulting PDF to a PDF format.
21
+ def native_pdf_format format
22
+ properties['nativePdfFormat'] = format
23
+
24
+ self
25
+ end
26
+
27
+ # Sets the PDF format of the resulting PDF.
28
+ # See https://gotenberg.dev/docs/modules/pdf-engines#engines.
29
+ def pdf_format format
30
+ properties['pdfFormat'] = format
31
+
32
+ self
33
+ end
34
+
35
+ # Merges the resulting PDFs.
36
+ def merge
37
+ properties['merge'] = true
38
+
39
+ self
40
+ end
41
+
42
+ private
43
+
44
+ def properties
45
+ @properties ||= {}
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,68 @@
1
+ require 'gotenberg/libreoffice/properties'
2
+ require 'gotenberg/libreoffice/files'
3
+ require 'gotenberg/headers'
4
+ require 'gotenberg/metadata'
5
+ require 'gotenberg/client'
6
+ require 'gotenberg/exiftools'
7
+ require 'gotenberg/exceptions'
8
+
9
+ module Gotenberg
10
+ class Libreoffice
11
+ include Properties, Files, Headers, Metadata
12
+
13
+ attr_accessor :base_path
14
+ attr_reader :endpoint, :response, :exception
15
+
16
+ def self.call(base_path, &block)
17
+ new(base_path: base_path, &block).call
18
+ end
19
+
20
+ def initialize args
21
+ args.each do |key, value|
22
+ public_send(('%s=' % key), value)
23
+ end
24
+
25
+ yield self if block_given?
26
+ end
27
+
28
+ def call
29
+ transform
30
+ modify_metadata if modify_metadata?
31
+
32
+ self
33
+ end
34
+
35
+ def success?
36
+ exception == nil
37
+ end
38
+
39
+ def to_binary
40
+ response || raise(exception)
41
+ end
42
+
43
+ private
44
+
45
+ def modify_metadata?
46
+ return false if webhook_request?
47
+ return false if zip_mode?
48
+
49
+ success? && metadata_available?
50
+ end
51
+
52
+ def transform
53
+ @response = client.adapter.post(endpoint, properties.merge(files: files), headers).body
54
+ rescue StandardError => e
55
+ @exception = Gotenberg::TransformError.new(e)
56
+ end
57
+
58
+ def modify_metadata
59
+ @response = Exiftools.modify(response, metadata)
60
+ rescue StandardError => e
61
+ @exception = Gotenberg::ModifyMetadataError.new(e)
62
+ end
63
+
64
+ def client
65
+ Client.new(base_path)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ module Gotenberg
2
+ module Metadata
3
+ # set meta headers for PDF file with exiftools (title, creator, etc...)
4
+ def meta elements
5
+ metadata.merge!(elements)
6
+
7
+ self
8
+ end
9
+
10
+ private
11
+
12
+ def metadata_available?
13
+ !metadata.empty?
14
+ end
15
+
16
+ def metadata
17
+ @metadata ||= {}
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,58 @@
1
+ require 'faraday'
2
+ require 'faraday/multipart'
3
+ require 'gotenberg/utilities/index'
4
+
5
+ module Gotenberg
6
+ class PdfEngines
7
+ module Files
8
+
9
+ # Merges PDFs into a unique PDF.
10
+ # Note: the merging order is determined by the order of the arguments.
11
+ # See https://gotenberg.dev/docs/modules/pdf-engines#merge.
12
+ def merge *sources
13
+ sources.each.with_index(1) do |source, index|
14
+ files << multipart_file(IO.binread(source), merge_prefix(index) + File.basename(source))
15
+ end
16
+
17
+ @endpoint = '/forms/pdfengines/merge'
18
+
19
+ self
20
+ end
21
+
22
+ # Converts PDF(s) to a specific PDF format.
23
+ # Gotenberg will return the PDF or a ZIP archive with the PDFs.
24
+ # https://gotenberg.dev/docs/modules/pdf-engines#convert.
25
+ # https://gotenberg.dev/docs/modules/pdf-engines#engines.
26
+ def convert format, *sources
27
+ properties['pdfFormat'] = format
28
+
29
+ sources.each.with_index(1) do |source, index|
30
+ files << multipart_file(IO.binread(source), File.basename(source))
31
+ end
32
+
33
+ @endpoint = '/forms/pdfengines/convert'
34
+ @pdf_engines_convert = true
35
+
36
+ self
37
+ end
38
+
39
+ private
40
+
41
+ def files
42
+ @files ||= []
43
+ end
44
+
45
+ def zip_mode?
46
+ @pdf_engines_convert && files.size > 1
47
+ end
48
+
49
+ def merge_prefix number
50
+ Gotenberg::Utilities::Index::to_alpha(number) + '_'
51
+ end
52
+
53
+ def multipart_file body, filename, content_type = 'application/octet-stream'
54
+ Faraday::Multipart::FilePart.new(StringIO.new(body), content_type, filename)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ module Gotenberg
2
+ class PdfEngines
3
+ module Properties
4
+
5
+ # Sets the PDF format of the resulting PDF.
6
+ # See https://gotenberg.dev/docs/modules/pdf-engines#engines.
7
+ def pdf_format format
8
+ properties['pdfFormat'] = format
9
+
10
+ self
11
+ end
12
+
13
+ private
14
+
15
+ def properties
16
+ @properties ||= {}
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,67 @@
1
+ require 'gotenberg/pdf_engines/properties'
2
+ require 'gotenberg/pdf_engines/files'
3
+ require 'gotenberg/headers'
4
+ require 'gotenberg/metadata'
5
+ require 'gotenberg/client'
6
+ require 'gotenberg/exiftools'
7
+ require 'gotenberg/exceptions'
8
+
9
+ module Gotenberg
10
+ class PdfEngines
11
+ include Properties, Files, Headers, Metadata
12
+
13
+ attr_accessor :base_path
14
+ attr_reader :endpoint, :response, :exception
15
+
16
+ def self.call(base_path, &block)
17
+ new(base_path: base_path, &block).call
18
+ end
19
+
20
+ def initialize args
21
+ args.each do |key, value|
22
+ public_send(('%s=' % key), value)
23
+ end
24
+
25
+ yield self if block_given?
26
+ end
27
+
28
+ def call
29
+ transform
30
+ modify_metadata if modify_metadata?
31
+
32
+ self
33
+ end
34
+
35
+ def success?
36
+ exception == nil
37
+ end
38
+
39
+ def to_binary
40
+ response || raise(exception)
41
+ end
42
+
43
+ private
44
+
45
+ def modify_metadata?
46
+ return false if webhook_request?
47
+
48
+ success? && metadata_available?
49
+ end
50
+
51
+ def transform
52
+ @response = client.adapter.post(endpoint, properties.merge(files: files), headers).body
53
+ rescue StandardError => e
54
+ @exception = Gotenberg::TransformError.new(e)
55
+ end
56
+
57
+ def modify_metadata
58
+ @response = Exiftools.modify(response, metadata)
59
+ rescue StandardError => e
60
+ @exception = Gotenberg::ModifyMetadataError.new(e)
61
+ end
62
+
63
+ def client
64
+ Client.new(base_path)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ module Gotenberg
2
+ module Utilities
3
+ class Index
4
+ def self.to_alpha index, alpha = ''
5
+ return '' if index <= 0
6
+
7
+ until index.zero?
8
+ pointer = (index - 1) % 26
9
+ index = ((index - pointer) / 26).to_i
10
+ alpha = (65 + pointer).chr + alpha
11
+ end
12
+
13
+ alpha
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ require 'base64'
2
+
3
+ module Gotenberg
4
+ module Utilities
5
+ class InlineResource
6
+ MIME_TYPES = {
7
+ 'bmp' => 'image/bmp',
8
+ 'gif' => 'image/gif',
9
+ 'png' => 'image/png',
10
+ 'jpe' => 'image/jpeg',
11
+ 'jpeg' => 'image/jpeg',
12
+ 'jpg' => 'image/jpeg',
13
+ 'jfif' => 'image/pipeg',
14
+ 'svg' => 'image/svg+xml',
15
+ 'tif' => 'image/tiff',
16
+ 'tiff' => 'image/tiff',
17
+ 'ico' => 'image/x-icon',
18
+ 'eot' => 'application/vnd.ms-fontobject',
19
+ 'otf' => 'application/font-sfnt',
20
+ 'ttf' => 'application/font-sfnt',
21
+ 'woff' => 'application/font-woff',
22
+ 'woff2' => 'application/font-woff2',
23
+ }.freeze
24
+
25
+ attr_reader :filename, :binary
26
+
27
+ def initialize filename, binary
28
+ @filename = filename
29
+ @binary = binary
30
+ end
31
+
32
+ def call
33
+ 'data:%s;base64,%s' % [mimetype, Base64.strict_encode64(binary)]
34
+ end
35
+
36
+ private
37
+
38
+ def extension
39
+ @extension ||= File.extname(filename).downcase[1..-1]
40
+ end
41
+
42
+ def mimetype
43
+ @mimetype ||= MIME_TYPES[extension] || 'application/octet-stream'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Gotenberg
2
- VERSION = '1.0.4'
2
+ VERSION = '1.0.6'
3
3
  end
@@ -3,6 +3,8 @@ require 'gotenberg/railtie' if defined?(Rails::Railtie)
3
3
 
4
4
  module Gotenberg
5
5
  autoload :Chromium, 'gotenberg/chromium'
6
+ autoload :Libreoffice, 'gotenberg/libreoffice'
7
+ autoload :PdfEngines, 'gotenberg/pdf_engines'
6
8
  autoload :Configuration, 'gotenberg/configuration'
7
9
 
8
10
  def self.configuration
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gotenberg-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - sanzstez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-23 00:00:00.000000000 Z
11
+ date: 2022-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -87,11 +87,10 @@ files:
87
87
  - lib/gotenberg/analyzers/css.rb
88
88
  - lib/gotenberg/analyzers/image.rb
89
89
  - lib/gotenberg/analyzers/js.rb
90
+ - lib/gotenberg/analyzers/resource.rb
90
91
  - lib/gotenberg/backtrace.rb
91
92
  - lib/gotenberg/chromium.rb
92
93
  - lib/gotenberg/chromium/files.rb
93
- - lib/gotenberg/chromium/headers.rb
94
- - lib/gotenberg/chromium/metadata.rb
95
94
  - lib/gotenberg/chromium/properties.rb
96
95
  - lib/gotenberg/client.rb
97
96
  - lib/gotenberg/compiler.rb
@@ -99,8 +98,18 @@ files:
99
98
  - lib/gotenberg/exceptions.rb
100
99
  - lib/gotenberg/exiftools.rb
101
100
  - lib/gotenberg/extractors.rb
101
+ - lib/gotenberg/headers.rb
102
102
  - lib/gotenberg/helpers/action_view.rb
103
+ - lib/gotenberg/libreoffice.rb
104
+ - lib/gotenberg/libreoffice/files.rb
105
+ - lib/gotenberg/libreoffice/properties.rb
106
+ - lib/gotenberg/metadata.rb
107
+ - lib/gotenberg/pdf_engines.rb
108
+ - lib/gotenberg/pdf_engines/files.rb
109
+ - lib/gotenberg/pdf_engines/properties.rb
103
110
  - lib/gotenberg/railtie.rb
111
+ - lib/gotenberg/utilities/index.rb
112
+ - lib/gotenberg/utilities/inline_resource.rb
104
113
  - lib/gotenberg/version.rb
105
114
  homepage: https://github.com/sanzstez/gotenberg-ruby
106
115
  licenses:
@@ -1,50 +0,0 @@
1
- require 'json'
2
-
3
- module Gotenberg
4
- class Chromium
5
- module Headers
6
- # Sets the callback and error callback that Gotenberg will use to send
7
- # respectively the output file and the error response.
8
- def webhook url, error_url
9
- headers['Gotenberg-Webhook-Url'] = url
10
- headers['Gotenberg-Webhook-Error-Url'] = error_url
11
-
12
- self
13
- end
14
-
15
- # Overrides the default HTTP method that Gotenberg will use to call the webhook.
16
- # Either "POST", "PATCH", or "PUT" - default "POST".
17
- def webhook_method method
18
- headers['Gotenberg-Webhook-Method'] = method
19
-
20
- self
21
- end
22
-
23
- # Overrides the default HTTP method that Gotenberg will use to call the error webhook.
24
- # Either "POST", "PATCH", or "PUT" - default "POST".
25
- def webhook_error_method method
26
- headers['Gotenberg-Webhook-Error-Method'] = method
27
-
28
- self
29
- end
30
-
31
- # Sets the extra HTTP headers that Gotenberg will send alongside the request to the webhook and error webhook.
32
- def webhook_extra_http_headers headers
33
- headers['Gotenberg-Webhook-Extra-Http-Headers'] = headers.to_json
34
-
35
- self
36
- end
37
-
38
- # Overrides the default UUID trace, or request ID, that identifies a request in Gotenberg's logs.
39
- def trace trace, header = 'Gotenberg-Trace'
40
- headers[header] = trace
41
-
42
- self
43
- end
44
-
45
- def headers
46
- @headers = {}
47
- end
48
- end
49
- end
50
- end
@@ -1,24 +0,0 @@
1
- require 'json'
2
-
3
- module Gotenberg
4
- class Chromium
5
- module Metadata
6
- # set meta headers for PDF file with exiftools (title, creator, etc...)
7
- def meta elements
8
- metadata.merge!(elements)
9
-
10
- self
11
- end
12
-
13
- def metadata_available?
14
- !metadata.empty?
15
- end
16
-
17
- private
18
-
19
- def metadata
20
- @metadata ||= {}
21
- end
22
- end
23
- end
24
- end