simple_teams 0.1.0

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 (98) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/simple_teams_manifest.js +1 -0
  6. data/app/assets/stylesheets/simple_teams/application.css +15 -0
  7. data/app/controllers/simple_teams/accept_invitations_controller.rb +57 -0
  8. data/app/controllers/simple_teams/admin/invitations_controller.rb +60 -0
  9. data/app/controllers/simple_teams/admin/memberships_controller.rb +60 -0
  10. data/app/controllers/simple_teams/admin/teams_controller.rb +60 -0
  11. data/app/controllers/simple_teams/application_controller.rb +13 -0
  12. data/app/controllers/simple_teams/invitations_controller.rb +96 -0
  13. data/app/controllers/simple_teams/leave_teams_controller.rb +25 -0
  14. data/app/controllers/simple_teams/memberships_controller.rb +61 -0
  15. data/app/controllers/simple_teams/related_members_controller.rb +33 -0
  16. data/app/controllers/simple_teams/teams_controller.rb +19 -0
  17. data/app/forms/simple_teams/invitation_form.rb +77 -0
  18. data/app/forms/simple_teams/invitation_forms/create.rb +24 -0
  19. data/app/forms/simple_teams/invitation_forms/create_bulk.rb +125 -0
  20. data/app/forms/simple_teams/invitation_forms/create_combo.rb +75 -0
  21. data/app/forms/simple_teams/invitation_forms/update.rb +29 -0
  22. data/app/forms/simple_teams/membership_form.rb +91 -0
  23. data/app/helpers/simple_teams/application_helper.rb +4 -0
  24. data/app/helpers/simple_teams/invitations_helper.rb +4 -0
  25. data/app/helpers/simple_teams/memberships_helper.rb +4 -0
  26. data/app/helpers/simple_teams/teams_helper.rb +4 -0
  27. data/app/jobs/simple_teams/application_job.rb +4 -0
  28. data/app/mailers/simple_teams/application_mailer.rb +6 -0
  29. data/app/mailers/simple_teams/mailer.rb +17 -0
  30. data/app/models/concerns/simple_teams/member_object.rb +22 -0
  31. data/app/models/concerns/simple_teams/team_object.rb +23 -0
  32. data/app/models/simple_teams/ability.rb +34 -0
  33. data/app/models/simple_teams/application_record.rb +5 -0
  34. data/app/models/simple_teams/invitation.rb +85 -0
  35. data/app/models/simple_teams/membership.rb +16 -0
  36. data/app/models/simple_teams/team.rb +23 -0
  37. data/app/notifications/application_notification.rb +4 -0
  38. data/app/notifications/simple_teams/bulk_invitations_notification.rb +51 -0
  39. data/app/notifications/simple_teams/invitation_notification.rb +54 -0
  40. data/app/notifications/simple_teams/invitations/accepted_notification.rb +13 -0
  41. data/app/notifications/simple_teams/invitations/created_notification.rb +13 -0
  42. data/app/notifications/simple_teams/invitations/destroyed_notification.rb +13 -0
  43. data/app/notifications/simple_teams/invitations/updated_notification.rb +13 -0
  44. data/app/notifications/simple_teams/membership_notification.rb +58 -0
  45. data/app/notifications/simple_teams/memberships/destroyed_notification.rb +13 -0
  46. data/app/notifications/simple_teams/memberships/left_notification.rb +17 -0
  47. data/app/notifications/simple_teams/memberships/updated_notification.rb +17 -0
  48. data/app/service_objects/simple_teams/accept_invitation_service.rb +61 -0
  49. data/app/service_objects/simple_teams/initialize_team_service.rb +25 -0
  50. data/app/service_objects/simple_teams/leave_team_service.rb +56 -0
  51. data/app/views/layouts/simple_teams/application.html.erb +20 -0
  52. data/app/views/simple_teams/_roles_field.html.erb +22 -0
  53. data/app/views/simple_teams/accept_invitations/invalid_token.html.erb +7 -0
  54. data/app/views/simple_teams/accept_invitations/new.html.erb +18 -0
  55. data/app/views/simple_teams/admin/invitations/_form.html.erb +62 -0
  56. data/app/views/simple_teams/admin/invitations/_invitation.html.erb +47 -0
  57. data/app/views/simple_teams/admin/invitations/edit.html.erb +10 -0
  58. data/app/views/simple_teams/admin/invitations/index.html.erb +14 -0
  59. data/app/views/simple_teams/admin/invitations/new.html.erb +9 -0
  60. data/app/views/simple_teams/admin/invitations/show.html.erb +10 -0
  61. data/app/views/simple_teams/admin/memberships/_form.html.erb +32 -0
  62. data/app/views/simple_teams/admin/memberships/_membership.html.erb +17 -0
  63. data/app/views/simple_teams/admin/memberships/edit.html.erb +10 -0
  64. data/app/views/simple_teams/admin/memberships/index.html.erb +14 -0
  65. data/app/views/simple_teams/admin/memberships/new.html.erb +9 -0
  66. data/app/views/simple_teams/admin/memberships/show.html.erb +10 -0
  67. data/app/views/simple_teams/admin/teams/_form.html.erb +22 -0
  68. data/app/views/simple_teams/admin/teams/_team.html.erb +7 -0
  69. data/app/views/simple_teams/admin/teams/edit.html.erb +10 -0
  70. data/app/views/simple_teams/admin/teams/index.html.erb +14 -0
  71. data/app/views/simple_teams/admin/teams/new.html.erb +9 -0
  72. data/app/views/simple_teams/admin/teams/show.html.erb +10 -0
  73. data/app/views/simple_teams/invitations/_bulk_form.html.erb +63 -0
  74. data/app/views/simple_teams/invitations/_form.html.erb +15 -0
  75. data/app/views/simple_teams/invitations/_invitation.html.erb +19 -0
  76. data/app/views/simple_teams/invitations/_invitation.json.jbuilder +2 -0
  77. data/app/views/simple_teams/invitations/edit.html.erb +12 -0
  78. data/app/views/simple_teams/invitations/new.html.erb +12 -0
  79. data/app/views/simple_teams/leave_teams/edit.html.erb +2 -0
  80. data/app/views/simple_teams/memberships/_form.html.erb +12 -0
  81. data/app/views/simple_teams/memberships/_membership.html.erb +23 -0
  82. data/app/views/simple_teams/memberships/edit.html.erb +12 -0
  83. data/app/views/simple_teams/related_members/index.json.jbuilder +5 -0
  84. data/app/views/simple_teams/related_members/select2.json.jbuilder +6 -0
  85. data/app/views/simple_teams/teams/_add_member_link.html.erb +3 -0
  86. data/app/views/simple_teams/teams/_members_table.html.erb +20 -0
  87. data/app/views/simple_teams/teams/show.html.erb +38 -0
  88. data/app/views/simple_teams/teams_mailer/invitation_notification.html.erb +9 -0
  89. data/config/locales/simple_teams.en.yml +18 -0
  90. data/config/routes.rb +21 -0
  91. data/db/migrate/20240311052758_create_simple_teams_teams.rb +9 -0
  92. data/db/migrate/20240311053006_create_simple_teams_memberships.rb +11 -0
  93. data/db/migrate/20240311053607_create_simple_teams_invitations.rb +17 -0
  94. data/lib/simple_teams/engine.rb +22 -0
  95. data/lib/simple_teams/version.rb +3 -0
  96. data/lib/simple_teams.rb +6 -0
  97. data/lib/tasks/simple_teams_tasks.rake +4 -0
  98. metadata +160 -0
