biovision-base 0.17.180619 → 0.19.180703.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/biovision/base/icons/back.svg +18 -27
  3. data/app/assets/images/biovision/base/icons/create.svg +19 -1
  4. data/app/assets/images/biovision/base/icons/destroy.svg +8 -2
  5. data/app/assets/images/biovision/base/icons/gear.svg +9 -2
  6. data/app/assets/images/biovision/base/icons/lock-closed.svg +12 -1
  7. data/app/assets/images/biovision/base/icons/lock-open.svg +12 -1
  8. data/app/assets/images/biovision/base/icons/notice.svg +9 -1
  9. data/app/assets/images/biovision/base/icons/return.svg +25 -1
  10. data/app/assets/images/biovision/base/icons/warning.svg +31 -42
  11. data/app/assets/images/biovision/base/icons/world.svg +9 -2
  12. data/app/assets/images/biovision/base/placeholders/16x9.svg +5 -0
  13. data/app/assets/images/biovision/base/placeholders/3x2.svg +5 -0
  14. data/app/assets/javascripts/biovision/base/biovision.js +75 -17
  15. data/app/assets/stylesheets/biovision/base/admin.scss +1 -0
  16. data/app/assets/stylesheets/biovision/base/biovision.scss +10 -0
  17. data/app/controllers/admin/editable_blocks_controller.rb +27 -0
  18. data/app/controllers/admin/editable_pages_controller.rb +1 -1
  19. data/app/controllers/admin/link_block_items_controller.rb +23 -0
  20. data/app/controllers/admin/link_blocks_controller.rb +27 -0
  21. data/app/controllers/admin/privileges_controller.rb +0 -1
  22. data/app/controllers/concerns/removable_image.rb +33 -0
  23. data/app/controllers/editable_blocks_controller.rb +64 -0
  24. data/app/controllers/editable_pages_controller.rb +1 -1
  25. data/app/controllers/feedback_requests_controller.rb +1 -0
  26. data/app/controllers/link_block_items_controller.rb +68 -0
  27. data/app/controllers/link_blocks_controller.rb +64 -0
  28. data/app/helpers/editable_pages_helper.rb +19 -0
  29. data/app/helpers/link_blocks_helper.rb +18 -0
  30. data/app/models/editable_block.rb +49 -0
  31. data/app/models/link_block.rb +43 -0
  32. data/app/models/link_block_item.rb +81 -0
  33. data/app/models/privilege.rb +10 -2
  34. data/app/models/privilege_group.rb +5 -0
  35. data/app/models/user.rb +4 -0
  36. data/app/models/user_privilege.rb +8 -3
  37. data/app/services/user_profile_handler.rb +2 -2
  38. data/app/uploaders/editable_page_image_uploader.rb +5 -1
  39. data/app/uploaders/link_block_image_uploader.rb +17 -0
  40. data/app/views/admin/editable_blocks/_nav_item.html.erb +6 -0
  41. data/app/views/admin/editable_blocks/entity/_in_list.html.erb +29 -0
  42. data/app/views/admin/editable_blocks/index.html.erb +14 -0
  43. data/app/views/admin/editable_blocks/show.html.erb +72 -0
  44. data/app/views/admin/index/_biovision_base.html.erb +2 -1
  45. data/app/views/admin/index/dashboard/_biovision_links.html.erb +11 -0
  46. data/app/views/admin/index/dashboard/_editorial.html.erb +5 -6
  47. data/app/views/admin/link_block_items/entity/_in_list.html.erb +39 -0
  48. data/app/views/admin/link_block_items/show.html.erb +74 -0
  49. data/app/views/admin/link_blocks/_nav_item.html.erb +6 -0
  50. data/app/views/admin/link_blocks/entity/_in_list.html.erb +26 -0
  51. data/app/views/admin/link_blocks/entity/_items.html.erb +23 -0
  52. data/app/views/admin/link_blocks/index.html.erb +14 -0
  53. data/app/views/admin/link_blocks/show.html.erb +57 -0
  54. data/app/views/admin/metrics/show.html.erb +1 -1
  55. data/app/views/admin/privileges/entity/_groups.html.erb +1 -1
  56. data/app/views/admin/privileges/entity/_in_list.html.erb +8 -1
  57. data/app/views/admin/users/entity/_in_list.html.erb +3 -0
  58. data/app/views/admin/users/privileges.html.erb +3 -3
  59. data/app/views/editable_blocks/_entity.html.erb +36 -0
  60. data/app/views/editable_blocks/_form.html.erb +171 -0
  61. data/app/views/editable_blocks/edit.html.erb +17 -0
  62. data/app/views/editable_blocks/new.html.erb +15 -0
  63. data/app/views/link_block_items/_form.html.erb +158 -0
  64. data/app/views/link_block_items/_list.html.erb +32 -0
  65. data/app/views/link_block_items/edit.html.erb +18 -0
  66. data/app/views/link_block_items/new.html.erb +18 -0
  67. data/app/views/link_blocks/_entity.html.erb +34 -0
  68. data/app/views/link_blocks/_form.html.erb +97 -0
  69. data/app/views/link_blocks/edit.html.erb +17 -0
  70. data/app/views/link_blocks/new.html.erb +15 -0
  71. data/app/views/my/index/index/_dashboard.html.erb +1 -3
  72. data/app/views/privileges/_form.html.erb +2 -7
  73. data/app/views/shared/_counters.html.erb +3 -0
  74. data/app/views/shared/forms/_entity_flags.html.erb +5 -1
  75. data/app/views/shared/forms/_image_remover.html.erb +13 -0
  76. data/config/locales/common-en.yml +1 -0
  77. data/config/locales/common-ru.yml +1 -0
  78. data/config/locales/editable-pages-ru.yml +50 -0
  79. data/config/locales/links-ru.yml +95 -0
  80. data/config/locales/users-en.yml +1 -0
  81. data/config/locales/users-ru.yml +1 -0
  82. data/config/routes.rb +35 -0
  83. data/db/migrate/20170302000101_create_privileges.rb +1 -0
  84. data/db/migrate/20180622140000_create_link_blocks.rb +29 -0
  85. data/db/migrate/20180622140001_create_link_block_items.rb +23 -0
  86. data/db/migrate/20180627190000_create_editable_blocks.rb +39 -0
  87. data/db/migrate/20180703111111_add_fields_to_editable_blocks.rb +14 -0
  88. data/lib/biovision/base/version.rb +1 -1
  89. metadata +46 -2
