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,39 @@
1
+ module Sinicum
2
+ module Imaging
3
+ # Internal: Resizes an image to a predefined maximum size.
4
+ class MaxSizeConverter
5
+ include Converter
6
+ include Sinicum::Logger
7
+
8
+ attr_reader :format
9
+
10
+ def initialize(configuration)
11
+ super(configuration)
12
+ @format = configuration['format'] || 'jpeg'
13
+ end
14
+
15
+ def convert(infile_path, outfile_path)
16
+ x = device_pixel_size(@x)
17
+ y = device_pixel_size(@y)
18
+ special = '-background transparent' if @format == 'png'
19
+ command = "convert #{infile_path} #{interlace_option(x, y)} #{special} " \
20
+ "#{quality_option} " +
21
+ "-resize #{x}x#{y} #{outfile_path}"
22
+ `#{command}`
23
+ optimize_png_outfile(outfile_path)
24
+ end
25
+
26
+ def converted_size
27
+ original_ratio = ratio(@document.width, @document.height)
28
+ x = @x.to_f
29
+ y = @y.to_f
30
+ if @y != '' && x / original_ratio > y
31
+ x = (y * original_ratio).round
32
+ else
33
+ y = (x / original_ratio).round
34
+ end
35
+ [x, y]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ module Sinicum
2
+ module Imaging
3
+ # Internal: Resizes an image to an exact given size and crops anything
4
+ # else.
5
+ class ResizeCropConverter
6
+ include Converter
7
+ include Sinicum::Logger
8
+
9
+ attr_reader :format
10
+
11
+ def initialize(configuration)
12
+ if !configuration['format'] || !configuration['x'] || !configuration['y']
13
+ fail ArgumentError.new("Converter requires the arguments: format, x, y")
14
+ end
15
+ super(configuration)
16
+ @format = configuration['format'] || 'jpeg'
17
+ end
18
+
19
+ def convert(infile_path, outfile_path)
20
+ x = device_pixel_size(@x)
21
+ y = device_pixel_size(@y)
22
+ special = '-background transparent' if format == 'png'
23
+ cmd = "convert #{infile_path} #{interlace_option(x, y)} #{special} " \
24
+ "#{quality_option} " +
25
+ "-resize #{x}x#{y}^ -gravity center -extent #{x}x#{y} #{outfile_path}"
26
+ `#{cmd}`
27
+ optimize_png_outfile(outfile_path)
28
+ end
29
+
30
+ def converted_size
31
+ [@x, @y]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ module Sinicum
2
+ module Jcr
3
+ module ApiClient
4
+ include ::Sinicum::Logger
5
+ def api_get(path, *args, &block)
6
+ full_path = api_full_path(path)
7
+ log_get_path(full_path, args)
8
+
9
+ instrumentation_query = args[0] && args[0]["query"] ? args[0]["query"] : path
10
+
11
+ ActiveSupport::Notifications.instrument(
12
+ "jcr_query.sinicum",
13
+ query: instrumentation_query,
14
+ context: "Sinicum API GET:") do
15
+ start = Time.now
16
+ result = ApiQueries.http_client.get(full_path, *args, &block)
17
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
18
+ logger.debug(" Completed request in #{elapsed_time}ms")
19
+ result
20
+ end
21
+ end
22
+
23
+ def api_post(path, *args, &block)
24
+ full_path = api_full_path(path)
25
+ log = " Sinicum API POST: " + full_path
26
+ [:body, :query].each do |key|
27
+ if args[0] && args[0].respond_to?(:[]) && args[0][key]
28
+ log << "\n Parameters (#{key.to_s.capitalize}): " + args[0][key].inspect
29
+ end
30
+ end
31
+ logger.debug(log)
32
+ ApiQueries.http_client.post(full_path, *args, &block)
33
+ end
34
+
35
+ private
36
+
37
+ def log_get_path(full_path, args)
38
+ log = " Sinicum API GET: " + full_path
39
+ if args[0] && args[0].respond_to?(:[])
40
+ log << "\n Parameters (Query): " + args[0].inspect
41
+ end
42
+ logger.debug(log)
43
+ end
44
+
45
+ def api_full_path(path)
46
+ ApiQueries.jcr_configuration.base_url + path
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,37 @@
1
+ require 'httpclient'
2
+
3
+ module Sinicum
4
+ module Jcr
5
+ # Private: Encapsulates the functionality to run queries on the server.
6
+ class ApiQueries
7
+ @@http_client_mutex = Mutex.new
8
+ class << self
9
+ attr_reader :jcr_configuration
10
+
11
+ def configure_jcr=(config_hash)
12
+ @http_client = nil
13
+ if config_hash
14
+ @jcr_configuration = JcrConfiguration.new(config_hash.dup.with_indifferent_access)
15
+ if @jcr_configuration.username.present? || @jcr_configuration.password.present?
16
+ http_client.set_auth(nil, @jcr_configuration.username, @jcr_configuration.password)
17
+ http_client.www_auth.basic_auth.challenge(@jcr_configuration.base_proto_host_port)
18
+ end
19
+ if @jcr_configuration.protocol == "https"
20
+ http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
21
+ end
22
+ end
23
+ end
24
+
25
+ def http_client
26
+ # Thread Safety?
27
+ return @http_client if @http_client
28
+ @@http_client_mutex.synchronize do
29
+ return @http_client if @http_client
30
+ @http_client ||= HTTPClient.new
31
+ end
32
+ @http_client
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ module Sinicum
2
+ module Jcr
3
+ module Cache
4
+ # Public: Fetches the global cache key from the JCR server.
5
+ class GlobalCache
6
+ API_PATH = "/_cache/global"
7
+ JSON_CACHE_KEY = "cacheKey"
8
+ include ::Sinicum::Jcr::ApiClient
9
+
10
+ def current_key
11
+ result = nil
12
+ response = api_get(API_PATH)
13
+ if response.ok?
14
+ begin
15
+ json = MultiJson.load(response.body)
16
+ result = json[JSON_CACHE_KEY]
17
+ rescue => e
18
+ Rails.logger.error("Cannot load global cache key: " + e.message)
19
+ end
20
+ end
21
+ result
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,57 @@
1
+ module Sinicum
2
+ module Jcr
3
+ module Dam
4
+ # Public: Wrapper around documents stored in Magnolia's DAM workspace.
5
+ class Document < ::Sinicum::Jcr::Node
6
+ FINGERPRINT_VERSION = "2"
7
+
8
+ %w(name subject description type).each do |field|
9
+ define_method(field) { self[field.to_sym] }
10
+ end
11
+
12
+ # Returns a node, which contains the properties of the document
13
+ def properties
14
+ self[:'jcr:content'] if self[:'jcr:content']
15
+ end
16
+
17
+ def path(options = {})
18
+ converter_name = options[:converter].presence ||
19
+ ::Sinicum::Imaging.default_converter_name
20
+ path = "#{::Sinicum::Imaging.path_prefix}/#{converter_name}#{super}-#{fingerprint}"
21
+ if properties && properties[:extension].present?
22
+ path << ".#{properties[:extension]}"
23
+ end
24
+ path
25
+ end
26
+
27
+ def file_size
28
+ properties[:size].to_i if properties
29
+ end
30
+
31
+ def file_name
32
+ [properties[:fileName], properties[:extension]].join(".") if properties
33
+ end
34
+
35
+ def mime_type
36
+ properties[:'jcr:mimeType'] if properties
37
+ end
38
+
39
+ def date
40
+ self[:date1] || updated_at
41
+ end
42
+
43
+ private
44
+
45
+ def fingerprint
46
+ unless @fingerprint
47
+ attributes = [
48
+ FINGERPRINT_VERSION, jcr_path, id, properties[:'jcr:lastModified'],
49
+ properties[:'jcr:lastModifiedBy'], properties[:size]]
50
+ @fingerprint = Digest::MD5.hexdigest(attributes.join("-"))
51
+ end
52
+ @fingerprint
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,40 @@
1
+ module Sinicum
2
+ module Jcr
3
+ module Dam
4
+ # Public: Wrapper around image files stored in Magnolia's DAM workspace.
5
+ class Image < Document
6
+ def width(converter_name = nil)
7
+ fetch_value(:width, converter_name)
8
+ end
9
+
10
+ def height(converter_name = nil)
11
+ fetch_value(:height, converter_name)
12
+ end
13
+
14
+ def alt
15
+ self[:subject] || ""
16
+ end
17
+
18
+ private
19
+
20
+ def image_size_converter(converter_name)
21
+ @conv_cache ||= {}
22
+ unless @conv_cache[converter_name]
23
+ @conv_cache[converter_name] =
24
+ Sinicum::Imaging::ImageSizeConverter.new(self, converter_name, workspace: "dam")
25
+ end
26
+ @conv_cache[converter_name]
27
+ end
28
+
29
+ def fetch_value(dimension, converter_name)
30
+ value = nil
31
+ if properties && properties[dimension]
32
+ value = properties[dimension].to_i
33
+ value = image_size_converter(converter_name).send(dimension) if converter_name
34
+ end
35
+ value
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,67 @@
1
+ module Sinicum
2
+ module Jcr
3
+ # Public: Handles the configuration for accessing the JCR server.
4
+ class JcrConfiguration
5
+ attr_accessor :host, :protocol, :path_prefix, :username, :password
6
+ DEFAULT_HOST = "localhost"
7
+ DEFAULT_PORT = "8080"
8
+ DEFAULT_PROTOCOL = "http"
9
+ DEFAULT_PREFIX = "/sinicum-rest"
10
+
11
+ def initialize(params = {})
12
+ [:host, :port, :protocol, :path_prefix, :username, :password].each do |param|
13
+ send("#{param}=", params[param]) if params.key?(param)
14
+ end
15
+ end
16
+
17
+ def path_prefix=(path_prefix)
18
+ path_prefix = "/" + path_prefix if path_prefix.size > 0 && path_prefix[0] != "/"
19
+ @path_prefix = path_prefix
20
+ end
21
+
22
+ def port=(port)
23
+ @port = port.to_s
24
+ end
25
+
26
+ def port
27
+ port = @port
28
+ unless port
29
+ if protocol == "http"
30
+ port = "80"
31
+ elsif protocol == "https"
32
+ port = "443"
33
+ else
34
+ port = ""
35
+ end
36
+ end
37
+ port
38
+ end
39
+
40
+ def protocol
41
+ @protocol || DEFAULT_PROTOCOL
42
+ end
43
+
44
+ def base_url
45
+ unless defined?(@base_url)
46
+ base_url = base_proto_host_port.dup
47
+ base_url << (path_prefix || DEFAULT_PREFIX)
48
+ @base_url = base_url
49
+ end
50
+ @base_url
51
+ end
52
+
53
+ def base_proto_host_port
54
+ unless defined?(@base_proto_host_port)
55
+ base_proto_host_port = protocol.dup
56
+ base_proto_host_port << "://"
57
+ base_proto_host_port << (host || DEFAULT_HOST)
58
+ unless (port.to_i == 80 && protocol == "http") || port.to_i == 443 && protocol == "https"
59
+ base_proto_host_port << ":" << port
60
+ end
61
+ @base_proto_host_port = base_proto_host_port
62
+ end
63
+ @base_proto_host_port
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,11 @@
1
+ module Sinicum
2
+ module Jcr
3
+ module Mgnl4Compatibility
4
+ def mgnl_authorid
5
+ end
6
+
7
+ def mgnl_activatorid
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,268 @@
1
+ module Sinicum
2
+ module Jcr
3
+ # Public: Base class to handle objects from the JCR store.
4
+ class Node
5
+ extend ActiveSupport::Inflector
6
+ include ActiveModel::Conversion
7
+ extend ActiveModel::Naming
8
+ extend ActiveModel::Translation
9
+ include ActiveModel::Validations
10
+ include ActiveModel::AttributeMethods
11
+
12
+ include NodeQueries
13
+ include Mgnl4Compatibility
14
+
15
+ ISO_8601_REGEX = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[+-]\d{2}:\d{2}/
16
+ ISO_8601_DATE_REGEX = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z/
17
+ IMPLICIT_ARRAY_REGEX = /^\d+$/
18
+ BOOL_TRUE_STRING_VALUE = "true"
19
+ BOOL_FALSE_STRING_VALUE = "false"
20
+ METADATA_NODE_NAME = "MetaData"
21
+ META_KEY = "meta"
22
+ PROPERTIES_KEY = "properties"
23
+ NODES_KEY = "nodes"
24
+ ARRAY_CHILD_NODE_PATTERN = /^\d+$/
25
+
26
+ SETABLE_JCR_PROPERTIES = :jcr_path, :jcr_name, :jcr_primary_type, :jcr_primary_type,
27
+ :jcr_super_types, :jcr_workspace, :jcr_mixin_node_types
28
+ PROHIBITED_JCR_PROPERTIES = :uuid, :jcr_depth, :created_at, :updated_at, :lastaction_at
29
+ SETABLE_MGNL_PROPERTIES = [:mgnl_template, :mgnl_created_by]
30
+ PROHIBITED_MGNL_PROPERTIES = :mgnl_authorid, :mgnl_activatorid
31
+
32
+ attr_reader *SETABLE_JCR_PROPERTIES, *PROHIBITED_JCR_PROPERTIES,
33
+ *SETABLE_MGNL_PROPERTIES, *PROHIBITED_MGNL_PROPERTIES
34
+
35
+ def initialize(params = {})
36
+ if params.key?(:json_response)
37
+ @__json_response = params[:json_response]
38
+ initialize_properties_from_json
39
+ else
40
+ initialize_from_hash(params)
41
+ end
42
+ end
43
+
44
+ def id
45
+ uuid
46
+ end
47
+
48
+ def path(options = {})
49
+ jcr_path
50
+ end
51
+
52
+ def to_model
53
+ self
54
+ end
55
+
56
+ def persisted?
57
+ !!@persisted
58
+ end
59
+
60
+ def [](property_name)
61
+ result = nil
62
+ property_key = property_name.to_s
63
+ if jcr_properties && jcr_properties.key?(property_key)
64
+ result = transform_jcr_types(jcr_properties[property_key])
65
+ elsif node_cache.key?(property_key) || (jcr_nodes && jcr_nodes.key?(property_key))
66
+ result = return_child_node(property_key)
67
+ end
68
+ result
69
+ end
70
+
71
+ def children
72
+ children = []
73
+ jcr_nodes.each do |child|
74
+ next if child && child[0] == "MetaData"
75
+ children << NodeInitializer.initialize_node_from_json(child[1])
76
+ end
77
+ children
78
+ end
79
+
80
+ def parent
81
+ fetch_from_parent_cache do
82
+ current_node_path = path.split("/")
83
+ current_node_path.slice!(-1) if current_node_path.size > 1
84
+ Sinicum::Jcr::Node.find_by_path(jcr_workspace, current_node_path.join("/"))
85
+ end
86
+ end
87
+
88
+ def to_s
89
+ "#{self.class.name}, uuid: '#{uuid}', path: '#{jcr_path}'"
90
+ end
91
+
92
+ def inspect
93
+ properties = []
94
+ jcr_properties.each_key { |key| properties << key } if jcr_properties
95
+ nodes = []
96
+ jcr_nodes.each_key { |key| nodes << key } if jcr_nodes
97
+ to_s + ", properties: #{properties}, nodes: #{nodes}\n"
98
+ end
99
+
100
+ protected
101
+
102
+ def jcr_properties
103
+ @__json_response[PROPERTIES_KEY] if @__json_response
104
+ end
105
+
106
+ def jcr_nodes
107
+ @__json_response[NODES_KEY] if @__json_response
108
+ end
109
+
110
+ private
111
+
112
+ def initialize_properties_from_json
113
+ meta_info = @__json_response[META_KEY]
114
+ @uuid = meta_info["jcr:uuid"].freeze
115
+ @jcr_path = meta_info["path"].freeze
116
+ @jcr_name = meta_info["name"].freeze
117
+ @jcr_primary_type = meta_info["jcr:primaryType"].freeze
118
+ @jcr_super_types = meta_info["superTypes"].freeze
119
+ @jcr_mixin_node_types = meta_info["mixinNodeTypes"].freeze
120
+ @jcr_workspace = meta_info["workspace"].freeze
121
+ @jcr_depth = meta_info["depth"].freeze
122
+ @created_at = jcr_time_string_to_datetime(meta_info["mgnl:created"]).freeze
123
+ @updated_at = jcr_time_string_to_datetime(meta_info["mgnl:lastModified"]).freeze
124
+ @mgnl_template = meta_info["mgnl:template"].freeze
125
+ @mgnl_created_by = meta_info["mgnl:createdBy"].freeze
126
+ @persisted = true
127
+ initialize_from_mgnl4_meta_data_node(meta_info)
128
+ end
129
+
130
+ def initialize_from_mgnl4_meta_data_node(meta_info)
131
+ @created_at = jcr_time_string_to_datetime(meta_info["jcr:created"]).freeze
132
+ end
133
+
134
+ def initialize_from_hash(hash)
135
+ @__json_response = { PROPERTIES_KEY => {} }
136
+ hash.each do |key, value|
137
+ check_for_allowed_properties(key)
138
+ unless set_system_property(key, value)
139
+ @__json_response[PROPERTIES_KEY][key.to_s] = value
140
+ end
141
+ end
142
+ end
143
+
144
+ def check_for_allowed_properties(key)
145
+ key_sym = key.to_sym
146
+ if PROHIBITED_JCR_PROPERTIES.include?(key_sym) ||
147
+ PROHIBITED_MGNL_PROPERTIES.include?(key_sym)
148
+ fail Error.new("Property '#{key_sym}' cannot be set manually. It has to be generated " +
149
+ "when fetching a node from the JCR repository")
150
+ end
151
+ end
152
+
153
+ def set_system_property(key, value)
154
+ key_sym = key.to_sym
155
+ if SETABLE_JCR_PROPERTIES.include?(key_sym) || SETABLE_MGNL_PROPERTIES.include?(key_sym)
156
+ instance_variable_set(:"@#{key}", value)
157
+ return true
158
+ end
159
+ false
160
+ end
161
+
162
+ def return_child_node(node_key)
163
+ fetch_from_node_cache(node_key) do
164
+ value = nil
165
+ child_node = jcr_nodes[node_key]
166
+ if implicit_array?(node_key)
167
+ value = convert_implicit_array(node_key)
168
+ else
169
+ value = Node.new(json_response: child_node)
170
+ end
171
+ value
172
+ end
173
+ end
174
+
175
+ def transform_jcr_types(value)
176
+ result = jcr_time_string_to_datetime(value)
177
+ result = mgnl_boolean_string_to_boolean(result)
178
+ result
179
+ end
180
+
181
+ def implicit_array?(node_key)
182
+ has_array_pattern = false
183
+ child_node = jcr_nodes[node_key]
184
+ primary_type = nil
185
+ if child_node && child_node["meta"]
186
+ primary_type = child_node["meta"]["jcr:primaryType"]
187
+ end
188
+ if child_node && child_node[NODES_KEY] && child_node[NODES_KEY].size > 0 &&
189
+ primary_type != "mgnl:area"
190
+ child_nodes = child_node[NODES_KEY]
191
+ child_nodes.each_key do |key|
192
+ next if key == METADATA_NODE_NAME
193
+ if key =~ IMPLICIT_ARRAY_REGEX
194
+ has_array_pattern = true
195
+ else
196
+ has_array_pattern = false
197
+ break
198
+ end
199
+ end
200
+ end
201
+ has_array_pattern
202
+ end
203
+
204
+ def convert_implicit_array(node_key)
205
+ result = []
206
+ child_node = jcr_nodes.delete(node_key)
207
+ child_node[NODES_KEY].each_key do |key|
208
+ next if key == METADATA_NODE_NAME
209
+ child = child_node[NODES_KEY].delete(key)
210
+ result << Node.new(json_response: child)
211
+ end
212
+ result
213
+ end
214
+
215
+ def jcr_time_string_to_datetime(value)
216
+ result = nil
217
+ if value && value =~ ISO_8601_REGEX
218
+ result = DateTime.parse(value)
219
+ elsif value && value =~ ISO_8601_DATE_REGEX
220
+ result = Date.parse(value)
221
+ else
222
+ result = value
223
+ end
224
+ result
225
+ end
226
+
227
+ def fetch_from_node_cache(node_key, &block)
228
+ result = nil
229
+ if node_cache.key?(node_key)
230
+ result = node_cache[node_key]
231
+ else
232
+ result = yield
233
+ node_cache[node_key] = result
234
+ end
235
+ result
236
+ end
237
+
238
+ def node_cache
239
+ @__node_cache ||= {}
240
+ end
241
+
242
+ def fetch_from_parent_cache(&block)
243
+ result = nil
244
+ if parent_cache
245
+ result = parent_cache
246
+ else
247
+ result = yield
248
+ @__parent_cache = result
249
+ end
250
+ result
251
+ end
252
+
253
+ def parent_cache
254
+ @__parent_cache
255
+ end
256
+
257
+ def mgnl_boolean_string_to_boolean(value)
258
+ result = value
259
+ if value == BOOL_TRUE_STRING_VALUE
260
+ result = true
261
+ elsif value == BOOL_FALSE_STRING_VALUE
262
+ result = false
263
+ end
264
+ result
265
+ end
266
+ end
267
+ end
268
+ end