@@ -0,0 +1,125 @@
1
+ module SimpleTeams
2
+ class InvitationForms::CreateBulk < ApplicationForm
3
+
4
+ attr_accessor :team, :current_user, :single_vs_multiple, :select2_emails, :accessible_emails, :emails, :role
5
+
6
+ def initialize(team, current_user)
7
+ @team = team
8
+ @current_user = current_user
9
+ @emails = []
10
+ end
11
+
12
+ def perform(params)
13
+ self.assign_attributes(params)
14
+ if accessible?
15
+ self.emails = accessible_emails.split(",").map(&:strip).uniq.reject(&:empty?)
16
+ else
17
+ self.emails = select2_emails.map(&:strip).uniq.reject(&:empty?)
18
+ end
19
+
20
+ if valid?
21
+ create_invitations
22
+ generate_notification
23
+ else
24
+ false
25
+ end
26
+ end
27
+
28
+ # Attributes
29
+ def available_roles
30
+ SimpleTeams::Membership.roles
31
+ end
32
+
33
+ private
34
+
35
+ def accessible?
36
+ single_vs_multiple == "accessible"
37
+ end
38
+
39
+ def address_attribute
40
+ accessible? ? :accessible_emails : :select2_emails
41
+ end
42
+
43
+ def valid?
44
+ self.errors.clear
45
+ validate_attributes_present
46
+ validate_invitations
47
+ validate_role_is_available
48
+ validate_current_user_has_rights_to_invite_an_owner
49
+ !self.errors.present?
50
+ end
51
+
52
+ def validate_attributes_present
53
+ [:team, :current_user, :role].each do |a|
54
+ unless self.send(a).present?
55
+ self.errors.add(a, "can't be blank")
56
+ end
57
+ end
58
+ unless self.emails.present?
59
+ self.errors.add(address_attribute, "can't be blank")
60
+ end
61
+ end
62
+
63
+ def validate_invitations
64
+ emails.each do |email|
65
+ invitation = SimpleTeams::Invitation.new(
66
+ :team => team,
67
+ :inviter => current_user,
68
+ :role => role,
69
+ :email => email
70
+ )
71
+ unless invitation.valid?
72
+ invitation.errors[:email].each do |error|
73
+ if error == "is invalid"
74
+ error_message = "#{email} is not a valid email address"
75
+ else
76
+ error_message = error.gsub("this email address", email)
77
+ end
78
+ self.errors.add(address_attribute, error_message)
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def validate_role_is_available
85
+ # Note: Users will never see this error message unless they hack the form
86
+ if role.present?
87
+ unless available_roles.keys.include? role
88
+ self.errors.add(:role, "that role is not available for this resource")
89
+ end
90
+ end
91
+ end
92
+
93
+ def validate_current_user_has_rights_to_invite_an_owner
94
+ if role == "owner"
95
+ unless current_user.membership_for_team(team).owner?
96
+ self.errors.add(:role, "you must be an owner yourself to add add another owner")
97
+ end
98
+ end
99
+ end
100
+
101
+ def create_invitations
102
+ ActiveRecord::Base.transaction do
103
+ emails.each do |email|
104
+ SimpleTeams::Invitation.create!(
105
+ :team => team,
106
+ :inviter => current_user,
107
+ :role => role,
108
+ :email => email
109
+ )
110
+ end
111
+ end
112
+ end
113
+
114
+ def generate_notification
115
+ SimpleTeams::BulkInvitationsNotification.with(
116
+ :team_id => team.id,
117
+ :user_id => current_user.id,
118
+ :team_name => team.name,
119
+ :user_name => current_user.full_name,
120
+ :invitation_names => self.emails,
121
+ ).deliver_later(team.members)
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,75 @@
1
+ module SimpleTeams
2
+ class InvitationForms::CreateCombo < ApplicationForm
3
+
4
+ attr_accessor :team, :current_user, :single_vs_multiple, :email, :emails, :select2_emails, :accessible_emails, :role, :form_instance
5
+
6
+ def initialize(team, current_user)
7
+ @team = team
8
+ @current_user = current_user
9
+ end
10
+
11
+ def perform(params)
12
+ # Store input
13
+ self.assign_attributes(params)
14
+
15
+ # Set form instance from input
16
+ @form_instance = selected_form_klass.new(team, current_user)
17
+
18
+ # Perform
19
+ if form_instance.perform(filter_params(params))
20
+ return true
21
+ else
22
+ reassign_errors
23
+ unless single?
24
+ self.emails = form_instance.emails
25
+ end
26
+ false
27
+ end
28
+ end
29
+
30
+ def available_roles
31
+ SimpleTeams::Membership.roles
32
+ end
33
+
34
+ private
35
+
36
+ def single?
37
+ !multiple? and !accessible?
38
+ end
39
+
40
+ def multiple?
41
+ single_vs_multiple == "multiple"
42
+ end
43
+
44
+ def accessible?
45
+ single_vs_multiple == "accessible"
46
+ end
47
+
48
+ def selected_form_klass
49
+ if single?
50
+ SimpleTeams::InvitationForms::Create
51
+ else
52
+ SimpleTeams::InvitationForms::CreateBulk
53
+ end
54
+ end
55
+
56
+ def filter_params(params)
57
+ if single?
58
+ params.except(:single_vs_multiple, :select2_emails, :accessible_emails)
59
+ else
60
+ params.except(:email)
61
+ end
62
+ end
63
+
64
+ def reassign_errors
65
+ [:team, :current_user, :email, :select2_emails, :accessible_emails, :role].each do |a|
66
+ if form_instance.errors[a].present?
67
+ form_instance.errors[a].each do |error|
68
+ self.errors.add(a, error)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,29 @@
1
+ module SimpleTeams
2
+ class InvitationForms::Update < SimpleTeams::InvitationForm
3
+
4
+ def initialize(invitation, current_user)
5
+ @invitation = invitation
6
+ @team = @invitation.team
7
+ @current_user = current_user
8
+
9
+ # Get existing attributes
10
+ self.class.invitation_attributes.each do |a|
11
+ self.assign_attributes(a => @invitation.send(a))
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def generate_notification
18
+ SimpleTeams::Invitations::UpdatedNotification.with(
19
+ :team_id => team.id,
20
+ :invitation_id => invitation.id,
21
+ :user_id => current_user.id,
22
+ :team_name => team.name,
23
+ :invitation_name => invitation.email,
24
+ :user_name => current_user.full_name
25
+ ).deliver_later(team.members)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,91 @@
1
+ module SimpleTeams
2
+ class MembershipForm < ApplicationForm
3
+
4
+ attr_accessor :membership, :current_user, :role
5
+
6
+ def initialize(membership, current_user)
7
+ @membership = membership
8
+ @current_user = current_user
9
+
10
+ # Get existing attributes
11
+ @role = @membership.role
12
+ end
13
+
14
+ def valid?
15
+ self.errors.clear
16
+ validate_role_is_available
17
+ validate_current_user_has_rights_to_modify_an_existing_owner
18
+ validate_current_user_has_rights_to_add_an_owner
19
+ validate_not_last_owner
20
+ !self.errors.present?
21
+ end
22
+
23
+ def perform(params)
24
+ self.assign_attributes(params)
25
+
26
+ if valid?
27
+ membership.update(params)
28
+ generate_notification
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ def available_roles
35
+ SimpleTeams::Membership.roles
36
+ end
37
+
38
+ private
39
+
40
+ def validate_role_is_available
41
+ # Note: Users will never see this error message unless they hack the form
42
+ if role.present?
43
+ unless available_roles.keys.include? role
44
+ self.errors.add(:role, "that role is not available for this resource")
45
+ end
46
+ end
47
+ end
48
+
49
+ def validate_not_last_owner
50
+ if membership.owner? and only_one_owner? and role != "owner"
51
+ self.errors.add(:role, "you can't remove the last owner of a team")
52
+ end
53
+ end
54
+
55
+ def validate_current_user_has_rights_to_modify_an_existing_owner
56
+ if membership.owner?
57
+ unless current_user.membership_for_team(team).owner?
58
+ self.errors.add(:role, "you must be an owner yourself to modify another owner")
59
+ end
60
+ end
61
+ end
62
+
63
+ def validate_current_user_has_rights_to_add_an_owner
64
+ if role == "owner" and !membership.owner?
65
+ unless current_user.membership_for_team(team).owner?
66
+ self.errors.add(:role, "you must be an owner yourself to add add another owner")
67
+ end
68
+ end
69
+ end
70
+
71
+ def only_one_owner?
72
+ team.memberships.where(:role => :owner).count == 1
73
+ end
74
+
75
+ def team
76
+ membership.team
77
+ end
78
+
79
+ def generate_notification
80
+ SimpleTeams::Memberships::UpdatedNotification.with(
81
+ :team_id => team.id,
82
+ :member_id => membership.member.id,
83
+ :user_id => current_user.id,
84
+ :team_name => team.name,
85
+ :member_name => membership.member.full_name,
86
+ :user_name => current_user.full_name
87
+ ).deliver_later(team.members)
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleTeams
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleTeams
2
+ module InvitationsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleTeams
2
+ module MembershipsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleTeams
2
+ module TeamsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module SimpleTeams
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module SimpleTeams
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ module SimpleTeams
2
+ class Mailer < ApplicationMailer
3
+
4
+ def invitation_notification(invitation)
5
+ @invitation = invitation
6
+ @name = invitation.team.name
7
+ @resource_name = invitation.team.teamable.class.model_name.human
8
+ @invitation_url = accept_team_invitation_url(@invitation.token)
9
+
10
+ mail(
11
+ to: (@invitation.email),
12
+ subject: "Invitation to #{@name} #{@resource_name}"
13
+ )
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ module SimpleTeams::MemberObject
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ has_many :team_memberships, :class_name => "SimpleTeams::Membership", :foreign_key => :member_id, :dependent => :destroy
6
+ has_many :teams, :through => :team_memberships, :class_name => "SimpleTeams::Team"
7
+ has_many :team_members, :through => :teams, :source => :members, :class_name => SimpleTeams.member_class.to_s
8
+ end
9
+
10
+ def member_of_team?(team)
11
+ team_memberships.where(team: team).present?
12
+ end
13
+
14
+ def membership_for_team(team)
15
+ team_memberships.find_by(:team_id => team.id)
16
+ end
17
+
18
+ def role_for_team(team)
19
+ membership_for_team(team).role if membership_for_team(team).present?
20
+ end
21
+
22
+ end
@@ -0,0 +1,23 @@
1
+ module SimpleTeams::TeamObject
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ attr_accessor :team_owner
6
+
7
+ has_one :team, :as => :teamable, :class_name => "SimpleTeams::Team", :dependent => :destroy
8
+
9
+ after_create :generate_team
10
+
11
+ def self.team_object?
12
+ true
13
+ end
14
+
15
+ end
16
+
17
+ private
18
+
19
+ def generate_team
20
+ self.create_team!
21
+ end
22
+
23
+ end
@@ -0,0 +1,34 @@
1
+ module SimpleTeams
2
+ class Ability
3
+ include ::CanCan::Ability
4
+
5
+ def initialize(user)
6
+
7
+ return unless user.present?
8
+
9
+ can :create, Team
10
+
11
+ # Team
12
+ can :read, Team do |team|
13
+ user.member_of_team?(team)
14
+ end
15
+
16
+ can [:update], Team do |team|
17
+ %w"owner administrator".include? user.role_for_team(team)
18
+ end
19
+
20
+ can [:destroy], Team do |team|
21
+ %w"owner".include? user.role_for_team(team)
22
+ end
23
+
24
+ # Team Memberships/Invitations
25
+ can :read, [Membership, Invitation] do |object|
26
+ user.member_of_team?(object.team)
27
+ end
28
+
29
+ can :manage, [Membership, Invitation] do |object|
30
+ %w"owner administrator".include? user.role_for_team(object.team)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module SimpleTeams
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,85 @@
1
+ module SimpleTeams
2
+ class Invitation < ApplicationRecord
3
+ belongs_to :team
4
+ belongs_to :inviter, :class_name => SimpleTeams.member_class.to_s
5
+ belongs_to :membership, :optional => true
6
+
7
+ # validations
8
+ validates_presence_of :email, :role
9
+ validates_format_of :email, :with => URI::MailTo::EMAIL_REGEXP
10
+ validate :email_uninvited, :on => :create
11
+
12
+ # callbacks
13
+ before_validation :format_email
14
+ before_create :generate_token
15
+ before_create :set_expires_at
16
+ after_create :send_invitation_notification
17
+ after_update :send_invitation_notification, :if => :saved_change_to_email?
18
+
19
+ # scopes
20
+ scope :expired, -> { where("? > expires_at", Time.now) }
21
+ scope :unexpired, -> { where("? <= expires_at", Time.now) }
22
+
23
+ # enums
24
+ enum :role, [:member, :administrator, :owner]
25
+ enum :status, [:initial, :accepted, :declined]
26
+
27
+ def expired?
28
+ Time.now > expires_at
29
+ end
30
+
31
+ def unexpired?
32
+ Time.now <= expires_at
33
+ end
34
+
35
+ def reset_invitation_token
36
+ generate_token
37
+ set_expires_at
38
+ self.save
39
+ end
40
+
41
+ def resend_invitation_notification(options = {})
42
+ if Time.now > expires_at - self.class.expiration_window + 1.day
43
+ reset_invitation_token
44
+ end
45
+ send_invitation_notification(options)
46
+ end
47
+
48
+ def self.expiration_window
49
+ 2.weeks
50
+ end
51
+
52
+ private
53
+
54
+ def format_email
55
+ self.email = self.email.downcase.strip if email.present?
56
+ end
57
+
58
+ def generate_token
59
+ self.token = SecureRandom.hex(32)
60
+ end
61
+
62
+ def set_expires_at
63
+ self.expires_at = Time.now + self.class.expiration_window
64
+ end
65
+
66
+ def send_invitation_notification(options = {})
67
+ if options[:now] == true
68
+ SimpleTeams::Mailer.invitation_notification(self).deliver_now
69
+ else
70
+ SimpleTeams::Mailer.invitation_notification(self).deliver_later
71
+ end
72
+ end
73
+
74
+ def email_uninvited
75
+ if team.members.map { |m| m.email }.include?(email)
76
+ self.errors.add :email, "A person with this email address is already a member of this team."
77
+ return false
78
+ elsif team.invitations.initial.where(:email => email).present?
79
+ self.errors.add :email, "A person with this email address has already been invited to this team."
80
+ return false
81
+ end
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,16 @@
1
+ module SimpleTeams
2
+ class Membership < ApplicationRecord
3
+ belongs_to :team
4
+ belongs_to :member, :class_name => SimpleTeams.member_class.to_s
5
+ has_one :invitation, :dependent => :nullify
6
+
7
+ enum :role, [:member, :administrator, :owner]
8
+
9
+ validates_presence_of :role
10
+
11
+ def role_to_s
12
+ role.humanize.capitalize
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ module SimpleTeams
2
+ class Team < ApplicationRecord
3
+
4
+ # Polymorphic relationship
5
+ belongs_to :teamable, polymorphic: true
6
+
7
+ # Team Relationships
8
+ has_many :invitations, :dependent => :destroy
9
+ has_many :memberships, :dependent => :destroy
10
+ has_many :members, :through => :memberships
11
+
12
+ delegate :name, :to => :teamable
13
+
14
+ def membership_for(member)
15
+ memberships.find_by(:member_id => member.id)
16
+ end
17
+
18
+ def remove_member(member)
19
+ memberships.find_by(:member_id => member.id).destroy
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationNotification < Noticed::Base
2
+ deliver_by :database
3
+
4
+ end
@@ -0,0 +1,51 @@
1
+ module SimpleTeams
2
+ class BulkInvitationsNotification < ApplicationNotification
3
+
4
+ param :team_id, :user_id, :team_name, :user_name, :invitation_names
5
+
6
+ def message
7
+ "#{user_name} invited #{invitation_names.to_sentence} to #{team_name}."
8
+ end
9
+
10
+ def subject
11
+ "Users Invited"
12
+ end
13
+
14
+ def url
15
+ if team.present? and team.members.include? recipient
16
+ "/teams/#{team.id}"
17
+ end
18
+ end
19
+
20
+ def link_text
21
+ "View Invitations"
22
+ end
23
+
24
+ # Objects
25
+ def team
26
+ Team.find_by(id: params[:team_id])
27
+ end
28
+
29
+ def user
30
+ SimpleTeams.member_class.find_by(id: params[:user_id])
31
+ end
32
+
33
+ # Names (fallback)
34
+ def team_name
35
+ team.present? ? team.name : params[:team_name]
36
+ end
37
+
38
+ def invitation_names
39
+ params[:invitation_names]
40
+ end
41
+
42
+ def user_name
43
+ if recipient.id == params[:user_id]
44
+ "You"
45
+ else
46
+ user.present? ? user.full_name : params[:user_name]
47
+ end
48
+ end
49
+
50
+ end
51
+ end