muck-invites 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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