inviter 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 245696d791f13ecdd7c706f6f89ff0dbefd403b2
4
+ data.tar.gz: 5b502006187c8a0f98204161037bd012258d7f54
5
+ SHA512:
6
+ metadata.gz: ffe0b5f629b966fc7d1d69a2c8d909715695d4338c0355553ddcb9b33757e47b35cd294e8fac87b576522ed754aba6675011ecbe6b546f9eec69e547411310b2
7
+ data.tar.gz: a9f98ca39050895d3467c79e703367e70862760f24b99d62b7d43c4f09318daf58b08929d7cdc43ad57d1584d8705ac4b81464352232a9f46b22db4bf6362df3
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Manuel Morales
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.
@@ -0,0 +1,180 @@
1
+ # Inviter
2
+ Take control of your rails app's invitation system using a set of model unique callbacks.
3
+
4
+ ## Installation
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'inviter'
9
+ ```
10
+
11
+ And then execute:
12
+ ```bash
13
+ $ bundle
14
+ ```
15
+
16
+ Or install it yourself as:
17
+ ```bash
18
+ $ gem install inviter
19
+ ```
20
+
21
+ Run the Installer:
22
+ ```bash
23
+ rails g inviter:initializer install
24
+ ```
25
+
26
+ Run new migrations:
27
+ ```bash
28
+ rails db:migrate
29
+ ```
30
+
31
+ ## Usage
32
+ include the Inviterable module into your application controller
33
+ ```ruby
34
+ class ApplicationRecord < ActiveRecord::Base
35
+ include Inviterable
36
+ ```
37
+ this gives you access to three 'acts_as' methods you can use to set up your invitation relations.
38
+ * acts_as_inviter
39
+ * acts_as_invitee
40
+ * acts_as_invited_to
41
+
42
+ place the acts_as_inviter method at the top of any model with the ability to send invitations
43
+ ```ruby
44
+ class User < ApplicationRecord
45
+ acts_as_inviter
46
+ ```
47
+ like wise place the acts_as_invitee method wthin any model that can recieive invites. A model will frequently contain both
48
+ acts_as_inviter and acts_as_invitee.
49
+ ```ruby
50
+ class User < ApplicationRecord
51
+ acts_as_inviter
52
+ acts_as_invitee
53
+ ```
54
+ all invitee models have access to **.invitations** which returns an active record collection of all
55
+ their invitee associated **Invitations**.
56
+ ```ruby
57
+ invitee = User.first
58
+ invitee.invitations == Invitations.where(invitee: invitee)
59
+ ```
60
+ Inviter models can also view there invitations using **.sent_invitations**
61
+ ```ruby
62
+ inviter = User.first
63
+ inviter.sent_invitations == Invitations.where(inviter: inviter)
64
+ ```
65
+
66
+ An inviter can use the **.send_invitation** method to create an invitation. The method takes a
67
+ an invitee resource and invited_to model as arguments.
68
+ ```ruby
69
+ inviter = User.first
70
+ invitee = User.second
71
+ invited_to = Party.first
72
+ inviter.send_invitation(invitee, invited_to)
73
+ ```
74
+ place the acts_as_invited_to method in any model meant to show relation between an inviter and an invitee
75
+ ```ruby
76
+ class Party < ApplicationRecord
77
+ acts_as_invited_to
78
+ ```
79
+ Like an invitee, the invited_to model can access its associated invitations using **.invitations**
80
+ ```ruby
81
+ invited_to = Party.first
82
+ invited_to.invitations == Invitations.where(invited_to: invited_to)
83
+ ```
84
+ ## The Invitation Model
85
+ The invitation model gives you options to manipulate created invitations.
86
+
87
+ ```ruby
88
+ accepted? # Returns true if accepted_at IS NOT NIL
89
+ declined? # Returns true if declined_at IS NOT NIL
90
+ accepted_or_declined? #Returns true if the invitation has been accepted or declined
91
+ accept #Accepts an invitation not already accepted or declined
92
+ decline #Declines an invitation not already accepted or declined
93
+ reset #Sets the declined_at and accepted_at timestamps to nil
94
+ ```
95
+
96
+ ## Callbacks
97
+ When an valid action is done on an invitation, all invitee, inviter, and invited_to models are sent an associated _callback method for response.
98
+ The valid actions are create, accept, declined and reset.
99
+ To view the method name that each action will create use the
100
+ **Inviter::InvitationCallbacks** module.
101
+ The Inviter::InvitationCallbacks module contains a callback generator for each available valid action.
102
+ ```ruby
103
+ Inviter::InvitationCallbacks.invitation_created_callback
104
+ Inviter::InvitationCallbacks.invitation_accepted_callback
105
+ Inviter::InvitationCallbacks.invitation_declined_callback
106
+ Inviter::InvitationCallbacks.invitation_reset_callback
107
+ ```
108
+ These methods take an inviter, invitee, and invited_to instance class as arguments and return a method name string.
109
+ For example:
110
+ ```ruby
111
+ args = [User.first, User.second, Party.first]
112
+ Inviter::InvitationCallbacks.invitation_created_callback(*args)
113
+ #=> 'user_invited_user_to_party'
114
+ Inviter::InvitationCallbacks.invitation_accepted_callback(*args)
115
+ #=> 'user_accepted_invite_from_user_to_party'
116
+ Inviter::InvitationCallbacks.invitation_declined_callback(*args)
117
+ #=> 'user_declined_invite_from_user_to_party'
118
+ Inviter::InvitationCallbacks.invitation_reset_callback
119
+ #=> 'user_reset_invite_from_user_to_party
120
+ ```
121
+
122
+ # Example Models
123
+
124
+ ```ruby
125
+ class Party < ApplicationRecord
126
+ acts_as_invited_to
127
+
128
+ has_many :user_parties
129
+ has_many :users, through: :user_parties
130
+ end
131
+ ```
132
+
133
+ ```ruby
134
+ class UserParty < ApplicationRecord
135
+ belongs_to :user
136
+ belongs_to :party
137
+ end
138
+ ```
139
+ ```ruby
140
+ class User < ApplicationRecord
141
+ acts_as_inviter
142
+ acts_as_invitee
143
+
144
+ has_many :user_parties
145
+ has_many :parties, through: :user_parties
146
+
147
+ private
148
+
149
+ class << self
150
+ def user_invited_user_to_party(invitation)
151
+ # Do Something when user invites user to party
152
+ UserMailer.invitatation_sent_email
153
+ end
154
+
155
+ def user_accepted_invite_from_user_to_party(invitation)
156
+ # Add user to party users collection
157
+ invitation.invited_to.users << invitation.invitee
158
+ end
159
+
160
+ def user_declined_invite_from_user_to_party(invitation)
161
+ # Do Something when user declined invite from user to party
162
+ UserMailer.invitation_declined_email
163
+ end
164
+
165
+ def user_reset_invite_from_user_to_party(invitation)
166
+ # Do Something when user resets invite from user to party
167
+ UserMailer.invitation_reset_email
168
+ end
169
+ end
170
+ end
171
+ ```
172
+
173
+ These same methods would also be executed on the Party Model if they existed.
174
+ Each callback method also brings its associated invitation through the invitations variable.
175
+
176
+ ## Contributing
177
+ TBA
178
+
179
+ ## License
180
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,33 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Inviter'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+
33
+ task default: :test
@@ -0,0 +1,19 @@
1
+ module Inviterable
2
+ extend ActiveSupport::Concern
3
+
4
+ private
5
+
6
+ module ClassMethods
7
+ def acts_as_inviter
8
+ self.include(Inviter::ActsAsInviter)
9
+ end
10
+
11
+ def acts_as_invitee
12
+ self.include(Inviter::ActsAsInvitee)
13
+ end
14
+
15
+ def acts_as_invited_to
16
+ self.include(Inviter::ActsAsInvitedTo)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,67 @@
1
+ class Invitation < ActiveRecord::Base
2
+ belongs_to :inviter, polymorphic: true
3
+ belongs_to :invitee, polymorphic: true
4
+ belongs_to :invited_to, polymorphic: true
5
+
6
+ alias_attribute :accepted?, :accepted_at?
7
+ alias_attribute :declined?, :declined_at?
8
+
9
+ after_save :trigger_callbacks, if: :valid_callback?
10
+
11
+ def accepted_or_declined?
12
+ accepted? || declined?
13
+ end
14
+
15
+ def accept
16
+ update!(accepted_at: Time.current) unless accepted_or_declined?
17
+ end
18
+
19
+ def decline
20
+ update!(declined_at: Time.current) unless accepted_or_declined?
21
+ end
22
+
23
+ def reset
24
+ update!(accepted_at: nil, declined_at: nil)
25
+ end
26
+
27
+ private
28
+
29
+ [:accepted, :declined, :created].each do |action|
30
+ define_method("invitation_#{action}?") { eval("saved_change_to_#{action}_at?") }
31
+ end
32
+
33
+ def valid_callback?
34
+ invitation_created? || invitation_accepted? || invitation_declined?
35
+ end
36
+
37
+ def invitation_reset?
38
+ return true unless declined? || accepted?
39
+ false
40
+ end
41
+
42
+ def callback_type
43
+ return 'created' if invitation_created?
44
+ return 'reset' if invitation_reset?
45
+ return 'declined' if invitation_declined?
46
+ 'accepted'
47
+ end
48
+
49
+ def call_back_method
50
+ callback_args = [inviter, invitee, invited_to]
51
+ current_callback = "invitation_#{callback_type}_callback"
52
+ Inviter::InvitationCallbacks.send(current_callback, *callback_args)
53
+ end
54
+
55
+ def trigger_callbacks
56
+ inviters = Inviter::ActsAsInviter.inviters
57
+ invitees = Inviter::ActsAsInvitee.invitees
58
+ invited_tos = Inviter::ActsAsInvitedTo.invited_tos
59
+ listeners = inviters | invitees | invited_tos
60
+
61
+ return unless listeners
62
+ listeners.each do |klass|
63
+ _call_back_method = call_back_method
64
+ klass.send(_call_back_method, self) if klass.respond_to?(_call_back_method)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Create migration for invitations table
3
+
4
+ Example:
5
+ rails generate initializer install
6
+
7
+ This will create:
8
+ db/migrate/#{time_stamp}_inviter_create_invitations.rb
@@ -0,0 +1,24 @@
1
+ module Inviter
2
+ class InitializerGenerator < Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def install
6
+ template 'inviations_migration.rb',
7
+ "db/migrate/#{time_stamp}_inviter_create_invitations.rb",
8
+ time_stamp: time_stamp,
9
+ migration_version: migration_version
10
+ end
11
+
12
+ private
13
+
14
+ def time_stamp
15
+ Time.current.strftime('%Y%m%d%H%M%S')
16
+ end
17
+
18
+ def migration_version
19
+ if Rails::VERSION::MAJOR == 5
20
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ class InviterCreateInvitations < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ create_table :invitations do |t|
4
+ t.references :inviter, polymorphic: true, index: true, null: false
5
+ t.references :invitee, polymorphic: true, index: true, null: false
6
+ t.references :invited_to, polymorphic: true, index: true, null: false
7
+ t.timestamp :accepted_at
8
+ t.timestamp :declined_at
9
+ t.timestamps
10
+ end
11
+
12
+ add_index(:invitations, :accepted_at)
13
+ add_index(:invitations, :declined_at)
14
+ add_index(:invitations, [:accepted_at, :declined_at])
15
+ add_index(:invitations, [:inviter_id, :inviter_type, :invitee_type, :invitee_id, :invited_to_id,
16
+ :invited_to_type], unique: true, name: :unique_invitation_index)
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ module Inviter
2
+ require 'inviter/invitation_callbacks'
3
+ require 'inviter/acts_as_invited_to'
4
+ require 'inviter/acts_as_invitee'
5
+ require 'inviter/acts_as_inviter'
6
+ require 'app/models/concerns/inviterable'
7
+ require 'app/models/invitation'
8
+ end
@@ -0,0 +1,19 @@
1
+ module Inviter
2
+ module ActsAsInvitedTo
3
+ extend ActiveSupport::Concern
4
+ class << self
5
+ attr_reader :invited_tos
6
+ end
7
+
8
+ included do
9
+ has_many :invitations, as: :invited_to
10
+ end
11
+
12
+ private
13
+
14
+ def self.included(base)
15
+ @invited_tos ||= []
16
+ @invited_tos << base
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Inviter
2
+ module ActsAsInvitee
3
+ extend ActiveSupport::Concern
4
+ class << self
5
+ attr_reader :invitees
6
+ end
7
+
8
+ included do
9
+ has_many :invitations, as: :invitee
10
+ end
11
+
12
+ private
13
+
14
+ def self.included(base)
15
+ @invitees ||= []
16
+ @invitees << base
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ module Inviter
2
+ module ActsAsInviter
3
+ extend ActiveSupport::Concern
4
+ class << self
5
+ attr_reader :inviters
6
+ end
7
+
8
+ included do
9
+ has_many :sent_invitations, as: :inviter, class_name: Invitation
10
+ end
11
+
12
+ def send_invitation(invitee, invited_to)
13
+ Invitation.create!(inviter: self, invitee: invitee, invited_to: invited_to)
14
+ end
15
+
16
+ private
17
+
18
+ def self.included(base)
19
+ @inviters ||= []
20
+ @inviters << base
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Inviter
2
+ module InvitationCallbacks
3
+ class << self
4
+ def invitation_created_callback(inviter, invitee, invited_to)
5
+ "#{inviter.class.name}_invited_#{invitee.class.name}_to_#{invited_to.class.name}".downcase
6
+ end
7
+
8
+ ['accepted', 'declined', 'reset'].each do |action|
9
+ define_method("invitation_#{action}_callback") do |inviter, invitee, invited_to|
10
+ "#{invitee.class.name}_#{action}_invite_from_#{inviter.class.name}_to_#{invited_to.class.name}".downcase
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Inviter
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :inviter do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inviter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Manuel Morales
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: ''
42
+ email:
43
+ - morales.jmanuel16@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - lib/app/models/concerns/inviterable.rb
52
+ - lib/app/models/invitation.rb
53
+ - lib/generators/inviter/initializer/USAGE
54
+ - lib/generators/inviter/initializer/initializer_generator.rb
55
+ - lib/generators/inviter/initializer/templates/inviations_migration.rb
56
+ - lib/inviter.rb
57
+ - lib/inviter/acts_as_invited_to.rb
58
+ - lib/inviter/acts_as_invitee.rb
59
+ - lib/inviter/acts_as_inviter.rb
60
+ - lib/inviter/invitation_callbacks.rb
61
+ - lib/inviter/version.rb
62
+ - lib/tasks/inviter_tasks.rake
63
+ homepage: https://github.com/mjmorales/inviter
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.6.8
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: A Light weight invitation system for Ruby on Rails.
87
+ test_files: []