gotenberg-ruby 1.0.4 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
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