agile_rails 0.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 (259) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +285 -0
  5. data/Rakefile +39 -0
  6. data/agile_rails.gemspec +36 -0
  7. data/app/assets/fonts/ibm-plex-sans-300.woff2 +0 -0
  8. data/app/assets/fonts/ibm-plex-sans-400.woff2 +0 -0
  9. data/app/assets/fonts/ibm-plex-sans-500.woff2 +0 -0
  10. data/app/assets/fonts/ibm-plex-sans-600.woff2 +0 -0
  11. data/app/assets/fonts/ibm-plex-sans-700.woff2 +0 -0
  12. data/app/assets/fonts/ibm-plex-sans-italic.woff2 +0 -0
  13. data/app/assets/images/32px.png +0 -0
  14. data/app/assets/images/throbber.gif +0 -0
  15. data/app/assets/javascripts/agile/agile.js +1489 -0
  16. data/app/assets/javascripts/agile/jquery-migrate.js +702 -0
  17. data/app/assets/javascripts/agile/jquery.bpopup.js +372 -0
  18. data/app/assets/javascripts/agile/jquery.datetimepicker.js +1353 -0
  19. data/app/assets/javascripts/agile/jstree.min.js +6 -0
  20. data/app/assets/javascripts/agile/select-multiple.js +459 -0
  21. data/app/assets/javascripts/agile/some_scripts.js +33 -0
  22. data/app/assets/javascripts/agile.js +22 -0
  23. data/app/assets/javascripts/agile_application.js +22 -0
  24. data/app/assets/javascripts/agile_editor.js +22 -0
  25. data/app/assets/stylesheets/agile/agile.css +1882 -0
  26. data/app/assets/stylesheets/agile/agile_apps.css +149 -0
  27. data/app/assets/stylesheets/agile/jquery.datetimepicker.css +304 -0
  28. data/app/assets/stylesheets/agile/jstree.css +1107 -0
  29. data/app/assets/stylesheets/agile/select-multiple.css +110 -0
  30. data/app/assets/stylesheets/agile/th-bg.png +0 -0
  31. data/app/assets/stylesheets/agile/theme.css +49 -0
  32. data/app/assets/stylesheets/agile.css +21 -0
  33. data/app/assets/stylesheets/agile_application.css +20 -0
  34. data/app/assets/stylesheets/agile_editor.css +19 -0
  35. data/app/controllers/agile_application_controller.rb +735 -0
  36. data/app/controllers/agile_common_controller.rb +345 -0
  37. data/app/controllers/agile_controller.rb +977 -0
  38. data/app/controllers/agile_main_controller.rb +36 -0
  39. data/app/controls/agile_control.rb +120 -0
  40. data/app/controls/agile_report.rb +364 -0
  41. data/app/controls/ar_category_control.rb +39 -0
  42. data/app/controls/ar_help_control.rb +139 -0
  43. data/app/controls/ar_image_control.rb +180 -0
  44. data/app/controls/ar_journal_control.rb +47 -0
  45. data/app/controls/ar_menu_item_control.rb +55 -0
  46. data/app/controls/ar_page_control.rb +64 -0
  47. data/app/controls/ar_poll_result_control.rb +84 -0
  48. data/app/controls/ar_setup_control.rb +62 -0
  49. data/app/controls/belongs_to_control.rb +61 -0
  50. data/app/controls/browse_models_control.rb +98 -0
  51. data/app/controls/settings_form_control.rb +137 -0
  52. data/app/forms/agile_help.yml +112 -0
  53. data/app/forms/agile_menu.yml +140 -0
  54. data/app/forms/agile_report_defaults.yml +39 -0
  55. data/app/forms/all_options.yml +810 -0
  56. data/app/forms/ar_ad.yml +121 -0
  57. data/app/forms/ar_big_table.yml +60 -0
  58. data/app/forms/ar_big_table_value.yml +52 -0
  59. data/app/forms/ar_browse_fields.yml +35 -0
  60. data/app/forms/ar_browse_models.yml +48 -0
  61. data/app/forms/ar_category.yml +73 -0
  62. data/app/forms/ar_category_as_tree.yml +31 -0
  63. data/app/forms/ar_design.yml +75 -0
  64. data/app/forms/ar_filter.yml +52 -0
  65. data/app/forms/ar_folder_permission.yml +56 -0
  66. data/app/forms/ar_folder_rule.yml +48 -0
  67. data/app/forms/ar_gallery.yml +55 -0
  68. data/app/forms/ar_image.yml +126 -0
  69. data/app/forms/ar_image_search.yml +83 -0
  70. data/app/forms/ar_journal.yml +76 -0
  71. data/app/forms/ar_json_ld.yml +56 -0
  72. data/app/forms/ar_key_value.yml +33 -0
  73. data/app/forms/ar_key_value_store.yml +33 -0
  74. data/app/forms/ar_link.yml +60 -0
  75. data/app/forms/ar_menu.yml +67 -0
  76. data/app/forms/ar_menu_item.yml +141 -0
  77. data/app/forms/ar_page.yml +187 -0
  78. data/app/forms/ar_part.yml +91 -0
  79. data/app/forms/ar_permission.yml +52 -0
  80. data/app/forms/ar_permission_rule.yml +40 -0
  81. data/app/forms/ar_piece.yml +106 -0
  82. data/app/forms/ar_policy.yml +64 -0
  83. data/app/forms/ar_policy_rule.yml +42 -0
  84. data/app/forms/ar_policy_rule_nocms.yml +40 -0
  85. data/app/forms/ar_poll.yml +118 -0
  86. data/app/forms/ar_poll_item.yml +78 -0
  87. data/app/forms/ar_poll_result.yml +88 -0
  88. data/app/forms/ar_poll_result_export.yml +35 -0
  89. data/app/forms/ar_removed_url.yml +41 -0
  90. data/app/forms/ar_role.yml +43 -0
  91. data/app/forms/ar_seo.yml +32 -0
  92. data/app/forms/ar_setup.yml +45 -0
  93. data/app/forms/ar_site.yml +149 -0
  94. data/app/forms/ar_steps_template.yml +51 -0
  95. data/app/forms/ar_user.yml +140 -0
  96. data/app/forms/ar_user_role.yml +57 -0
  97. data/app/forms/help/dc_category_as_tree.en +4 -0
  98. data/app/forms/help/dc_category_as_tree.sl +5 -0
  99. data/app/forms/json_ld_schema.yml +168 -0
  100. data/app/helpers/agile_application_helper.rb +1162 -0
  101. data/app/helpers/agile_category_helper.rb +128 -0
  102. data/app/helpers/agile_common_helper.rb +308 -0
  103. data/app/helpers/agile_edit_helper.rb +645 -0
  104. data/app/helpers/agile_helper.rb +509 -0
  105. data/app/helpers/agile_index_helper.rb +677 -0
  106. data/app/helpers/ar_image_helper.rb +128 -0
  107. data/app/models/agile_form_fields/action.rb +61 -0
  108. data/app/models/agile_form_fields/agile_form_field.rb +322 -0
  109. data/app/models/agile_form_fields/belongs_to.rb +112 -0
  110. data/app/models/agile_form_fields/check_box.rb +73 -0
  111. data/app/models/agile_form_fields/comment.rb +62 -0
  112. data/app/models/agile_form_fields/date_picker.rb +104 -0
  113. data/app/models/agile_form_fields/date_select.rb +68 -0
  114. data/app/models/agile_form_fields/datetime_picker.rb +88 -0
  115. data/app/models/agile_form_fields/datetime_select.rb +73 -0
  116. data/app/models/agile_form_fields/file_field.rb +52 -0
  117. data/app/models/agile_form_fields/file_select.rb +69 -0
  118. data/app/models/agile_form_fields/hidden_field.rb +51 -0
  119. data/app/models/agile_form_fields/html_field.rb +69 -0
  120. data/app/models/agile_form_fields/journal_diff.rb +62 -0
  121. data/app/models/agile_form_fields/link_to.rb +69 -0
  122. data/app/models/agile_form_fields/method.rb +66 -0
  123. data/app/models/agile_form_fields/multitext_autocomplete.rb +215 -0
  124. data/app/models/agile_form_fields/number_field.rb +92 -0
  125. data/app/models/agile_form_fields/password_field.rb +63 -0
  126. data/app/models/agile_form_fields/radio_button.rb +95 -0
  127. data/app/models/agile_form_fields/readonly.rb +77 -0
  128. data/app/models/agile_form_fields/select.rb +281 -0
  129. data/app/models/agile_form_fields/submit_tag.rb +58 -0
  130. data/app/models/agile_form_fields/text_area.rb +61 -0
  131. data/app/models/agile_form_fields/text_autocomplete.rb +171 -0
  132. data/app/models/agile_form_fields/text_field.rb +55 -0
  133. data/app/models/agile_form_fields/text_with_select.rb +94 -0
  134. data/app/models/agile_form_fields/tree_select.rb +170 -0
  135. data/app/models/ar_big_table.rb +82 -0
  136. data/app/models/ar_big_table_value.rb +53 -0
  137. data/app/models/ar_category.rb +109 -0
  138. data/app/models/ar_design.rb +116 -0
  139. data/app/models/ar_filter.rb +200 -0
  140. data/app/models/ar_folder_permission.rb +50 -0
  141. data/app/models/ar_folder_rule.rb +47 -0
  142. data/app/models/ar_gallery.rb +53 -0
  143. data/app/models/ar_image.rb +198 -0
  144. data/app/models/ar_internals.rb +60 -0
  145. data/app/models/ar_journal.rb +46 -0
  146. data/app/models/ar_json_ld.rb +131 -0
  147. data/app/models/ar_key_value_store.rb +128 -0
  148. data/app/models/ar_link.rb +48 -0
  149. data/app/models/ar_memory.rb +172 -0
  150. data/app/models/ar_menu.rb +144 -0
  151. data/app/models/ar_menu_item.rb +106 -0
  152. data/app/models/ar_page.rb +74 -0
  153. data/app/models/ar_part.rb +66 -0
  154. data/app/models/ar_permission.rb +180 -0
  155. data/app/models/ar_permission_rule.rb +65 -0
  156. data/app/models/ar_policy.rb +78 -0
  157. data/app/models/ar_policy_rule.rb +65 -0
  158. data/app/models/ar_poll.rb +74 -0
  159. data/app/models/ar_poll_item.rb +47 -0
  160. data/app/models/ar_poll_result.rb +38 -0
  161. data/app/models/ar_removed_url.rb +42 -0
  162. data/app/models/ar_role.rb +84 -0
  163. data/app/models/ar_setup.rb +115 -0
  164. data/app/models/ar_site.rb +68 -0
  165. data/app/models/ar_temp.rb +150 -0
  166. data/app/models/ar_user.rb +72 -0
  167. data/app/models/ar_user_group.rb +38 -0
  168. data/app/models/ar_user_role.rb +54 -0
  169. data/app/models/ar_visit.rb +41 -0
  170. data/app/models/concerns/ar_page_concern.rb +128 -0
  171. data/app/models/concerns/ar_part_concern.rb +48 -0
  172. data/app/models/concerns/ar_piece_concern.rb +48 -0
  173. data/app/models/concerns/ar_policy_rule_concern.rb +87 -0
  174. data/app/models/concerns/ar_seo_concern.rb +66 -0
  175. data/app/models/concerns/ar_site_concern.rb +103 -0
  176. data/app/models/concerns/ar_user_concern.rb +195 -0
  177. data/app/renderers/agile_common_renderer.rb +93 -0
  178. data/app/renderers/agile_renderer.rb +59 -0
  179. data/app/renderers/ar_ad_renderer.rb +219 -0
  180. data/app/renderers/ar_captcha_renderer.rb +113 -0
  181. data/app/renderers/ar_common_renderer.rb +90 -0
  182. data/app/renderers/ar_gallery_renderer.rb +107 -0
  183. data/app/renderers/ar_menu_renderer.rb +195 -0
  184. data/app/renderers/ar_page_renderer.rb +147 -0
  185. data/app/renderers/ar_part_renderer.rb +235 -0
  186. data/app/renderers/ar_piece_renderer.rb +119 -0
  187. data/app/renderers/ar_poll_renderer.rb +272 -0
  188. data/app/views/agile/_edit_stuff.html.erb +57 -0
  189. data/app/views/agile/_form.html.erb +24 -0
  190. data/app/views/agile/_result.html.erb +28 -0
  191. data/app/views/agile/edit.html.erb +13 -0
  192. data/app/views/agile/error.html.erb +2 -0
  193. data/app/views/agile/index.html.erb +14 -0
  194. data/app/views/agile/login.html.erb +19 -0
  195. data/app/views/agile/new.html.erb +12 -0
  196. data/app/views/agile_common/_help.html.erb +18 -0
  197. data/app/views/agile_common/_iframe_edit.html.erb +2 -0
  198. data/app/views/agile_common/paste_clipboard.html.erb +17 -0
  199. data/app/views/layouts/agile.html.erb +17 -0
  200. data/app/views/layouts/content.html.erb +20 -0
  201. data/app/views/models/dump_models.html.erb +47 -0
  202. data/config/initializers/kaminari_patch.rb +56 -0
  203. data/config/locales/agile_de.yml +138 -0
  204. data/config/locales/agile_en.yml +162 -0
  205. data/config/locales/agile_sl.yml +163 -0
  206. data/config/locales/datetimepicker.yml +19 -0
  207. data/config/locales/de.yml +231 -0
  208. data/config/locales/en.yml +13 -0
  209. data/config/locales/kaminari.yml +26 -0
  210. data/config/locales/models_en.yml +1032 -0
  211. data/config/locales/models_sl.yml +1065 -0
  212. data/config/locales/sl.yml +211 -0
  213. data/db/migrate/20240120160001_add_sessions_table.rb +12 -0
  214. data/db/migrate/20240120160002_ar_big_table.rb +17 -0
  215. data/db/migrate/20240120160003_ar_big_table_value.rb +18 -0
  216. data/db/migrate/20240120160004_ar_category.rb +22 -0
  217. data/db/migrate/20240120160005_ar_design.rb +20 -0
  218. data/db/migrate/20240120160006_ar_filter.rb +17 -0
  219. data/db/migrate/20240120160007_ar_gallery.rb +21 -0
  220. data/db/migrate/20240120160008_ar_journal.rb +19 -0
  221. data/db/migrate/20240120160009_ar_key_value_store.rb +11 -0
  222. data/db/migrate/20240120160010_ar_link.rb +19 -0
  223. data/db/migrate/20240120160011_ar_memory.rb +8 -0
  224. data/db/migrate/20240120160012_ar_menu.rb +21 -0
  225. data/db/migrate/20240120160013_ar_menu_item.rb +28 -0
  226. data/db/migrate/20240120160014_ar_page.rb +50 -0
  227. data/db/migrate/20240120160015_ar_part.rb +33 -0
  228. data/db/migrate/20240120160016_ar_permission.rb +16 -0
  229. data/db/migrate/20240120160017_ar_permission_rule.rb +17 -0
  230. data/db/migrate/20240120160018_ar_piece.rb +28 -0
  231. data/db/migrate/20240120160019_ar_policy.rb +21 -0
  232. data/db/migrate/20240120160020_ar_policy_rule.rb +18 -0
  233. data/db/migrate/20240120160021_ar_poll.rb +27 -0
  234. data/db/migrate/20240120160022_ar_poll_item.rb +23 -0
  235. data/db/migrate/20240120160023_ar_poll_result.rb +14 -0
  236. data/db/migrate/20240120160024_ar_removed_url.rb +16 -0
  237. data/db/migrate/20240120160025_ar_role.rb +17 -0
  238. data/db/migrate/20240120160026_ar_site.rb +37 -0
  239. data/db/migrate/20240120160027_ar_temp.rb +11 -0
  240. data/db/migrate/20240120160028_ar_user.rb +42 -0
  241. data/db/migrate/20240120160029_ar_user_group.rb +12 -0
  242. data/db/migrate/20240120160030_ar_user_role.rb +18 -0
  243. data/db/migrate/20240120160031_ar_visit.rb +15 -0
  244. data/db/migrate/20240703016001_ar_setup.rb +16 -0
  245. data/db/migrate/20240703016002_ar_folder_permission.rb +15 -0
  246. data/db/migrate/20240703016003_ar_folder_rule.rb +14 -0
  247. data/db/migrate/20250115000001_ar_image.rb +25 -0
  248. data/lib/agile/configuration.rb +43 -0
  249. data/lib/agile/engine.rb +29 -0
  250. data/lib/agile/version.rb +27 -0
  251. data/lib/agile.rb +282 -0
  252. data/lib/agile_rails.rb +1 -0
  253. data/lib/generators/agile/USAGE +11 -0
  254. data/lib/generators/agile/new_form_generator.rb +369 -0
  255. data/lib/generators/convert_to_ar/convert_to_ar_generator.rb +158 -0
  256. data/lib/tasks/agile_db_clone.rake +132 -0
  257. data/lib/tasks/agile_db_export_to_yaml.rake +37 -0
  258. data/lib/tasks/agile_db_migrate.rake +35 -0
  259. metadata +414 -0