@@ -0,0 +1,23 @@
1
+ class Admin::LinkBlockItemsController < AdminController
2
+ include ToggleableEntity
3
+ include EntityPriority
4
+
5
+ before_action :set_entity
6
+
7
+ # get /admin/link_block_items/:id
8
+ def show
9
+ end
10
+
11
+ private
12
+
13
+ def restrict_access
14
+ require_privilege :content_manager
15
+ end
16
+
17
+ def set_entity
18
+ @entity = LinkBlockItem.find_by(id: params[:id])
19
+ if @entity.nil?
20
+ handle_http_404("Cannot find link_block_item #{params[:id]}")
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ class Admin::LinkBlocksController < AdminController
2
+ include ToggleableEntity
3
+
4
+ before_action :set_entity, except: [:index]
5
+
6
+ # get /admin/link_blocks
7
+ def index
8
+ @collection = LinkBlock.list_for_administration
9
+ end
10
+
11
+ # get /admin/link_blocks/:id
12
+ def show
13
+ end
14
+
15
+ private
16
+
17
+ def restrict_access
18
+ require_privilege :content_manager
19
+ end
20
+
21
+ def set_entity
22
+ @entity = LinkBlock.find_by(id: params[:id])
23
+ if @entity.nil?
24
+ handle_http_404("Cannot find link_block #{params[:id]}")
25
+ end
26
+ end
27
+ end
@@ -4,7 +4,6 @@ class Admin::PrivilegesController < AdminController
4
4
  include ToggleableEntity
5
5
 
6
6
  before_action :set_entity, except: [:index]
