muck-invites 0.1.3 → 0.1.4

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.
@@ -1,6 +1,39 @@
1
1
  = Muck Invites
2
-
2
+ Make it easy to let users invite other users.
3
3
 
4
4
  == Setup
5
5
 
6
- Copyright (c) 2009 Muck Your App, released under the MIT license
6
+ === Inviter model
7
+ Add 'acts_as_muck_inviter' to the class that you wish to have do the inviting. This is commonly the user model, but
8
+ might also be another model - for example Event.
9
+
10
+ class User < ActiveRecord::Base
11
+ acts_as_authentic do |c|
12
+ c.crypto_provider = Authlogic::CryptoProviders::BCrypt
13
+ end
14
+ acts_as_muck_user
15
+ acts_as_muck_inviter
16
+ end
17
+
18
+ or
19
+
20
+ class Event < ActiveRecord::Base
21
+ acts_as_muck_inviter
22
+ end
23
+
24
+ === Other models
25
+ These models are required for the invite system to function and must be named as specified. Addition functionality
26
+ can be added to each model as needed.
27
+
28
+ Create an Invitee model:
29
+ class Invitee < ActiveRecord::Base
30
+ acts_as_muck_invitee
31
+ end
32
+
33
+ Create an Invite model:
34
+ class Invite < ActiveRecord::Base
35
+ acts_as_muck_invite
36
+ end
37
+
38
+
39
+ Copyright (c) 2009 Tatemae.com, released under the MIT license
data/Rakefile CHANGED
@@ -16,7 +16,7 @@ end
16
16
  begin
17
17
  require 'rcov/rcovtask'
18
18
  Rcov::RcovTask.new do |t|
19
- #t.libs << 'lib'
19
+ t.libs << 'lib'
20
20
  t.libs << 'test/rails_root/lib'
21
21
  t.pattern = 'test/rails_root/test/**/*_test.rb'
22
22
  t.verbose = true
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
@@ -38,10 +38,17 @@ class Muck::InvitesController < ApplicationController
38
38
 
39
39
  def create
40
40
  if params[:emails]
41
- current_user.invite(params[:emails])
42
- flash[:notice] = t('muck.invites.create_success', :emails => params[:emails].join(', '), :app_name => GlobalConfig.application_name)
43
- end
44
- redirect_to('/')
41
+ current_user.invite(params[:emails], current_user)
42
+ message = t('muck.invites.create_success', :emails => params[:emails].join(', '), :app_name => GlobalConfig.application_name)
43
+ end
44
+ respond_to do |format|
45
+ format.html do
46
+ flash[:notice] = message
47
+ redirect_to('/')
48
+ end
49
+ format.pjs { render :text => message }
50
+ end
51
+
45
52
  rescue ActiveRecord::RecordInvalid => ex
46
53
  if @invite
47
54
  errors = @invite.errors.full_messages.to_sentence
@@ -49,6 +56,10 @@ class Muck::InvitesController < ApplicationController
49
56
  errors = ex
50
57
  end
51
58
  flash[:error] = t('muck.invites.create_error', :errors => errors)
59
+ respond_to do |format|
60
+ format.html { render :template => 'invites/new' }
61
+ format.pjs { render :template => 'invites/new', :layout => false }
62
+ end
52
63
  end
53
64
 
54
65
  protected
@@ -0,0 +1,27 @@
1
+ class MakeInvitesPolymorphic < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ drop_table :user_invites
5
+ rename_table :invites, :invitees
6
+ create_table :invites, :force => true do |t|
7
+ t.integer :user_id
8
+ t.integer :invitee_id, :null => false
9
+ t.integer :inviter_id, :null => false
10
+ t.string :inviter_type
11
+ t.timestamps
12
+ end
13
+ add_index :invites, ["inviter_id", "inviter_type"]
14
+ end
15
+
16
+ def self.down
17
+ drop_table :invites
18
+ rename_table :invitees, :invites
19
+ create_table :user_invites, :force => true do |t|
20
+ t.integer :user_id, :null => false
21
+ t.integer :invite_id, :null => false
22
+ t.timestamp :created_at, :null => false
23
+ end
24
+ add_index :user_invites, ["user_id"]
25
+ end
26
+
27
+ end
@@ -8,21 +8,17 @@ module ActiveRecord
8
8
  module ClassMethods
9
9
 
10
10
  def acts_as_muck_invite(options = {})
