diff --git a/app/abilities/people_manager_ability.rb b/app/abilities/people_manager_ability.rb index 1956d88..66db36a 100644 --- a/app/abilities/people_manager_ability.rb +++ b/app/abilities/people_manager_ability.rb @@ -11,20 +11,34 @@ class PeopleManagerAbility < AbilityDsl::Base permission(:any).may(:new_managed, :new_manager).everybody permission(:any).may(:create_managed, :destroy_managed).if_can_change_managed permission(:any).may(:create_manager, :destroy_manager).if_can_change_manager + permission(:any).may(:show).for_leaded_events_or_readable_manageds end def if_can_change_manager - can?(:change_managers, subject.managed) || creating_new_managed_person? + can?(:change_managers, managed) || creating_new_managed_person? end def if_can_change_managed can?(:update, subject.manager) end + def for_leaded_events_or_readable_manageds + for_leaded_events || can?(:show, managed) + end + + def for_leaded_events + leaded_event_ids = user_context.events_with_permission(:event_full) + managed&.event_participations&.exists?(event_id: leaded_event_ids) + end + private + def managed + subject.managed + end + def creating_new_managed_person? - subject.managed&.new_record? && + managed&.new_record? && FeatureGate.enabled?("people.people_managers.self_service_managed_creation") end diff --git a/app/models/people_manager.rb b/app/models/people_manager.rb index 60f3b04..5d1e811 100644 --- a/app/models/people_manager.rb +++ b/app/models/people_manager.rb @@ -25,6 +25,14 @@ class PeopleManager < ActiveRecord::Base has_paper_trail on: [] + def email + manager.email + end + + def phone_number + manager.phone_numbers.first { _1.public } || manager.phone_numbers.first + end + def create_paper_trail_versions_for_create_event [manager_id, managed_id].each do |main_id| PaperTrail::RecordTrail.new(self).send(:build_version_on_create, diff --git a/app/views/event/participations/_asides_youth.html.haml b/app/views/event/participations/_asides_youth.html.haml new file mode 100644 index 0000000..f31ed09 --- /dev/null +++ b/app/views/event/participations/_asides_youth.html.haml @@ -0,0 +1,9 @@ +- # frozen_string_literal: true +- +- # Copyright (c) 2024, Schweizer Alpen-Club. This file is part of +- # hitobito and licensed under the Affero General Public License version 3 +- # or later. See the COPYING file at the top-level directory or at +- # https://github.com/hitobito/hitobito. + + += render 'people_managers' diff --git a/app/views/event/participations/_people_managers.html.haml b/app/views/event/participations/_people_managers.html.haml new file mode 100644 index 0000000..d27f520 --- /dev/null +++ b/app/views/event/participations/_people_managers.html.haml @@ -0,0 +1,11 @@ +- # frozen_string_literal: true + +- # Copyright (c) 2024, Schweizer Alpen-Club. This file is part of +- # hitobito and licensed under the Affero General Public License version 3 +- # or later. See the COPYING file at the top-level directory or at +- # https://github.com/hitobito/hitobito. + +- FeatureGate.if('people.people_managers') do + - if entry.person.people_managers.any? + %section + = render 'person/managers/list', person: entry.person, readonly: true diff --git a/app/views/person/managers/_list.html.haml b/app/views/person/managers/_list.html.haml index f1edfdc..4217470 100644 --- a/app/views/person/managers/_list.html.haml +++ b/app/views/person/managers/_list.html.haml @@ -3,15 +3,23 @@ - # or later. See the COPYING file at the top-level directory or at - # https://github.com/hitobito/hitobito_youth. +- readonly = defined?(readonly) && readonly - content_for(:section_header) do = t('people_managers.managers_heading') - %span.float-end - = Dropdown::AddPeopleManager.new(self, person).to_s -= render layout: 'people_managers/section', locals: { list: person.people_managers } do + - if !readonly + %span.float-end + = Dropdown::AddPeopleManager.new(self, person).to_s + += render layout: 'people_managers/section', locals: { readonly: readonly, list: person.people_managers } do - person.people_managers.each do |item| - %tr - %td - %strong= link_to(item.manager, item.manager, data: { turbo_frame: :_top }) - - if can?(:destroy_manager, item) - %td=render 'people_managers/delete_link', path: person_manager_path(person_id: person.id, id: item.id) + - if can?(:show, item) + %tr + %td + %strong= link_to_if(can?(:show, item.manager), item.manager, item.manager, data: { turbo_frame: :_top }) + %div.d-flex.gap-2 + = mail_to(item.email) + = phone_to(item.phone_number.number, item.phone_number) if item.phone_number.present? + + - if !readonly && can?(:destroy_manager, item) + %td=render 'people_managers/delete_link', path: person_manager_path(person_id: person.id, id: item.id) diff --git a/spec/abilities/people_manager_ability_spec.rb b/spec/abilities/people_manager_ability_spec.rb index 9a55ae0..1ec051b 100644 --- a/spec/abilities/people_manager_ability_spec.rb +++ b/spec/abilities/people_manager_ability_spec.rb @@ -18,6 +18,35 @@ def build(managed: nil, manager: nil) PeopleManager.new(managed: managed, manager: manager) end + describe :show do + let(:person) { Fabricate(:person) } + let(:manager) { Fabricate(:person) } + let(:managed) { bottom_member } + let(:people_manager) { build(managed: managed, manager: manager) } + + context 'with no relation' do + it { is_expected.not_to be_able_to(:show, people_manager) } + end + + context 'with leader role on participation event' do + let(:event) { events(:top_event) } + before do + roles = { person => Event::Role::Leader, people_manager.managed => Event::Role::Participant } + x = roles.map do |person, role| + Fabricate(role.name, participation: Fabricate(:event_participation, event: event, person: person)) + end + people_manager.save + people_manager.reload + end + it { is_expected.to be_able_to(:show, people_manager) } + end + + context 'with layer permissions' do + let(:person) { top_leader } + it { is_expected.to be_able_to(:show, people_manager) } + end + end + [:create_manager, :destroy_manager].each do |action| context 'top leader' do diff --git a/spec/views/event/participations/_attrs.html.haml_spec.rb b/spec/views/event/participations/_attrs.html.haml_spec.rb new file mode 100644 index 0000000..bb47fb0 --- /dev/null +++ b/spec/views/event/participations/_attrs.html.haml_spec.rb @@ -0,0 +1,54 @@ +# Copyright (c) 2012-2013, Jungwacht Blauring Schweiz. This file is part of +# hitobito and licensed under the Affero General Public License version 3 +# or later. See the COPYING file at the top-level directory or at +# https://github.com/hitobito/hitobito. + +require "spec_helper" + +describe "event/participations/_attrs.html.haml" do + let(:event) { EventDecorator.decorate(Fabricate(:course, groups: [groups(:top_layer)])) } + let(:participation) { Fabricate(:event_participation, event: event) } + subject(:dom) do + render + Capybara::Node::Simple.new(@rendered) + end + + let(:params) do + {"action" => "show", + "controller" => "event/participations", + "group_id" => "1", + "event_id" => "36"} + end + + before do + assign(:event, event) + assign(:group, event.groups.first.decorate) + assign(:answers, []) + allow(view).to receive_messages(parent: event) + allow(view).to receive_messages(entry: participation.decorate) + allow(view).to receive_messages(params: params) + end + + context "with PeopleManager assigned" do + let!(:manager) do + Fabricate(:person).tap do |manager| + manager.phone_numbers.create(number: "+41 44 123 45 57", label: "Privat") + participation.person.managers << manager + end + end + + it "marks participations where required questions are unanswered" do + login_as(people(:top_leader)) + + expect(dom).to have_text PeopleManager.model_name.human(count: 2) + expect(dom).to have_text manager.to_s + expect(dom).to have_text manager.email + expect(dom).to have_text manager.phone_numbers.first + end + end + + def login_as(user) + allow(controller).to receive_messages(current_user: user) + allow(view).to receive_messages(current_user: user) + end +end