7
- before_action :check_entity_lock, only: [:toggle]
8
7
 
9
8
  # get /admin/privileges
10
9
  def index
@@ -0,0 +1,33 @@
1
+ module RemovableImage
2
+ extend ActiveSupport::Concern
3
+
4
+ # Remove entity image when allowed
5
+ def destroy_image
6
+ if entity_image_is_locked?
7
+ render json: { errors: { locked: true } }, status: :forbidden
8
+ elsif entity_image_is_editable?
9
+ @entity.remove_image!
10
+ render json: { meta: { result: @entity.save } }
11
+ else
12
+ head :unauthorized
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def entity_image_is_editable?
19
+ if @entity.respond_to?(:editable_by?)
20
+ @entity.editable_by?(current_user)
21
+ else
22
+ true
23
+ end
24
+ end
25
+
26
+ def entity_image_is_locked?
27
+ if @entity.respond_to?(:locked?)
28
+ @entity.locked?
29
+ else
30
+ false
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,64 @@
1
+ class EditableBlocksController < AdminController
2
+ before_action :set_entity, only: [:edit, :update, :destroy]
3
+
4
+ # post /editable_blocks/check
5
+ def check
6
+ @entity = EditableBlock.instance_for_check(params[:entity_id], entity_parameters)
7
+
8
+ render 'shared/forms/check'
9
+ end
10
+
11
+ # get /editable_blocks/new
12
+ def new
13
+ @entity = EditableBlock.new
14
+ end
15
+
16
+ # post /editable_blocks
17
+ def create
18
+ @entity = EditableBlock.new(entity_parameters)
19
+ if @entity.save
20
+ form_processed_ok(admin_editable_block_path(id: @entity.id))
21
+ else
22
+ form_processed_with_error(:new)
23
+ end
24
+ end
25
+
26
+ # get /editable_blocks/:id/edit
27
+ def edit
28
+ end
29
+
30
+ # patch /editable_blocks/:id
31
+ def update
32
+ if @entity.update(entity_parameters)
33
+ flash[:notice] = t('editable_blocks.update.success')
34
+ form_processed_ok(admin_editable_block_path(id: @entity.id))
35
+ else
36
+ form_processed_with_error(:edit)
37
+ end
38
+ end
39
+
40
+ # delete /editable_blocks/:id
41
+ def destroy
42
+ if @entity.destroy
43
+ flash[:notice] = t('editable_blocks.destroy.success')
44
+ end
45
+ redirect_to(admin_editable_blocks_path)
46
+ end
47
+
48
+ protected
49
+
50
+ def restrict_access
51
+ require_privilege :content_manager
52
+ end
53
+
54
+ def set_entity
55
+ @entity = EditableBlock.find_by(id: params[:id])
56
+ if @entity.nil?
57
+ handle_http_404('Cannot find editable_block')
58
+ end
59
+ end
60
+
61
+ def entity_parameters
62
+ params.require(:editable_block).permit(EditableBlock.entity_parameters)
63
+ end
64
+ end
@@ -41,7 +41,7 @@ class EditablePagesController < AdminController
41
41
  protected
42
42
 
43
43
  def restrict_access
44
- require_privilege :chief_editor
44
+ require_privilege :content_manager
45
45
  end
46
46
 
47
47
  def set_entity
@@ -5,6 +5,7 @@ class FeedbackRequestsController < ApplicationController
5
5
  if @entity.save
6
6
  respond_to do |format|
7
7
  format.html { redirect_to root_path }
8
+ format.json { head :no_content }
8
9
  format.js
9
10
  end
10
11
 