11
-
12
- has_many :user_invites
13
- has_many :users, :through => :user_invites
14
- validates_presence_of :email
15
-
11
+ belongs_to :invitee
12
+ belongs_to :inviter, :polymorphic => true
13
+ # User and inviter might be the same. For example, if a user invites their friends then user == inviter.
14
+ # However if inviter is something else for example an Event then having a user field let's us quickly
15
+ # discover who created the invite. (Used by who_invited?)
16
+ belongs_to :user
17
+
16
18
  named_scope :by_newest, :order => "created_at DESC"
17
19
  named_scope :by_oldest, :order => "created_at ASC"
18
20
  named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
19
21
 
20
- email_name_regex = '[\w\.%\+\-]+'.freeze
21
- domain_head_regex = '(?:[A-Z0-9\-]+\.)+'.freeze
22
- domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'.freeze
23
- email_regex = /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
24
-
25
- validates_format_of :email, :with => email_regex, :message => 'does not look like a valid email address.'
26
22
 
27
23
  include ActiveRecord::Acts::MuckInvite::InstanceMethods
28
24
  extend ActiveRecord::Acts::MuckInvite::SingletonMethods
@@ -32,25 +28,10 @@ module ActiveRecord
32
28
 
33
29
  # class methods
34
30
  module SingletonMethods
35
-
36
- def who_invited?(email, id = nil)
37
- users = []
38
-
39
- if !id.nil?
40
- invite = Invite.find(id)
41
- users |= invite.users if !invite.nil?
42
- end
43
-
44
- invite = Invite.find_by_email(email)
45
- users |= invite.users if !invite.nil?
46
-
47
- users
48
- end
49
31
  end
50
32
 
51
33
  # All the methods available to a record that has had <tt>acts_as_muck_invite</tt> specified.
52
34
  module InstanceMethods
53
-
54
35
  end
55
36
  end
56
37
  end
@@ -0,0 +1,57 @@
1
+ module ActiveRecord
2
+ module Acts #:nodoc:
3
+ module MuckInvitee #:nodoc:
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ def acts_as_muck_invitee(options = {})
11
+
12
+ has_many :invites
13
+ has_many :users, :through => :invites
14
+ validates_presence_of :email
15
+
16
+ named_scope :by_newest, :order => "created_at DESC"
17
+ named_scope :by_oldest, :order => "created_at ASC"
18
+ named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
19
+
20
+ email_name_regex = '[\w\.%\+\-]+'.freeze
21
+ domain_head_regex = '(?:[A-Z0-9\-]+\.)+'.freeze
22
+ domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'.freeze
23
+ email_regex = /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
24
+
25
+ validates_format_of :email, :with => email_regex, :message => 'does not look like a valid email address.'
26
+
27
+ include ActiveRecord::Acts::MuckInvitee::InstanceMethods
28
+ extend ActiveRecord::Acts::MuckInvitee::SingletonMethods
29
+
30
+ end
31
+ end
32
+
33
+ # class methods
34
+ module SingletonMethods
35
+
36
+ def who_invited?(email, invitee_id = nil)
37
+ users = []
38
+
39
+ if !invitee_id.nil?
40
+ invite = Invitee.find(invitee_id)
41
+ users |= invite.users if !invite.nil?
42
+ end
43
+
44
+ invite = Invitee.find_by_email(email)
45
+ users |= invite.users if !invite.nil?
46
+
47
+ users
48
+ end
49
+ end
50
+
51
+ # All the methods available to a record that has had <tt>acts_as_muck_invitee</tt> specified.
52
+ module InstanceMethods
53
+
54
+ end
55
+ end
56
+ end
57
+ end
@@ -8,10 +8,8 @@ module ActiveRecord
8
8
  module ClassMethods
9
9
 
10
10
  def acts_as_muck_inviter(options = {})
11
-
12
- has_many :user_invites
13
- has_many :invites, :through => :user_invites
14
-
11
+ has_many :invites, :as => :inviter
12
+ has_many :invitees, :through => :invites
15
13
  named_scope :by_newest, :order => "created_at DESC"
16
14
  named_scope :by_oldest, :order => "created_at ASC"
17
15
  named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
@@ -34,8 +32,14 @@ module ActiveRecord
34
32
  # All the methods available to a record that has had <tt>acts_as_muck_inviter</tt> specified.
35
33
  module InstanceMethods
36
34
 
