effective_committees 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +186 -0
  4. data/Rakefile +18 -0
  5. data/app/assets/config/effective_committees_manifest.js +3 -0
  6. data/app/assets/javascripts/effective_committees/base.js +0 -0
  7. data/app/assets/javascripts/effective_committeesjs +1 -0
  8. data/app/assets/stylesheets/effective_committees/base.scss +0 -0
  9. data/app/assets/stylesheets/effective_committees.scss +1 -0
  10. data/app/controllers/admin/committee_files_controller.rb +16 -0
  11. data/app/controllers/admin/committee_folders_controller.rb +16 -0
  12. data/app/controllers/admin/committee_members_controller.rb +16 -0
  13. data/app/controllers/admin/committees_controller.rb +22 -0
  14. data/app/controllers/effective/committee_folders_controller.rb +7 -0
  15. data/app/controllers/effective/committee_members_controller.rb +19 -0
  16. data/app/controllers/effective/committees_controller.rb +17 -0
  17. data/app/datatables/admin/effective_committee_files_datatable.rb +24 -0
  18. data/app/datatables/admin/effective_committee_folders_datatable.rb +28 -0
  19. data/app/datatables/admin/effective_committee_members_datatable.rb +32 -0
  20. data/app/datatables/admin/effective_committees_datatable.rb +34 -0
  21. data/app/datatables/effective_committee_members_datatable.rb +42 -0
  22. data/app/datatables/effective_committees_datatable.rb +31 -0
  23. data/app/helpers/effective_committees_helper.rb +3 -0
  24. data/app/models/concerns/effective_committees_user.rb +40 -0
  25. data/app/models/effective/committee.rb +55 -0
  26. data/app/models/effective/committee_file.rb +40 -0
  27. data/app/models/effective/committee_folder.rb +42 -0
  28. data/app/models/effective/committee_member.rb +76 -0
  29. data/app/views/admin/committee_files/_form.html.haml +14 -0
  30. data/app/views/admin/committee_folders/_form.html.haml +21 -0
  31. data/app/views/admin/committee_members/_form.html.haml +31 -0
  32. data/app/views/admin/committee_members/_user_fields.html.haml +7 -0
  33. data/app/views/admin/committees/_fields.html.haml +7 -0
  34. data/app/views/admin/committees/_form.html.haml +20 -0
  35. data/app/views/admin/committees/_form_committee.html.haml +6 -0
  36. data/app/views/effective/committee_folders/_committee_folder.html.haml +24 -0
  37. data/app/views/effective/committee_members/_form.html.haml +35 -0
  38. data/app/views/effective/committee_members/_user_fields.html.haml +7 -0
  39. data/app/views/effective/committees/_committee.html.haml +23 -0
  40. data/app/views/effective/committees/_dashboard.html.haml +10 -0
  41. data/app/views/effective/committees/_fields.html.haml +2 -0
  42. data/app/views/effective/committees/_form.html.haml +8 -0
  43. data/app/views/effective/committees/_form_committee.html.haml +11 -0
  44. data/app/views/effective/committees/index.html.haml +21 -0
  45. data/config/effective_committees.rb +13 -0
  46. data/config/routes.rb +24 -0
  47. data/db/migrate/01_create_effective_committees.rb.erb +14 -0
  48. data/db/seeds.rb +1 -0
  49. data/lib/effective_committees/engine.rb +18 -0
  50. data/lib/effective_committees/version.rb +3 -0
  51. data/lib/effective_committees.rb +18 -0
  52. data/lib/generators/effective_committees/install_generator.rb +31 -0
  53. data/lib/generators/templates/effective_committees_mailer_preview.rb +4 -0
  54. data/lib/tasks/effective_committees_tasks.rake +8 -0
  55. metadata +250 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b793fe3d40958ea8fc7e853979a10ef40cdbdfc043893b93690ad62f8d5c7604