@@ -0,0 +1,68 @@
1
+ class LinkBlockItemsController < AdminController
2
+ before_action :set_entity, only: [:edit, :update, :destroy]
3
+
4
+ # post /admin/link_blocks/check
5
+ def check
6
+ @entity = LinkBlockItem.instance_for_check(params[:entity_id], entity_parameters)
7
+
8
+ render 'shared/forms/check'
9
+ end
10
+
11
+ # get /link_block_items/new
12
+ def new
13
+ @entity = LinkBlockItem.new
14
+ end
15
+
16
+ # post /link_block_items
17
+ def create
18
+ @entity = LinkBlockItem.new(creation_parameters)
19
+ if @entity.save
20
+ form_processed_ok(admin_link_block_item_path(id: @entity.id))
21
+ else
22
+ form_processed_with_error(:new)
23
+ end
24
+ end
25
+
26
+ # get /link_block_items/:id/edit
27
+ def edit
28
+ end
29
+
30
+ # patch /link_block_items/:id
31
+ def update
32
+ if @entity.update(entity_parameters)
33
+ flash[:notice] = t('link_block_items.update.success')
34
+ form_processed_ok(admin_link_block_item_path(id: @entity.id))
35
+ else
36
+ form_processed_with_error(:edit)
37
+ end
38
+ end
39
+
40
+ # delete /link_block_items/:id
41
+ def destroy
42
+ if @entity.destroy
43
+ flash[:notice] = t('link_block_items.destroy.success')
44
+ end
45
+ redirect_to(admin_link_block_items_path)
46
+ end
47
+
48
+ protected
49
+
50
+ def restrict_access
51
+ require_privilege :content_manager
52
+ end
53
+
54
+ def set_entity
55
+ @entity = LinkBlockItem.find_by(id: params[:id])
56
+ if @entity.nil?
57
+ handle_http_404('Cannot find link_block_item')
58
+ end
59
+ end
60
+
61
+ def entity_parameters
62
+ params.require(:link_block_item).permit(LinkBlockItem.entity_parameters)
63
+ end
64
+
65
+ def creation_parameters
66
+ params.require(:link_block_item).permit(LinkBlockItem.creation_parameters)
67
+ end
68
+ end
@@ -0,0 +1,64 @@
1
+ class LinkBlocksController < AdminController
2
+ before_action :set_entity, only: [:edit, :update, :destroy]
3
+
4
+ # post /link_blocks/check
5
+ def check
6
+ @entity = LinkBlock.instance_for_check(params[:entity_id], entity_parameters)
7
+
8
+ render 'shared/forms/check'
9
+ end
10
+
11
+ # get /link_blocks/new
12
+ def new
13
+ @entity = LinkBlock.new
14
+ end
15
+
16
+ # post /link_blocks
17
+ def create
18
+ @entity = LinkBlock.new(entity_parameters)
19
+ if @entity.save
20
+ form_processed_ok(admin_link_block_path(id: @entity.id))
21
+ else
22
+ form_processed_with_error(:new)
23
+ end
24
+ end
25
+
26
+ # get /link_blocks/:id/edit
27
+ def edit
28
+ end
29
+
30
+ # patch /link_blocks/:id
31
+ def update
32
+ if @entity.update(entity_parameters)
33
+ flash[:notice] = t('link_blocks.update.success')
34
+ form_processed_ok(admin_link_block_path(id: @entity.id))
35
+ else
36
+ form_processed_with_error(:edit)
37
+ end
38
+ end
39
+
40
+ # delete /link_blocks/:id
41
+ def destroy
42
+ if @entity.destroy
43
+ flash[:notice] = t('link_blocks.destroy.success')
44
+ end
45
+ redirect_to(admin_link_blocks_path)
46
+ end
47
+
48
+ protected
49
+
50
+ def restrict_access
51
+ require_privilege :content_manager
52
+ end
53
+
54
+ def set_entity
55
+ @entity = LinkBlock.find_by(id: params[:id])
56
+ if @entity.nil?
57
+ handle_http_404('Cannot find link_block')
58
+ end
59
+ end
60
+
61
+ def entity_parameters
62
+ params.require(:link_block).permit(LinkBlock.entity_parameters)
63
+ end
64
+ end
@@ -4,6 +4,11 @@ module EditablePagesHelper
4
4
  link_to(entity.name, admin_editable_page_path(id: entity.id))
5
5
  end
6
6
 
7
+ # @param [EditableBlock] entity
8
+ def admin_editable_block_link(entity)
9
+ link_to(entity.name, admin_editable_block_path(id: entity.id))
10
+ end
11
+
7
12
  # @param [EditablePage] entity