35
+ # Gets all emails have been invited
36
+ def invitee_emails
37
+ invitees.map(&:email)
38
+ end
39
+
40
+ # Sends out notification email and adds an activity to each of the inviters activity feeds
37
41
  def notify_inviters(invite_id = nil)
38
- inviters = Invite.who_invited?(self.email, invite_id)
42
+ inviters = Invitee.who_invited?(self.email, invite_id)
39
43
  if inviters.size > 0
40
44
  content = I18n.t('muck.activities.joined_status', :name => self.full_name, :application_name => GlobalConfig.application_name)
41
45
  inviters.each do |inviter|
@@ -49,13 +53,18 @@ module ActiveRecord
49
53
 
50
54
  end
51
55
 
52
- def invite(emails)
56
+ def invite(emails, user)
53
57
  emails = emails.split(/[, ]/) if !emails.is_a?(Array)
54
- emails = emails.find_all { |email| !email.blank?}
58
+ emails = emails.find_all { |email| !email.blank? }
59
+ emails = emails.flatten.collect { |email| email.strip }
55
60
  raise I18n.t('muck.invites.no_email_error') if emails.blank?
61
+ check_emails = invitee_emails
56
62
  emails.each do |email|
57
- invite = Invite.find_by_email(email) || Invite.create(:email => email)
58
- invites << invite if !invites.include?(invite)
63
+ if !check_emails.include?(email)
64
+ check_emails << email
65
+ invitee = Invitee.find_by_email(email) || Invitee.create!(:email => email)
66
+ Invite.create!(:inviter => self, :invitee => invitee, :user => user)
67
+ end
59
68
  end
60
69
  end
61
70
 
@@ -1,3 +1,4 @@
1
+ ActiveRecord::Base.class_eval { include ActiveRecord::Acts::MuckInvitee }
1
2
  ActiveRecord::Base.class_eval { include ActiveRecord::Acts::MuckInvite }
2
3
  ActiveRecord::Base.class_eval { include ActiveRecord::Acts::MuckInviter }
3
4
  I18n.load_path += Dir[ File.join(File.dirname(__FILE__), '..', 'locales', '*.{rb,yml}') ]
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{muck-invites}
8
- s.version = "0.1.3"
8
+ s.version = "0.1.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Justin Ball, Joel Duffin"]
12
- s.date = %q{2009-11-13}
12
+ s.date = %q{2009-11-30}
13
13
  s.description = %q{The invite engine for the muck system.}
14
14
  s.email = %q{justin@tatemae.com}
