diff --git a/README.md b/README.md index 0df0d243..4db5be36 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ Additional features include member census, camps and course conditions. # Jubla Organization Hierarchy + * Organisation + * Organisation + * Administrator: 2FA [:layer_and_below_full, :admin] * Bund * Bund * Adressverwaltung: [:group_full] @@ -155,6 +158,54 @@ Additional features include member census, camps and course conditions. * Mitglied: [:group_read] * Extern: [] * Versandadresse: [] + * NEJB + * NEJB + * Adressverwaltung: [:group_full] + * Versandadresse: [] + * IT Support: [:admin, :impersonation] + * NEJB Bundesleitung + * Adressverwaltung: [:admin, :layer_and_below_full, :contact_data] + * Netzwerk Ehemalige Jungwacht Blauring + * Leitung: [:group_and_below_full, :contact_data] + * Adressverwaltung: [:group_and_below_full] + * Kassier*in: [:group_and_below_read] + * Aktivmitglied: [:group_read] + * Passivmitglied: [:group_read] + * Kollektivmitglied: [:group_read] + * Neumitglied: [] + * Extern: [] + * Versandadresse: [] + * Kanton (Ehemalige) + * Kanton (Ehemalige) + * Adressverwaltung: [:admin, :layer_and_below_full, :contact_data] + * Kantonaler Ehemaligenverein + * Leitung: [:group_and_below_full, :contact_data] + * Adressverwaltung: [:group_and_below_full] + * Kassier*in: [:group_and_below_read] + * Mitglied Ehemalige: [:group_read] + * Neumitglied: [] + * Extern: [] + * Versandadresse: [] + * Region (Ehemalige) + * Region (Ehemalige) + * Adressverwaltung: [:admin, :layer_and_below_full, :contact_data] + * Regionaler Ehemaligenverein + * Leitung: [:group_and_below_full, :contact_data] + * Adressverwaltung: [:group_and_below_full] + * Kassier*in: [:group_and_below_read] + * Mitglied Ehemalige: [:group_read] + * Neumitglied: [] + * Extern: [] + * Versandadresse: [] + * Ehemaligenschar + * Ehemaligenschar + * Leitung: [:group_and_below_full, :contact_data] + * Adressverwaltung: [:group_and_below_full] + * Kassier*in: [:group_and_below_read] + * Mitglied Ehemalige: [:group_read] + * Neumitglied: [] + * Extern: [] + * Versandadresse: [] * Global * Einfache Gruppe * Leitung: [:group_full] diff --git a/app/domain/jubla/mailing_lists/subscribers.rb b/app/domain/jubla/mailing_lists/subscribers.rb index 0d5c8ed0..48d05abc 100644 --- a/app/domain/jubla/mailing_lists/subscribers.rb +++ b/app/domain/jubla/mailing_lists/subscribers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Copyright (c) 2017-2021, Jungwacht Blauring Schweiz. This file is part of +# Copyright (c) 2017-2024, 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. @@ -25,7 +25,10 @@ def excluded_subscriber_ids_with_preferences end def excluded_by_contact_preference - Person.alumnus_only.where("contactable_by_#{layer_type}": false).select(:id) + preference_column = "contactable_by_#{layer_type}" + return Person.none unless Person.column_names.include?(preference_column) + + Person.alumnus_only.where("#{preference_column}": false).select(:id) end def layer_type diff --git a/app/domain/jubla/person/filter/list.rb b/app/domain/jubla/person/filter/list.rb index 71fa5aa6..aa333a9a 100644 --- a/app/domain/jubla/person/filter/list.rb +++ b/app/domain/jubla/person/filter/list.rb @@ -19,8 +19,9 @@ def accessibles_with_excluded def excluded_people_ids layer_type = group.layer_group.type.demodulize.underscore - return [] if layer_type == "root" + preference_column = "contactable_by_#{layer_type}" + return Person.none unless Person.column_names.include?(preference_column) - Person.alumnus_only.where("contactable_by_#{layer_type}": false).pluck(:id) + Person.alumnus_only.where("#{preference_column}": false).pluck(:id) end end diff --git a/app/models/group/kanton_ehemaligenverein.rb b/app/models/group/kanton_ehemaligenverein.rb new file mode 100644 index 00000000..2f1f12dd --- /dev/null +++ b/app/models/group/kanton_ehemaligenverein.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Copyright (c) 2024-2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::KantonEhemaligenverein < ::Group + ### ROLES + + class Leader < ::Role + self.permissions = [:group_and_below_full, :contact_data] + end + + class GroupAdmin < ::Role + self.permissions = [:group_and_below_full] + end + + class Treasurer < ::Role + self.permissions = [:group_and_below_read] + end + + class NejbMember < ::Role + self.permissions = [:group_read] + end + + class NejbJoiner < ::Role + self.permissions = [] + end + + class External < ::Role + self.permissions = [] + end + + class DispatchAddress < ::Role + self.permissions = [] + end + + roles Leader, GroupAdmin, Treasurer, NejbMember, NejbJoiner, External, DispatchAddress +end diff --git a/app/models/group/nejb.rb b/app/models/group/nejb.rb new file mode 100644 index 00000000..57267350 --- /dev/null +++ b/app/models/group/nejb.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# Copyright (c) 2024-2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::Nejb < ::Group + self.layer = true + children Group::NejbBundesleitung, + Group::NetzwerkEhemaligeJungwachtBlauring, + Group::NejbKanton + + ### ROLES + + class GroupAdmin < ::Role + self.permissions = [:group_full] + end + + class DispatchAddress < ::Role + self.permissions = [] + end + + class ITSupport < ::Role + self.permissions = [:admin, :impersonation] + end + + roles GroupAdmin, DispatchAddress, ITSupport +end diff --git a/app/models/group/nejb_bundesleitung.rb b/app/models/group/nejb_bundesleitung.rb new file mode 100644 index 00000000..98b84df5 --- /dev/null +++ b/app/models/group/nejb_bundesleitung.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Copyright (c) 2024-2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::NejbBundesleitung < ::Group + class GroupAdmin < ::Role + self.permissions = [:admin, :layer_and_below_full, :contact_data] + end + + roles GroupAdmin +end diff --git a/app/models/group/nejb_kanton.rb b/app/models/group/nejb_kanton.rb new file mode 100644 index 00000000..237362fe --- /dev/null +++ b/app/models/group/nejb_kanton.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Copyright (c) 2024-2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::NejbKanton < ::Group + children Group::KantonEhemaligenverein, Group::NejbRegion + self.layer = true + + class GroupAdmin < ::Role + self.permissions = [:admin, :layer_and_below_full, :contact_data] + end + + roles GroupAdmin +end diff --git a/app/models/group/nejb_region.rb b/app/models/group/nejb_region.rb new file mode 100644 index 00000000..6d7a9a51 --- /dev/null +++ b/app/models/group/nejb_region.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Copyright (c) 2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::NejbRegion < ::Group + children Group::RegionEhemaligenverein, Group::NejbSchar + self.layer = true + + class GroupAdmin < ::Role + self.permissions = [:admin, :layer_and_below_full, :contact_data] + end + + roles GroupAdmin +end diff --git a/app/models/group/nejb_schar.rb b/app/models/group/nejb_schar.rb new file mode 100644 index 00000000..a1f7db84 --- /dev/null +++ b/app/models/group/nejb_schar.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Copyright (c) 2024-2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::NejbSchar < ::Group + self.layer = true + + ### ROLES + + class Leader < ::Role + self.permissions = [:group_and_below_full, :contact_data] + end + + class GroupAdmin < ::Role + self.permissions = [:group_and_below_full] + end + + class Treasurer < ::Role + self.permissions = [:group_and_below_read] + end + + class NejbMember < ::Role + self.permissions = [:group_read] + end + + class NejbJoiner < ::Role + self.permissions = [] + end + + class External < ::Role + self.permissions = [] + end + + class DispatchAddress < ::Role + self.permissions = [] + end + + roles Leader, GroupAdmin, Treasurer, NejbMember, NejbJoiner, External, DispatchAddress +end diff --git a/app/models/group/netzwerk_ehemalige_jungwacht_blauring.rb b/app/models/group/netzwerk_ehemalige_jungwacht_blauring.rb new file mode 100644 index 00000000..c599be58 --- /dev/null +++ b/app/models/group/netzwerk_ehemalige_jungwacht_blauring.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# Copyright (c) 2024-2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::NetzwerkEhemaligeJungwachtBlauring < ::Group + ### ROLES + + class Leader < ::Role + self.permissions = [:group_and_below_full, :contact_data] + end + + class GroupAdmin < ::Role + self.permissions = [:group_and_below_full] + end + + class Treasurer < ::Role + self.permissions = [:group_and_below_read] + end + + class ActiveMember < ::Role + self.permissions = [:group_read] + end + + class PassiveMember < ::Role + self.permissions = [:group_read] + end + + class CollectiveMember < ::Role + self.permissions = [:group_read] + end + + class NejbJoiner < ::Role + self.permissions = [] + end + + class External < ::Role + self.permissions = [] + end + + class DispatchAddress < ::Role + self.permissions = [] + end + + roles Leader, GroupAdmin, Treasurer, ActiveMember, PassiveMember, CollectiveMember, NejbJoiner, External, DispatchAddress +end diff --git a/app/models/group/region_ehemaligenverein.rb b/app/models/group/region_ehemaligenverein.rb new file mode 100644 index 00000000..f7933360 --- /dev/null +++ b/app/models/group/region_ehemaligenverein.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Copyright (c) 2024, Jungwacht Blauring Schweiz. This file is part of +# hitobito_jubla 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_jubla. + +class Group::RegionEhemaligenverein < ::Group + ### ROLES + + class Leader < ::Role + self.permissions = [:group_and_below_full, :contact_data] + end + + class GroupAdmin < ::Role + self.permissions = [:group_and_below_full] + end + + class Treasurer < ::Role + self.permissions = [:group_and_below_read] + end + + class NejbMember < ::Role + self.permissions = [:group_read] + end + + class NejbJoiner < ::Role + self.permissions = [] + end + + class External < ::Role + self.permissions = [] + end + + class DispatchAddress < ::Role + self.permissions = [] + end + + roles Leader, GroupAdmin, Treasurer, NejbMember, NejbJoiner, External, DispatchAddress +end diff --git a/app/models/group/root.rb b/app/models/group/root.rb index c1079a2b..4243abb7 100644 --- a/app/models/group/root.rb +++ b/app/models/group/root.rb @@ -30,5 +30,5 @@ def alumnus_manager roles Admin - children Group::Federation + children Group::Federation, Group::Nejb end diff --git a/app/models/jubla/group.rb b/app/models/jubla/group.rb index 1485f64b..fbd9f24e 100644 --- a/app/models/jubla/group.rb +++ b/app/models/jubla/group.rb @@ -1,4 +1,4 @@ -# Copyright (c) 2012-2017, Jungwacht Blauring Schweiz. This file is part of +# Copyright (c) 2012-2024, Jungwacht Blauring Schweiz. This file is part of # hitobito_jubla 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_jubla. @@ -34,7 +34,7 @@ module Jubla::Group # define global children children Group::SimpleGroup - root_types Group::Federation + root_types Group::Root, Group::Federation, Group::Nejb private diff --git a/config/locales/models.de.yml b/config/locales/models.de.yml index 5772c631..51d1dae8 100644 --- a/config/locales/models.de.yml +++ b/config/locales/models.de.yml @@ -182,6 +182,69 @@ de: one: Kind other: Kinder + group/nejb: NEJB + group/nejb_bundesleitung: NEJB Bundesleitung + group/netzwerk_ehemalige_jungwacht_blauring: Netzwerk Ehemalige Jungwacht Blauring + group/nejb_kanton: + one: Kanton (Ehemalige) + other: Kantone + group/kanton_ehemaligenverein: + one: Kantonaler Ehemaligenverein + other: Kantonale Ehemaligenvereine + group/nejb_region: + one: Region (Ehemalige) + other: Regionen + group/region_ehemaligenverein: + one: Regionaler Ehemaligenverein + other: Regionale Ehemaligenvereine + group/nejb_schar: + one: Ehemaligenschar + other: Ehemaligenscharen + + group/nejb/group_admin: Adressverwaltung + group/nejb/dispatch_address: Versandadresse + group/nejb/it_support: IT Support + + group/nejb_bundesleitung/group_admin: Adressverwaltung + + group/netzwerk_ehemalige_jungwacht_blauring/leader: Leitung + group/netzwerk_ehemalige_jungwacht_blauring/group_admin: Adressverwaltung + group/netzwerk_ehemalige_jungwacht_blauring/treasurer: Kassier*in + group/netzwerk_ehemalige_jungwacht_blauring/active_member: Aktivmitglied + group/netzwerk_ehemalige_jungwacht_blauring/passive_member: Passivmitglied + group/netzwerk_ehemalige_jungwacht_blauring/collective_member: Kollektivmitglied + group/netzwerk_ehemalige_jungwacht_blauring/nejb_joiner: Neumitglied + group/netzwerk_ehemalige_jungwacht_blauring/external: Extern + group/netzwerk_ehemalige_jungwacht_blauring/dispatch_address: Versandadresse + + group/nejb_kanton/group_admin: Adressverwaltung + + group/kanton_ehemaligenverein/leader: Leitung + group/kanton_ehemaligenverein/group_admin: Adressverwaltung + group/kanton_ehemaligenverein/treasurer: Kassier*in + group/kanton_ehemaligenverein/nejb_member: Mitglied Ehemalige + group/kanton_ehemaligenverein/nejb_joiner: Neumitglied + group/kanton_ehemaligenverein/external: Extern + group/kanton_ehemaligenverein/dispatch_address: Versandadresse + + group/nejb_region/group_admin: Adressverwaltung + + group/region_ehemaligenverein/leader: Leitung + group/region_ehemaligenverein/group_admin: Adressverwaltung + group/region_ehemaligenverein/treasurer: Kassier*in + group/region_ehemaligenverein/nejb_member: Mitglied Ehemalige + group/region_ehemaligenverein/nejb_joiner: Neumitglied + group/region_ehemaligenverein/external: Extern + group/region_ehemaligenverein/dispatch_address: Versandadresse + + group/nejb_schar/leader: Leitung + group/nejb_schar/group_admin: Adressverwaltung + group/nejb_schar/treasurer: Kassier*in + group/nejb_schar/nejb_member: Mitglied Ehemalige + group/nejb_schar/nejb_joiner: Neumitglied + group/nejb_schar/external: Extern + group/nejb_schar/dispatch_address: Versandadresse + jubla/role/external: Extern jubla/role/alumnus: Ehemalig jubla/role/coach: Coach diff --git a/lib/tasks/nejb.rake b/lib/tasks/nejb.rake index dd8d2e28..550f124b 100644 --- a/lib/tasks/nejb.rake +++ b/lib/tasks/nejb.rake @@ -56,5 +56,10 @@ namespace :nejb do Group.rebuild!(false) Group.archival_validation = true end + + say_with_time "Regenerating ordering tables" do + require Rails.root.join("db", "seeds", "support", "order_table_seeder") + OrderTableSeeder.new.seed + end end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 2aa8e248..c1b60388 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -1,16 +1,12 @@ -# encoding: utf-8 - -# Copyright (c) 2012-2013, Jungwacht Blauring Schweiz. This file is part of +# Copyright (c) 2012-2024, Jungwacht Blauring Schweiz. This file is part of # hitobito_jubla 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_jubla. -require 'spec_helper' +require "spec_helper" describe Group do - - include_examples 'group types' - + include_examples "group types" describe Group::Federation do subject { Group::Federation } @@ -20,7 +16,7 @@ it { is_expected.to have(5).role_types } it { is_expected.to be_layer } - its(:possible_children) { should include(Group::SimpleGroup) } + its(:possible_children) { is_expected.to include(Group::SimpleGroup) } end describe Group::Flock do @@ -31,66 +27,65 @@ it { is_expected.to have(11).role_types } it { is_expected.to be_layer } - it 'may have same name as other flock with different kind' do + it "may have same name as other flock with different kind" do parent = groups(:city) - flock = Group::Flock.new(name: 'bla', kind: 'Jungwacht') + flock = Group::Flock.new(name: "bla", kind: "Jungwacht") flock.parent = parent flock.save! - other = Group::Flock.new(name: 'bla', kind: 'Blauring') + other = Group::Flock.new(name: "bla", kind: "Blauring") other.parent = parent other.valid? expect(other.errors.full_messages).to eq([]) end - end describe Group::SimpleGroup do subject { Group::SimpleGroup } + it { is_expected.to have(1).possible_children } it { is_expected.to have(0).default_children } it { is_expected.to have(6).role_types } it { is_expected.not_to be_layer } - its(:possible_children) { should include(Group::SimpleGroup) } + its(:possible_children) { is_expected.to include(Group::SimpleGroup) } - it 'includes the common roles' do + it "includes the common roles" do expect(subject.role_types).to include(Group::SimpleGroup::GroupAdmin) end - it 'includes the external role' do + it "includes the external role" do expect(subject.role_types).to include(Group::SimpleGroup::External) end - it 'may have same name as other group with different parent' do - flock = Group::SimpleGroup.new(name: 'bla') + it "may have same name as other group with different parent" do + flock = Group::SimpleGroup.new(name: "bla") flock.parent = groups(:city) flock.save! - other = Group::SimpleGroup.new(name: 'bla') + other = Group::SimpleGroup.new(name: "bla") other.parent = groups(:bern) expect(other).to be_valid end - end - describe '#all_types' do + describe "#all_types" do subject { Group.all_types } - it 'must have root as the first item' do - expect(subject.first).to eq(Group::Federation) + it "must have root as the first item" do + expect(subject.first).to eq(Group::Root) end - it 'must have simple group as last item' do + it "must have simple group as last item" do expect(subject.last).to eq(Group::SimpleGroup) end - context '#destroy' do - it 'deletes Layer if there are only Alumnus Group childs' do + context "#destroy" do + it "deletes Layer if there are only Alumnus Group childs" do group = Group::Region.all.first group.children.delete_all - alumnus_group = Group::RegionalAlumnusGroup.create(name: 'test_group', parent_id: group.id) - alumnus_group2 = Group::RegionalAlumnusGroup.create(name: 'test_group2', - parent_id: group.id) - alumnus_group3 = Group::RegionalAlumnusGroup.create(name: 'test_group3', - parent_id: alumnus_group2.id) + alumnus_group = Group::RegionalAlumnusGroup.create(name: "test_group", parent_id: group.id) + alumnus_group2 = Group::RegionalAlumnusGroup.create(name: "test_group2", + parent_id: group.id) + alumnus_group3 = Group::RegionalAlumnusGroup.create(name: "test_group3", + parent_id: alumnus_group2.id) expect(group.destroy).not_to be false @@ -100,10 +95,10 @@ expect(Group.without_deleted.where(id: alumnus_group3.id)).not_to exist end - it 'deletes all alumnus roles when deleting an alumnus group via its layer' do + it "deletes all alumnus roles when deleting an alumnus group via its layer" do group = Group::Region.all.first group.children.delete_all - alumnus_group = Group::RegionalAlumnusGroup.create(name: 'test_group', parent_id: group.id) + alumnus_group = Group::RegionalAlumnusGroup.create(name: "test_group", parent_id: group.id) Role.create(group: alumnus_group) expect(Role.with_deleted.where.not(group_id: Group.with_deleted.select(:id)).count).to be 0 @@ -113,19 +108,19 @@ end end - describe '.course_offerers' do + describe ".course_offerers" do subject { Group.course_offerers } - it 'includes federation' do + it "includes federation" do is_expected.to include groups(:ch) end - it 'includes states' do + it "includes states" do is_expected.to include groups(:be) is_expected.to include groups(:no) end - it 'does not include flocks' do + it "does not include flocks" do is_expected.not_to include groups(:thun) is_expected.not_to include groups(:ausserroden) is_expected.not_to include groups(:innerroden) @@ -133,29 +128,27 @@ is_expected.not_to include groups(:muri) end - it 'orders by parent and name' do - expected = ['Jubla Schweiz', 'Kanton Bern', 'Nordostschweiz'] + it "orders by parent and name" do + expected = ["Jubla Schweiz", "Kanton Bern", "Nordostschweiz"] expect(subject.map(&:name)).to eq expected end end - describe 'alumnus filter' do + describe "alumnus filter" do let(:group) { groups(:ch) } - it 'creating non alumnus group creats alumnus filter' do + it "creating non alumnus group creats alumnus filter" do expect do - board = Group::FederalBoard.create(name: 'board', parent_id: group.id) - filter = board.people_filters.find_by(name: 'Ehemalige') + board = Group::FederalBoard.create(name: "board", parent_id: group.id) + filter = board.people_filters.find_by(name: "Ehemalige") expect(filter.filter_chain).to be_present - end.to change { PeopleFilter.count }.by(1) + end.to change { PeopleFilter.count }.by(1) end - it 'creating alumnus group does not create alumnus filter' do + it "creating alumnus group does not create alumnus filter" do expect do - Group::FederalAlumnusGroup.create(name: 'board', parent_id: group.id) - end.not_to change { PeopleFilter.count } + Group::FederalAlumnusGroup.create(name: "board", parent_id: group.id) + end.not_to change { PeopleFilter.count } end - end - end diff --git a/spec/models/role_spec.rb b/spec/models/role_spec.rb index 55f5dc72..40d48879 100644 --- a/spec/models/role_spec.rb +++ b/spec/models/role_spec.rb @@ -49,7 +49,7 @@ subject { Role.all_types } it 'starts with top most role' do - expect(subject.first).to eq(Group::Federation::GroupAdmin) + expect(subject.first).to eq(Group::Root::Admin) end it 'finishes with bottom most role' do