8
13
  def editable_page_image_preview(entity)
9
14
  return '' if entity.image.blank?
@@ -17,4 +22,18 @@ module EditablePagesHelper
17
22
  versions = "#{entity.image.medium_2x.url} 2x"
18
23
  image_tag(entity.image.medium.url, alt: entity.name, srcset: versions)
19
24
  end
25
+
26
+ # @param [EditableBlock] entity
27
+ def editable_block_image_preview(entity)
28
+ return '' if entity.image.blank?
29
+ versions = "#{entity.image.preview_2x.url} 2x"
30
+ image_tag(entity.image.preview.url, alt: entity.name, srcset: versions)
31
+ end
32
+
33
+ # @param [EditableBlock] entity
34
+ def editable_block_image_medium(entity)
35
+ return '' if entity.image.blank?
36
+ versions = "#{entity.image.medium_2x.url} 2x"
37
+ image_tag(entity.image.medium.url, alt: entity.name, srcset: versions)
38
+ end
20
39
  end
@@ -0,0 +1,18 @@
1
+ module LinkBlocksHelper
2
+ # @param [LinkBlock] entity
3
+ def admin_link_block_link(entity)
4
+ text = entity.title.blank? ? entity.slug : entity.title
5
+ link_to(text, admin_link_block_path(id: entity.id))
6
+ end
7
+
8
+ # @param [LinkBlockItem] entity
9
+ def admin_link_block_item_link(entity)
10
+ link_to(entity.text_for_link, admin_link_block_item_path(id: entity.id))
11
+ end
12
+
13
+ # @param [LinkBlock] entity
14
+ def link_block_image(entity)
15
+ return '' if entity.image.blank?
16
+ image_tag(entity.image.url, alt: entity.image_alt_text)
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ class EditableBlock < ApplicationRecord
2
+ include Checkable
3
+ include Toggleable
4
+
5
+ DESCRIPTION_LIMIT = 250
6
+ NAME_LIMIT = 50
7
+ SLUG_LIMIT = 50
8
+ SLUG_PATTERN = /\A[a-z][-_a-z0-9]*[a-z]\z/i
9
+ SLUG_PATTERN_HTML = '^[a-zA-Z][-_a-zA_Z0-9]*[a-zA-Z]$'
10
+ TITLE_LIMIT = 255
11
+ TEXT_LIMIT = 5000
12
+
13
+ toggleable :visible, :raw_output
14
+
15
+ mount_uploader :image, EditablePageImageUploader
16
+
17
+ belongs_to :language, optional: true
18
+
19
+ validates_presence_of :name
20
+ validates_uniqueness_of :slug, scope: [:language_id]
21
+ validates_format_of :slug, with: SLUG_PATTERN
22
+ validates_length_of :slug, maximum: SLUG_LIMIT
23
+ validates_length_of :name, maximum: NAME_LIMIT
24
+ validates_length_of :title, maximum: TITLE_LIMIT
25
+ validates_length_of :lead, maximum: TEXT_LIMIT
26
+ validates_length_of :body, maximum: TEXT_LIMIT
27
+ validates_length_of :footer, maximum: TEXT_LIMIT
28
+
29
+ scope :ordered_by_slug, -> { order('slug asc, language_id asc nulls first') }
30
+ scope :visible, -> { where(visible: true) }
31
+ scope :list_for_administration, -> { ordered_by_slug }
32
+
33
+ # @param [String] slug
34
+ # @param [String] language_code
35
+ def self.localized_block(slug, language_code)
36
+ language = Language.find_by(code: language_code)
37
+ criteria = { visible: true, slug: slug }
38
+ find_by(criteria.merge(language: language)) || find_by(criteria)
39
+ end
40
+
41
+ def self.entity_parameters
42
+ %i[body description footer image language_id lead name raw_output slug title visible]
43
+ end
44
+
45
+ # @param [User] user
46
+ def editable_by?(user)
47
+ UserPrivilege.user_has_privilege?(user, :content_manager)
48
+ end
49
+ end
@@ -0,0 +1,43 @@
1
+ class LinkBlock < ApplicationRecord
2
+ include Checkable
3
+ include Toggleable
4
+
5
+ toggleable :visible
6
+
7
+ SLUG_LIMIT = 50
8
+ SLUG_PATTERN = /\A[a-z][-_a-z0-9]*[a-z]\z/i
9
+ SLUG_PATTERN_HTML = '^[a-zA-Z][-_a-zA_Z0-9]*[a-zA-Z]$'
10
+ TITLE_LIMIT = 255
11
+ TEXT_LIMIT = 5000
12
+
13
+ belongs_to :language, optional: true
14
+ has_many :link_block_items, dependent: :destroy
15
+
16
+ validates_uniqueness_of :slug, scope: [:language_id]
17
+ validates_format_of :slug, with: SLUG_PATTERN
18
+ validates_length_of :slug, maximum: SLUG_LIMIT
19
+ validates_length_of :title, maximum: TITLE_LIMIT
20
+ validates_length_of :lead, maximum: TEXT_LIMIT
21
+ validates_length_of :footer_text, maximum: TEXT_LIMIT
22
+
23
+ scope :ordered_by_slug, -> { order('slug asc, language_id asc nulls first') }
24
+ scope :visible, -> { where(visible: true) }
25
+ scope :list_for_administration, -> { ordered_by_slug }
26
+
27
+ # @param [String] slug
28
+ # @param [String] language_code
29
+ def self.localized_block(slug, language_code)
30
+ language = Language.find_by(code: language_code)
31
+ criteria = { visible: true, slug: slug }
32
+ find_by(criteria.merge(language: language)) || find_by(criteria)
33
+ end
34
+
35
+ def self.entity_parameters
36
+ %i(footer_text language_id lead slug title visible)
37
+ end
38
+
39
+ # @param [User] user
40
+ def editable_by?(user)
41
+ UserPrivilege.user_has_privilege?(user, :content_manager)
42
+ end
43
+ end
@@ -0,0 +1,81 @@
1
+ class LinkBlockItem < ApplicationRecord
2
+ include Checkable
3
+ include Toggleable
4
+
5
+ BUTTON_TEXT_LIMIT = 50
6
+ META_LIMIT = 255
7
+ PRIORITY_RANGE = (1..32767)
8
+ SLUG_LIMIT = 50
9
+ SLUG_PATTERN = /\A[a-z][-_a-z0-9]*[a-z]\z/i
10
+ SLUG_PATTERN_HTML = '^[a-zA-Z][-_a-zA_Z0-9]*[a-zA-Z]$'
11
+ TITLE_LIMIT = 255
12
+ TEXT_LIMIT = 5000
13
+ URL_LIMIT = 255
14
+
15
+ toggleable :visible
16
+
17
+ mount_uploader :image, LinkBlockImageUploader
18
+
19
+ belongs_to :link_block
20
+
21
+ after_initialize :set_next_priority
22
+ before_validation { self.slug = nil if slug.blank? }
23
+ before_validation { self.slug = slug.strip unless slug.nil? }
24
+ before_validation :normalize_priority
25
+
26
+ validates_format_of :slug, with: SLUG_PATTERN, allow_nil: true
27
+ validates_length_of :body, maximum: TEXT_LIMIT
28
+ validates_length_of :button_text, maximum: BUTTON_TEXT_LIMIT
29
+ validates_length_of :button_url, maximum: URL_LIMIT
30
+ validates_length_of :image_alt_text, maximum: META_LIMIT
31
+ validates_length_of :slug, maximum: SLUG_LIMIT
32
+ validates_length_of :title, maximum: TITLE_LIMIT
33
+
34
+ scope :ordered_by_priority, -> { order('priority asc, slug asc') }
35
+ scope :siblings, -> (link_block_id) { where(link_block_id: link_block_id) }
36
+ scope :visible, -> { where(visible: true) }
37
+ scope :list_for_administration, -> { ordered_by_priority }
38
+ scope :list_for_visitors, -> { visible.ordered_by_priority }
39
+
40
+ def self.entity_parameters
41
+ %i(body button_text button_url image image_alt_text priority slug title visible)
42
+ end
43
+
44
+ def self.creation_parameters
45
+ entity_parameters + %i(link_block_id)
46
+ end
47
+
48
+ def text_for_link
49
+ if title.blank?
50
+ slug.blank? ? "#{link_block.slug}-#{priority}" : slug
51
+ else
52
+ title
53
+ end
54
+ end
55
+
56
+ # @param [Integer] delta
57
+ def change_priority(delta)
58
+ new_priority = priority + delta
59
+ criteria = { priority: new_priority }
60
+ adjacent = self.class.siblings(link_block_id).find_by(criteria)
61
+ if adjacent.is_a?(self.class) && (adjacent.id != id)
62
+ adjacent.update!(priority: priority)
63
+ end
64
+ update(priority: new_priority)
65
+
66
+ self.class.siblings(link_block_id).ordered_by_priority.map { |e| [e.id, e.priority] }.to_h
67
+ end
68
+
69
+ private
70
+
71
+ def set_next_priority
72
+ if id.nil? && priority == 1
73
+ self.priority = self.class.siblings(link_block_id).maximum(:priority).to_i + 1
74
+ end
75
+ end
76
+
77
+ def normalize_priority
78
+ self.priority = PRIORITY_RANGE.first if priority < PRIORITY_RANGE.first
79
+ self.priority = PRIORITY_RANGE.last if priority > PRIORITY_RANGE.last
80
+ end
81
+ end
@@ -34,8 +34,10 @@ class Privilege < ApplicationRecord
34
34
  scope :ordered_by_priority, -> { order('priority asc, name asc') }
