linked_rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +65 -0
  4. data/Rakefile +34 -0
  5. data/app/controllers/linked_rails/actions/items_controller.rb +9 -0
  6. data/app/controllers/linked_rails/bulk_controller.rb +195 -0
  7. data/app/controllers/linked_rails/current_user_controller.rb +13 -0
  8. data/app/controllers/linked_rails/enum_values_controller.rb +49 -0
  9. data/app/controllers/linked_rails/forms_controller.rb +13 -0
  10. data/app/controllers/linked_rails/manifests_controller.rb +21 -0
  11. data/app/controllers/linked_rails/menus/items_controller.rb +9 -0
  12. data/app/controllers/linked_rails/menus/lists_controller.rb +9 -0
  13. data/app/controllers/linked_rails/not_found_controller.rb +15 -0
  14. data/app/controllers/linked_rails/ontologies_controller.rb +7 -0
  15. data/app/models/linked_rails/actions/default_actions/create.rb +60 -0
  16. data/app/models/linked_rails/actions/default_actions/destroy.rb +45 -0
  17. data/app/models/linked_rails/actions/default_actions/update.rb +50 -0
  18. data/app/models/linked_rails/actions/default_actions.rb +17 -0
  19. data/app/models/linked_rails/actions/item.rb +234 -0
  20. data/app/models/linked_rails/actions/list.rb +113 -0
  21. data/app/models/linked_rails/collection/filter.rb +16 -0
  22. data/app/models/linked_rails/collection/filter_field.rb +30 -0
  23. data/app/models/linked_rails/collection/filter_option.rb +17 -0
  24. data/app/models/linked_rails/collection/filterable.rb +92 -0
  25. data/app/models/linked_rails/collection/infinite_view.rb +98 -0
  26. data/app/models/linked_rails/collection/iri.rb +74 -0
  27. data/app/models/linked_rails/collection/iri_mapping.rb +33 -0
  28. data/app/models/linked_rails/collection/paginated_view.rb +41 -0
  29. data/app/models/linked_rails/collection/sortable.rb +60 -0
  30. data/app/models/linked_rails/collection/sorting.rb +72 -0
  31. data/app/models/linked_rails/collection/view.rb +101 -0
  32. data/app/models/linked_rails/collection.rb +220 -0
  33. data/app/models/linked_rails/condition.rb +7 -0
  34. data/app/models/linked_rails/creative_work.rb +21 -0
  35. data/app/models/linked_rails/current_user.rb +28 -0
  36. data/app/models/linked_rails/entry_point.rb +53 -0
  37. data/app/models/linked_rails/enum_value.rb +33 -0
  38. data/app/models/linked_rails/form/field/association_input.rb +23 -0
  39. data/app/models/linked_rails/form/field/checkbox_group.rb +10 -0
  40. data/app/models/linked_rails/form/field/checkbox_input.rb +10 -0
  41. data/app/models/linked_rails/form/field/color_input.rb +17 -0
  42. data/app/models/linked_rails/form/field/date_input.rb +10 -0
  43. data/app/models/linked_rails/form/field/date_time_input.rb +10 -0
  44. data/app/models/linked_rails/form/field/email_input.rb +10 -0
  45. data/app/models/linked_rails/form/field/file_input.rb +10 -0
  46. data/app/models/linked_rails/form/field/location_input.rb +11 -0
  47. data/app/models/linked_rails/form/field/markdown_input.rb +10 -0
  48. data/app/models/linked_rails/form/field/number_input.rb +10 -0
  49. data/app/models/linked_rails/form/field/password_input.rb +10 -0
  50. data/app/models/linked_rails/form/field/postal_range_input.rb +10 -0
  51. data/app/models/linked_rails/form/field/radio_group.rb +10 -0
  52. data/app/models/linked_rails/form/field/resource_field.rb +23 -0
  53. data/app/models/linked_rails/form/field/select_input.rb +11 -0
  54. data/app/models/linked_rails/form/field/slider_input.rb +10 -0
  55. data/app/models/linked_rails/form/field/text_area_input.rb +10 -0
  56. data/app/models/linked_rails/form/field/text_input.rb +10 -0
  57. data/app/models/linked_rails/form/field/toggle_button_group.rb +10 -0
  58. data/app/models/linked_rails/form/field.rb +117 -0
  59. data/app/models/linked_rails/form/field_factory.rb +219 -0
  60. data/app/models/linked_rails/form/group.rb +39 -0
  61. data/app/models/linked_rails/form/page.rb +31 -0
  62. data/app/models/linked_rails/form.rb +156 -0
  63. data/app/models/linked_rails/manifest.rb +102 -0
  64. data/app/models/linked_rails/media_object.rb +31 -0
  65. data/app/models/linked_rails/menus/item.rb +92 -0
  66. data/app/models/linked_rails/menus/list.rb +138 -0
  67. data/app/models/linked_rails/ontology/base.rb +50 -0
  68. data/app/models/linked_rails/ontology/class.rb +43 -0
  69. data/app/models/linked_rails/ontology/property.rb +19 -0
  70. data/app/models/linked_rails/ontology.rb +34 -0
  71. data/app/models/linked_rails/property_query.rb +11 -0
  72. data/app/models/linked_rails/resource.rb +17 -0
  73. data/app/models/linked_rails/sequence.rb +64 -0
  74. data/app/models/linked_rails/shacl/node_shape.rb +21 -0
  75. data/app/models/linked_rails/shacl/property_shape.rb +53 -0
  76. data/app/models/linked_rails/shacl/shape.rb +33 -0
  77. data/app/models/linked_rails/web_page.rb +22 -0
  78. data/app/models/linked_rails/web_site.rb +17 -0
  79. data/app/models/linked_rails/widget.rb +55 -0
  80. data/app/policies/linked_rails/actions/item_policy.rb +11 -0
  81. data/app/policies/linked_rails/actions/list_policy.rb +11 -0
  82. data/app/policies/linked_rails/collection/view_policy.rb +13 -0
  83. data/app/policies/linked_rails/collection_policy.rb +41 -0
  84. data/app/policies/linked_rails/enum_value_policy.rb +32 -0
  85. data/app/policies/linked_rails/menus/item_policy.rb +11 -0
  86. data/app/policies/linked_rails/menus/list_policy.rb +11 -0
  87. data/app/policies/linked_rails/sequence_policy.rb +9 -0
  88. data/app/serializers/linked_rails/actions/item_serializer.rb +28 -0
  89. data/app/serializers/linked_rails/collection/filter_field_serializer.rb +12 -0
  90. data/app/serializers/linked_rails/collection/filter_option_serializer.rb +12 -0
  91. data/app/serializers/linked_rails/collection/filter_serializer.rb +13 -0
  92. data/app/serializers/linked_rails/collection/sorting_serializer.rb +13 -0
  93. data/app/serializers/linked_rails/collection/view_serializer.rb +22 -0
  94. data/app/serializers/linked_rails/collection_serializer.rb +44 -0
  95. data/app/serializers/linked_rails/condition_serializer.rb +9 -0
  96. data/app/serializers/linked_rails/creative_work_serializer.rb +10 -0
  97. data/app/serializers/linked_rails/current_user_serializer.rb +7 -0
  98. data/app/serializers/linked_rails/entry_point_serializer.rb +20 -0
  99. data/app/serializers/linked_rails/enum_value_serializer.rb +12 -0
  100. data/app/serializers/linked_rails/form/field/association_input_serializer.rb +13 -0
  101. data/app/serializers/linked_rails/form/field/resource_field_serializer.rb +11 -0
  102. data/app/serializers/linked_rails/form/field/select_input_serializer.rb +11 -0
  103. data/app/serializers/linked_rails/form/field_serializer.rb +39 -0
  104. data/app/serializers/linked_rails/form/group_serializer.rb +14 -0
  105. data/app/serializers/linked_rails/form/page_serializer.rb +13 -0
  106. data/app/serializers/linked_rails/form_serializer.rb +9 -0
  107. data/app/serializers/linked_rails/media_object_serializer.rb +17 -0
  108. data/app/serializers/linked_rails/menus/item_serializer.rb +35 -0
  109. data/app/serializers/linked_rails/menus/list_serializer.rb +13 -0
  110. data/app/serializers/linked_rails/ontology/class_serializer.rb +19 -0
  111. data/app/serializers/linked_rails/ontology/property_serializer.rb +16 -0
  112. data/app/serializers/linked_rails/ontology_serializer.rb +8 -0
  113. data/app/serializers/linked_rails/rdf_error_serializer.rb +8 -0
  114. data/app/serializers/linked_rails/sequence_serializer.rb +14 -0
  115. data/app/serializers/linked_rails/shacl/node_shape_serializer.rb +12 -0
  116. data/app/serializers/linked_rails/shacl/property_shape_serializer.rb +38 -0
  117. data/app/serializers/linked_rails/shacl/shape_serializer.rb +25 -0
  118. data/app/serializers/linked_rails/web_page_serializer.rb +10 -0
  119. data/app/serializers/linked_rails/web_site_serializer.rb +11 -0
  120. data/app/serializers/linked_rails/widget_serializer.rb +15 -0
  121. data/config/initializers/inflections.rb +5 -0
  122. data/lib/generators/linked_rails/install/install_generator.rb +65 -0
  123. data/lib/generators/linked_rails/install/templates/app_menu_list.rb +41 -0
  124. data/lib/generators/linked_rails/install/templates/application_action_list.rb +3 -0
  125. data/lib/generators/linked_rails/install/templates/application_form.rb +3 -0
  126. data/lib/generators/linked_rails/install/templates/application_menu_list.rb +3 -0
  127. data/lib/generators/linked_rails/install/templates/application_policy.rb +18 -0
  128. data/lib/generators/linked_rails/install/templates/application_serializer.rb +5 -0
  129. data/lib/generators/linked_rails/install/templates/initializer.rb +9 -0
  130. data/lib/generators/linked_rails/install/templates/locales.yml +12 -0
  131. data/lib/generators/linked_rails/install/templates/rdf_responder.rb +5 -0
  132. data/lib/generators/linked_rails/install/templates/rdf_serializers_initializer.rb +5 -0
  133. data/lib/generators/linked_rails/install/templates/vocab.rb +5 -0
  134. data/lib/generators/linked_rails/install/templates/vocab.yml +26 -0
  135. data/lib/generators/linked_rails/model/model_generator.rb +58 -0
  136. data/lib/generators/linked_rails/model/templates/action_list.rb.tt +6 -0
  137. data/lib/generators/linked_rails/model/templates/controller.rb.tt +7 -0
  138. data/lib/generators/linked_rails/model/templates/create_table_migration.rb.tt +24 -0
  139. data/lib/generators/linked_rails/model/templates/form.rb.tt +6 -0
  140. data/lib/generators/linked_rails/model/templates/menu_list.rb.tt +6 -0
  141. data/lib/generators/linked_rails/model/templates/model.rb.tt +15 -0
  142. data/lib/generators/linked_rails/model/templates/module.rb.tt +7 -0
  143. data/lib/generators/linked_rails/model/templates/policy.rb.tt +6 -0
  144. data/lib/generators/linked_rails/model/templates/serializer.rb.tt +9 -0
  145. data/lib/linked_rails/active_response/controller/collections.rb +43 -0
  146. data/lib/linked_rails/active_response/controller/crud_defaults.rb +92 -0
  147. data/lib/linked_rails/active_response/controller/params.rb +51 -0
  148. data/lib/linked_rails/active_response/controller.rb +37 -0
  149. data/lib/linked_rails/active_response/responders/rdf.rb +158 -0
  150. data/lib/linked_rails/cache.rb +35 -0
  151. data/lib/linked_rails/callable_variable.rb +25 -0
  152. data/lib/linked_rails/constraints/whitelist.rb +36 -0
  153. data/lib/linked_rails/controller/authorization.rb +15 -0
  154. data/lib/linked_rails/controller/error_handling.rb +76 -0
  155. data/lib/linked_rails/controller.rb +43 -0
  156. data/lib/linked_rails/engine.rb +7 -0
  157. data/lib/linked_rails/enhanceable.rb +21 -0
  158. data/lib/linked_rails/enhancements/actionable/model.rb +71 -0
  159. data/lib/linked_rails/enhancements/actionable/serializer.rb +25 -0
  160. data/lib/linked_rails/enhancements/creatable/action.rb +15 -0
  161. data/lib/linked_rails/enhancements/creatable/controller.rb +15 -0
  162. data/lib/linked_rails/enhancements/destroyable/action.rb +15 -0
  163. data/lib/linked_rails/enhancements/destroyable/controller.rb +15 -0
  164. data/lib/linked_rails/enhancements/destroyable/routing.rb +19 -0
  165. data/lib/linked_rails/enhancements/indexable/model.rb +10 -0
  166. data/lib/linked_rails/enhancements/menuable/model.rb +36 -0
  167. data/lib/linked_rails/enhancements/menuable/serializer.rb +33 -0
  168. data/lib/linked_rails/enhancements/route_concerns.rb +56 -0
  169. data/lib/linked_rails/enhancements/singularable/controller.rb +43 -0
  170. data/lib/linked_rails/enhancements/singularable/model.rb +47 -0
  171. data/lib/linked_rails/enhancements/singularable/serializer.rb +28 -0
  172. data/lib/linked_rails/enhancements/tableable/model.rb +28 -0
  173. data/lib/linked_rails/enhancements/updatable/action.rb +15 -0
  174. data/lib/linked_rails/enhancements/updatable/controller.rb +15 -0
  175. data/lib/linked_rails/enhancements/updatable/routing.rb +20 -0
  176. data/lib/linked_rails/enhancements/updatable/serializer.rb +17 -0
  177. data/lib/linked_rails/enhancements.rb +22 -0
  178. data/lib/linked_rails/helpers/delta_helper.rb +86 -0
  179. data/lib/linked_rails/helpers/ontola_actions_helper.rb +32 -0
  180. data/lib/linked_rails/helpers/resource_helper.rb +70 -0
  181. data/lib/linked_rails/iri_mapper.rb +125 -0
  182. data/lib/linked_rails/middleware/linked_data_params.rb +224 -0
  183. data/lib/linked_rails/model/collections.rb +82 -0
  184. data/lib/linked_rails/model/dirty.rb +82 -0
  185. data/lib/linked_rails/model/enhancements.rb +61 -0
  186. data/lib/linked_rails/model/filtering.rb +89 -0
  187. data/lib/linked_rails/model/indexable.rb +51 -0
  188. data/lib/linked_rails/model/iri.rb +121 -0
  189. data/lib/linked_rails/model/iri_mapping.rb +69 -0
  190. data/lib/linked_rails/model/serialization.rb +88 -0
  191. data/lib/linked_rails/model/sorting.rb +20 -0
  192. data/lib/linked_rails/model.rb +68 -0
  193. data/lib/linked_rails/params_parser.rb +93 -0
  194. data/lib/linked_rails/policy/attribute_conditions.rb +53 -0
  195. data/lib/linked_rails/policy.rb +189 -0
  196. data/lib/linked_rails/rdf_error.rb +36 -0
  197. data/lib/linked_rails/renderers.rb +46 -0
  198. data/lib/linked_rails/routes.rb +108 -0
  199. data/lib/linked_rails/serializer.rb +137 -0
  200. data/lib/linked_rails/translate.rb +176 -0
  201. data/lib/linked_rails/version.rb +5 -0
  202. data/lib/linked_rails/vocab.rb +81 -0
  203. data/lib/linked_rails.rb +86 -0
  204. data/lib/nill_class_renderer.rb +3 -0
  205. data/lib/rails/welcome_controller.rb +45 -0
  206. data/lib/tasks/linked_rails_tasks.rake +6 -0
  207. metadata +416 -0
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # LinkedRails
2
+ LinkedRails is a gem for Ruby on Rails that helps you create a Linked Data application in a matter of seconds.
3
+
4
+ It includes among other things:
5
+ * Linked data serialization to Turtle, JSON-LD, N-Triples and more using [rdf-serializers](https://github.com/ontola/rdf-serializers)
6
+ * Controller abstraction using [active_response](https://github.com/ontola/active_response)
7
+ * Serialization of forms
8
+ * Serialization of collections using the [Activity Streams spec](https://www.w3.org/ns/activitystreams)
9
+ * Serialization of menus
10
+ * Communicating actions to be executed by the frontend using Exec Actions header
11
+ * Rendering errors as RDF
12
+ * Parsing linked data graphs as params
13
+
14
+ ## Work in progress
15
+ This gem is an extraction from an existing app. Tests are not yet sufficient but will be extended soon.
16
+
17
+ ## Installation
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'linked_rails'
22
+ ```
23
+
24
+ And then execute:
25
+ ```bash
26
+ $ bundle
27
+ ```
28
+
29
+ Or install it yourself as:
30
+ ```bash
31
+ $ gem install linked_rails
32
+ ```
33
+
34
+ ## Getting started
35
+
36
+ Add the following lines to application.rb to enable params parsing
37
+ ```
38
+ module MyApp
39
+ class Application < Rails::Application
40
+ [...]
41
+ config.middleware.use LinkedRails::Middleware::LinkedDataParams
42
+ [...]
43
+ end
44
+ end
45
+ ```
46
+
47
+ Add the following line to your models
48
+ ```
49
+ LinkedRails::Model
50
+ ```
51
+
52
+ Add the following line to your controllers
53
+ ```
54
+ LinkedRails::Controller
55
+ ```
56
+
57
+ Add the following line to your serializers
58
+ ```
59
+ LinkedRails::Serializer
60
+ ```
61
+
62
+ Add the following line to your policies
63
+ ```
64
+ LinkedRails::Policy
65
+ ```
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rdoc/task'
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = 'LinkedRails'
14
+ rdoc.options << '--line-numbers'
15
+ rdoc.rdoc_files.include('README.md')
16
+ rdoc.rdoc_files.include('lib/**/*.rb')
17
+ end
18
+
19
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
20
+ load 'rails/tasks/engine.rake'
21
+
22
+ load 'rails/tasks/statistics.rake'
23
+
24
+ require 'bundler/gem_tasks'
25
+
26
+ require 'rake/testtask'
27
+
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.libs << 'test'
30
+ t.pattern = 'test/**/*_test.rb'
31
+ t.verbose = false
32
+ end
33
+
34
+ task default: :test
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Actions
5
+ class ItemsController < LinkedRails.controller_parent_class
6
+ active_response :show
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+
5
+ module LinkedRails
6
+ class BulkController < ApplicationController # rubocop:disable Metrics/ClassLength
7
+ REQUEST_HEADERS = %w[HTTP_ACCEPT_LANGUAGE HTTP_AUTHORIZATION HTTP_FORWARDED HTTP_HOST HTTP_REFERER HTTP_USER_AGENT
8
+ HTTP_WEBSITE_IRI HTTP_X_DEVICE_ID HTTP_X_FORWARDED_FOR HTTP_X_FORWARDED_HOST
9
+ HTTP_X_FORWARDED_PROTO HTTP_X_FORWARDED_SSL HTTP_X_REAL_IP].freeze
10
+
11
+ def show
12
+ render json: authorized_resources
13
+
14
+ print_timings
15
+ end
16
+
17
+ private
18
+
19
+ def authorized_resource(opts)
20
+ return response_for_wrong_host(opts) if wrong_host?(opts[:iri])
21
+
22
+ include = opts[:include].to_s == 'true'
23
+
24
+ response_from_request(include, RDF::URI(opts[:iri]))
25
+ rescue StandardError => e
26
+ handle_resource_error(opts, e)
27
+ end
28
+
29
+ def authorized_resources
30
+ @authorized_resources ||=
31
+ params
32
+ .require(:resources)
33
+ .map { |param| param.permit(:include, :iri) }
34
+ .map(&method(:timed_authorized_resource))
35
+ end
36
+
37
+ def handle_resource_error(opts, error)
38
+ log_resource_error(error)
39
+ status = error_status(error)
40
+ body = error_body(status, error, opts[:iri]) if opts[:include].to_s == 'true'
41
+
42
+ resource_response(
43
+ opts[:iri],
44
+ body: body,
45
+ status: status
46
+ )
47
+ end
48
+
49
+ def error_body(status, error, iri)
50
+ resource_body(error_resource(status, error, iri))
51
+ end
52
+
53
+ def log_resource_error(error)
54
+ return unless log_resource_error?(error)
55
+
56
+ Rails.logger.error(error)
57
+ Rails.logger.error(error.backtrace.join("\n"))
58
+ end
59
+
60
+ def log_resource_error?(error)
61
+ !Rails.env.production? && error_status(error) >= 500
62
+ end
63
+
64
+ def print_timings
65
+ Rails.logger.debug(
66
+ "\n CPU system user+system real inc status cache iri\n" \
67
+ "#{timings.join("\n")}\n" \
68
+ " User: #{current_user.class}(#{current_user.id})"
69
+ )
70
+ end
71
+
72
+ def require_doorkeeper_token?
73
+ false
74
+ end
75
+
76
+ def resource_body(resource)
77
+ return if resource.nil?
78
+
79
+ serializer_options = RDF::Serializers::Renderers.transform_opts(
80
+ {include: resource&.try(:preview_includes)},
81
+ serializer_params
82
+ )
83
+ RDF::Serializers.serializer_for(resource).new(resource, serializer_options).send(:render_hndjson)
84
+ end
85
+
86
+ def resource_response_body(iri, rack_body, status)
87
+ return rack_body.body if rack_body.is_a?(ActionDispatch::Response::RackBody)
88
+
89
+ error_body(status, StandardError.new(I18n.t("linked_rails.status.#{status}")), iri)
90
+ end
91
+
92
+ def resource_request(iri)
93
+ env = resource_request_env(iri)
94
+ req = ActionDispatch::Request.new(env)
95
+ req.path_info = ActionDispatch::Journey::Router::Utils.normalize_path(req.path_info)
96
+ req.env['Current-User'] = current_user
97
+ req.env['Doorkeeper-Token'] = doorkeeper_token
98
+
99
+ req
100
+ end
101
+
102
+ def resource_request_env(iri)
103
+ path = sanitized_relative_path(iri.dup)
104
+ opts = resource_request_headers(iri)
105
+ Rack::MockRequest.env_for(path, opts)
106
+ end
107
+
108
+ def resource_request_headers(iri)
109
+ fullpath = iri.query.blank? ? iri.path : "#{iri.path}?#{iri.query}"
110
+
111
+ request.env.slice(*REQUEST_HEADERS).merge(
112
+ 'HTTP_ACCEPT' => 'application/hex+x-ndjson',
113
+ 'HTTP_OPERATOR_ARG_GRAPH' => 'true',
114
+ 'ORIGINAL_FULLPATH' => fullpath
115
+ )
116
+ end
117
+
118
+ def resource_response(iri, **opts)
119
+ {
120
+ body: nil,
121
+ cache: :private,
122
+ iri: iri,
123
+ status: 404
124
+ }.merge(opts)
125
+ end
126
+
127
+ def response_for_wrong_host(opts)
128
+ iri = opts[:iri]
129
+ term = term_from_vocab(iri)
130
+ return resource_response(iri) unless term
131
+
132
+ ontology_term_response(iri, term, opts[:include])
133
+ end
134
+
135
+ def term_from_vocab(iri)
136
+ vocab = Vocab.for(iri)
137
+ tag = iri.split(vocab.to_s).last
138
+ vocab[tag]
139
+ rescue NoMethodError
140
+ nil
141
+ end
142
+
143
+ def ontology_term_response(iri, term, include)
144
+ resource_response(
145
+ iri,
146
+ body: include ? resource_body(LinkedRails.ontology_property_class.new(iri: term)) : nil,
147
+ cache: :public,
148
+ language: I18n.locale,
149
+ status: 200
150
+ )
151
+ end
152
+
153
+ def response_from_request(include, iri) # rubocop:disable Metrics/AbcSize
154
+ status, headers, rack_body = Rails.application.routes.router.serve(resource_request(iri))
155
+ cache_from_header = headers['Cache-Control']&.squish&.presence
156
+
157
+ resource_response(
158
+ iri.to_s,
159
+ body: include ? resource_response_body(iri, rack_body, status) : nil,
160
+ cache: %w[no-cache private public].include?(cache_from_header.to_s.downcase) ? cache_from_header : :private,
161
+ language: response_language(headers),
162
+ status: status
163
+ )
164
+ end
165
+
166
+ def response_language(headers)
167
+ headers['Content-Language'] || I18n.locale
168
+ end
169
+
170
+ def sanitized_relative_path(iri) # rubocop:disable Metrics/AbcSize
171
+ iri.path = "#{iri.path}/" unless iri.path&.ends_with?('/')
172
+ uri = URI(LinkedRails.iri.path.present? ? iri.to_s.split("#{LinkedRails.iri.path}/").last : iri)
173
+
174
+ [uri.path, uri.query].compact.join('?')
175
+ end
176
+
177
+ def timings
178
+ @timings ||= []
179
+ end
180
+
181
+ def timed_authorized_resource(resource)
182
+ res = nil
183
+ time = Benchmark.measure { res = authorized_resource(resource) }
184
+ unless Rails.env.production?
185
+ include = resource[:include].to_s.ljust(5)
186
+ timings << "#{time.to_s[0..-2]} - #{include} #{res[:status]} #{res[:cache]} #{resource[:iri]}"
187
+ end
188
+ res
189
+ end
190
+
191
+ def wrong_host?(iri)
192
+ !iri.starts_with?(LinkedRails.iri)
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class CurrentUserController < LinkedRails.controller_parent_class
5
+ active_response :show
6
+
7
+ private
8
+
9
+ def current_resource
10
+ @current_resource ||= LinkedRails.current_user_class.new(user: current_user)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class EnumValuesController < LinkedRails.controller_parent_class
5
+ active_response :index
6
+
7
+ private
8
+
9
+ def enum_options!
10
+ serializer_class!.enum_options(params[:attribute]) || raise(ActiveRecord::RecordNotFound)
11
+ end
12
+
13
+ def requested_resource
14
+ return super unless action_name == 'index'
15
+
16
+ @requested_resource ||= LinkedRails::Sequence.new(
17
+ enum_options!.values,
18
+ id: index_iri,
19
+ scope: LinkedRails::EnumValuePolicy::Scope
20
+ )
21
+ end
22
+
23
+ def model_class
24
+ @model_class ||= self.class.linked_models.detect do |klass|
25
+ klass.to_s == ([params[:module]].compact + [params[:klass]&.singularize]).join('/').classify
26
+ end
27
+ end
28
+
29
+ def model_class!
30
+ model_class || raise(ActiveRecord::RecordNotFound)
31
+ end
32
+
33
+ def serializer_class
34
+ @serializer_class ||= RDF::Serializers.serializer_for(model_class!)
35
+ end
36
+
37
+ def serializer_class!
38
+ serializer_class || raise(ActiveRecord::RecordNotFound)
39
+ end
40
+
41
+ class << self
42
+ def linked_models
43
+ @linked_models ||= ObjectSpace.each_object(Class).select do |c|
44
+ c.included_modules.include?(LinkedRails::Model)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class FormsController < LinkedRails.controller_parent_class
5
+ active_response :show
6
+
7
+ class << self
8
+ def controller_class
9
+ LinkedRails.form_parent_class
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class ManifestsController < LinkedRails.controller_parent_class
5
+ def show
6
+ render json: current_resource.web_manifest
7
+ end
8
+
9
+ def tenant
10
+ render json: {
11
+ iri_prefix: LinkedRails.iri.host
12
+ }
13
+ end
14
+
15
+ private
16
+
17
+ def current_resource
18
+ @current_resource ||= LinkedRails.manifest_class.new
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Menus
5
+ class ItemsController < LinkedRails.controller_parent_class
6
+ active_response :index
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ module Menus
5
+ class ListsController < LinkedRails.controller_parent_class
6
+ active_response :show, :index
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class NotFoundController < LinkedRails.controller_parent_class
5
+ def show
6
+ handle_error(ActionController::RoutingError.new('Route not found'))
7
+ rescue ActionController::UnknownFormat
8
+ head 404
9
+ end
10
+
11
+ private
12
+
13
+ def authorize_action; end
14
+ end
15
+ end