diff --git a/Gemfile b/Gemfile index c839545c..0f5b22b0 100644 --- a/Gemfile +++ b/Gemfile @@ -76,4 +76,5 @@ group :development do gem 'spring' gem 'spring-commands-rspec' gem 'rack-mini-profiler' + gem 'faker' end diff --git a/Gemfile.lock b/Gemfile.lock index 978424b8..7bf442dc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -117,6 +117,8 @@ GEM factory_bot_rails (6.1.0) factory_bot (~> 6.1.0) railties (>= 5.0.0) + faker (2.19.0) + i18n (>= 1.6, < 2) faraday (0.15.4) multipart-post (>= 1.2, < 3) ffi (1.15.0) @@ -331,6 +333,7 @@ DEPENDENCIES em-http-request exception_handler (~> 0.8.0.0) factory_bot_rails + faker jquery-rails kaminari listen diff --git a/app/models/membership.rb b/app/models/membership.rb index 53abe877..00ba6c3d 100644 --- a/app/models/membership.rb +++ b/app/models/membership.rb @@ -44,6 +44,10 @@ def leader? has_post?(PostType::LEADER_POST_ID) end + def leader_assistant? + has_post?(PostType::LEADER_ASSISTANT_ID) + end + def newbie? has_post?(PostType::DEFAULT_POST_ID) && end_date.nil? && !archived? end diff --git a/app/models/post_type.rb b/app/models/post_type.rb index 4803e46f..a73c6a63 100644 --- a/app/models/post_type.rb +++ b/app/models/post_type.rb @@ -26,6 +26,7 @@ class PostType < ApplicationRecord PEK_ADMIN_ID = 66 NEW_MEMBER_ID = 104 EVALUATION_HELPER_ID = 1188 + LEADER_ASSISTANT_ID = 1460 COMMON_TYPES = [ FINANCIAL_OFFICER_POST_ID, @@ -34,7 +35,8 @@ class PostType < ApplicationRecord DEFAULT_POST_ID, PEK_ADMIN_ID, NEW_MEMBER_ID, - EVALUATION_HELPER_ID + EVALUATION_HELPER_ID, + LEADER_ASSISTANT_ID ].freeze scope :without_common, -> { where.not(id: COMMON_TYPES) } end diff --git a/app/models/user.rb b/app/models/user.rb index 5ebeceaf..f2b6e22d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -106,6 +106,11 @@ def leader_of?(group) membership&.leader? end + def leader_assistant_of?(group) + membership = membership_for(group) + membership&.leader_assistant? + end + def member_of?(group) membership = membership_for(group) membership&.active? diff --git a/app/policies/evaluation_policy.rb b/app/policies/evaluation_policy.rb index f30f98cb..49e6bca0 100644 --- a/app/policies/evaluation_policy.rb +++ b/app/policies/evaluation_policy.rb @@ -23,7 +23,6 @@ def edit? alias destroy? edit? alias copy_previous_principles? edit? - alias update_comments? show? def update_point_request? @@ -41,6 +40,7 @@ def cancel_point_request? def update_entry_request? update_request?(entry_request_status) end + alias edit_justification? update_entry_request? def submit_entry_request? @@ -71,7 +71,7 @@ def update_request?(request_status) def submit_request?(request_status) return false unless submittable_request?(request_status) - leader_of_the_group? || pek_admin? + leader_of_the_group? || leader_assistant_of_the_group? || pek_admin? end def submittable_request?(request_status) @@ -86,21 +86,25 @@ def cancel_request?(request_status) return false unless application_season? return false unless request_status == Evaluation::NOT_YET_ASSESSED - leader_of_the_group? || pek_admin? + leader_of_the_group? || leader_assistant_of_the_group? || pek_admin? end def leader_of_the_group? - cache { user.leader_of?(evaluation.group) } + user.leader_of?(evaluation.group) + end + + def leader_assistant_of_the_group? + user.leader_assistant_of?(evaluation.group) end def evaluation_helper_of_the_group? - cache { user.evaluation_helper_of?(evaluation.group) } + user.evaluation_helper_of?(evaluation.group) end def leader_of_the_resort? return false unless group_is_a_resort_member? - cache { user.leader_of?(evaluation.group.parent) } + user.leader_of?(evaluation.group.parent) end def leader_in_the_resort? @@ -125,7 +129,7 @@ def evaluation_helper_in_the_resort? end def group_is_a_resort_member? - cache { Group.resorts.include?(evaluation.group.parent) } + Group.resorts.include?(evaluation.group.parent) end def group_is_a_resort? @@ -142,19 +146,19 @@ def evaluation_helper_at_resort? end def rvt_member? - cache { user.roles.rvt_member? } + user.roles.rvt_member? end def rvt_leader? - cache { user.roles.rvt_leader? } + user.roles.rvt_leader? end def point_request_status - cache { evaluation.point_request_status } + evaluation.point_request_status end def entry_request_status - cache { evaluation.entry_request_status } + evaluation.entry_request_status end def evaluation @@ -162,6 +166,6 @@ def evaluation end def can_update_active_request? - leader_of_the_group? || evaluation_helper_of_the_group? || pek_admin? + leader_of_the_group? || leader_assistant_of_the_group? || evaluation_helper_of_the_group? || pek_admin? end end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 759ff45b..cd3648a4 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -19,7 +19,7 @@ def create? alias new? create? def manage_memberships? - leader? || evaluation_helper? + leader? || leader_assistant? || evaluation_helper? end alias manage_posts? manage_memberships? @@ -32,6 +32,10 @@ def leader? user.leader_of?(group) end + def leader_assistant? + user.leader_assistant_of?(group) + end + def evaluation_helper? user.evaluation_helper_of?(group) end diff --git a/app/policies/post_policy.rb b/app/policies/post_policy.rb index 451a1ee5..0592858f 100644 --- a/app/policies/post_policy.rb +++ b/app/policies/post_policy.rb @@ -4,9 +4,9 @@ class PostPolicy < ApplicationPolicy def create? return false unless group&.has_post_type?(post_type.id) return true if leader? - return true if evaluation_helper? && - (group.own_post_types.include?(post_type) || - post_type.id == PostType::NEW_MEMBER_ID) + return true if (evaluation_helper? || leader_assistant?) && + (group.own_post_types.include?(post_type) || + post_type.id == PostType::NEW_MEMBER_ID) false end @@ -25,7 +25,11 @@ def post_type def leader? user.leader_of?(group) - end + end + + def leader_assistant? + user.leader_assistant_of?(group) + end def evaluation_helper? user.evaluation_helper_of?(group) diff --git a/app/policies/sub_group_policy.rb b/app/policies/sub_group_policy.rb index 1ad5a9e2..c55a912c 100644 --- a/app/policies/sub_group_policy.rb +++ b/app/policies/sub_group_policy.rb @@ -8,7 +8,7 @@ def index? alias show? index? def create? - return true if leader_of_the_group? + return true if leader_of_the_group? || leader_assistant_of_the_group? end alias edit? create? @@ -33,6 +33,10 @@ def leader_of_the_group? membership.present? && membership.has_post?(PostType::LEADER_POST_ID) end + def leader_assistant_of_the_group? + membership.present? && membership.has_post?(PostType::LEADER_ASSISTANT_ID) + end + def membership user.membership_for(sub_group.group) end diff --git a/app/policies/sub_group_principle_policy.rb b/app/policies/sub_group_principle_policy.rb index 0c26636c..44b9a0b9 100644 --- a/app/policies/sub_group_principle_policy.rb +++ b/app/policies/sub_group_principle_policy.rb @@ -2,7 +2,7 @@ class SubGroupPrinciplePolicy < ApplicationPolicy alias principle record def index? - leader_of_the_group? || admin_of_the_sub_group? + leader_of_the_group? || leader_assistant_of_the_group? || admin_of_the_sub_group? end alias create? index? @@ -13,6 +13,10 @@ def leader_of_the_group? membership.present? && membership.has_post?(PostType::LEADER_POST_ID) end + def leader_assistant_of_the_group? + membership.present? && membership.has_post?(PostType::LEADER_ASSISTANT_ID) + end + def admin_of_the_sub_group? sub_group_membership.present? && sub_group_membership.admin? end diff --git a/spec/policies/evaluation_policy_spec.rb b/spec/policies/evaluation_policy_spec.rb index 7e3a1346..c067c9aa 100644 --- a/spec/policies/evaluation_policy_spec.rb +++ b/spec/policies/evaluation_policy_spec.rb @@ -1,16 +1,16 @@ RSpec.describe EvaluationPolicy, type: :policy do subject { described_class.new(user, evaluation) } - let(:evaluation) { create(:evaluation) } - let(:evaluation_actions) { %i[show current table edit update edit_justification] } + let(:evaluation) { create(:evaluation) } + let(:evaluation_actions) { %i[show current table edit update edit_justification] } let(:evaluation_view_actions) { evaluation_actions - %i[edit update edit_justification] } - let(:point_request_actions) { %i[submit_point_request cancel_point_request update_point_request] } - let(:entry_request_actions) { %i[submit_entry_request cancel_entry_request update_entry_request] } - let(:submit_actions) { %i[submit_point_request submit_entry_request] } - let(:cancel_actions) { %i[cancel_point_request cancel_entry_request] } - let(:update_request_actions) { %i[update_point_request update_entry_request] } - let(:update_comment_actions) { %i[update_comments] + evaluation_view_actions } - let(:all_action) { entry_request_actions + point_request_actions + evaluation_actions } + let(:point_request_actions) { %i[submit_point_request cancel_point_request update_point_request] } + let(:entry_request_actions) { %i[submit_entry_request cancel_entry_request update_entry_request] } + let(:submit_actions) { %i[submit_point_request submit_entry_request] } + let(:cancel_actions) { %i[cancel_point_request cancel_entry_request] } + let(:update_request_actions) { %i[update_point_request update_entry_request] } + let(:update_comment_actions) { %i[update_comments] + evaluation_view_actions } + let(:all_action) { entry_request_actions + point_request_actions + evaluation_actions } context 'when application season' do include_context 'application season' @@ -36,13 +36,36 @@ end end + context 'and the user is the group leader assistant' do + let(:user) do + evaluation.group.memberships.select(&:leader_assistant?).first.user + end + + it { is_expected.to permit_actions(all_action - cancel_actions) } + it { is_expected.to permit_actions(update_comment_actions) } + it { is_expected.to forbid_actions(cancel_actions) } + + context "and the request is submitted" do + before(:each) do + evaluation.point_request_status = Evaluation::NOT_YET_ASSESSED + evaluation.entry_request_status = Evaluation::NOT_YET_ASSESSED + end + + it { is_expected.to permit_actions(cancel_actions) } + it { is_expected.to forbid_actions(submit_actions) } + + it { is_expected.to permit_actions(evaluation_view_actions) } + it { is_expected.to forbid_actions(update_request_actions) } + end + end + context "and the user is the evaluation helper of the group" do let(:user) do evaluation.group.memberships.select(&:evaluation_helper?).first.user end - it { is_expected.to permit_actions(evaluation_view_actions + update_request_actions + [:edit_justification] ) } - it { is_expected.to forbid_actions(all_action - evaluation_view_actions - update_request_actions - [:edit_justification]) } + it { is_expected.to permit_actions(evaluation_view_actions + update_request_actions + [:edit_justification]) } + it { is_expected.to forbid_actions(all_action - evaluation_view_actions - update_request_actions - [:edit_justification]) } end context 'and the user is a leader of another the group' do @@ -52,10 +75,10 @@ end context 'and the user is a leader of another group in the resort' do - let(:user) { evaluation.group.parent.children.select{ |g| g != evaluation.group }.first.leader.user } + let(:user) { evaluation.group.parent.children.select { |g| g != evaluation.group }.first.leader.user } - it { is_expected.to permit_actions(evaluation_view_actions) } - it { is_expected.to forbid_actions(all_action - evaluation_view_actions) } + it { is_expected.to permit_actions(evaluation_view_actions) } + it { is_expected.to forbid_actions(all_action - evaluation_view_actions) } end context 'and the group has no parents' do @@ -156,6 +179,34 @@ end end + context "and the user is the group leader assistant" do + let(:user) do + evaluation.group.memberships.select(&:leader_assistant?).first.user + end + + context "and the evaluation is not yet assessed" do + before(:each) do + evaluation.point_request_status = Evaluation::NOT_YET_ASSESSED + evaluation.entry_request_status = Evaluation::NOT_YET_ASSESSED + end + + it { is_expected.to permit_actions(evaluation_view_actions) } + it { is_expected.to forbid_actions(all_action - evaluation_view_actions) } + end + + context "and the point request is rejected" do + before { evaluation.point_request_status = Evaluation::REJECTED } + + it { is_expected.to permit_actions(point_request_actions - cancel_actions) } + end + + context "when the entry_request is rejected" do + before { evaluation.entry_request_status = Evaluation::REJECTED } + + it { is_expected.to permit_actions(entry_request_actions - cancel_actions) } + end + end + context "when the user is the resort leader" do let(:user) { evaluation.group.parent.leader.user } diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index 4665412f..18458a8a 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -11,6 +11,17 @@ expect(subject).to permit(user, group) end end + + context 'when the user is the group leader assistant' do + let(:membership) { create(:membership, :leader) } + let(:user) { membership.user } + let(:group) { membership.group } + + it 'grants access' do + expect(subject).to permit(user, group) + end + end + context 'when the user is not the group leader' do let(:membership) { create(:membership) } let(:user) { membership.user } diff --git a/spec/policies/post_policy_spec.rb b/spec/policies/post_policy_spec.rb index 433cd486..9101b5a4 100644 --- a/spec/policies/post_policy_spec.rb +++ b/spec/policies/post_policy_spec.rb @@ -14,6 +14,14 @@ end end + context "when the current user is the group leader assistant" do + let(:user) { membership.group.memberships.first(&:leader_assistant?).user } + + it "is permitted" do + expect(subject).to permit(user, post.reload) + end + end + context "when the user is not a member" do let(:user) { create(:user) } it "is forbidden" do diff --git a/spec/policies/sub_group_policy_spec.rb b/spec/policies/sub_group_policy_spec.rb index 174d754b..c7f4bd78 100644 --- a/spec/policies/sub_group_policy_spec.rb +++ b/spec/policies/sub_group_policy_spec.rb @@ -14,6 +14,12 @@ it { is_expected.to permit_actions(all_action) } end + context 'when the user is the group leader assistant' do + let(:user) { sub_group.group.memberships.first(&:leader_assistant?).user } + + it { is_expected.to permit_actions(all_action) } + end + context 'when the user is a member' do let(:user) { create(:membership, group: sub_group.group).user } diff --git a/spec/policies/sub_group_principle_policy_spec.rb b/spec/policies/sub_group_principle_policy_spec.rb index 8e14e2b5..bb2a6d5f 100644 --- a/spec/policies/sub_group_principle_policy_spec.rb +++ b/spec/policies/sub_group_principle_policy_spec.rb @@ -13,6 +13,12 @@ it { is_expected.to permit_actions(all_action) } end + context 'when the user is the group leader assistant' do + let(:user) { group.memberships.first(&:leader_assistant?).user } + + it { is_expected.to permit_actions(all_action) } + end + context 'when the user is the sub group admin' do let(:user) { create(:sub_group_membership, sub_group: sub_group_principle.sub_group, diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b91f786f..328fc9dc 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -49,6 +49,7 @@ config.before(:suite) do FactoryBot.create(:post_type_leader) + FactoryBot.create(:post_type_leader_assistant) FactoryBot.create(:post_type_financial_officer) FactoryBot.create(:post_type_newbie) FactoryBot.create(:post_type_evaluation_helper) diff --git a/test/factories/groups.rb b/test/factories/groups.rb index b71d8547..c35712ea 100644 --- a/test/factories/groups.rb +++ b/test/factories/groups.rb @@ -22,6 +22,12 @@ membership = Membership.create!(user: user, group: group) CreatePost.call(group, membership, PostType::EVALUATION_HELPER_ID) end + + after(:create) do |group| + user = create(:user) + membership = Membership.create!(user: user, group: group) + CreatePost.call(group, membership, PostType::LEADER_ASSISTANT_ID) + end end factory :group_with_parent, parent: :group do diff --git a/test/factories/memberships.rb b/test/factories/memberships.rb index cf2398d0..5f79b401 100644 --- a/test/factories/memberships.rb +++ b/test/factories/memberships.rb @@ -10,6 +10,12 @@ end end + trait :leader_assistant do + after(:create) do |membership| + membership.posts << build(:post, :leader_assistant) + end + end + trait :newbie do after(:create) do |membership| membership.posts << build(:post, :newbie) diff --git a/test/factories/post_types.rb b/test/factories/post_types.rb index 196eb7a1..d9c71fb0 100644 --- a/test/factories/post_types.rb +++ b/test/factories/post_types.rb @@ -20,6 +20,11 @@ name { 'Korvezeto' } end + factory :post_type_leader_assistant, parent: :common_post_type do + id { PostType::LEADER_ASSISTANT_ID } + name { 'Korvezeto helyettes' } + end + factory :post_type_newbie, parent: :post_type do id { PostType::DEFAULT_POST_ID } name { 'Feldolgozas alatt' } diff --git a/test/factories/posts.rb b/test/factories/posts.rb index b0f83f4f..2c7c3122 100644 --- a/test/factories/posts.rb +++ b/test/factories/posts.rb @@ -6,6 +6,10 @@ post_type_id { PostType::LEADER_POST_ID } end + trait :leader_assistant do + post_type_id { PostType::LEADER_POST_ID } + end + trait :newbie do post_type_id { PostType::DEFAULT_POST_ID } end diff --git a/test/fixtures/post_type.yml b/test/fixtures/post_type.yml index 8a9b6198..5bb9cc2d 100644 --- a/test/fixtures/post_type.yml +++ b/test/fixtures/post_type.yml @@ -2,6 +2,10 @@ leader: id: 3 name: körvezető +leader_assistant: + id: 1460 + name: körvezető helyettes + newbie: id: 6 name: feldolgozás alatt