35
35
  scope :ordered_by_name, -> { order('name asc, slug asc') }
36
36
  scope :visible, -> { where(visible: true, deleted: false) }
37
+ scope :administrative, -> { where(administrative: true) }
37
38
  scope :for_tree, ->(parent_id = nil) { where(parent_id: parent_id).ordered_by_priority }
38
39
  scope :siblings, ->(item) { where(parent_id: item.parent_id) }
40
+ scope :list_for_administration, -> { ordered_by_name }
39
41
 
40
42
  def self.page_for_administration
41
43
  ordered_by_name
@@ -54,11 +56,16 @@ class Privilege < ApplicationRecord
54
56
  (parents.map(&:name) + [name]).join ' / '
55
57
  end
56
58
 
57
- # @return [Array<Integer>]
59
+ # @deprecated use #subbranch_ids
58
60
  def ids
59
61
  [id] + children_cache
60
62
  end
61
63
 
64
+ # @return [Array<Integer>]
65
+ def subbranch_ids
66
+ [id] + children_cache
67
+ end
68
+
62
69
  # @return [Array<Integer>]
63
70
  def branch_ids
64
71
  parents_cache.split(',').map(&:to_i).reject { |i| i < 1 }.uniq + [id]
@@ -124,7 +131,8 @@ class Privilege < ApplicationRecord
124
131
  # @param [Integer] delta