4
+ data.tar.gz: 414192d935ae2fc8f6b5b24617a97c219e72a069728c8e3a22241ef7449301bb
5
+ SHA512:
6
+ metadata.gz: 784a0ccd91b3d7fdff1023a75f41506a771b17293ad73cb4c14de8d1184cd1c580a10c46d29072302c182ed906d13910f6837e191169306e052fbf77b30a5a74
7
+ data.tar.gz: 0b09e1874e3a24d4e29b71e12ecddf4920634d4c57fcdbf0a1c5d6e49210fb5e5b18c80d9d4507d0fbec1bd8852f19b18d4c13a0befe7530c0e6924c4d5d7495
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Code and Effect Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # Effective Committees
2
+
3
+ Committees are groups of users that can all share files.
4
+
5
+ ## Getting Started
6
+
7
+ This requires Rails 6+ and Twitter Bootstrap 4 and just works with Devise.
8
+
9
+ Please first install the [effective_datatables](https://github.com/code-and-effect/effective_datatables) gem.
10
+
11
+ Please download and install the [Twitter Bootstrap4](http://getbootstrap.com)
12
+
13
+ Add to your Gemfile:
14
+
15
+ ```ruby
16
+ gem 'haml-rails' # or try using gem 'hamlit-rails'
17
+ gem 'effective_committees'
18
+ ```
19
+
20
+ Run the bundle command to install it:
21
+
22
+ ```console
23
+ bundle install
24
+ ```
25
+
26
+ Then run the generator:
27
+
28
+ ```ruby
29
+ rails generate effective_committees:install
30
+ ```
31
+
32
+ The generator will install an initializer which describes all configuration options and creates a database migration.
33
+
34
+ If you want to tweak the table names, manually adjust both the configuration file and the migration now.
35
+
36
+ Then migrate the database:
37
+
38
+ ```ruby
39
+ rake db:migrate
40
+ ```
41
+
42
+ Please add the following to your User model:
43
+
44
+ ```
45
+ effective_committees_user
46
+
47
+ Use the following datatables to display to your user their applicants dues:
48
+
49
+ ```haml
50
+ %h2 My Committees
51
+ = render 'effective/committees/dashboard'
52
+ ```
53
+
54
+ and
55
+
56
+ ```
57
+ Add a link to the admin menu:
58
+
59
+ ```haml
60
+ - if can? :admin, :effective_committees
61
+ = nav_dropdown 'Committees' do
62
+ - if can? :index, Effective::Committee
63
+ = nav_link_to 'Committees', effective_committees.admin_committees_path
64
+
65
+ - if can? :index, Effective::CommitteeMember
66
+ = nav_link_to 'Committee Members', effective_committees.admin_committee_members_path
67
+
68
+ - if can? :index, Effective::CommitteeFolder
69
+ = nav_link_to 'Committee Folders', effective_committees.admin_committee_folders_path
70
+
71
+ - if can? :index, Effective::CommitteeFile
72
+ = nav_link_to 'Committee Files', effective_committees.admin_committee_files_path
73
+ ```
74
+
75
+ ## Configuration
76
+
77
+ ## Authorization
78
+
79
+ All authorization checks are handled via the effective_resources gem found in the `config/initializers/effective_resources.rb` file.
80
+
81
+ ## Effective Roles
82
+
83
+ This gem works with effective roles for the representative roles.
84
+
85
+ Configure your `config/initializers/effective_roles.rb` something like this:
86
+
87
+ ```
88
+ EffectiveRoles.setup do |config|
89
+ config.roles = [:admin, :reserved, :owner, :billing] # Only add to the end of this array. Never prepend roles.
90
+
91
+ # config.role_descriptions
92
+ # ========================
93
+ # This setting configures the text that is displayed by form helpers (see README.md)
94
+
95
+ config.role_descriptions = {
96
+ 'User' => {
97
+ # User roles
98
+ admin: 'can log in to the /admin section of the website. full access to everything.',
99
+ },
100
+ 'Effective::CommitteeMember' => {
101
+ owner: 'committee owner. full access to everything.',
102
+ billing: 'the billing contact. full access to everything.'
103
+ }
104
+ }
105
+
106
+ # config.assignable_roles
107
+ # Which roles can be assigned by whom
108
+ # =======================
109
+ # When current_user is passed into a form helper function (see README.md)
110
+ # this setting determines which roles that current_user may assign
111
+ config.assignable_roles = {
112
+ 'User' => { admin: [:admin] },
113
+
114
+ 'Effective::CommitteeMember' => {
115
+ admin: [:owner, :billing],
116
+ owner: [:owner, :billing],
117
+ billing: [:billing]
118
+ }
119
+ }
120
+ end
121
+ ```
122
+
123
+ ## Permissions
124
+
125
+ The permissions you actually want to define are as follows (using CanCan):
126
+
127
+ ```ruby
128
+ if user.persisted?
129
+ can :index, Effective::Committee
130
+ can(:show, Effective::Committee) { |committee| user.committees.include?(committee) }
131
+
132
+ can([:edit, :update], Effective::Committee) do |committee|
133
+ user.committee_member(committee: committee)&.is?(:owner)
134
+ end
135
+
136
+ can :index, Effective::CommitteeMember
137
+
138
+ can(:show, Effective::CommitteeMember) { |member| user.committees.include?(member.committee) }
139
+ can(:new, Effective::CommitteeMember)
140
+
141
+ can([:create, :edit, :update], Effective::CommitteeMember) do |cm|
142
+ user.committee_member(committee: cm.committee)&.is?(:owner)
143
+ end
144
+
145
+ can(:destroy, Effective::CommitteeMember) do |member|
146
+ user.committee_member(committee: member.committee)&.is?(:owner) && !member.is?(:owner)
147
+ end
148
+
149
+ can(:show, Effective::CommitteeFolder) { |folder| user.committees.include?(folder.committee) }
150
+ can(:show, Effective::CommitteeFile) { |file| user.committees.include?(file.committee) }
151
+ end
152
+
153
+ if user.admin?
154
+ can :admin, :effective_committees
155
+
156
+ can(crud - [:destroy], Effective::Committee)
157
+ can(:destroy, Effective::Committee) { |committee| committee.committee_members_count == 0 }
158
+
159
+ can(crud - [:destroy], Effective::CommitteeFolder)
160
+ can(:destroy, Effective::CommitteeFolder) { |folder| folder.committee_files_count == 0 }
161
+
162
+ can(crud, Effective::CommitteeMember)
163
+ can(crud, Effective::CommitteeFile)
164
+ end
165
+ ```
166
+
167
+ ## License
168
+
169
+ MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
170
+
171
+ ## Testing
172
+
173
+ Run tests by:
174
+
175
+ ```ruby
176
+ rails test
177
+ ```
178
+
179
+ ## Contributing
180
+
181
+ 1. Fork it
182
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
183
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
184
+ 4. Push to the branch (`git push origin my-new-feature`)
185
+ 5. Bonus points for test coverage
186
+ 6. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
9
+
10
+ require "rake/testtask"
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'test'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = false
16
+ end
17
+
18
+ task default: :test
@@ -0,0 +1,3 @@
1
+ //= link_directory ../javascripts .js
2
+ //= link_directory ../stylesheets .css
3
+ //= link_tree ../images
@@ -0,0 +1 @@
1
+ //= require_tree ./effective_committees
@@ -0,0 +1 @@
1
+ @import 'effective_committees/base';
@@ -0,0 +1,16 @@
1
+ module Admin
2
+ class CommitteeFilesController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_committees) }
5
+
6
+ include Effective::CrudController
7
+
8
+ private
9
+
10
+ def permitted_params
11
+ model = (params.key?(:effective_committee_file) ? :effective_committee_file : :committee_file)
12
+ params.require(model).permit!
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Admin
2
+ class CommitteeFoldersController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_committees) }
5
+
6
+ include Effective::CrudController
7
+
8
+ private
9
+
10
+ def permitted_params
11
+ model = (params.key?(:effective_committee_folder) ? :effective_committee_folder : :committee_folder)
12
+ params.require(model).permit!
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Admin
2
+ class CommitteeMembersController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_committees) }
5
+
6
+ include Effective::CrudController
7
+
8
+ private
9
+
10
+ def permitted_params
11
+ model = (params.key?(:effective_committee_member) ? :effective_committee_member : :committee_member)
12
+ params.require(model).permit!
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ module Admin
2
+ class CommitteesController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_committees) }
5
+
6
+ include Effective::CrudController
7
+
8
+ submit :save, 'Save'
9
+ submit :save, 'Save and Add New', redirect: :new
10
+ submit :save, 'Save and View', redirect: -> { effective_committees.committee_path(resource) }
11
+
12
+ resource_scope -> { Effective::Committee.deep.all }
13
+
14
+ private
15
+
16
+ def permitted_params
17
+ model = (params.key?(:effective_committee) ? :effective_committee : :committee)
18
+ params.require(model).permit!
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ module Effective
2
+ class CommitteeFoldersController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+
5
+ include Effective::CrudController
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module Effective
2
+ class CommitteeMembersController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+
5
+ include Effective::CrudController
6
+
7
+ resource_scope -> {
8
+ committees = Effective::Committee.deep.where(id: current_user.committees)
9
+ Effective::CommitteeMember.deep.where(committee: committees)
10
+ }
11
+
12
+ private
13
+
14
+ def permitted_params
15
+ params.require(:effective_committee_member).permit!
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module Effective
2
+ class CommitteesController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+
5
+ include Effective::CrudController
6
+
7
+ resource_scope -> { Effective::Committee.all.deep }
8
+
9
+ private
10
+
11
+ def permitted_params
12
+ model = (params.key?(:effective_committee) ? :effective_committee : :committee)
13
+ params.require(model).permit!
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ module Admin
2
+ class EffectiveCommitteeFilesDatatable < Effective::Datatable
3
+ datatable do
4
+ col :updated_at, visible: false
5
+ col :created_at, visible: false
6
+
7
+ col :id, visible: false
8
+
9
+ col :committee, search: :string
10
+ col :committee_folder, search: :string, label: 'Folder'
11
+
12
+ col :file
13
+ col :title
14
+ col :notes
15
+
16
+ actions_col
17
+ end
18
+
19
+ collection do
20
+ Effective::CommitteeFile.deep.all
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ module Admin
2
+ class EffectiveCommitteeFoldersDatatable < Effective::Datatable
3
+ datatable do
4
+ reorder :position
5
+
6
+ col :updated_at, visible: false
7
+ col :created_at, visible: false
8
+
9
+ col :id, visible: false
10
+
11
+ col :committee, search: :string
12
+
13
+ col :title, label: 'Folder'
14
+ col :slug, visible: false
15
+ col :body
16
+
17
+ col :committee_files, label: 'Files', search: :string
18
+ col :committee_files_count, label: 'Files Count', visible: false
19
+
20
+ actions_col
21
+ end
22
+
23
+ collection do
24
+ Effective::CommitteeFolder.deep.all
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,32 @@
1
+ module Admin
2
+ class EffectiveCommitteeMembersDatatable < Effective::Datatable
3
+ datatable do
4
+ col :id, visible: false
5
+ col :user_id, visible: false
6
+
7
+ col :committee
8
+ col :user
9
+
10
+ unless attributes[:user_id]
11
+ col :email do |committee_member|
12
+ mail_to(committee_member.user.email)
13
+ end
14
+ end
15
+
16
+ if EffectiveCommittees.use_effective_roles
17
+ col :roles, search: roles_collection
18
+ end
19
+
20
+ actions_col
21
+ end
22
+
23
+ collection do
24
+ Effective::CommitteeMember.deep.all
25
+ end
26
+
27
+ def roles_collection
28
+ EffectiveRoles.roles_collection(Effective::CommitteeMember.new).map(&:second)
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module Admin
2
+ class EffectiveCommitteesDatatable < Effective::Datatable
3
+ datatable do
4
+
5
+ col :updated_at, visible: false
6
+ col :created_at, visible: false
7
+
8
+ col :id, visible: false
9
+
10
+ col :title, label: 'Committee'
11
+ col :slug, visible: false
12
+ col :body
13
+
14
+ col :committee_members, label: 'Members', search: :string
15
+ col :committee_members_count, label: 'Members Count', visible: false
16
+
17
+ col :committee_folders, label: 'Folders', search: :string
18
+ col :committee_folders_count, label: 'Folders Count', visible: false
19
+
20
+ col :committee_files, label: 'Files', search: :string
21
+ col :committee_files_count, label: 'Files Count', visible: false
22
+
23
+ actions_col do |committee|
24
+ dropdown_link_to('View Committee', effective_committees.committee_path(committee), target: '_blank')
25
+ end
26
+
27
+ end
28
+
29
+ collection do
30
+ Effective::Committee.deep.all
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ class EffectiveCommitteeMembersDatatable < Effective::Datatable
2
+ datatable do
3
+ col :id, visible: false
4
+
5
+ col :committee
6
+ col :user
7
+
8
+ unless attributes[:user_id]
9
+ col :email do |committee_member|
10
+ mail_to(committee_member.user.email)
11
+ end
12
+ end
13
+
14
+ if EffectiveCommittees.use_effective_roles
15
+ col :roles, search: roles_collection
16
+ end
17
+
18
+ unless attributes[:actions] == false
19
+ actions_col
20
+ end
21
+
22
+ end
23
+
24
+ collection do
25
+ scope = Effective::CommitteeMember.deep.all.where(committee: current_user.committees)
26
+
27
+ if attributes[:committee_id]
28
+ scope = scope.where(committee_id: attributes[:committee_id])
29
+ end
30
+
31
+ if attributes[:user_id]
32
+ scope = scope.where(user_id: attributes[:user_id])
33
+ end
34
+
35
+ scope
36
+ end
37
+
38
+ def roles_collection
39
+ EffectiveRoles.roles_collection(Effective::CommitteeMember.new).map(&:second)
40
+ end
41
+
42
+ end
@@ -0,0 +1,31 @@
1
+ # Dashboard Committees
2
+ class EffectiveCommitteesDatatable < Effective::Datatable
3
+ datatable do
4
+ order :title
5
+
6
+ col :id, visible: false
7
+
8
+ col :title, label: 'Committee'
9
+
10
+ col :committee_members, search: :string, label: 'Members'
11
+
12
+ col :committee_folders, search: :string, label: 'Folders'
13
+
14
+ col :committee_folders_count, label: 'Folders', visible: false do |committee|
15
+ pluralize(committee.committee_folders_count, 'folders')
16
+ end
17
+
18
+ col :committee_files, search: :string, label: 'Files', visible: false
19
+
20
+ col :committee_files_count, label: 'Files' do |committee|
21
+ pluralize(committee.committee_files_count, 'files')
22
+ end
23
+
24
+ actions_col
25
+ end
26
+
27
+ collection do
28
+ Effective::Committee.deep.where(id: current_user.committees)
29
+ end
30
+
31
+ end
@@ -0,0 +1,3 @@
1
+ module EffectiveCommitteesHelper
2
+
3
+ end
@@ -0,0 +1,40 @@
1
+ # EffectiveCommitteesUser
2
+ #
3
+ # Mark your user model with effective_committees_user to get all the includes
4
+
5
+ module EffectiveCommitteesUser
6
+ extend ActiveSupport::Concern
7
+
8
+ module Base
9
+ def effective_committees_user
10
+ include ::EffectiveCommitteesUser
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def effective_committees_user?; true; end
16
+ end
17
+
18
+ included do
19
+ has_many :committee_members, -> { Effective::CommitteeMember.sorted },
20
+ class_name: 'Effective::CommitteeMember', inverse_of: :user, dependent: :delete_all
21
+
22
+ accepts_nested_attributes_for :committee_members, allow_destroy: true
23
+ end
24
+
25
+ # Instance Methods
26
+
27
+ def committee_member(committee:)
28
+ committee_members.find { |rep| rep.committee_id == committee.id }
29
+ end
30
+
31
+ # Find or build
32
+ def build_committee_member(committee:)
33
+ committee_member(committee: committee) || committee_members.build(committee: committee)
34
+ end
35
+
36
+ def committees
37
+ committee_members.reject(&:marked_for_destruction?).map(&:committee)
38
+ end
39
+
40
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Effective
4
+ class Committee < ActiveRecord::Base
5
+ self.table_name = EffectiveCommittees.committees_table_name.to_s
6
+
7
+ acts_as_slugged
8
+
9
+ log_changes if respond_to?(:log_changes)
10
+ has_rich_text :body
11
+
12
+ has_many :committee_members, -> { Effective::CommitteeMember.sorted }, class_name: 'Effective::CommitteeMember', inverse_of: :committee, dependent: :delete_all
13
+ accepts_nested_attributes_for :committee_members, allow_destroy: true
14
+
15
+ has_many :committee_folders, -> { Effective::CommitteeFolder.sorted }, class_name: 'Effective::CommitteeFolder', inverse_of: :committee, dependent: :delete_all
16
+ accepts_nested_attributes_for :committee_folders, allow_destroy: true
17
+
18
+ has_many :committee_files, -> { Effective::CommitteeFile.sorted }, class_name: 'Effective::CommitteeFile', inverse_of: :committee, dependent: :delete_all
19
+ accepts_nested_attributes_for :committee_files, allow_destroy: true
20
+
21
+ effective_resource do
22
+ title :string
23
+ slug :string
24
+
25
+ committee_members_count :integer # Counter Cache
26
+ committee_folders_count :integer # Counter Cache
27
+ committee_files_count :integer # Counter Cache
28
+
29
+ timestamps
30
+ end
31
+
32
+ scope :sorted, -> { order(:title) }
33
+ scope :deep, -> { includes(:committee_members) }
34
+
35
+ validates :title, presence: true, uniqueness: true, length: { maximum: 255 }
36
+
37
+ def to_s
38
+ title.presence || 'New Committee'
39
+ end
40
+
41
+ def committee_member(user:)
42
+ committee_members.find { |member| member.user_id == user.id }
43
+ end
44
+
45
+ # Find or build
46
+ def build_committee_member(user:)
47
+ committee_member(user: user) || committee_members.build(user: user)
48
+ end
49
+
50
+ def users
51
+ committee_members.reject(&:marked_for_destruction?).map(&:user)
52
+ end
53
+
54
+ end
55
+ end