Browse Source

Fixes #3997 - KB: granular permissions misconfiguration is allowed by UI

Mantas 3 years ago
parent
commit
4a71dc4eeb

+ 2 - 2
app/assets/javascripts/app/controllers/knowledge_base/agent_controller.coffee

@@ -358,10 +358,10 @@ class App.KnowledgeBaseAgentController extends App.Controller
       parentController: @
     )
 
-  access: (params) ->
+  access: (params) =>
     @constructor
       .pickObjectUsing(params, @)
-      ?.access()
+      ?.access(@kb_locale())
 
   isEditor: ->
     @access(@lastParams) == 'editor'

+ 14 - 1
app/assets/javascripts/app/controllers/knowledge_base/permissions_dialog.coffee

@@ -54,6 +54,19 @@ class App.KnowledgeBasePermissionsDialog extends App.ControllerModal
     elem.accessLevel = role_name
     elem.limit = _.findWhere(data.inherited, { role_id: elem.id })?.access
 
+    if elem.limit?
+      elem.accessLevelIsDisabled = {
+        editor: elem.limit != 'editor'
+        reader: elem.limit == 'none'
+        none:   false
+      }
+    else
+      elem.accessLevelIsDisabled = {
+        editor: elem.accessLevel != 'editor'
+        reader: false
+        none:   false
+      }
+
   load: =>
     @ajax(
       id:          'knowledge_base_permissions_get'
@@ -68,7 +81,7 @@ class App.KnowledgeBasePermissionsDialog extends App.ControllerModal
     )
 
   toggleDisabled: (state) =>
-    @el.find('input, button').attr('disabled', state)
+    @el.find('input:not([data-permanently-disabled]), button').attr('disabled', state)
 
   onSubmit: (e) =>
     @clearAlerts()

+ 3 - 1
app/assets/javascripts/app/lib/mixins/knowledge_base_access.coffee

@@ -1,5 +1,5 @@
 InstanceMethods =
-  access: ->
+  access: (kb_locale) ->
     permission_reader = App.Permission.findByAttribute('name', 'knowledge_base.reader')
     permission_editor = App.Permission.findByAttribute('name', 'knowledge_base.editor')
 
@@ -20,6 +20,8 @@ InstanceMethods =
             return 'editor'
           when 'reader'
             access = 'reader'
+          when 'none'
+            access = 'reader' if kb_locale && @visiblePublicly(kb_locale)
       else if role = App.Role.find(role_id)
         if role.permission_ids.indexOf(permission_editor.id) > -1
           return 'editor'

+ 1 - 1
app/assets/javascripts/app/models/knowledge_base.coffee

@@ -77,7 +77,7 @@ class App.KnowledgeBase extends App.Model
     , initial
 
   visibleInternally: (kb_locale) ->
-    @active && @access() != 'none'
+    @active && @access(kb_locale) != 'none'
 
   visiblePublicly: (kb_locale) ->
     @active

+ 4 - 1
app/assets/javascripts/app/models/knowledge_base_answer.coffee

@@ -96,4 +96,7 @@ class App.KnowledgeBaseAnswer extends App.Model
     'Answer'
 
   visibleInternally: (kb_locale) =>
-    (@is_internally_published(kb_locale) && @access() != 'none') || @is_published(kb_locale)
+    (@is_internally_published(kb_locale) && @access(kb_locale) != 'none') || @is_published(kb_locale)
+
+  visiblePublicly: (kb_locale) =>
+    @is_published(kb_locale)

+ 0 - 2
app/assets/javascripts/app/models/knowledge_base_category.coffee

@@ -167,8 +167,6 @@ class App.KnowledgeBaseCategory extends App.Model
       'draft'
 
   visibleInternally: (kb_locale) =>
-    #return false if @access() == 'none'
-
     @findDeepAnswer( (record) ->
       record.is_internally_published(kb_locale)
     )?

+ 3 - 3
app/assets/javascripts/app/views/knowledge_base/permissions_dialog.jst.eco

@@ -18,9 +18,9 @@
             value="<%= key %>"
             name="<%= role.id %>"
             <% if @params[role.id] == key: %>checked<% end %>
-            <% if role.limit?: %>
-              <% if key == 'editor' && role.limit != 'editor': %>disabled<% end %>
-              <% if key == 'reader' && role.limit == 'none': %>disabled<% end %>
+            <% if role.accessLevelIsDisabled[key]: %>
+              disabled
+              data-permanently-disabled
             <% end %>
             />
           <%- @Icon('radio', 'icon-unchecked') %>

+ 4 - 2
app/controllers/application_controller/handles_errors.rb

@@ -84,8 +84,10 @@ module ApplicationController::HandlesErrors
       error: e.message
     }
 
-    if (message = e.try(:record)&.errors&.full_messages&.first)
-      data[:error_human] = message
+    if (base_error = e.try(:record)&.errors&.messages&.find { |key, _| key.match? %r{[\w+.]?base} }&.last&.last)
+      data[:error_human] = base_error
+    elsif (first_error = e.try(:record)&.errors&.full_messages&.first)
+      data[:error_human] = first_error
     elsif e.message.match?(%r{(already exists|duplicate key|duplicate entry)}i)
       data[:error_human] = __('Object already exists!')
     elsif e.message =~ %r{null value in column "(.+?)" violates not-null constraint}i || e.message =~ %r{Field '(.+?)' doesn't have a default value}i

+ 8 - 0
app/models/knowledge_base.rb

@@ -179,6 +179,14 @@ class KnowledgeBase < ApplicationModel
     KnowledgeBase::Permission.any?
   end
 
+  def public_content?(kb_locale = nil)
+    scope = answers.published
+
+    scope = scope.localed(kb_locale.system_locale) if kb_locale
+
+    scope.any?
+  end
+
   private
 
   def set_defaults

+ 21 - 1
app/models/knowledge_base/permission.rb

@@ -4,13 +4,33 @@ class KnowledgeBase::Permission < ApplicationModel
   belongs_to :permissionable, polymorphic: true, touch: true
   belongs_to :role
 
-  validates :access, inclusion: { in: %w[editor reader none] }
   validates :role, uniqueness: { scope: %i[permissionable_id permissionable_type] }
 
+  validate :ensure_access_matches_role
+
   # cache key for calculated permissions
   # @param permissionable [KnowledgeBase::Category, KnowledgeBase]
   # @return [String]
   def self.cache_key(permissionable)
     "#{permissionable.class}::aws::#{permissionable.id}::permission::#{permissionable.updated_at}"
   end
+
+  private
+
+  def ensure_access_matches_role
+    return if role.blank?
+    return if allowed_access.include? access
+
+    errors.add :base, __('This permission level is not available based on the current roles permissions.')
+  end
+
+  def allowed_access
+    if role.with_permission? 'knowledge_base.editor'
+      %w[editor reader none]
+    elsif role.with_permission? 'knowledge_base.reader'
+      %w[reader none]
+    else
+      []
+    end
+  end
 end

Some files were not shown because too many files changed in this diff