drg_cms 0.7.0.2 → 0.7.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/drg_cms/drg_cms.js +110 -35
  3. data/app/assets/javascripts/drg_cms/jquery.bpopup.js +372 -0
  4. data/app/assets/javascripts/drg_cms_application.js +1 -1
  5. data/app/assets/javascripts/drg_cms_cms.js +1 -1
  6. data/app/assets/stylesheets/drg_cms/drg_cms.css +126 -36
  7. data/app/assets/stylesheets/drg_cms/select-multiple.css +6 -7
  8. data/app/controllers/cmsedit_controller.rb +78 -47
  9. data/app/controllers/dc_application_controller.rb +22 -25
  10. data/app/controllers/dc_common_controller.rb +9 -6
  11. data/app/controllers/dc_main_controller.rb +0 -1
  12. data/app/controls/{dc_category_control.rb → dc_gallery_control.rb} +15 -30
  13. data/app/controls/dc_image_control.rb +180 -0
  14. data/app/controls/dc_page_control.rb +3 -3
  15. data/app/controls/dc_poll_result_control.rb +38 -39
  16. data/app/controls/dc_report.rb +9 -4
  17. data/app/controls/dc_setup_control.rb +53 -0
  18. data/app/controls/design_element_settings_control.rb +88 -37
  19. data/app/forms/all_options.yml +20 -9
  20. data/app/forms/cms_menu.yml +14 -2
  21. data/app/forms/dc_gallery.yml +1 -1
  22. data/app/forms/dc_image.yml +122 -0
  23. data/app/forms/dc_image_search.yml +72 -0
  24. data/app/forms/dc_page.yml +11 -8
  25. data/app/forms/dc_poll.yml +2 -1
  26. data/app/forms/dc_poll_result.yml +10 -7
  27. data/app/forms/dc_setup.yml +45 -0
  28. data/app/forms/dc_steps_template.yml +6 -2
  29. data/app/helpers/cms_common_helper.rb +36 -24
  30. data/app/helpers/cms_edit_helper.rb +26 -33
  31. data/app/helpers/cms_helper.rb +29 -12
  32. data/app/helpers/cms_index_helper.rb +109 -80
  33. data/app/helpers/dc_application_helper.rb +108 -86
  34. data/app/helpers/dc_image_helper.rb +127 -0
  35. data/app/models/concerns/dc_policy_rule_concern.rb +1 -1
  36. data/app/models/concerns/dc_user_concern.rb +13 -5
  37. data/app/models/dc_big_table.rb +1 -1
  38. data/app/models/dc_category.rb +12 -0
  39. data/app/models/dc_design.rb +5 -4
  40. data/app/models/dc_filter.rb +24 -27
  41. data/app/models/dc_image.rb +237 -0
  42. data/app/models/dc_internals.rb +5 -9
  43. data/app/models/dc_memory.rb +2 -2
  44. data/app/models/dc_policy_role.rb +8 -8
  45. data/app/models/dc_setup.rb +111 -0
  46. data/app/models/drgcms_form_fields/datetime_picker.rb +1 -1
  47. data/app/models/drgcms_form_fields/drgcms_field.rb +9 -26
  48. data/app/models/drgcms_form_fields/embedded.rb +28 -17
  49. data/app/models/drgcms_form_fields/journal_diff.rb +2 -2
  50. data/app/models/drgcms_form_fields/multitext_autocomplete.rb +88 -76
  51. data/app/models/drgcms_form_fields/select.rb +41 -19
  52. data/app/models/drgcms_form_fields/text_with_select.rb +5 -9
  53. data/app/renderers/dc_big_menu_renderer.rb +18 -20
  54. data/app/renderers/dc_gallery_renderer.rb +10 -4
  55. data/app/renderers/dc_menu_renderer.rb +21 -58
  56. data/app/renderers/dc_page_renderer.rb +7 -7
  57. data/app/renderers/dc_poll_renderer.rb +13 -12
  58. data/app/renderers/dc_simple_menu_renderer.rb +1 -1
  59. data/app/views/cmsedit/_edit_stuff.html.erb +4 -1
  60. data/app/views/cmsedit/edit.html.erb +1 -1
  61. data/app/views/cmsedit/index.html.erb +1 -1
  62. data/app/views/cmsedit/new.html.erb +1 -0
  63. data/config/locales/drgcms_en.yml +22 -2
  64. data/config/locales/drgcms_sl.yml +25 -6
  65. data/config/locales/models_en.yml +50 -1
  66. data/config/locales/models_sl.yml +60 -1
  67. data/drg_cms.gemspec +1 -1
  68. data/lib/drg_cms/version.rb +1 -1
  69. data/lib/drg_cms.rb +40 -27
  70. data/lib/generators/convert_to_ar/USAGE +8 -0
  71. data/lib/generators/convert_to_ar/convert_to_ar_generator.rb +158 -0
  72. data/lib/generators/new_drg_form/new_drg_form_generator.rb +32 -14
  73. metadata +19 -10
  74. data/app/assets/javascripts/drg_cms/jquery.bpopup.min.js +0 -7
  75. data/app/views/layouts/__cmsedit.html.erb +0 -16
