sinicum 0.5.0

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.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/.cane +19 -0
  3. data/.gitignore +14 -0
  4. data/.rubocop.yml +30 -0
  5. data/.travis.yml +14 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +24 -0
  8. data/README.md +327 -0
  9. data/Rakefile +37 -0
  10. data/app/assets/javascripts/sinicum/magnolia_client.js.coffee +233 -0
  11. data/app/controllers/sinicum/controller_base.rb +173 -0
  12. data/app/controllers/sinicum/controllers/cache_aware.rb +16 -0
  13. data/app/controllers/sinicum/controllers/global_state_cache.rb +83 -0
  14. data/app/helpers/sinicum/helper_utils.rb +152 -0
  15. data/app/helpers/sinicum/mgnl_helper.rb +145 -0
  16. data/app/helpers/sinicum/mgnl_helper5.rb +7 -0
  17. data/app/helpers/sinicum/mgnl_image_helper.rb +26 -0
  18. data/app/helpers/sinicum/taglib_helper5.rb +166 -0
  19. data/gemfiles/Gemfile-3.2 +6 -0
  20. data/gemfiles/Gemfile-4.0 +6 -0
  21. data/lib/generators/sinicum/install_generator.rb +162 -0
  22. data/lib/generators/sinicum/templates/VersionHandler.java +18 -0
  23. data/lib/generators/sinicum/templates/config/default/log4j-development.xml +203 -0
  24. data/lib/generators/sinicum/templates/config/default/log4j.xml +200 -0
  25. data/lib/generators/sinicum/templates/config/default/magnolia-author.properties +63 -0
  26. data/lib/generators/sinicum/templates/config/default/magnolia-public01.properties +63 -0
  27. data/lib/generators/sinicum/templates/config/default/magnolia.properties +63 -0
  28. data/lib/generators/sinicum/templates/config/repo-conf/jackrabbit-bundle-postgres-search-author.xml +73 -0
  29. data/lib/generators/sinicum/templates/config/repo-conf/jackrabbit-bundle-postgres-search-public01.xml +73 -0
  30. data/lib/generators/sinicum/templates/config/repo-conf/jackrabbit-bundle-postgres-search.xml +70 -0
  31. data/lib/generators/sinicum/templates/magnolia/config.modules.myproject.dialogs.xml +1625 -0
  32. data/lib/generators/sinicum/templates/magnolia/config.modules.myproject.templates.xml +247 -0
  33. data/lib/generators/sinicum/templates/module-config.xml +13 -0
  34. data/lib/generators/sinicum/templates/module-pom.xml +67 -0
  35. data/lib/generators/sinicum/templates/project-pom.xml +104 -0
  36. data/lib/generators/sinicum/templates/rails/_article.html.haml +15 -0
  37. data/lib/generators/sinicum/templates/rails/_content.html.haml +2 -0
  38. data/lib/generators/sinicum/templates/rails/_meta.html.haml +9 -0
  39. data/lib/generators/sinicum/templates/rails/application.html.haml +11 -0
  40. data/lib/generators/sinicum/templates/rails/content_controller.rb +5 -0
  41. data/lib/generators/sinicum/templates/rails/imaging.yml +8 -0
  42. data/lib/generators/sinicum/templates/rails/sinicum_server.yml +15 -0
  43. data/lib/sinicum.rb +53 -0
  44. data/lib/sinicum/content/aggregator.rb +173 -0
  45. data/lib/sinicum/content/website_content_resolver.rb +10 -0
  46. data/lib/sinicum/engine.rb +23 -0
  47. data/lib/sinicum/imaging.rb +29 -0
  48. data/lib/sinicum/imaging/config.rb +133 -0
  49. data/lib/sinicum/imaging/converter.rb +81 -0
  50. data/lib/sinicum/imaging/default_converter.rb +20 -0
  51. data/lib/sinicum/imaging/image_size_converter.rb +52 -0
  52. data/lib/sinicum/imaging/imaging.rb +171 -0
  53. data/lib/sinicum/imaging/imaging_file.rb +115 -0
  54. data/lib/sinicum/imaging/imaging_middleware.rb +56 -0
  55. data/lib/sinicum/imaging/max_size_converter.rb +39 -0
  56. data/lib/sinicum/imaging/resize_crop_converter.rb +35 -0
  57. data/lib/sinicum/jcr/api_client.rb +50 -0
  58. data/lib/sinicum/jcr/api_queries.rb +37 -0
  59. data/lib/sinicum/jcr/cache/global_cache.rb +26 -0
  60. data/lib/sinicum/jcr/dam/document.rb +57 -0
  61. data/lib/sinicum/jcr/dam/image.rb +40 -0
  62. data/lib/sinicum/jcr/jcr_configuration.rb +67 -0
  63. data/lib/sinicum/jcr/mgnl4_compatibility.rb +11 -0
  64. data/lib/sinicum/jcr/node.rb +268 -0
  65. data/lib/sinicum/jcr/node_initializer.rb +16 -0
  66. data/lib/sinicum/jcr/node_queries.rb +101 -0
  67. data/lib/sinicum/jcr/query_sanitizer.rb +24 -0
  68. data/lib/sinicum/jcr/type_translator.rb +38 -0
  69. data/lib/sinicum/jcr/type_translators/component_translator.rb +28 -0
  70. data/lib/sinicum/jcr/type_translators/dam_translator.rb +33 -0
  71. data/lib/sinicum/jcr/type_translators/data_translator.rb +31 -0
  72. data/lib/sinicum/jcr/type_translators/default_translator.rb +13 -0
  73. data/lib/sinicum/jcr/type_translators/translator_base.rb +40 -0
  74. data/lib/sinicum/logger.rb +28 -0
  75. data/lib/sinicum/navigation/default_navigation_element.rb +30 -0
  76. data/lib/sinicum/navigation/navigation_element.rb +39 -0
  77. data/lib/sinicum/navigation/navigation_element_list.rb +33 -0
  78. data/lib/sinicum/navigation/navigation_handler.rb +95 -0
  79. data/lib/sinicum/navigation/navigation_status.rb +27 -0
  80. data/lib/sinicum/templating/area_handler.rb +33 -0
  81. data/lib/sinicum/templating/dialog_resolver.rb +26 -0
  82. data/lib/sinicum/templating/templating_utils.rb +24 -0
  83. data/lib/sinicum/util.rb +12 -0
  84. data/lib/sinicum/version.rb +3 -0
  85. data/script/cibuild +31 -0
  86. data/sinicum.gemspec +29 -0
  87. data/spec/controllers/sinicum/controller_base_spec.rb +53 -0
  88. data/spec/controllers/sinicum/controllers/global_state_cache_spec.rb +35 -0
  89. data/spec/dummy/REVISION +1 -0
  90. data/spec/dummy/Rakefile +7 -0
  91. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  92. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  93. data/spec/dummy/app/views/application/index.html.erb +1 -0
  94. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  95. data/spec/dummy/app/views/layouts/layout_name.html.erb +0 -0
  96. data/spec/dummy/app/views/layouts/my-module/test.html.erb +0 -0
  97. data/spec/dummy/app/views/layouts/my_module/test.html.erb +0 -0
  98. data/spec/dummy/config.ru +4 -0
  99. data/spec/dummy/config/application.rb +45 -0
  100. data/spec/dummy/config/boot.rb +10 -0
  101. data/spec/dummy/config/database.yml +22 -0
  102. data/spec/dummy/config/environment.rb +5 -0
  103. data/spec/dummy/config/environments/development.rb +24 -0
  104. data/spec/dummy/config/environments/production.rb +51 -0
  105. data/spec/dummy/config/environments/test.rb +34 -0
  106. data/spec/dummy/config/imaging.yml +7 -0
  107. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  108. data/spec/dummy/config/initializers/inflections.rb +10 -0
  109. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  110. data/spec/dummy/config/initializers/secret_token.rb +11 -0
  111. data/spec/dummy/config/initializers/session_store.rb +8 -0
  112. data/spec/dummy/config/locales/en.yml +5 -0
  113. data/spec/dummy/config/routes.rb +59 -0
  114. data/spec/dummy/config/sinicum_server.yml +13 -0
  115. data/spec/dummy/public/404.html +26 -0
  116. data/spec/dummy/public/422.html +26 -0
  117. data/spec/dummy/public/500.html +26 -0
  118. data/spec/dummy/public/favicon.ico +0 -0
  119. data/spec/dummy/public/javascripts/application.js +2 -0
  120. data/spec/dummy/public/javascripts/controls.js +965 -0
  121. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  122. data/spec/dummy/public/javascripts/effects.js +1123 -0
  123. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  124. data/spec/dummy/public/javascripts/rails.js +191 -0
  125. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  126. data/spec/dummy/script/rails +6 -0
  127. data/spec/fixtures/api/cache_global.json +3 -0
  128. data/spec/fixtures/api/content_mgnl5.json +22 -0
  129. data/spec/fixtures/api/default_json.json.erb +47 -0
  130. data/spec/fixtures/api/default_json_mgnl5.json.erb +27 -0
  131. data/spec/fixtures/api/file.json +73 -0
  132. data/spec/fixtures/api/file_mgnl5.json +51 -0
  133. data/spec/fixtures/api/homepage.json +1497 -0
  134. data/spec/fixtures/api/homepage_parent.json +483 -0
  135. data/spec/fixtures/api/image.json +73 -0
  136. data/spec/fixtures/api/image_mgnl5.json +50 -0
  137. data/spec/fixtures/api/navigation_children.json +3107 -0
  138. data/spec/fixtures/api/navigation_parents.json +25 -0
  139. data/spec/fixtures/api/product.json +2084 -0
  140. data/spec/fixtures/api/query_result.json +61 -0
  141. data/spec/fixtures/mock_content.rb +6 -0
  142. data/spec/fixtures/mock_image.gif +0 -0
  143. data/spec/helpers/sinicum/helper_utils_spec.rb +55 -0
  144. data/spec/helpers/sinicum/mgnl_helper_spec.rb +315 -0
  145. data/spec/helpers/sinicum/mgnl_image_helper_spec.rb +103 -0
  146. data/spec/sinicum/content/aggregator_spec.rb +91 -0
  147. data/spec/sinicum/content/website_content_resolver_spec.rb +14 -0
  148. data/spec/sinicum/imaging/config_spec.rb +50 -0
  149. data/spec/sinicum/imaging/converter_spec.rb +41 -0
  150. data/spec/sinicum/imaging/image_size_converter_spec.rb +27 -0
  151. data/spec/sinicum/imaging/imaging.yml +15 -0
  152. data/spec/sinicum/imaging/imaging_file_spec.rb +125 -0
  153. data/spec/sinicum/imaging/imaging_middleware_spec.rb +79 -0
  154. data/spec/sinicum/imaging/max_size_converter_spec.rb +52 -0
  155. data/spec/sinicum/imaging/resize_crop_converter_spec.rb +18 -0
  156. data/spec/sinicum/imaging_spec.rb +13 -0
  157. data/spec/sinicum/jcr/api_client_spec.rb +69 -0
  158. data/spec/sinicum/jcr/cache/global_cache_spec.rb +29 -0
  159. data/spec/sinicum/jcr/dam/document_spec.rb +81 -0
  160. data/spec/sinicum/jcr/dam/image_spec.rb +46 -0
  161. data/spec/sinicum/jcr/jcr_configuration_spec.rb +57 -0
  162. data/spec/sinicum/jcr/mgnl4_compatibility_spec.rb +10 -0
  163. data/spec/sinicum/jcr/node_queries_spec.rb +113 -0
  164. data/spec/sinicum/jcr/node_spec.rb +261 -0
  165. data/spec/sinicum/jcr/query_sanitizer_spec.rb +26 -0
  166. data/spec/sinicum/jcr/type_translator_spec.rb +42 -0
  167. data/spec/sinicum/jcr/type_translators/component_translator_spec.rb +71 -0
  168. data/spec/sinicum/jcr/type_translators/data_translator_spec.rb +38 -0
  169. data/spec/sinicum/jcr/type_translators/default_translator_spec.rb +19 -0
  170. data/spec/sinicum/navigation/default_navigation_element_spec.rb +45 -0
  171. data/spec/sinicum/navigation/navigation_handler_spec.rb +71 -0
  172. data/spec/sinicum/templating/dialog_resolver_spec.rb +13 -0
  173. data/spec/sinicum/util_spec.rb +34 -0
  174. data/spec/spec_helper.rb +42 -0
  175. data/spec/support/default_node_reader.rb +40 -0
  176. metadata +434 -0