15
15
  s.extra_rdoc_files = [
@@ -23,7 +23,6 @@ Gem::Specification.new do |s|
23
23
  "VERSION",
24
24
  "app/controllers/muck/invites_controller.rb",
25
25
  "app/models/invite_mailer.rb",
26
- "app/models/user_invite.rb",
27
26
  "app/views/invite_mailer/invite_notification.text.html.erb",
28
27
  "app/views/invite_mailer/invite_notification.text.plain.erb",
29
28
  "app/views/invite_mailer/invited_joined_notification.text.html.erb",
@@ -32,8 +31,10 @@ Gem::Specification.new do |s|
32
31
  "app/views/invites/new.html.erb",
33
32
  "config/muck_invites_routes.rb",
34
33
  "db/migrate/20090928213532_create_invites.rb",
34
+ "db/migrate/20091128170318_make_invites_polymorphic.rb",
35
35
  "install.rb",
36
36
  "lib/active_record/acts/muck_invite.rb",
37
+ "lib/active_record/acts/muck_invitee.rb",
37
38
  "lib/active_record/acts/muck_inviter.rb",
38
39
  "lib/muck_invites.rb",
39
40
  "lib/muck_invites/initialize_routes.rb",
@@ -96,6 +97,7 @@ Gem::Specification.new do |s|
96
97
  "test/rails_root/app/models/.keep",
97
98
  "test/rails_root/app/models/activity.rb",
98
99
  "test/rails_root/app/models/invite.rb",
100
+ "test/rails_root/app/models/invitee.rb",
99
101
  "test/rails_root/app/models/user.rb",
100
102
  "test/rails_root/app/models/user_session.rb",
101
103
  "test/rails_root/app/views/default/index.html.erb",
@@ -124,6 +126,7 @@ Gem::Specification.new do |s|
124
126
  "test/rails_root/db/migrate/20090703055724_add_contents.rb",
125
127
  "test/rails_root/db/migrate/20090704220055_create_slugs.rb",
126
128
  "test/rails_root/db/migrate/20090928213532_create_invites.rb",
129
+ "test/rails_root/db/migrate/20091128170318_make_invites_polymorphic.rb",
127
130
  "test/rails_root/features/comments.feature",
128
131
  "test/rails_root/features/step_definitions/comment_steps.rb",
129
132
  "test/rails_root/features/step_definitions/common_steps.rb",
@@ -331,6 +334,7 @@ Gem::Specification.new do |s|
331
334
  "test/rails_root/test/unit/contacts_test.rb",
332
335
  "test/rails_root/test/unit/invite_mailer_test.rb",
333
336
  "test/rails_root/test/unit/invite_test.rb",
337
+ "test/rails_root/test/unit/invitee_test.rb",
334
338
  "test/rails_root/test/unit/user_test.rb",
335
339
  "test/rails_root/vendor/plugins/jrails/CHANGELOG",
336
340
  "test/rails_root/vendor/plugins/jrails/LICENSE",
@@ -365,6 +369,7 @@ Gem::Specification.new do |s|
365
369
  "test/rails_root/app/helpers/application_helper.rb",
366
370
  "test/rails_root/app/models/activity.rb",
367
371
  "test/rails_root/app/models/invite.rb",
372
+ "test/rails_root/app/models/invitee.rb",
368
373
  "test/rails_root/app/models/user.rb",
369
374
  "test/rails_root/app/models/user_session.rb",
370
375
  "test/rails_root/config/boot.rb",
@@ -388,6 +393,7 @@ Gem::Specification.new do |s|
388
393
  "test/rails_root/db/migrate/20090703055724_add_contents.rb",
389
394
  "test/rails_root/db/migrate/20090704220055_create_slugs.rb",
390
395
  "test/rails_root/db/migrate/20090928213532_create_invites.rb",
396
+ "test/rails_root/db/migrate/20091128170318_make_invites_polymorphic.rb",
391
397
  "test/rails_root/features/step_definitions/comment_steps.rb",
392
398
  "test/rails_root/features/step_definitions/common_steps.rb",
393
399
  "test/rails_root/features/step_definitions/webrat_steps.rb",
@@ -400,6 +406,7 @@ Gem::Specification.new do |s|
400
406
  "test/rails_root/test/unit/contacts_test.rb",
401
407
  "test/rails_root/test/unit/invite_mailer_test.rb",
402
408
  "test/rails_root/test/unit/invite_test.rb",
409
+ "test/rails_root/test/unit/invitee_test.rb",
403
410
  "test/rails_root/test/unit/user_test.rb",
404
411
  "test/rails_root/vendor/plugins/jrails/init.rb",
405
412
  "test/rails_root/vendor/plugins/jrails/install.rb",
@@ -1,4 +1,3 @@
1
1
  class Invite < ActiveRecord::Base
2
2
  acts_as_muck_invite
3
- end
4
-
3
+ end
@@ -0,0 +1,4 @@
1
+ class Invitee < ActiveRecord::Base
2
+ acts_as_muck_invitee
3
+ end
4
+
@@ -1,23 +1,16 @@
1
1
  development:
2
- adapter: sqlite3
3
- database: db/development.sqlite3
4
- timeout: 5000
5
-
6
- test: &TEST
7
- adapter: sqlite3
8
- database: db/test.sqlite3
9
- timeout: 5000
10
-
11
- production:
12
- adapter: sqlite3
13
- database: db/production.sqlite3
14
- timeout: 5000
15
-
2
+ adapter: mysql
3
+ database: muck_invites_development
4
+ username: root
5
+ password:
6
+ host: localhost
7
+ encoding: utf8
8
+ test:
9
+ adapter: mysql
10
+ database: muck_invites_test
11
+ username: root
12
+ password:
13
+ host: localhost
14
+ encoding: utf8
16
15
  cucumber:
17
16
  <<: *TEST
18
- cucumber:
19
- <<: *TEST
20
- cucumber:
21
- <<: *TEST
22
- cucumber:
23
- <<: *TEST
@@ -0,0 +1,27 @@
1
+ class MakeInvitesPolymorphic < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ drop_table :user_invites
5
+ rename_table :invites, :invitees
6
+ create_table :invites, :force => true do |t|
7
+ t.integer :user_id
8
+ t.integer :invitee_id, :null => false
9
+ t.integer :inviter_id, :null => false
10
+ t.string :inviter_type
11
+ t.timestamps
12
+ end
13
+ add_index :invites, ["inviter_id", "inviter_type"]
14
+ end
15
+
16
+ def self.down
17
+ drop_table :invites
18
+ rename_table :invitees, :invites
19
+ create_table :user_invites, :force => true do |t|
20
+ t.integer :user_id, :null => false
21
+ t.integer :invite_id, :null => false
22
+ t.timestamp :created_at, :null => false
23
+ end
24
+ add_index :user_invites, ["user_id"]
25
+ end
26
+
27
+ end
@@ -53,13 +53,19 @@ class Muck::InvitesControllerTest < ActionController::TestCase
53
53
  should_render_template :get_contacts
54
54
  end
55
55
 
56
- context "create invite" do
57
- should " be able to create a invite" do
58
- assert_difference "Invite.count" do
59
- post :create, :emails => [[Factory.next(:name),Factory.next(:email)]]
56
+ context "POST to create" do
57
+ should "create a invite s" do
58
+ assert_difference "Invite.count", 2 do
59
+ post :create, :emails => [[Factory.next(:email),Factory.next(:email)]]
60
+ end
61
+ end
62
+ should "create a invitee" do
63
+ assert_difference "Invite.count", 2 do
64
+ post :create, :emails => [[Factory.next(:email),Factory.next(:email)]]
60
65
  end
61
66
  end
62
67
  end
68
+
63
69
  end
64
70
 
65
71
  end
@@ -5,136 +5,15 @@ class InviteTest < ActiveSupport::TestCase
5
5
  context "Invite" do
6
6
  setup do
7
7
  @user = Factory(:user)
8
- @invite = Factory(:invite)
9
- @user.invites << @invite
8
+ @invitee = Factory(:invitee)
9
+ @invite = Invite.create(:inviter => @user, :invitee => @invitee, :user => @user)
10
10
  end
11
11
 
12
12
  subject { @invite }
13
- should_validate_presence_of :email
14
- should_have_many :users
15
13
 
16
- should_allow_values_for :email, 'a@x.com', 'de.veloper@example.com'
17
- should_not_allow_values_for :email, 'example.com', '@example.com', 'developer@example', 'developer', :message => 'does not look like a valid email address.'
18
-
19
- should "require email" do
20
- assert_no_difference 'Invite.count' do
21
- u = Factory.build(:invite, :email => nil)
22
- assert !u.valid?
23
- assert u.errors.on(:email)
24
- end
25
- end
26
-
27
- should "not create new invites when more than one person invites the same email address" do
28
- assert_no_difference 'Invite.count' do
29
- u = Factory(:user)
30
- u.invites << @invite
31
- u.save!
32
- end
33
- end
34
-
35
- should "be able to see how many inviters it has" do
36
- assert_equal 1, @invite.users.size
37
- end
38
-
39
- end
40
-
41
- context "User" do
42
- setup do
43
- @user = Factory(:user)
44
- end
45
-
46
- subject { @user }
47
-
48
- should "be able to call invite with a single email address" do
49
- @user.invite(Factory.next(:email))
50
- assert_equal 1, @user.invites.size
51
- end
52
-
53
- should "be able to call invite with a string specifying a space delimited list of email addresses" do
54
- @user.invite(Factory.next(:email) + ' ' + Factory.next(:email))
55
- assert_equal 2, @user.invites.size
56
- end
57
-
58
- should "be able to call invite with a string specifying a comma delimited list of email addresses" do
59
- @user.invite(Factory.next(:email) + ', ' + Factory.next(:email) + ',' + Factory.next(:email) + ',')
60
- assert_equal 3, @user.invites.size
61
- end
62
-
63
- should "be able to call invite with an array of email addresses" do
64
- @user.invite([Factory.next(:email),Factory.next(:email)])
65
- assert_equal 2, @user.invites.size
66
- end
67
-
68
- should "be able to look up who invited them by email" do
69
- inviter = Factory(:user)
70
- inviter.invites << Factory.build(:invite, :email => @user.email)
71
- assert_equal Invite.who_invited?(@user.email).first, inviter
72
- end
73
-
74
- should "be able to look up who invited them by id" do
75
- invite = Factory.build(:invite, :email => @user.email)
76
-
77
- inviter = Factory(:user)
78
- inviter.invites << Factory.build(:invite, :email => @user.email)
79
- assert_equal Invite.who_invited?(@user.email).first, inviter
80
- end
81
-
82
- should "look up multiple inviters by email" do
83
- invite = Factory.build(:invite, :email => @user.email)
84
-
85
- inviter1 = Factory(:user)
86
- inviter1.invites << invite
87
-
88
- inviter2 = Factory(:user)
89
- inviter2.invites << invite
90
-
91
- inviters = Invite.who_invited?(@user.email)
92
- assert_equal 2, inviters.count
93
- assert inviters.include?(inviter1)
94
- assert inviters.include?(inviter2)
95
- end
96
-
97
- should "not create new user invites if the user has invited them before" do
98
- user = Factory(:user)
99
- email = Factory.next(:email)
100
- user.invite(email)
101
- user.invite(email)
102
- assert_equal 1, Invite.all.size
103
- assert_equal 1, user.invites.size
104
- end
14
+ should_belong_to :user
15
+ should_belong_to :inviter
16
+ should_belong_to :invitee
17
+
105
18
  end
106
-
107
- context "Always" do
108
- should "be able to look up who invited them by id and by email" do
109
- user1 = Factory(:user)
110
- invite1 = Factory(:invite)
111
- user1.invites << invite1
112
-
113
- user2 = Factory(:user)
114
- invite2 = Factory(:invite)
115
- user2.invites << invite2
116
-
117
- inviters = Invite.who_invited?(invite1.email, invite2.id)
118
- assert_equal 2, inviters.size
119
- assert inviters.include?(user1)
120
- assert inviters.include?(user2)
121
- end
122
-
123
- should "notify inviters when a new user joins" do
124
- user1 = Factory(:user)
125
- invite1 = Factory(:invite)
126
- user1.invites << invite1
127
-
128
- user2 = Factory(:user)
129
- invite2 = Factory(:invite)
130
- user2.invites << invite2
131
-
132
- user3 = Factory.build(:user, :email => invite1.email)
133
-
134
- assert_nothing_raised do
135
- user3.notify_inviters(invite2.id)
136
- end
137
- end
138
- end
139
-
140
19
  end
@@ -0,0 +1,146 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class InviteeTest < ActiveSupport::TestCase
4
+
5
+ context "Invitee" do
6
+ setup do
7
+ @user = Factory(:user)
8
+ @invitee = Factory(:invitee)
9
+ @invite = Invite.create(:inviter => @user, :invitee => @invitee, :user => @user)
10
+ @user.reload
11
+ end
12
+
13
+ subject { @invitee }
14
+ should_validate_presence_of :email
15
+ should_have_many :users
16
+
17
+ should_allow_values_for :email, 'a@x.com', 'de.veloper@example.com'
18
+ should_not_allow_values_for :email, 'example.com', '@example.com', 'developer@example', 'developer', :message => 'does not look like a valid email address.'
19
+
20
+ should "require email" do
21
+ assert_no_difference 'Invite.count' do
22
+ u = Factory.build(:invitee, :email => nil)
23
+ assert !u.valid?
24
+ assert u.errors.on(:email)
25
+ end
26
+ end
27
+
28
+ should "not create new invites when more than one person invites the same email address" do
29
+ assert_no_difference 'Invite.count' do
30
+ u = Factory(:user)
31
+ u.invites << @invite
32
+ u.save!
33
+ end
34
+ end
35
+
36
+ should "be able to see how many inviters it has" do
37
+ assert_equal 1, @invitee.users.size
38
+ end
39
+
40
+ end
41
+
42
+ context "User" do
43
+ setup do
44
+ @user = Factory(:user)
45
+ end
46
+
47
+ subject { @user }
48
+
49
+ should "be able to call invite with a single email address" do
50
+ @user.invite(Factory.next(:email), @user)
51
+ assert_equal 1, @user.invites.size
52
+ end
53
+
54
+ should "be able to call invite with a string specifying a space delimited list of email addresses" do
55
+ @user.invite(Factory.next(:email) + ' ' + Factory.next(:email), @user)
56
+ assert_equal 2, @user.invites.size
57
+ end
58
+
59
+ should "be able to call invite with a string specifying a comma delimited list of email addresses" do
60
+ @user.invite(Factory.next(:email) + ', ' + Factory.next(:email) + ',' + Factory.next(:email) + ',', @user)
61
+ assert_equal 3, @user.invites.size
62
+ end
63
+
64
+ should "be able to call invite with an array of email addresses" do
65
+ @user.invite([Factory.next(:email),Factory.next(:email)], @user)
66
+ assert_equal 2, @user.invites.size
67
+ end
68
+
69
+ should "be able to look up who invited them by email" do
70
+ inviter = Factory(:user)
71
+ invitee = Factory.build(:invitee, :email => @user.email)
72
+ inviter.invites << Invite.create!(:inviter => inviter, :user => inviter, :invitee => invitee)
73
+ assert_equal Invitee.who_invited?(@user.email).first, inviter
74
+ end
75
+
76
+ should "be able to look up who invited them by id" do
77
+ invite = Factory.build(:invitee, :email => @user.email)
78
+
79
+ inviter = Factory(:user)
80
+ invitee = Factory.build(:invitee, :email => @user.email)
81
+ inviter.invites << Invite.create!(:inviter => inviter, :user => inviter, :invitee => invitee)
82
+ assert_equal Invitee.who_invited?(@user.email).first, inviter
83
+ end
84
+
85
+ should "look up multiple inviters by email" do
86
+ invitee = Factory.build(:invitee, :email => @user.email)
87
+
88
+ inviter1 = Factory(:user)
89
+ inviter1.invites << Invite.create!(:inviter => inviter1, :user => inviter1, :invitee => invitee)
90
+
91
+ inviter2 = Factory(:user)
92
+ inviter2.invites << Invite.create!(:inviter => inviter2, :user => inviter2, :invitee => invitee)
93
+
94
+ inviters = Invitee.who_invited?(@user.email)
95
+ assert_equal 2, inviters.count
96
+ assert inviters.include?(inviter1)
97
+ assert inviters.include?(inviter2)
98
+ end
99
+
100
+ should "not create new user invites if the user has invited them before" do
101
+ user = Factory(:user)
102
+ email = Factory.next(:email)
103
+ assert_difference "Invite.count" do
104
+ user.invite(email, user)
105
+ end
106
+ user.reload # if you don't reload the invite just created won't show up.
107
+ assert_no_difference "Invite.count" do
108
+ user.invite(email, user)
109
+ end
110
+ end
111
+ end
112
+
113
+ context "Always" do
114
+ should "be able to look up who invited them by id and by email" do
115
+ user1 = Factory(:user)
116
+ invitee1 = Factory(:invitee)
117
+ user1.invites << Invite.create!(:inviter => user1, :user => user1, :invitee => invitee1)
118
+
119
+ user2 = Factory(:user)
120
+ invitee2 = Factory(:invitee)
121
+ user2.invites << Invite.create!(:inviter => user2, :user => user2, :invitee => invitee2)
122
+
123
+ inviters = Invitee.who_invited?(invitee1.email, invitee2.id)
124
+ assert_equal 2, inviters.size
125
+ assert inviters.include?(user1)
126
+ assert inviters.include?(user2)
127
+ end
128
+
129
+ should "notify inviters when a new user joins" do
130
+ user1 = Factory(:user)
131
+ invitee1 = Factory(:invitee)
132
+ user1.invites << Invite.create!(:inviter => user1, :user => user1, :invitee => invitee1)
133
+
134
+ user2 = Factory(:user)
135
+ invitee2 = Factory(:invitee)
136
+ user2.invites << Invite.create!(:inviter => user2, :user => user2, :invitee => invitee2)
137
+
138
+ user3 = Factory.build(:user, :email => invitee1.email)
139
+
140
+ assert_nothing_raised do
141
+ user3.notify_inviters(invitee2.id)
142
+ end
143
+ end
144
+ end
145
+
146
+ end
@@ -5,9 +5,9 @@ class UserTest < ActiveSupport::TestCase
5
5
  context "A class that is inviteable" do
6
6
  setup do
7
7
  @user = Factory(:user)
8
- email = Factory.next(:email)
9
- @invite = @user.invites.build(:email => email)
10
- @user.save!
8
+ @invitee = Factory(:invitee)
9
+ Invite.create!(:inviter => @user, :invitee => @invitee, :user => @user)
10
+ @user.reload
11
11
  end
12
12
 
13
13
  should "have invites" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: muck-invites
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Ball, Joel Duffin
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-13 00:00:00 -07:00
12
+ date: 2009-11-30 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -48,7 +48,6 @@ files:
48
48
  - VERSION
49
49
  - app/controllers/muck/invites_controller.rb
50
50
  - app/models/invite_mailer.rb
51
- - app/models/user_invite.rb
52
51
  - app/views/invite_mailer/invite_notification.text.html.erb
53
52
  - app/views/invite_mailer/invite_notification.text.plain.erb
54
53
  - app/views/invite_mailer/invited_joined_notification.text.html.erb
@@ -57,8 +56,10 @@ files:
57
56
  - app/views/invites/new.html.erb
58
57
  - config/muck_invites_routes.rb
59
58
  - db/migrate/20090928213532_create_invites.rb
59
+ - db/migrate/20091128170318_make_invites_polymorphic.rb
60
60
  - install.rb
61
61
  - lib/active_record/acts/muck_invite.rb
62
+ - lib/active_record/acts/muck_invitee.rb
62
63
  - lib/active_record/acts/muck_inviter.rb
63
64
  - lib/muck_invites.rb
64
65
  - lib/muck_invites/initialize_routes.rb
@@ -121,6 +122,7 @@ files:
121
122
  - test/rails_root/app/models/.keep
122
123
  - test/rails_root/app/models/activity.rb
123
124
  - test/rails_root/app/models/invite.rb
125
+ - test/rails_root/app/models/invitee.rb
124
126
  - test/rails_root/app/models/user.rb
125
127
  - test/rails_root/app/models/user_session.rb
126
128
  - test/rails_root/app/views/default/index.html.erb
@@ -149,6 +151,7 @@ files:
149
151
  - test/rails_root/db/migrate/20090703055724_add_contents.rb
150
152
  - test/rails_root/db/migrate/20090704220055_create_slugs.rb
151
153
  - test/rails_root/db/migrate/20090928213532_create_invites.rb
154
+ - test/rails_root/db/migrate/20091128170318_make_invites_polymorphic.rb
152
155
  - test/rails_root/features/comments.feature
153
156
  - test/rails_root/features/step_definitions/comment_steps.rb
154
157
  - test/rails_root/features/step_definitions/common_steps.rb
@@ -356,6 +359,7 @@ files:
356
359
  - test/rails_root/test/unit/contacts_test.rb
357
360
  - test/rails_root/test/unit/invite_mailer_test.rb
358
361
  - test/rails_root/test/unit/invite_test.rb
362
+ - test/rails_root/test/unit/invitee_test.rb
359
363
  - test/rails_root/test/unit/user_test.rb
360
364
  - test/rails_root/vendor/plugins/jrails/CHANGELOG
361
365
  - test/rails_root/vendor/plugins/jrails/LICENSE
@@ -411,6 +415,7 @@ test_files:
411
415
  - test/rails_root/app/helpers/application_helper.rb
412
416
  - test/rails_root/app/models/activity.rb
413
417
  - test/rails_root/app/models/invite.rb
418
+ - test/rails_root/app/models/invitee.rb
414
419
  - test/rails_root/app/models/user.rb
415
420
  - test/rails_root/app/models/user_session.rb
416
421
  - test/rails_root/config/boot.rb
@@ -434,6 +439,7 @@ test_files:
434
439
  - test/rails_root/db/migrate/20090703055724_add_contents.rb
435
440
  - test/rails_root/db/migrate/20090704220055_create_slugs.rb
436
441
  - test/rails_root/db/migrate/20090928213532_create_invites.rb
442
+ - test/rails_root/db/migrate/20091128170318_make_invites_polymorphic.rb
437
443
  - test/rails_root/features/step_definitions/comment_steps.rb
438
444
  - test/rails_root/features/step_definitions/common_steps.rb
439
445
  - test/rails_root/features/step_definitions/webrat_steps.rb
@@ -446,6 +452,7 @@ test_files:
446
452
  - test/rails_root/test/unit/contacts_test.rb
447
453
  - test/rails_root/test/unit/invite_mailer_test.rb
448
454
  - test/rails_root/test/unit/invite_test.rb
455
+ - test/rails_root/test/unit/invitee_test.rb
449
456
  - test/rails_root/test/unit/user_test.rb
450
457
  - test/rails_root/vendor/plugins/jrails/init.rb
451
458
  - test/rails_root/vendor/plugins/jrails/install.rb
@@ -1,6 +0,0 @@
1
- class UserInvite < ActiveRecord::Base
2
- unloadable
3
-
4
- belongs_to :user
5
- belongs_to :invite
6
- end