@@ -260,7 +260,7 @@ def dc_table_title(text, result_set = nil)
260
260
  c = %(<div class="dc-title">#{text})
261
261
  c << dc_help_button(result_set)
262
262
 
263
- if result_set && result_set.respond_to?(:current_page)
263
+ if result_set&.respond_to?(:current_page)
264
264
  c << %(<div class="dc-paginate">#{paginate(result_set, :params => {action: 'index', clear: 'no', filter: nil})}</div>)
265
265
  end
266
266
  c << '<div style="clear: both;"></div></div>'
@@ -268,26 +268,27 @@ def dc_table_title(text, result_set = nil)
268
268
  end
269
269
 
270
270
  ############################################################################
271
- # Creates title for cmsedit edit action dialog.
272
- #
271
+ # Creates title for cmsedit edit action dialog.
272
+ #
273
273
  # Returns:
274
274
  # String. HTML code for title.
275
275
  ############################################################################
276
276
  def dc_edit_title
277
277
  session[:form_processing] = "form:title:"
278
- title = @form['form']['title']
278
+ title_data = @form['form']['title']
279
+ if title_data.class == String
280
+ t(title_data, title_data)
279
281
  # defined as form:title:edit
280
- if title && title['edit'] && !@form['readonly']
281
- t( title['edit'], title['edit'] )
282
- elsif title && title['show'] && @form['readonly']
283
- t( title['show'], title['show'] )
282
+ elsif title_data&.dig('edit') && !@form['readonly']
283
+ t( title_data['edit'], title_data['edit'] )
284
+ elsif title_data&.dig('show') && @form['readonly']
285
+ t( title_data['show'], title_data['show'] )
284
286
  else
285
- # concatenate title
286
287
  c = (@form['readonly'] ? t('drgcms.show') : t('drgcms.edit')) + " : "
287
288
  c << (@form['title'].class == String ? t( @form['title'], @form['title'] ) : t_tablename(@form['table']))
288
- title = title.try('field')
289
-
290
- c << "#{@record[ title ]}" if title && @record.respond_to?(title)
289
+ # add description field value to title
290
+ field_name = title_data['field'] if title_data
291
+ c << " : #{@record[ field_name ]}" if field_name && @record.respond_to?(field_name)
291
292
  c
292
293
  end
293
294
  end
@@ -300,14 +301,18 @@ end
300
301
  ############################################################################
301
302
  def dc_new_title
302
303
  session[:form_processing] = "form:title:"
303
- title = @form['form']['title']
304
+ title_data = @form['form']['title']
305
+ if title_data.class == String
306
+ t(title_data, title_data)
304
307
  # defined as form:title:new
305
- if title && title['new']
306
- t( title['new'], title['new'] )
308
+ elsif title_data&.dig('new')
309
+ t( title_data['new'], title_data['new'] )
307
310
  else
308
311
  # in memory structures
309
312
  if @form['table'] == 'dc_memory'
310
- t( @form['title'], @form['title'] )
313
+ return t( @form['title'], @form['title'] ) if @form['title']
314
+
315
+ t("#{@form['i18n_prefix']}.tabletitle", '')
311
316
  else
312
317
  "#{t('drgcms.new')} : #{t_tablename(@form['table'])}"
313
318
  end
@@ -684,51 +689,40 @@ end
684
689
  ############################################################################
685
690
  # Returns list of all collections (tables) as array of choices for usage in select fields.
686
691
  # List is collected from cms_menu.yml files and may not include all collections used in application.
687
- # Currently list is only used for helping defining collection names on dc_permission form.
688
- #
692
+ # Currently list is only used for helping defining collection names on dc_permission form.
693
+ #
689
694
  # Example (as used in forms):
690
695
  # form:
691
696
  # fields:
692
697
  # 10:
693
698
  # name: table_name
694
699
  # type: text_with_select
695
- # eval: dc_choices4_all_collections
700
+ # eval: dc_choices4_all_collections
696
701
  ############################################################################
697
702
  def dc_choices4_all_collections
698
- choices = {}
699
- DrgCms.paths(:forms).reverse.each do |path|
700
- filename = "#{path}/cms_menu.yml"
701
- next unless File.exist?(filename)
702
-
703
- menu = YAML.load_file(filename) rescue nil # load menu
704
- next if menu.nil? or !menu['menu'] # not menu or error
705
- menu['menu'].each do |section|
706
- next unless section.last['items'] # next if no items
707
- section.last['items'].each do |k, v| # look for caption and
708
- key = v['table']
709
- choices[key] ||= "#{key} - #{t(v['caption'], v['caption'])}"
710
- end
711
- end
712
- end
713
- choices.invert.to_a.sort # hash has to be inverted for values to be returned right
703
+ models = Mongoid.models.map(&:to_s).uniq.map(&:underscore).delete_if { |e| e.match('/') }
704
+ models.sort.inject([]) do |r, model_name|
705
+ r << ["#{model_name} - #{t("helpers.label.#{model_name}.tabletitle", '')}", model_name]
706
+ end
714
707
  end
715
708
 
716
709
  ##########################################################################
717
- # Returns choices for creating collection edit select field on CMS top menu.
710
+ # Code for top CMS menu.
718
711
  ##########################################################################
719
- def dc_choices4_cmsmenu
712
+ def dc_cms_menu
720
713
  menus = {}
721
714
  DrgCms.paths(:forms).reverse.each do |path|
722
715
  filename = "#{path}/cms_menu.yml"
723
- next unless File.exist?(filename)
724
- menu = YAML.load_file(filename) rescue nil # load menu
725
- next if menu.nil? or !menu['menu'] # not menu or error
726
- menus = CmsHelper.forms_merge(menu['menu'], menus) # ignore top level part
727
- end
716
+ next if !File.exist?(filename)
717
+
718
+ menu = YAML.load_file(filename) rescue nil # load menu
719
+ menus = CmsHelper.forms_merge(menu['menu'], menus) if menu.dig('menu') # merge menus
720
+ end
728
721
 
729
722
  html = '<ul>'
730
723
  menus.to_a.sort.each do |index, menu| # sort menus, result is array of sorted hashes
731
724
  next unless menu['caption']
725
+
732
726
  icon = menu['icon'].match('/') ? image_tag(menu['icon']) : fa_icon(menu['icon']) #external or fa- image
733
727
  html << %(<li class="cmsedit-top-level-menu"><div>#{icon}#{t(menu['caption'])}</div><ul>)
734
728
  menu['items'].to_a.sort.each do |index1, value| # again, sort menu items first
@@ -736,19 +730,18 @@ def dc_choices4_cmsmenu
736
730
  opts = { target: value['target'] || 'iframe_cms' }
737
731
  "<li>#{dc_link_to(t(value['caption']), value['icon'] || '', value['link'], opts)}</li>"
738
732
  else
739
- opts =
740
- { controller: value['controller'],
741
- action: value['action'],
742
- table: value['table'],
743
- form_name: value['form_name'] || value['table'],
744
- target: value['target'] || 'iframe_cms',
745
- }
733
+ opts = { controller: value['controller'], action: value['action'],
734
+ table: value['table'], form_name: value['form_name'] || value['table'],
735
+ target: value['target'] || 'iframe_cms',
736
+ }
737
+ # additional parameters
738
+ value['params'].each { |k, v| opts[k] = dc_value_for_parameter(v) } if value['params']
746
739
  "<li>#{dc_link_to(t(value['caption']), value['icon'] || '', opts)}</li>"
747
740
  end
748
741
  end
749
742
  html << '</ul></li>'
750
743
  end
751
- html
744
+ html.html_safe
752
745
  end
753
746
 
754
747
  ############################################################################
@@ -760,7 +753,7 @@ def dc_choices4_folders_list
760
753
  home = File.join(public,dc_get_site.files_directory)
761
754
  choices = Dir.glob(home + '/**/*/').select { |fn| File.directory?(fn) }
762
755
  choices << home # add home
763
- choices.collect! {|e| e.gsub(public,'')} # remove public part
756
+ choices.collect! { |e| e.gsub(public,'') } # remove public part
764
757
  choices.sort
765
758
  end
766
759
 
@@ -782,7 +775,7 @@ end
782
775
  # type: select
783
776
  # eval: dc_choices4('dc_poll','name','_id')
784
777
  ############################################################################
785
- def dc_choices4(model, name, id='_id', options = {})
778
+ def dc_choices4(model, name, id = '_id', options = {})
786
779
  model = model.classify.constantize
787
780
  qry = model.only(id, name)
788
781
  if (param = options[:site])
@@ -792,8 +785,6 @@ def dc_choices4(model, name, id='_id', options = {})
792
785
  end
793
786
  qry = qry.and(active: true) if model.method_defined?(:active)
794
787
  qry = qry.order_by(name => 1).collation(locale: I18n.locale.to_s)
795
- #choices = qry.inject([]) {|result,e| result << [ e[name], e[id] ]}
796
- #choices.sort_alphabetical_by(&:first) # use UTF-8 sort
797
788
  qry.map { |e| [e[name], e[id]] }
798
789
  end
799
790
 
@@ -864,10 +855,10 @@ def dc_user_can_view(ctrl, policy_id)
864
855
  policies = if site.inherit_policy.blank?
865
856
  site.dc_policies
866
857
  else
867
- Mongoid::QueryCache.cache { DcSite.find(site.inherit_policy) }.dc_policies
858
+ Mongo::QueryCache.cache { DcSite.find(site.inherit_policy) }.dc_policies
868
859
  end
869
860
  # permission defined by default policy
870
- default_policy = Mongoid::QueryCache.cache { policies.find_by(is_default: true) }
861
+ default_policy = Mongo::QueryCache.cache { policies.find_by(is_default: true) }
871
862
  return cache_add(policy_id, false, 'Default access policy not found for the site!') unless default_policy
872
863
 
873
864
  permissions = {}
@@ -875,14 +866,14 @@ def dc_user_can_view(ctrl, policy_id)
875
866
  # update permissions with defined policy
876
867
  part_policy = nil
877
868
  if policy_id
878
- part_policy = Mongoid::QueryCache.cache { policies.find(policy_id) }
869
+ part_policy = Mongo::QueryCache.cache { policies.find(policy_id) }
879
870
  return cache_add(policy_id, false, 'Access policy not found for part!') unless part_policy
880
871
 
881
872
  part_policy.dc_policy_rules.to_a.each { |v| permissions[v.dc_policy_role_id] = v.permission }
882
873
  end
883
874
  # apply guest role if no roles defined
884
875
  if ctrl.session[:user_roles].nil?
885
- role = Mongoid::QueryCache.cache { DcPolicyRole.find_by(system_name: 'guest', active: true) }
876
+ role = Mongo::QueryCache.cache { DcPolicyRole.find_by(system_name: 'guest', active: true) }
886
877
  return cache_add(policy_id, false, 'System guest role not defined!') unless role
887
878
 
888
879
  ctrl.session[:user_roles] = [role.id]
@@ -1008,7 +999,15 @@ def dc_big_table(key)
1008
999
  desc = v.value if desc.blank? # still blank. Use value as description
1009
1000
  ret << [desc, v.value]
1010
1001
  end
1011
- ret
1002
+ ret.sort_alphabetical_by(&:first)
1003
+ end
1004
+
1005
+ ########################################################################
1006
+ # Will return name for value defined in dc_big_table
1007
+ ########################################################################
1008
+ def dc_big_table_name_for_value(key, value)
1009
+ dc_big_table(key).each { |k, val| return k if val.to_s == value.to_s}
1010
+ '???'
1012
1011
  end
1013
1012
 
1014
1013
  ########################################################################
@@ -1073,25 +1072,25 @@ end
1073
1072
  ########################################################################
1074
1073
  def dc_internal_var(object, var_name, current_document = nil)
1075
1074
  begin
1076
- case
1077
- when object == 'session' then _origin.session[var_name]
1078
- when object == 'params' then _origin.params[var_name]
1079
- when object == 'site' then _origin.dc_get_site.send(var_name)
1080
- when object == 'page' then _origin.page.send(var_name)
1081
- when object == 'record' then
1075
+ case object
1076
+ when 'session' then _origin.session[var_name]
1077
+ when 'params' then _origin.params[var_name]
1078
+ when 'site' then _origin.dc_get_site.send(var_name)
1079
+ when 'page' then _origin.page.send(var_name)
1080
+ when 'record' then
1082
1081
  current_document ? current_document.send(var_name) : _origin.record.send(var_name)
1083
- when object == 'class' then
1082
+ when 'class' then
1084
1083
  clas, method_name = var_name.split('.')
1085
1084
  klas = clas.classify.constantize
1086
1085
  # call method. Error will be caught below.
1087
1086
  klas.send(method_name)
1088
1087
  else
1089
- 'VARIABLE: UNKNOWN OBJECT'
1088
+ 'dc_internal: UNKNOWN OBJECT'
1090
1089
  end
1091
1090
  rescue Exception => e
1092
1091
  Rails.logger.debug "\ndc_internal_var. Runtime error. #{e.message}\n"
1093
1092
  Rails.logger.debug(e.backtrace.join($/)) if Rails.env.development?
1094
- 'VARIABLE: ERROR'
1093
+ 'dc_internal: ERROR'
1095
1094
  end
1096
1095
  end
1097
1096
 
@@ -1119,14 +1118,13 @@ end
1119
1118
  # Returns:
1120
1119
  # HTML data to be embedded into page header
1121
1120
  #######################################################################
1122
- def dc_get_json_ld()
1123
- return '' if @json_ld.nil? or @json_ld.size == 0
1121
+ def dc_get_json_ld
1122
+ return '' if @json_ld.blank?
1124
1123
 
1125
- %Q[
1124
+ %(
1126
1125
  <script type="application/ld+json">
1127
- #{JSON.pretty_generate({'@context' => 'http://schema.org', '@graph' => @json_ld})}
1128
- </script>
1129
- ].html_safe
1126
+ #{JSON.pretty_generate({ '@context' => 'http://schema.org', '@graph' => @json_ld })}
1127
+ </script>).html_safe
1130
1128
  end
1131
1129
 
1132
1130
  ########################################################################
@@ -1145,21 +1143,40 @@ def dc_add_json_ld(element)
1145
1143
  end
1146
1144
 
1147
1145
  ########################################################################
1148
- # Will return meta data for SEO optimizations
1146
+ # Will return meta data for SEO optimizations.
1147
+ # It will also create special link rel="canonical" tag if defined in meta tags or page document.
1149
1148
  #
1150
1149
  # Returns:
1151
1150
  # HTML data to be embedded into page header
1152
1151
  #######################################################################
1153
- def dc_get_seo_meta_tags()
1152
+ def dc_get_seo_meta_tags
1154
1153
  html = ''
1155
- html << "<link rel=\"canonical\" href=\"#{@page.canonical_link}\">\n " unless @page&.canonical_link.blank?
1156
-
1157
- html << @meta_tags.inject('') do |r, hash|
1158
- r << "<meta #{hash.first} content=\"#{hash.last}\">\n "
1154
+ has_canonical = false
1155
+ html << @meta_tags.inject('') do |r, tag|
1156
+ r << if tag.first.match('canonical')
1157
+ has_canonical = true
1158
+ dc_get_link_canonical_tag(tag.last)
1159
+ else
1160
+ %(<meta #{tag.first} content="#{tag.last}">\n )
1161
+ end
1159
1162
  end if @meta_tags
1163
+ html << dc_get_link_canonical_tag(@page&.canonical_link) unless has_canonical
1160
1164
  html.html_safe
1161
1165
  end
1162
1166
 
1167
+ ########################################################################
1168
+ # helper for setting canonical link on the page
1169
+ #######################################################################
1170
+ def dc_get_link_canonical_tag(href = nil)
1171
+ return %(<link rel="canonical" href="#{request.url}">\n) if href.blank?
1172
+
1173
+ unless href.match(/^http/i)
1174
+ uri = URI.parse(request.url)
1175
+ href = "#{uri.scheme}://#{uri.host}/#{href.delete_prefix('/')}"
1176
+ end
1177
+ %(<link rel="canonical" href="#{href}">\n)
1178
+ end
1179
+
1163
1180
  ########################################################################
1164
1181
  # Will add a meta tag to internal hash structure. If meta tag already exists it
1165
1182
  # will be overwritten.
@@ -1170,6 +1187,7 @@ end
1170
1187
  ########################################################################
1171
1188
  def dc_add_meta_tag(type, name, content)
1172
1189
  return if content.blank?
1190
+
1173
1191
  @meta_tags ||= {}
1174
1192
  key = "#{type}=\"#{name}\""
1175
1193
  @meta_tags[key] = content
@@ -1187,8 +1205,8 @@ end
1187
1205
  # Returns:
1188
1206
  # [String] alt="image-tag"
1189
1207
  #######################################################################
1190
- def dc_img_alt_tag(file_name, text=nil)
1191
- " alt=\"#{dc_img_alt(file_name, text)}\" ".html_safe
1208
+ def dc_img_alt_tag(file_name, text = nil)
1209
+ %( alt="#{dc_img_alt(file_name, text)}" ).html_safe
1192
1210
  end
1193
1211
 
1194
1212
  #######################################################################
@@ -1203,15 +1221,19 @@ end
1203
1221
  # Returns:
1204
1222
  # [String] alt_image_name
1205
1223
  #######################################################################
1206
- def dc_img_alt(file_name, text=nil)
1207
- return text unless text.blank?
1224
+ def dc_img_alt(file_name, text = nil)
1225
+ return text if text.present?
1226
+
1208
1227
  name = File.basename(file_name.to_s)
1209
- name[0,name.index('.')].downcase rescue name
1228
+ name[0, name.index('.')].downcase rescue name
1210
1229
  end
1211
1230
 
1212
1231
  private
1213
1232
 
1214
- # will cache dc_user_can_view response
1233
+ ########################################################################
1234
+ # To cache localy dc_user_can_view response for a single call. It has large gains on sites
1235
+ # with large menus.
1236
+ ########################################################################
1215
1237
  def cache_add(id, can_view, msg)
1216
1238
  @can_view_cache[id] = [can_view, msg]
1217
1239
  end
@@ -0,0 +1,127 @@
1
+ #--
2
+ # Copyright (c) 2022+ 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
+ ####################################################################
26
+ # Helpers needed by some form fields
27
+ ####################################################################
28
+ module DcImageHelper
29
+
30
+ ############################################################################
31
+ # Will return code for previewing image on top of dc_image entry form
32
+ ############################################################################
33
+ def dc_image_preview(document, *parms)
34
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{document.first_available_image}"
35
+ %(<span class="dc-image-preview dc-image-preview-1"><img src="#{src}"></img></span>).html_safe
36
+ end
37
+
38
+ ############################################################################
39
+ # Will return code for previewing resized images on dc_image entry form
40
+ ############################################################################
41
+ def dc_image_preview_resized(document, yaml, ignore)
42
+ size = yaml['name'].last
43
+ return '' if document["size_#{size}"].blank?
44
+
45
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{document.id}-#{size}.#{document.img_type}?#{Time.now.to_i}"
46
+ %(<span class="dc-image-preview"><img src="#{src}"></img></span><div id="dc-image-preview"></div>).html_safe
47
+ end
48
+
49
+ ############################################################################
50
+ # Will return choices for preset image sizes
51
+ ############################################################################
52
+ def dc_image_choices_for_image_size
53
+ sizes = dc_get_site.params.dig('dc_image', 'sizes')
54
+ return ['300x200'] if sizes.blank?
55
+
56
+ sizes.split(",").map(&:strip)
57
+ end
58
+
59
+ ############################################################################
60
+ # Will return code for invoking dc_image_search form to select image select on a DRG Form.
61
+ #
62
+ # @param [String] field_name : Field name to which selected image value will be saved.
63
+ ###########################################################################
64
+ def dc_image_invoke(field_name)
65
+ return '' unless dc_get_site.params.dig('dc_image', 'location')
66
+
67
+ url = url_for(controller: :cmsedit, form_name: :dc_image_search, table: :dc_image, field_name: field_name)
68
+ %(<span class="dc-window-open" data-url="#{url}" title="#{t('drgcms.dc_image.invoke')}">#{mi_icon('image-o')}</span>).html_safe
69
+ end
70
+
71
+ ############################################################################
72
+ # Will return code for previewing image on top of dc_image entry form
73
+ ############################################################################
74
+ def first_dc_image(document, *parms)
75
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{document.first_available_image}"
76
+ %(<span class="dc-image-preview"><img src="#{src}"></img></span><span id="dc-image-preview">).html_safe
77
+ end
78
+
79
+ ######################################################################
80
+ # Will format qry result as html code for selecting image
81
+ ######################################################################
82
+ def select_links_for_dc_image(doc, *parms)
83
+ %w[o s m l].inject('') { | r,size| r << dc_image_link_for_select(doc, size) }.html_safe
84
+ end
85
+
86
+ ######################################################################
87
+ # Will return HTML code for selecting image
88
+ ######################################################################
89
+ def dc_image_link_for_select(doc, what)
90
+ field = "size_#{what}"
91
+ value = doc.send(field)
92
+ return '' if value.blank?
93
+
94
+ value = value.split(/\+/).first
95
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{doc.id}-#{what}.#{doc.img_type}"
96
+ %(
97
+ <div class="img-link"><div>
98
+ #{value}<br>
99
+ <i class="mi-o mi-preview" onclick="dc_image_preview('#{src}');" title="#{t('drgcms.dc_image.preview')}"></i>
100
+ <i class="mi-o mi-check_circle" onclick="dc_image_select('#{src}');" title="#{t('drgcms.dc_image.select')}"></i>
101
+ </div></div>)
102
+ end
103
+
104
+ ######################################################################
105
+ # Will return image file for requested size.
106
+ #
107
+ # @param [String] file_name : Image file name
108
+ # @param [String] size : Preferred image size
109
+ #
110
+ # @return [String] : Image file name if requested size is found. Otherwise first available image.
111
+ ######################################################################
112
+ def dc_image_get_by_size(file_name, size)
113
+ id = file_name[file_name.rindex('/') + 1, 24]
114
+ return 'error: ID not valid' unless BSON::ObjectId.legal?(id)
115
+
116
+ image = DcImage.find(id)
117
+ return 'error: ID not found' unless image
118
+
119
+ what = %w[o s m l].inject('l') do |r, e|
120
+ field_name = "size_#{e}".to_sym
121
+ break e if doc.send(field_name) == size
122
+ e
123
+ end
124
+ "/#{dc_get_site.params.dig('dc_image', 'location')}/#{doc.id}-#{what}.#{doc.img_type}"
125
+ end
126
+
127
+ end
@@ -52,7 +52,7 @@ after_destroy :cache_clear
52
52
  def self.values_for_permissions
53
53
  key = 'helpers.label.dc_policy_rule.choices4_permission'
54
54
  c = I18n.t(key)
55
- c = I18n.t(key, locale: 'en') if c.class == Hash or c.match( 'translation missing' )
55
+ c = I18n.t(key, locale: 'en') if c.class == Hash || c.match(/translation missing/i)
56
56
  c.split(',').inject([]) { |r,e| r << (ar = e.split(':'); [ar.first, ar.last.to_i]) }
57
57
  end
58
58
 
@@ -80,7 +80,7 @@ index group: 1
80
80
  validates_length_of :username, minimum: 4
81
81
  validates :username, uniqueness: true
82
82
  validates :email, uniqueness: true
83
- validate :do_validate
83
+ validate :additional_validates
84
84
 
85
85
  before_save :do_before_save
86
86
  before_validation :do_before_validation
@@ -97,8 +97,16 @@ def has_role?(role_id)
97
97
  role = DcPolicyRole.get_role(role_id)
98
98
  role_id = role.id if role
99
99
  end
100
- role = self.dc_user_roles.where(dc_policy_role_id: role_id).first
101
- (role && role.active)
100
+ role = dc_user_roles.find_by(dc_policy_role_id: role_id)
101
+
102
+ # user can be member of groups
103
+ if role.nil? && member.present?
104
+ member.each do |group_id|
105
+ role = DrgCms.cached(DcUser, group_id).dc_user_roles.find_by(dc_policy_role_id: role_id)
106
+ break if role
107
+ end
108
+ end
109
+ role&.active?
102
110
  end
103
111
 
104
112
  ##########################################################################
@@ -141,7 +149,7 @@ end
141
149
  # Will return list of available groups
142
150
  ##########################################################################
143
151
  def self.groups_for_select
144
- where(group: true, active: true).order_by(name: 1).inject([]) { |r, e| r << [e.name, e.id] }
152
+ where(group: true, active: true).order_by(name: 1).map { [_1.name, _1.id] }
145
153
  end
146
154
 
147
155
  private
@@ -169,7 +177,7 @@ end
169
177
  ##########################################################################
170
178
  # Perform some additional validations
171
179
  ##########################################################################
172
- def do_validate
180
+ def additional_validates
173
181
  if group && member.present?
174
182
  errors.add('member', I18n.t('errors.messages.present'))
175
183
  end
@@ -94,7 +94,7 @@ def self.choices4(key, site = nil, locale = nil)
94
94
  end
95
95
  # Error if empty
96
96
  result = [[I18n.t('drgcms.error'),I18n.t('drgcms.error')]] if result.size == 0
97
- result
97
+ result.sort_alphabetical_by(&:first)
98
98
  end
99
99
 
100
100
  end
@@ -63,6 +63,16 @@ validates :name, presence: true
63
63
 
64
64
  before_destroy :can_destroy?
65
65
 
66
+ after_save :cache_clear
67
+ after_destroy :cache_clear
68
+
69
+ ####################################################################
70
+ # Clear cache if cache is configured
71
+ ####################################################################
72
+ def cache_clear
73
+ DrgCms.cache_clear(:dc_category)
74
+ end
75
+
66
76
  private
67
77
 
68
78
  #########################################################################
@@ -88,6 +98,8 @@ def self.values_for_parent(site_id = nil) #:nodoc:
88
98
  parent = v.parent
89
99
  until parent.nil?
90
100
  doc = find(parent)
101
+ break if doc.nil?
102
+
91
103
  name = doc.name + ' / ' + name
92
104
  parent = doc.parent
93
105
  end
@@ -124,10 +124,11 @@ end
124
124
  # have site assigned will be selected. Too much designs to select often confuses
125
125
  # end user.
126
126
  ########################################################################
127
- def self.choices4_design(site=nil)
128
- list = site.nil? ? where(active: true) : where(active: true).in(site_id: [nil,site.id]).to_a
129
- list.sort! { |w1, w2| w1.description.casecmp(w2.description) }
130
- list.inject([]) { |r, design| r << [ design.description, design._id] }
127
+ def self.choices4_design(site)
128
+ (site.blank? ? where(active: true) : where(:site_id.in => [nil, BSON::ObjectId.from_string(site) ], active: true))
129
+ .only(:id, :description)
130
+ .order_by(description: 1)
131
+ .map { |design| [design.description, design.id] }
131
132
  end
132
133
 
133
134
  end