permissions_update_spec.rb 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe KnowledgeBase::PermissionsUpdate do
  4. describe '#update!' do
  5. include_context 'basic Knowledge Base'
  6. let(:role_editor) { create(:role, permission_names: %w[knowledge_base.editor]) }
  7. let(:role_another) { create(:role, permission_names: %w[knowledge_base.editor]) }
  8. let(:role_reader) { create(:role, permission_names: %w[knowledge_base.reader]) }
  9. let(:child_category) { create(:knowledge_base_category, parent: category) }
  10. describe 'updating itself' do
  11. shared_examples 'updating itself' do |object_name:|
  12. let(:object) { send(object_name) }
  13. it 'adds role permission for self' do
  14. described_class.new(object).update! role_editor => 'editor'
  15. expect(object.permissions)
  16. .to contain_exactly have_attributes(permissionable: object, role: role_editor, access: 'editor')
  17. end
  18. it 'adds additional role permission for self' do
  19. described_class.new(object).update! role_editor => 'reader'
  20. described_class.new(object).update! role_editor => 'reader', role_another => 'reader'
  21. expect(object.permissions)
  22. .to contain_exactly(have_attributes(role: role_editor), have_attributes(role: role_another))
  23. end
  24. it 'does not update when re-adding an existing permission' do
  25. described_class.new(object).update! role_editor => 'reader'
  26. expect { described_class.new(object).update! role_editor => 'reader' }
  27. .not_to change(object, :updated_at)
  28. end
  29. it 'throws error when role does not allow given access' do
  30. expect { described_class.new(object).update! role_reader => 'editor' }
  31. .to raise_error(%r{Validation failed})
  32. end
  33. end
  34. context 'when saving role on KB itself' do
  35. include_context 'updating itself', object_name: :knowledge_base
  36. end
  37. context 'when saving role on KB category' do
  38. include_context 'updating itself', object_name: :category
  39. end
  40. end
  41. describe 'updating descendants' do
  42. context 'when saving role on KB itself' do
  43. it 'adds effective permissions to descendant categories' do
  44. described_class.new(knowledge_base).update! role_editor => 'reader'
  45. expect(category.permissions_effective)
  46. .to contain_exactly have_attributes(role: role_editor, access: 'reader', permissionable: knowledge_base)
  47. end
  48. it 'removing permission opens up access to descendants' do
  49. described_class.new(knowledge_base).update! role_editor => 'editor'
  50. described_class.new(knowledge_base).update!(**{})
  51. expect(category.permissions_effective).to be_blank
  52. end
  53. context 'when category has editor role has editor role with editor permission' do
  54. before do
  55. described_class.new(category).update! role_editor => 'editor'
  56. category.reload
  57. end
  58. it 'removes identical permissions on descendant roles' do
  59. described_class.new(knowledge_base).update! role_editor => 'editor'
  60. category.reload
  61. expect(category.permissions_effective)
  62. .to contain_exactly have_attributes(role: role_editor, access: 'editor', permissionable: knowledge_base)
  63. end
  64. end
  65. context 'when child category has another role permission' do
  66. before do
  67. create(:knowledge_base_permission, permissionable: category, role: role_another, access: 'reader')
  68. end
  69. it 'removes conflicting permissions on descendant role but keeps another role' do
  70. described_class.new(knowledge_base).update! role_editor => 'editor'
  71. category.reload
  72. expect(category.permissions_effective)
  73. .to contain_exactly(
  74. have_attributes(role: role_editor, access: 'editor', permissionable: knowledge_base),
  75. have_attributes(role: role_another, access: 'reader', permissionable: category),
  76. )
  77. end
  78. end
  79. context 'when limiting sub-category in category with editor permission' do
  80. before do
  81. create(:knowledge_base_permission, permissionable: category, role: role_editor, access: 'editor')
  82. end
  83. it 'ignores redundant editor permission' do
  84. described_class.new(child_category).update! role_editor => 'editor'
  85. child_category.reload
  86. expect(child_category.permissions_effective)
  87. .to contain_exactly(
  88. have_attributes(role: role_editor, access: 'editor', permissionable: category),
  89. )
  90. end
  91. it 'raises error on updating to reader permission' do
  92. expect { described_class.new(child_category).update! role_editor => 'reader' }
  93. .to raise_error(Exceptions::UnprocessableEntity)
  94. end
  95. it 'raises error on updating to none permission' do
  96. expect { described_class.new(child_category).update! role_editor => 'none' }
  97. .to raise_error(Exceptions::UnprocessableEntity)
  98. end
  99. end
  100. context 'when limiting sub-category in category with none permission' do
  101. before do
  102. create(:knowledge_base_permission, permissionable: category, role: role_editor, access: 'none')
  103. end
  104. it 'ignores redundant none permission' do
  105. described_class.new(child_category).update! role_editor => 'none'
  106. child_category.reload
  107. expect(child_category.permissions_effective)
  108. .to contain_exactly(
  109. have_attributes(role: role_editor, access: 'none', permissionable: category),
  110. )
  111. end
  112. it 'raises error on updating to reader permission' do
  113. expect { described_class.new(child_category).update! role_editor => 'reader' }
  114. .to raise_error(Exceptions::UnprocessableEntity)
  115. end
  116. it 'raises error on updating to editor permission' do
  117. expect { described_class.new(child_category).update! role_editor => 'editor' }
  118. .to raise_error(Exceptions::UnprocessableEntity)
  119. end
  120. end
  121. end
  122. context 'when saving role on KB category' do
  123. it 'adds effective permissions to descendant roles' do
  124. described_class.new(category).update! role_editor => 'reader'
  125. expect(child_category.permissions_effective)
  126. .to contain_exactly have_attributes(role: role_editor, access: 'reader', permissionable: category)
  127. end
  128. context 'when child category has editor role with editor permission' do
  129. before do
  130. described_class.new(child_category).update! role_editor => 'editor'
  131. category.reload
  132. child_category.reload
  133. end
  134. it 'removes conflicting permissions on descendant roles' do
  135. described_class.new(category).update! role_editor => 'none'
  136. category.reload
  137. child_category.reload
  138. expect(child_category.permissions_effective)
  139. .to contain_exactly have_attributes(role: role_editor, access: 'none', permissionable: category)
  140. end
  141. it 'removes identical permissions on descendant roles' do
  142. described_class.new(category).update! role_editor => 'editor'
  143. category.reload
  144. child_category.reload
  145. expect(child_category.permissions_effective)
  146. .to contain_exactly have_attributes(role: role_editor, access: 'editor', permissionable: category)
  147. end
  148. context 'when child category has another role permission' do
  149. before do
  150. create(:knowledge_base_permission, permissionable: child_category, role: role_another, access: 'reader')
  151. end
  152. it 'removes conflicting permissions on descendant role but keeps another role' do
  153. described_class.new(category).update! role_editor => 'none'
  154. category.reload
  155. child_category.reload
  156. expect(child_category.permissions_effective)
  157. .to contain_exactly(
  158. have_attributes(role: role_editor, access: 'none', permissionable: category),
  159. have_attributes(role: role_another, access: 'reader', permissionable: child_category),
  160. )
  161. end
  162. end
  163. end
  164. context 'when category has role editor with none permission' do
  165. before do
  166. described_class.new(category).update! role_editor => 'none'
  167. category.reload
  168. end
  169. it 'removing permission opens up access to descendants' do
  170. described_class.new(category).update!(**{})
  171. category.reload
  172. expect(child_category.permissions_effective).to be_blank
  173. end
  174. end
  175. end
  176. end
  177. describe 'preventing user lockout' do
  178. let(:user) { create(:admin) }
  179. let(:role) { user.roles.first }
  180. shared_examples 'preventing user lockout' do |object_name:|
  181. let(:object) { send(object_name) }
  182. it 'raises an error when saving a lockout change for a given user' do
  183. expect { described_class.new(object, user).update! role => 'reader' }
  184. .to raise_error(Exceptions::UnprocessableEntity)
  185. end
  186. it 'allows to save same change without a user' do
  187. expect { described_class.new(object).update! role => 'reader' }.not_to raise_error
  188. end
  189. end
  190. context 'when saving role on KB itself' do
  191. include_context 'preventing user lockout', object_name: 'knowledge_base'
  192. end
  193. context 'when saving role on KB category' do
  194. include_context 'preventing user lockout', object_name: 'category'
  195. end
  196. end
  197. end
  198. describe '#update_using_params!' do
  199. subject(:updater) { described_class.new(category) }
  200. let(:role) { create(:role, permission_names: %w[knowledge_base.editor]) }
  201. let(:category) { create(:knowledge_base_category) }
  202. it 'calls update! with given roles' do
  203. updater.update_using_params!({ permissions: { role.id => 'editor' } })
  204. expect(category.permissions.first).to have_attributes(role: role, access: 'editor', permissionable: category)
  205. end
  206. it 'raises an error when given a non existant role' do
  207. expect { updater.update_using_params!({ permissions: { (role.id + 1) => 'editor' } }) }
  208. .to raise_error(ActiveRecord::RecordNotFound)
  209. end
  210. end
  211. end