125
132
  def change_priority(delta)
126
133
  new_priority = priority + delta
127
- adjacent = self.class.siblings(self).find_by(priority: new_priority)
134
+ criteria = { priority: new_priority }
135
+ adjacent = self.class.siblings(self).find_by(criteria)
128
136
  if adjacent.is_a?(self.class) && (adjacent.id != id)
129
137
  adjacent.update!(priority: priority)
130
138
  end
@@ -30,6 +30,11 @@ class PrivilegeGroup < ApplicationRecord
30
30
  %i(name slug description)
31
31
  end
32
32
 
33
+ # @param [String] slug
34
+ def self.users(slug)
35
+ User.with_privilege_ids(ids(slug)).ordered_by_screen_name
36
+ end
37
+
33
38
  # @param [Privilege] privilege
34
39
  def has_privilege?(privilege)
35
40
  privilege_group_privileges.exists?(privilege: privilege)
data/app/models/user.rb CHANGED
@@ -39,6 +39,8 @@ class User < ApplicationRecord
39
39
  before_save :normalize_slug
40
40
  before_save :prepare_search_string
41
41
 
42
+ before_validation { self.email = nil if email.blank? }
43
+
42
44
  validates_acceptance_of :consent
43
45
  validates_presence_of :screen_name
44
46
  validates_format_of :screen_name, with: SCREEN_NAME_PATTERN, if: :native_slug?