@@ -0,0 +1,36 @@
1
+ #--
2
+ # Copyright (c) 2024+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #+
23
+
24
+ ##########################################################################
25
+ # AgileRails entry point for processing page request.
26
+ ##########################################################################
27
+ class AgileMainController < AgileApplicationController
28
+
29
+ ##########################################################################
30
+ # Request processing starts here
31
+ ##########################################################################
32
+ def page
33
+ agile_process_default_request
34
+ end
35
+
36
+ end
@@ -0,0 +1,120 @@
1
+ #--
2
+ # Copyright (c) 2024+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #+
23
+
24
+ ######################################################################
25
+ # Common controls for Agile controller
26
+ ######################################################################
27
+ module AgileControl
28
+
29
+ ######################################################################
30
+ # Clear current form filter
31
+ ######################################################################
32
+ def filter_off
33
+ table_name = AgileHelper.table_param(params).strip.split(';').first.underscore
34
+ save_filter_value(nil, table_name, :filter)
35
+ save_filter_value(1, table_name, :page)
36
+ url = url_for(controller: :agile, t: table_name, f: AgileHelper.form_param(params))
37
+
38
+ render json: { url: url }
39
+ end
40
+
41
+ ######################################################################
42
+ # Set current filter for table
43
+ ######################################################################
44
+ def filter_on
45
+ table_name = AgileHelper.table_param(params).strip.split(';').first.underscore
46
+ save_filter_value(1, table_name, :page)
47
+ set_session_filter(table_name)
48
+ url = url_for(controller: :agile, table: table_name, form_name: AgileHelper.form_param(params))
49
+ respond_to do |format|
50
+ format.json { render json: { url: url } }
51
+ format.html { redirect_to url }
52
+ end
53
+
54
+ end
55
+
56
+ ########################################################################
57
+ # Will check and set sorting options for current dataset. Subroutine of index method.
58
+ ########################################################################
59
+ def sort
60
+ return if params['sort'].nil?
61
+
62
+ table_name = AgileHelper.table_param(params).strip.split(';').first.underscore
63
+ old_sort = session.dig(:filters, table_name, :sort).to_s
64
+ sort, direction = old_sort.split(' ')
65
+ # reverse sort if same selected
66
+ direction = direction == 'asc' ? 'desc' : 'asc' if params['sort'] == sort
67
+ direction ||= 'asc'
68
+ save_filter_value("#{params[:sort]} #{direction}", table_name, :sort)
69
+ save_filter_value(1, table_name, :page)
70
+
71
+ params['sort'] = nil # otherwise there is problem with other links
72
+ url = url_for(controller: :agile, t: table_name, f: AgileHelper.form_param(params))
73
+
74
+ render json: { url: url }
75
+ end
76
+
77
+ private
78
+ ########################################################################
79
+ # Will set session[table_name]['filter'] and save last filter settings to session.
80
+ # subroutine of check_filter_options.
81
+ ########################################################################
82
+ def set_session_filter(table_name)
83
+ # models that can not be filtered (for now)
84
+ return if table_name.in?(%w[(ar_temp ar_memory])
85
+ # field_name should exist on set filter condition
86
+ return if params[:filter_oper] && params[:filter_field].blank? && params[:filter_value].blank?
87
+
88
+ filter_value = if params[:filter_value].blank?
89
+ '#NIL' # #NIL indicates that no filtering is needed
90
+ elsif params[:filter_value].to_s[0] == '@'
91
+ # Internal value. Remove leading @ and evaluate expression
92
+ expression = ArInternals.get(params[:filter_value])
93
+ eval(expression) rescue 'Error!'
94
+ else
95
+ params[:filter_value]
96
+ end
97
+ if params[:filter_oper] == 'eval'
98
+ save_filter_value({ table: table_name, operation: 'eval', value: params[:filter_value] }, table_name, :filter)
99
+ # if filter field parameter is omitted then just set filter value
100
+ elsif params[:filter_field].nil?
101
+ save_filter_value(filter_value, table_name, :filter, :value)
102
+ else
103
+ # as field defined. Split name and alternative input field
104
+ field = if params[:filter_field].match(' as ')
105
+ params[:filter_input] = params[:filter_field].split(' as ').last.strip
106
+ params[:filter_field].split(' as ').first.strip
107
+ else
108
+ params[:filter_field]
109
+ end
110
+ new_filter = { field: field, operation: params[:filter_oper], value: filter_value, input: params[:filter_input], table: table_name }
111
+ save_filter_value(new_filter, table_name, :filter)
112
+ end
113
+ # must be. Otherwise, kaminari includes params on paging links
114
+ params[:filter_id] = nil
115
+ params[:filter_oper] = nil
116
+ params[:filter_input] = nil
117
+ params[:filter_field] = nil
118
+ end
119
+
120
+ end
@@ -0,0 +1,364 @@
1
+ #--
2
+ # Copyright (c) 2024+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #+
23
+
24
+ ######################################################################
25
+ # Common methods required by reports
26
+ ######################################################################
27
+ module AgileReport
28
+ attr_accessor :report_id, :bulk
29
+
30
+ ######################################################################
31
+ # Clear data unless params[:clear] is 'no'
32
+ ######################################################################
33
+ def new_record
34
+ ArTemp.clear(temp_key) unless params[:clear].to_s == 'no'
35
+ end
36
+
37
+ ######################################################################
38
+ # Will replace @form with @form['report'] if table=ar_temp.
39
+ # Will load agile_report_defaults if table=ar_memory and actions are not present.
40
+ ######################################################################
41
+ def update_form
42
+ agile_form_read if @form.nil?
43
+ if AgileHelper.table_param(params) == 'ar_temp' && @form['report'].present?
44
+ @form = @form['report']
45
+ elsif AgileHelper.table_param(params) == 'ar_memory' && !AgileHelper.dont?(@form['defaults'])
46
+ defaults = File.read(AgileHelper.form_file_find('agile_report_defaults'))
47
+ defaults.gsub!('&report', AgileHelper.form_param(params))
48
+ defaults = YAML.load(defaults) rescue nil
49
+ return if defaults.nil?
50
+
51
+ case @form['form']['actions'].class.to_s
52
+ when 'NilClass'
53
+ when 'Hash' then defaults = {}
54
+ when 'String' # only print or export are specified
55
+ if @form['form']['actions'] == 'print'
56
+ defaults['form']['actions'].delete(30)
57
+ elsif @form['form']['actions'] == 'export'
58
+ defaults['form']['actions'].delete(20)
59
+ end
60
+ end
61
+ @form.deep_merge!(defaults)
62
+ end
63
+ end
64
+
65
+ ######################################################################
66
+ # Print to PDF action
67
+ ######################################################################
68
+ def print
69
+ begin
70
+ pdf_do
71
+ rescue Exception => e
72
+ Agile.dump_exception(e)
73
+ render json: { msg_error: t('agile.runtime_error') } and return
74
+ end
75
+
76
+ pdf_file = "tmp/dokument-#{Time.now.to_i}.pdf"
77
+ @pdf.render_file Rails.root.join('public', pdf_file)
78
+
79
+ render json: print_response(pdf_file)
80
+ end
81
+
82
+ ######################################################################
83
+ # Export data do excel action
84
+ ######################################################################
85
+ def export
86
+ export_to_excel(temp_key)
87
+ end
88
+
89
+ ######################################################################
90
+ # Default filter to select data for result.
91
+ ######################################################################
92
+ def data_filter
93
+ params['clear'].to_s == 'yes' ? ArTemp.where(key: false) : ArTemp.where(key: temp_key).order(:order)
94
+ end
95
+
96
+ private
97
+
98
+ ######################################################################
99
+ # Will create response message for print action. Response consists of
100
+ # opening pdf file in new browser tab and additional print_message if defined.
101
+ ######################################################################
102
+ def print_response(pdf_file)
103
+ response = { window: "/#{pdf_file}" }
104
+ response.merge!(report_message) if respond_to?(:report_message, true)
105
+ response
106
+ end
107
+
108
+ ######################################################################
109
+ # Temp key consists of report name and user's id. Key should be added
110
+ # to every ar_temp document and is used to define data, which belongs
111
+ # to current user.
112
+ ######################################################################
113
+ def temp_key
114
+ "#{@report_id}-#{session[:user_id]}"
115
+ end
116
+
117
+ ######################################################################
118
+ # Initialize report. Set report_id internal variable and initialize bulk
119
+ # for bulk saving data to ar_temp table.
120
+ ######################################################################
121
+ def report_init(id)
122
+ @report_id = id
123
+ @bulk = []
124
+ end
125
+
126
+ ######################################################################
127
+ # Check if all send fields are blank.
128
+ ######################################################################
129
+ def all_blank?(*fields)
130
+ fields.each { _1.blank? ? true : (break false) }
131
+ end
132
+
133
+ ######################################################################
134
+ # Clears report data
135
+ ######################################################################
136
+ def clear_data
137
+ ArTemp.clear(temp_key)
138
+ end
139
+
140
+ ######################################################################
141
+ # Will write data in bulks to ar_temp collection.
142
+ ######################################################################
143
+ def write(data)
144
+ the_end = data.nil? || data[:end]
145
+ @bulk << data unless the_end && data.size < 2
146
+
147
+ if (the_end && @bulk.size > 0) || @bulk.size > 100
148
+ ArTemp.insert_all(
149
+ @bulk.map { |e| { 'key' => temp_key, 'data' => e.stringify_keys.to_yaml, 'order' => e[:order] } }
150
+ )
151
+ @bulk = []
152
+ end
153
+ end
154
+
155
+ ######################################################################
156
+ # Export data to Excel
157
+ ######################################################################
158
+ def export_to_excel(report_id)
159
+ agile_form_read if @form.blank?
160
+ # use report options if present
161
+ columns = (@form['report'] || @form)['index']['data_set']['columns'].sort
162
+
163
+ n, workbook = 0, Spreadsheet::Workbook.new
164
+ excel = workbook.create_worksheet(name: report_id)
165
+ # header
166
+ columns.each_with_index do |column, i|
167
+ caption = column.last['caption'] || column.last['label']
168
+ label = t(caption)
169
+ excel[n, i] = label.match(/translation missing/i) ? caption : label
170
+ end
171
+
172
+ data_filter.each do |doc|
173
+ n += 1
174
+ columns.each_with_index do |column, i|
175
+ value = doc[column.last['name']].to_s.gsub('<br>', ";")
176
+ value = value.gsub(/\<\/strong\>|\<strong\>|\<\/b\>|\<b\>/, '')
177
+ excel[n, i] = value
178
+ end
179
+ end
180
+ file_name = "#{report_id}-#{Time.now.to_i}.xls"
181
+ workbook.write Rails.root.join('public', 'tmp', file_name)
182
+ agile_render_ajax(operation: :window, value: "/tmp/#{file_name}")
183
+ end
184
+
185
+ ############################################################################
186
+ # Returns html code for displaying date/time formatted by strftime. Will return '' if value is nil.
187
+ #
188
+ # Parameters:
189
+ # [value] Date/DateTime/Time.
190
+ # [format] String. strftime format mask. Defaults to locale's default format.
191
+ ############################################################################
192
+ def agile_format_date_time(value, format = nil)
193
+ return '' if value.nil?
194
+
195
+ format ||= value.instance_of?(Date) ? t('date.formats.default') : t('time.formats.default')
196
+ value.strftime(format)
197
+ end
198
+
199
+ ##############################################################################
200
+ # Initialize PDF document.
201
+ #
202
+ # @opts [Hash] : PDF creation options
203
+ #
204
+ # Some default options are:
205
+ # :font_size (10)
206
+ # :margin [30,30,30,30]
207
+ # :page_size 'A4'
208
+ # :font %w[Arial arial.ttf arialbd.ttf]
209
+ ##############################################################################
210
+ def pdf_init(opts = {})
211
+ default_pdf_options(opts, :font_size, 10)
212
+ default_pdf_options(opts, :margin, [30, 30, 30, 30])
213
+ default_pdf_options(opts, :page_size, 'A4')
214
+ default_pdf_options(opts, :min_version, 1.7)
215
+
216
+ @pdf = Prawn::Document.new(opts)
217
+ @pdf.font_size = opts[:font_size]
218
+
219
+ @pdf.encrypt_document(owner_password: :random,
220
+ permissions: { print_document: true,
221
+ modify_contents: false,
222
+ copy_contents: false,
223
+ modify_annotations: false })
224
+ params[:font] ||= %w[Arial arial.ttf arialbd.ttf]
225
+ @pdf.font_families.update(
226
+ params[:font][0] => { normal: Rails.root.join('public', params[:font][1]),
227
+ bold: Rails.root.join('public', params[:font][2]) }
228
+ )
229
+ @pdf.font(params[:font][0])
230
+ @pdf.renderer.min_version(opts[:min_version])
231
+ end
232
+
233
+ ################################################################################
234
+ # Sets default pdf creation options whether from initial call or from form's print options.
235
+ ###############################################################################
236
+ def default_pdf_options(opts, option, default)
237
+ form_value = @form.dig('print', option.to_s)
238
+ @form['print'].delete(option.to_s) if form_value
239
+ opts[option] ||= form_value || default
240
+ end
241
+
242
+ ################################################################################
243
+ # Prepares pdf default header from form definition
244
+ #
245
+ # Example if overwritten in report control file:
246
+ # @table = %w[caption1 caption\ 2 caption\ 3 .......]
247
+ ###############################################################################
248
+ def pdf_header
249
+ pdf_head if defined?(:pdf_head)
250
+ return if @table
251
+
252
+ tab = []
253
+ @form['print'].select{ |k, v| k.is_a?(Integer) }.sort { |a, b| a.first <=> b.first }.each do |k, v|
254
+ tab << if v['caption']
255
+ AgileHelper.t(v['caption'], v['caption'])
256
+ else
257
+ v['name'].capitalize
258
+ end
259
+ end
260
+ @table = [tab]
261
+ end
262
+
263
+ ################################################################################
264
+ # Reads report data and adds fields defined on form to @table array.
265
+ #
266
+ # Example if overwritten in report control file:
267
+ # @table += data_filter.map { |e| [e.field1, e.field3, e.field3 ....] }
268
+ ###############################################################################
269
+ def pdf_data
270
+ keys = @form['print'].select{ |k, v| k.is_a?(Integer)}.sort { |a, b| a.first <=> b.first }.map{ |k, v| v['name'] }
271
+ @table += data_filter.map do |rec|
272
+ keys.map{ |key| rec[key] }
273
+ end
274
+ end
275
+
276
+ ################################################################################
277
+ # Prepare pdf report
278
+ #
279
+ # Any of those methods can be overwritten in report control file.
280
+ # pdf_init
281
+ # pdf_header
282
+ # pdf_data
283
+ # pdf_render
284
+ ################################################################################
285
+ def pdf_do
286
+ pdf_init
287
+ pdf_header
288
+ pdf_data
289
+ pdf_render
290
+ end
291
+
292
+ ################################################################################
293
+ # Renders table data
294
+ #
295
+ # Example if overwritten in report control file:
296
+ # @pdf.table(@table, header: true, cell_style: { padding: [2, 2, 2, 2], align: :left, border_width: 0.5 }) do
297
+ # column(0).style width: 80
298
+ # column(1).style width: 50
299
+ # column(3).style width: 35, align: :right
300
+ # end
301
+ ###############################################################################
302
+ def pdf_render
303
+ opts = {}
304
+ default_pdf_options(opts, 'header', true)
305
+ header_style = @form['print'].delete('header_style')
306
+
307
+ @form['print'].select{ |k, v| k.is_a?(String)}.each do |option, value|
308
+ if option.is_a?(Hash)
309
+ @form['print'][option].each do |k, v|
310
+ opts[option] ||= {}
311
+ opts[option][k] = v
312
+ end
313
+ else
314
+ opts[option] = value
315
+ end
316
+ end
317
+
318
+ print = @form['print'] # @form is nil inside table do loop ????
319
+ @pdf.table(@table, opts) do
320
+ #@TODO Find out how different styles can be defined for print header
321
+ #if header_style
322
+ #_opts = {}
323
+ #header_style.each { |k, v| _opts[k.to_sym] = v }
324
+ # row(0).style(opts)
325
+ # header_style.each { |k, v| row(0).send(k.to_sym, v) }
326
+ #end
327
+
328
+ print.select{ |k, v| k.is_a?(Integer)}.sort{ |a, b| a.first <=> b.first }.each_with_index do |data, i|
329
+ options = data.last
330
+ next unless options['style']
331
+
332
+ _opts = {}
333
+ options['style'].each { |k, v| _opts[k.to_sym] = v }
334
+ column(i).style(_opts)
335
+ end
336
+ end
337
+ end
338
+
339
+ ################################################################################
340
+ # Prints out single text (or object) on report.
341
+ #
342
+ # @param [Object] txt : Text or object. Result of to_s method of the object is
343
+ # @param [Hash] opts
344
+ ###############################################################################
345
+ def pdf_text(txt, opts = {})
346
+ box_opts = opts.dup
347
+ ypos = @pdf.cursor
348
+ xpos = opts.delete(:atx) || 0
349
+ box_opts[:single_line] ||= true
350
+ box_opts[:at] ||= [xpos, ypos]
351
+
352
+ @pdf.text_box(txt.to_s, box_opts)
353
+ end
354
+
355
+ ################################################################################
356
+ # Skip line on report
357
+ #
358
+ # @param [Integer] skip . Number of lines to skip. Default 1.
359
+ ###############################################################################
360
+ def pdf_skip(skip = 1)
361
+ @pdf.text('<br>' * skip, inline_format: true)
362
+ end
363
+
364
+ end
@@ -0,0 +1,39 @@
1
+ #--
2
+ # Copyright (c) 2024+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #+
23
+
24
+ ######################################################################
25
+ # Controls for ar_categories table.
26
+ ######################################################################
27
+ module ArCategoryControl
28
+
29
+ ######################################################################
30
+ # Called when new empty record is created
31
+ ######################################################################
32
+ def new_record
33
+ return if params[:p_parent].blank?
34
+
35
+ parent = ArCategory.find(params[:p_parent])
36
+ @record.ar_site_id = parent.ar_site_id
37
+ end
38
+
39
+ end