@@ -0,0 +1,81 @@
1
+ require 'digest/md5'
2
+ require 'open3'
3
+
4
+ module Sinicum
5
+ module Imaging
6
+ # Collection of helper methods common to Converters
7
+ module Converter
8
+ CONVERTER_VERSION = "1" # change to change Hash signature
9
+ PNG_OPTIMIZER_SUFFIX = "-fs8.png"
10
+
11
+ attr_writer :document
12
+
13
+ def initialize(configuration)
14
+ @x = configuration['x'] || ''
15
+ @y = configuration['y'] || ''
16
+ @render_type = configuration['render_type']
17
+ @hires_factor = configuration['hires_factor'] || 1.0
18
+ @configuration = configuration
19
+ end
20
+
21
+ # Computes a standard hash for a converted image, consisting of `x`, `y`, `render_type`
22
+ # and `format`.
23
+ #
24
+ # @return [String] A hash based on the current converter's configuration
25
+ def config_hash
26
+ digest = Digest::MD5.hexdigest(
27
+ "#{@x}-#{@y}-#{@hires_factor}-#{@render_type}-#{@format}-#{CONVERTER_VERSION}")
28
+ digest
29
+ end
30
+
31
+ # Returns the interlace command line option if an image is large enough
32
+ # (> 80px x 80px)
33
+ #
34
+ # @param [String, Fixnum] x the x size of an image
35
+ # @param [String, Fixnum] y the y size of an image
36
+ # @return [String] the command line option to interlace an image or an empty String
37
+ def interlace_option(x, y)
38
+ x.to_i * y.to_i > 80 * 80 ? "-interlace plane" : ""
39
+ end
40
+
41
+ def ratio(x, y)
42
+ x.to_f / y.to_f
43
+ end
44
+
45
+ private
46
+
47
+ def device_pixel_size(pixel)
48
+ px = pixel.to_f * @hires_factor.to_f
49
+ if px == 0
50
+ ''
51
+ else
52
+ px.round
53
+ end
54
+ end
55
+
56
+ def quality_option
57
+ "-quality 50" if @hires_factor && @hires_factor > 1.5
58
+ end
59
+
60
+ def optimize_png_outfile(outfile_path)
61
+ return unless format == "png"
62
+ cmd = "pngquant -- \"#{outfile_path}\""
63
+ exec_command(cmd)
64
+ cmd = "mv \"#{outfile_path}#{PNG_OPTIMIZER_SUFFIX}\" \"#{outfile_path}\""
65
+ exec_command(cmd)
66
+ rescue
67
+ # Fail silently
68
+ end
69
+
70
+ def exec_command(command)
71
+ status = nil
72
+ Open3.popen2(command) do |stdin, stdout, wait_thr|
73
+ status = wait_thr.value.exitstatus
74
+ end
75
+ if status != 0
76
+ fail "Command '#{command}' failed with exit status #{status}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,20 @@
1
+ module Sinicum
2
+ module Imaging
3
+ # Internal: Simple converter that simply serves a copy of the original file.
4
+ class DefaultConverter
5
+ include Converter
6
+ include Sinicum::Logger
7
+
8
+ def initialize(configuration)
9
+ end
10
+
11
+ def convert(infile_path, outfile_path)
12
+ `cp #{infile_path} #{outfile_path}`
13
+ end
14
+
15
+ def format
16
+ ".#{@document[:document][:extension]}" if @document && @document[:document]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ module Sinicum
2
+ module Imaging
3
+ # Public: Calculates the size of an image based on the converter used to
4
+ # render the image.
5
+ class ImageSizeConverter
6
+ DEFAULT_WORKSPACE = "dam"
7
+
8
+ def initialize(image_or_jcr_path, converter_name, options = {})
9
+ if image_or_jcr_path.is_a?(String)
10
+ workspace = options[:workspace].presence || DEFAULT_WORKSPACE
11
+ @image = Sinicum::Jcr::Node.find_by_path(workspace, image_or_jcr_path)
12
+ elsif image_or_jcr_path.respond_to?(:width) && image_or_jcr_path.respond_to?(:height)
13
+ @image = image_or_jcr_path
14
+ end
15
+ @converter_name = converter_name
16
+ end
17
+
18
+ def width
19
+ unless defined?(@width)
20
+ if converter.respond_to?(:converted_size)
21
+ @width = converter.converted_size[0]
22
+ else
23
+ @width = @image.width
24
+ end
25
+ end
26
+ @width
27
+ end
28
+
29
+ def height
30
+ unless defined?(@height)
31
+ if converter.respond_to?(:converted_size)
32
+ @height = converter.converted_size[1]
33
+ else
34
+ @height = @image.height
35
+ end
36
+ end
37
+ @height
38
+ end
39
+
40
+ private
41
+
42
+ def converter
43
+ unless defined?(@converter)
44
+ conf = Config.read_configuration
45
+ @converter = conf.converter(@converter_name)
46
+ @converter.document = @image if @converter
47
+ end
48
+ @converter
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,171 @@
1
+ require 'tempfile'
2
+ require 'fileutils'
3
+
4
+ module Sinicum
5
+ module Imaging
6
+ # Internal: Class that handles more or less all of the imaging
7
+ # functionality.
8
+ class Imaging
9
+ RENDER_MUTEX = Mutex.new
10
+ include Sinicum::Logger
11
+
12
+ attr_reader :fingerprint
13
+
14
+ # Render the image from path `original_path` with the renderer `renderer`
15
+ #
16
+ # @param [String] original_path The original path of the image.
17
+ # @param [String] renderer The name of the renderer
18
+ # @return [RenderResult] The result of the conversion
19
+ def self.rendered_resource(original_path, extension, renderer, fingerprint, workspace = nil)
20
+ imaging = Imaging.new(original_path, extension, renderer, fingerprint, workspace)
21
+ result = imaging.fetch_image
22
+ result
23
+ end
24
+
25
+ def initialize(original_path, extension, renderer, fingerprint, workspace = nil)
26
+ @original_path = original_path
27
+ @extension = extension
28
+ @renderer = renderer
29
+ @fingerprint = fingerprint
30
+ @workspace = workspace
31
+ end
32
+
33
+ def fetch_image
34
+ result = nil
35
+ @image, @doc = find_image_objects_by_path(@original_path)
36
+ if @image && @doc
37
+ if convert_file?
38
+ result = perform_conversion
39
+ else
40
+ format = converter.format
41
+ mime_type =
42
+ case format
43
+ when "gif" then "image/gif"
44
+ when "png" then "image/png"
45
+ when "ogv" then "video/ogg"
46
+ when "mp4" then "video/mp4"
47
+ when "m4a" then "audio/mp4"
48
+ when "ogg" then "audio/ogg"
49
+ when "webm" then "audio/webm"
50
+ else "image/jpeg"
51
+ end
52
+ result = RenderResult.new(
53
+ file_rendered, mime_type,
54
+ "#{@doc[:fileName]}.#{@doc[:extension]}", fingerprint)
55
+ end
56
+ end
57
+ result
58
+ end
59
+
60
+ # The temporary file as it comes out of the repository
61
+ def file_out
62
+ @_file_out ||= File.join(config_data.tmp_dir, @renderer + "-" + "out" + "-" + random)
63
+ end
64
+
65
+ # The temporary file the converter writes to
66
+ def file_converted
67
+ @_file_converted ||= File.join(config_data.tmp_dir, @renderer + "-" + "converted" +
68
+ "-" + random + "." + converter.format)
69
+ end
70
+
71
+ # The "final" file to be sent to the client
72
+ def file_rendered
73
+ @_file_rendered ||= File.join(config_data.file_dir, "/" + @renderer + "-" +
74
+ converter.config_hash + "-" + @image.uuid + "." +
75
+ converter.format)
76
+ end
77
+
78
+ # Finds the image objects by path
79
+ #
80
+ # @param [String] original_path The original path
81
+ # @return [Array] An `Array` in the form `[Image, Document]`
82
+ def find_image_objects_by_path(original_path)
83
+ result = [nil, nil]
84
+ if @workspace == :dam
85
+ image_node_path = original_path.gsub(/^\/dam/, "")
86
+ image = Sinicum::Jcr::Node.find_by_path("dam", image_node_path)
87
+ elsif @workspace == :dms
88
+ image_node_path = original_path.gsub(/^\/dms/, "")
89
+ image = Sinicum::Jcr::Node.find_by_path("dms", image_node_path)
90
+ end
91
+ if image
92
+ doc = image.properties
93
+ result = [image, doc]
94
+ end
95
+ result
96
+ end
97
+
98
+ private
99
+
100
+ def perform_conversion
101
+ RENDER_MUTEX.synchronize {
102
+ out_file = File.open(file_out, "wb")
103
+ out_file.close
104
+ in_file = File.open(file_converted, "wb")
105
+ begin
106
+ write_doc_to_tempfile(in_file)
107
+ in_file.close
108
+ convert(in_file.path, out_file.path)
109
+ FileUtils.mv(out_file.path, file_rendered)
110
+ FileUtils.chmod(0644, file_rendered)
111
+ RenderResult.new(
112
+ file_rendered, @doc["jcr:mimeType"],
113
+ "#{@doc[:fileName]}.#{@doc[:extension]}", fingerprint)
114
+ rescue => e
115
+ FileUtils.rm(out_file.path) if File.exist?(out_file.path)
116
+ raise e
117
+ ensure
118
+ FileUtils.rm(in_file.path) if File.exist?(in_file.path)
119
+ end
120
+ }
121
+ end
122
+
123
+ def convert(infile_path, outfile_path)
124
+ converter.convert(infile_path, outfile_path)
125
+ end
126
+
127
+ def write_doc_to_tempfile(tempfile)
128
+ begin
129
+ Sinicum::Jcr::Node.stream_attribute(@doc.jcr_workspace, @doc.path, "jcr:data", tempfile)
130
+ rescue => e
131
+ logger.error("Cannot write to tempfile: " + e.to_s)
132
+ end
133
+ end
134
+
135
+ def convert_file?
136
+ last_modified = @doc["jcr:lastModified"]
137
+ # File.size == 0 is related to a (temporary?) bug on one server
138
+ # should be possible to remove
139
+ result = !File.exist?(file_rendered) || File.mtime(file_rendered) <
140
+ last_modified || File.size(file_rendered) == 0
141
+ result
142
+ end
143
+
144
+ def random
145
+ @random ||= "#{Process.pid}-#{rand(1_000_000_000)}"
146
+ end
147
+
148
+ def config_data
149
+ Config.read_configuration
150
+ end
151
+
152
+ def converter
153
+ conv = config_data.converter(@renderer)
154
+ conv.document = @image if conv
155
+ conv
156
+ end
157
+ end
158
+
159
+ # Internal: Simple wrapper around imaging results.
160
+ class RenderResult
161
+ attr_accessor :path, :mime_type, :filename, :fingerprint
162
+
163
+ def initialize(path, mime_type, filename, fingerprint = nil)
164
+ @path = path
165
+ @mime_type = mime_type
166
+ @filename = filename
167
+ @fingerprint = fingerprint
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+ module Sinicum
3
+ module Imaging
4
+ # Representation of a DAM file as seen by the imaging middleware.
5
+ class ImagingFile
6
+ ORIGINAL_DAM_PATH_START = ::Sinicum::Imaging.dam_path_prefix + "/"
7
+ ORIGINAL_DAM_PATH_REPLACEMENT = ::Sinicum::Imaging.path_prefix + "/" +
8
+ ::Sinicum::Imaging.default_converter_name + "/"
9
+ ORIGINAL_DMS_PATH_START = ::Sinicum::Imaging.dms_path_prefix + "/"
10
+ ORIGINAL_DMS_PATH_REPLACEMENT = ::Sinicum::Imaging.path_prefix_mgnl4 + "/" +
11
+ ::Sinicum::Imaging.default_converter_name + "/"
12
+ DEFAULT_CACHE_TIME = 24 * 60 * 60
13
+ FINGERPRINT_CACHE_TIME = 7 * 24 * 60 * 60
14
+
15
+ attr_reader :normalized_request_path, :extension, :fingerprint, :workspace
16
+
17
+ # Public: Create a new instance
18
+ #
19
+ # path_info - The request's path_info
20
+ def initialize(path_info)
21
+ @path_info = path_info
22
+ set_up
23
+ end
24
+
25
+ def result?
26
+ !!imaging_result
27
+ end
28
+
29
+ def path
30
+ imaging_result.path
31
+ end
32
+
33
+ def filename
34
+ imaging_result.filename
35
+ end
36
+
37
+ def cache_time
38
+ if fingerprint
39
+ FINGERPRINT_CACHE_TIME
40
+ else
41
+ DEFAULT_CACHE_TIME
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def imaging_result
48
+ @imaging_result ||= create_imaging_result
49
+ end
50
+
51
+ def create_imaging_result
52
+ result = ::Sinicum::Imaging::Imaging.rendered_resource(
53
+ @file_asset_path, extension, @renderer, fingerprint, @workspace)
54
+ result
55
+ end
56
+
57
+ # Private: "Normalizes" the request path. In particular, a request
58
+ # to "/dam/something" gets converted to
59
+ # "/damfiles/default/something".
60
+ #
61
+ # Then it extracts the fingerprint and extension, if any of them
62
+ # exist.
63
+ def set_up
64
+ if @path_info.index(ORIGINAL_DAM_PATH_START) == 0
65
+ path = @path_info.sub(ORIGINAL_DAM_PATH_START, ORIGINAL_DAM_PATH_REPLACEMENT)
66
+ path = cutoff_document_path_repetition(path)
67
+ elsif @path_info.index(ORIGINAL_DMS_PATH_START) == 0
68
+ path = @path_info.sub(ORIGINAL_DMS_PATH_START, ORIGINAL_DMS_PATH_REPLACEMENT)
69
+ path = cutoff_document_path_repetition(path)
70
+ else
71
+ path = @path_info.dup
72
+ end
73
+ if path =~ /^\/dam/
74
+ @workspace = :dam
75
+ elsif path =~ /^\/dms/
76
+ @workspace = :dms
77
+ end
78
+ @normalized_request_path, @extension, @fingerprint = extract_fingerprint(path)
79
+ renderer_image = normalized_request_path[
80
+ ::Sinicum::Imaging.path_prefix.size + 1, normalized_request_path.size]
81
+ @renderer = renderer_image[0, renderer_image.index("/")]
82
+ @file_asset_path = renderer_image[@renderer.size, renderer_image.size]
83
+ nil
84
+ end
85
+
86
+ def extract_fingerprint(path)
87
+ if match = path.match(/(.+?)-(\h{32})(\.\w+)?$/)
88
+ extension = nil
89
+ extension = match[3][1..match[3].length] if match[3]
90
+ [match[1], extension, match[2]]
91
+ else
92
+ extension = nil
93
+ if match = path.match(/(.+)\.(\w+)$/)
94
+ extension = match[2]
95
+ path = match[1]
96
+ end
97
+ [path, extension, nil]
98
+ end
99
+ end
100
+
101
+ def cutoff_document_path_repetition(path)
102
+ parts = path.split("/")
103
+ if parts.size > 3
104
+ if match = parts.last.match(/(.+)(\.\w+)$/)
105
+ last_part = match[1]
106
+ if last_part == parts[parts.size - 2]
107
+ path = path[0..(path.rindex("/") - 1)] + match[2]
108
+ end
109
+ end
110
+ end
111
+ path
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,56 @@
1
+ module Sinicum
2
+ module Imaging
3
+ # Public: Rack middleware to handle a request to the imaging fuctionality.
4
+ class ImagingMiddleware < Rack::File
5
+ SUFFIX_REGEX = /\.\w+$/
6
+ DEFAULT_CACHE_TIME = 24 * 60 * 60
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ if on_imaging_path?(env['PATH_INFO'])
14
+ dup._call(env)
15
+ else
16
+ @app.call(env)
17
+ end
18
+ end
19
+
20
+ def _call(env)
21
+ unless ALLOWED_VERBS.include? env["REQUEST_METHOD"]
22
+ return fail(405, "Method Not Allowed")
23
+ end
24
+ request = Rack::Request.new(env)
25
+ imaging_file = ImagingFile.new(request.path_info)
26
+ if imaging_file.result?
27
+ @path = imaging_file.path
28
+ available = begin
29
+ F.file?(@path) && F.readable?(@path)
30
+ rescue SystemCallError
31
+ false
32
+ end
33
+ end
34
+ if available
35
+ @headers = {}
36
+ @headers["Content-Disposition"] = "inline; filename=\"#{imaging_file.filename}\""
37
+ if Rails.configuration.action_controller.perform_caching
38
+ @headers["Cache-Control"] = "max-age=#{imaging_file.cache_time}, public"
39
+ end
40
+ serving(env)
41
+ else
42
+ fail(404, "File not found: #{request.path_info}")
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def on_imaging_path?(path)
49
+ path && (path.index(::Sinicum::Imaging.path_prefix) == 0 ||
50
+ path.index(ImagingFile::ORIGINAL_DAM_PATH_START) == 0 ||
51
+ path.index(::Sinicum::Imaging.path_prefix_mgnl4) == 0 ||
52
+ path.index(ImagingFile::ORIGINAL_DMS_PATH_START) == 0)
53
+ end
54
+ end
55
+ end
56
+ end