@@ -52,6 +54,8 @@ class User < ApplicationRecord
52
54
  validates_length_of :notice, maximum: NOTICE_LIMIT
53
55
 
54
56
  scope :with_privilege, ->(privilege) { joins(:user_privileges).where(user_privileges: { privilege_id: privilege.branch_ids }) }
57
+ scope :with_privilege_ids, -> (privilege_ids) { joins(:user_privileges).where(user_privileges: { privilege_id: privilege_ids }) }
58
+ scope :ordered_by_screen_name, -> { order('screen_name asc') }
55
59
  scope :bots, ->(flag) { where(bot: flag.to_i > 0) unless flag.blank? }
56
60
  scope :email_like, ->(val) { where('email ilike ?', "%#{val}%") unless val.blank? }
57
61
  scope :with_email, ->(email) { where('lower(email) = lower(?)', email) }
@@ -11,7 +11,7 @@ class UserPrivilege < ApplicationRecord
11
11
  def self.ids(user)
12
12
  privileges = user&.privileges
13
13
  return [] if privileges.blank?
14
- privileges.map(&:ids).flatten.uniq
14
+ privileges.map(&:subbranch_ids).flatten.uniq
15
15
  end
16
16
 
17
17
  # @param [User] user
@@ -25,10 +25,15 @@ class UserPrivilege < ApplicationRecord
25
25
  end
26
26
 
27
27
  # @param [User] user
28
- def self.user_has_any_privilege?(user)
28
+ # @param [TrueClass|FalseClass] administrative
29
+ def self.user_has_any_privilege?(user, administrative = true)
29
30
  return false if user.nil?
30
31
  return true if user.super_user?
31
- exists?(user: user)
32
+ criteria = { user: user }
33
+ if administrative
34
+ criteria[:privilege_id] = Privilege.administrative.pluck(:id)
35
+ end
36
+ exists?(criteria)
32
37
  end
33
38
 
34
39
  # @param [User] user
@@ -2,13 +2,13 @@ class UserProfileHandler
2
2
  GENDERS = { 0 => 'female', 1 => 'male' }
3
3
 
4
4
  def self.allowed_parameters
5
- %w(gender name patronymic surname)
5
+ %w(gender name patronymic surname about)
6
6
  end
7
7
 
8
8
  # @param [Hash] input
9
9
  def self.clean_parameters(input)
10
10
  if input.key?('gender')
11
- gender_key = input['gender'].to_i
11
+ gender_key = input['gender'].blank? ? nil : input['gender'].to_i
12
12
  gender = GENDERS.key?(gender_key) ? gender_key : nil
13
13
  else
14
14
  gender = nil
@@ -14,7 +14,11 @@ class EditablePageImageUploader < CarrierWave::Uploader::Base
14
14
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
15
15
  end
16
16
 
17
- version :medium_2x do
17
+ version :large do
18
+ resize_to_fit 1920, 1920
19
+ end
20
+
21
+ version :medium_2x, from_version: :large do
18
22
  resize_to_fit 1280, 1280
19
23
  end
20
24
 
@@ -0,0 +1,17 @@
1
+ class LinkBlockImageUploader < CarrierWave::Uploader::Base
2
+ # Choose what kind of storage to use for this uploader:
3
+ storage :file
4
+ # storage :fog
5
+
6
+ # Override the directory where uploaded files will be stored.
7
+ # This is a sensible default for uploaders that are meant to be mounted:
8
+ def store_dir
9
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
10
+ end
11
+
12
+ # Add a white list of extensions which are allowed to be uploaded.
13
+ # For images you might use something like this:
14
+ def extension_whitelist
15
+ %w(jpg jpeg png svg)
16
+ end
17
+ end