invite_link functionailty mostly works

This commit is contained in:
Maxwell Salzberg 2011-12-12 11:24:52 -08:00 committed by danielgrippi
parent 35cef7727f
commit 7bac633987
33 changed files with 674 additions and 571 deletions

View file

@ -15,7 +15,6 @@ gem 'rack-cors', '~> 0.2.4', :require => 'rack/cors'
# authentication
gem 'devise', '~> 1.3.1'
gem 'devise_invitable', '0.5.0'
gem 'jwt'
gem 'oauth2-provider', '0.0.19'

View file

@ -138,9 +138,6 @@ GEM
bcrypt-ruby (~> 2.1.2)
orm_adapter (~> 0.0.3)
warden (~> 1.0.3)
devise_invitable (0.5.0)
devise (~> 1.3.1)
rails (>= 3.0.0, <= 3.2)
diff-lcs (1.1.3)
em-http-request (1.0.2)
addressable (>= 2.2.3)
@ -465,7 +462,6 @@ DEPENDENCIES
cucumber-rails (= 1.2.1)
database_cleaner (= 0.7.1)
devise (~> 1.3.1)
devise_invitable (= 0.5.0)
diaspora-client!
em-synchrony (= 1.0.0)
factory_girl_rails

View file

@ -0,0 +1,16 @@
class InvitationCodesController < ApplicationController
before_filter :ensure_valid_invite_code
rescue_from ActiveRecord::RecordNotFound do
redirect_to root_url, :notice => "That invite code is no longer valid"
end
def show
sign_out(current_user) if user_signed_in?
redirect_to new_user_registration_path(:invite => {:token => params[:id]})
end
def ensure_valid_invite_code
InvitationCode.find_by_token!(params[:id])
end
end

View file

@ -2,12 +2,12 @@
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
class InvitationsController < Devise::InvitationsController
require Rails.root.join('lib', 'email_inviter')
before_filter :check_token, :only => [:edit, :email]
before_filter :check_if_invites_open, :only =>[:create]
class InvitationsController < ApplicationController
def new
@invite_code = current_user.invitation_code
@sent_invitations = current_user.invitations_from_me.includes(:recipient)
respond_to do |format|
format.html do
@ -16,65 +16,18 @@ class InvitationsController < Devise::InvitationsController
end
end
# this is for legacy invites. We try to look the person who sent them the
# invite, and use their new invite code
def edit
user = User.find_by_invitation_token(params[:invitation_token])
invitation_code = user.ugly_accept_invitation_code
redirect_to invite_code_path(invitation_code)
end
def create
aspect_id = params[:user].delete(:aspects)
message = params[:user].delete(:invite_messages)
emails = params[:user][:email].to_s.gsub(/\s/, '').split(/, */)
#NOTE should we try and find users by email here? probs
aspect = current_user.aspects.find(aspect_id)
language = params[:user][:language]
invites = Invitation.batch_invite(emails, :message => message, :sender => current_user, :aspect => aspect, :service => 'email', :language => language)
flash[:notice] = extract_messages(invites)
redirect_to :back
end
def update
invitation_token = params[:user][:invitation_token]
if invitation_token.nil? || invitation_token.blank?
redirect_to :back, :error => I18n.t('invitations.check_token.not_found')
return
end
user = User.find_by_invitation_token!(invitation_token)
user.accept_invitation!(params[:user])
if user.persisted? && user.person && user.person.persisted?
user.seed_aspects
flash[:notice] = I18n.t 'registrations.create.success'
sign_in_and_redirect(:user, user)
else
user.errors.delete(:person)
flash[:error] = user.errors.full_messages.join(", ")
redirect_to accept_user_invitation_path(:invitation_token => params[:user][:invitation_token])
end
end
def resend
invitation = current_user.invitations_from_me.where(:id => params[:id]).first
if invitation
Resque.enqueue(Jobs::ResendInvitation, invitation.id)
flash[:notice] = I18n.t('invitations.create.sent') + invitation.recipient.email
end
redirect_to :back
end
def email
@invs = []
@resource = User.find_by_invitation_token(params[:invitation_token])
render 'devise/mailer/invitation_instructions', :layout => false
end
protected
def check_token
if User.find_by_invitation_token(params[:invitation_token]).nil?
render 'invitations/token_not_found'
end
inviter = EmailInviter.new(params[:email_inviter][:emails], params[:email_inviter])
redirect_to :back, :notice => "Great! Invites were sent off to #{inviter.emails.join(', ')}"
end
def check_if_invites_open
@ -84,26 +37,4 @@ class InvitationsController < Devise::InvitationsController
return
end
end
# @param invites [Array<Invitation>] Invitations to be sent.
# @return [String] A full list of success and error messages.
def extract_messages(invites)
success_message = "Invites Successfully Sent to: "
failure_message = "There was a problem with: "
following_message = " already are on Diaspora, so you are now sharing with them."
successes, failures = invites.partition{|x| x.persisted? }
followings, real_failures = failures.partition{|x| x.errors[:recipient].present? }
success_message += successes.map{|k| k.identifier }.to_sentence
failure_message += real_failures.map{|k| k.identifier }.to_sentence
following_message += followings.map{|k| k.identifier}.to_sentence
messages = []
messages << success_message if successes.present?
messages << failure_message if failures.present?
messages << following_message if followings.present?
messages.join('\n')
end
end
end

View file

@ -3,10 +3,12 @@
# the COPYRIGHT file.
class RegistrationsController < Devise::RegistrationsController
before_filter :check_registrations_open!
before_filter :check_registrations_open_or_vaild_invite!
def create
@user = User.build(params[:user])
@user.process_invite_acceptence(invite) if invite.present?
if @user.save
flash[:notice] = I18n.t 'registrations.create.success'
@user.seed_aspects
@ -26,10 +28,19 @@ class RegistrationsController < Devise::RegistrationsController
end
private
def check_registrations_open!
def check_registrations_open_or_vaild_invite!
return true if invite.present?
if AppConfig[:registrations_closed]
flash[:error] = t('registrations.closed')
redirect_to new_user_session_path
end
end
def invite
if params[:invite].present?
@invite ||= InvitationCode.find_by_token(params[:invite][:token])
end
end
helper_method :invite
end

View file

@ -99,24 +99,8 @@ class ServicesController < ApplicationController
#{t('services.inviter.click_link_to_accept_invitation')}:
\n
\n
#{accept_invitation_url(user, :invitation_token => user.invitation_token)}
#{invitation_code_url(user.invitation_code)}
MSG
"https://www.facebook.com/messages/#{facebook_uid}?msg_prefill=#{message}"
end
def invite_redirect_json(invite, user, service_user)
if invite.email_like_identifer
{:message => t("invitations.create.sent") + service_user.name }
else
{:url => facebook_message_url(user, service_user.uid)}
end
end
def invite_redirect_url(invite, user, service_user)
if invite.email_like_identifer
redirect_to(friend_finder_path(:provider => 'facebook'), :notice => "you re-invited #{service_user.name}")
else
redirect_to(facebook_message_url(user, service_user.uid))
end
end
end
end

View file

@ -0,0 +1,28 @@
module InvitationCodesHelper
def invite_welcome_message
if invite.present?
content_tag(:div) do
person_image_link(invite.user.person) +
I18n.translate('invitation_codes.excited', :name => invite.user.name)
end
end
end
def invite_hidden_tag(invite)
if invite.present?
hidden_field_tag 'invite[token]', invite.token
end
end
def invite_link(invite_code)
text_field_tag :invite_code, invite_code_url(@invite_code), :readonly => true
end
def invited_by_message
inviter = current_user.invited_by
if inviter.present?
contact = current_user.contact_for(inviter.person) || Contact.new
render :partial => 'people/add_contact', :locals => {:inviter => inviter.person, :contact => contact}
end
end
end

View file

@ -33,6 +33,21 @@ class Notifier < ActionMailer::Base
mail(default_opts)
end
def invite(email, message, inviter, invitation_code, locale)
@inviter = inviter
@message = message
@locale = locale
@invitation_code = invitation_code
mail_opts = {:to => email, :from => AppConfig[:smtp_sender_address],
:subject => I18n.t('notifier.invited!'),
:host => AppConfig[:pod_uri].host}
I18n.with_locale(locale) do
mail(mail_opts)
end
end
def started_sharing(recipient_id, sender_id)
send_notification(:started_sharing, recipient_id, sender_id)
end

View file

@ -0,0 +1,17 @@
class InvitationCode < ActiveRecord::Base
belongs_to :user
validates_presence_of :user
before_create :generate_token
def to_param
token
end
def generate_token
begin
self.token = ActiveSupport::SecureRandom.hex(6)
end while InvitationCode.exists?(:token => self[:token])
end
end

View file

@ -8,12 +8,11 @@ require 'rest-client'
class User < ActiveRecord::Base
include Encryptor::Private
include Connecting
include Querying
include SocialActions
devise :invitable, :database_authenticatable, :registerable,
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:timeoutable, :token_authenticatable, :lockable,
:lock_strategy => :none, :unlock_strategy => :none
@ -40,7 +39,10 @@ class User < ActiveRecord::Base
has_many :invitations_from_me, :class_name => 'Invitation', :foreign_key => :sender_id
has_many :invitations_to_me, :class_name => 'Invitation', :foreign_key => :recipient_id
has_many :aspects, :order => 'order_id ASC'
belongs_to :auto_follow_back_aspect, :class_name => 'Aspect'
belongs_to :invited_by, :class_name => 'User'
has_many :aspect_memberships, :through => :aspects
has_many :contacts
@ -64,7 +66,6 @@ class User < ActiveRecord::Base
before_save :guard_unconfirmed_email,
:save_person!
before_create :infer_email_from_invitation_provider
attr_accessible :getting_started,
:password,
@ -82,6 +83,7 @@ class User < ActiveRecord::Base
User.joins(:contacts).where(:contacts => {:person_id => person.id})
end
<<<<<<< HEAD
def self.monthly_actives(start_day = Time.now)
logged_in_since(start_day - 1.month)
end
@ -115,23 +117,24 @@ class User < ActiveRecord::Base
existing_user = User.where(:email => identifier).first
else
existing_user = User.joins(:services).where(:services => {:type => "Services::#{service.titleize}", :uid => identifier}).first
=======
#should be deprecated
def ugly_accept_invitation_code
begin
self.invitations_to_me.first.sender.invitation_code
rescue Exception => e
nil
>>>>>>> invite_link functionailty mostly works
end
if existing_user.nil?
i = Invitation.where(:service => service, :identifier => identifier).first
existing_user = i.recipient if i
end
existing_user
end
# @return [User]
def self.find_or_create_by_invitation(invitation)
if existing_user = self.find_by_invitation(invitation)
existing_user
else
self.create_from_invitation!(invitation)
end
def process_invite_acceptence(invite)
self.invited_by = invite.user
end
def invitation_code
InvitationCode.find_or_create_by_user_id(self.id)
end
def hidden_shareables
@ -389,39 +392,6 @@ class User < ActiveRecord::Base
end
end
# This method is called when an invited user accepts his invitation
#
# @param [Hash] opts the options to accept the invitation with
# @option opts [String] :username The username the invited user wants.
# @option opts [String] :password
# @option opts [String] :password_confirmation
def accept_invitation!(opts = {})
log_hash = {:event => :invitation_accepted, :username => opts[:username], :uid => self.id}
log_hash[:inviter] = invitations_to_me.first.sender.diaspora_handle if invitations_to_me.first && invitations_to_me.first.sender
if self.invited?
self.setup(opts)
self.invitation_token = nil
self.password = opts[:password]
self.password_confirmation = opts[:password_confirmation]
self.save
return unless self.errors.empty?
# moved old Invitation#share_with! logic into here,
# but i don't think we want to destroy the invitation
# anymore. we may want to just call self.share_with
invitations_to_me.each do |invitation|
if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect)
invitation.destroy
end
end
log_hash[:status] = "success"
Rails.logger.info(log_hash)
self
end
end
###Helpers############
def self.build(opts = {})
@ -511,14 +481,6 @@ class User < ActiveRecord::Base
self.person
end
# Set the User's email to the one they've been invited at, if the user
# is being created via an invitation.
#
# @return [User]
def infer_email_from_invitation_provider
self.email = self.invitation_identifier if self.invitation_service == 'email'
self
end
def no_person_with_same_username
diaspora_id = "#{self.username}#{User.diaspora_id_host}"

View file

@ -8,34 +8,35 @@
.description
= t('.if_they_accept_info')
%br
.span-7.append-1
.span-7.append-1.last
#email_invitation
= form_for User.new, :url => invitation_path(User) do |invite|
= form_tag new_user_invitation_path do
%h4
= t('email')
= invite.text_field :email, :title => t('.comma_seperated_plz'), :placeholder => 'foo@bar.com, max@foo.com...'
%br
%h4
= t('.aspect')
= invite.select(:aspects, options_from_collection_for_select(all_aspects, 'id', 'name'))
= text_field_tag 'email_inviter[emails]' ,nil, :title => t('.comma_seperated_plz'), :placeholder => 'foo@bar.com, max@foo.com...'
%br
%br
%h4
= t('.language')
= invite.select(:language, available_language_options, :selected => current_user.language)
= select_tag('email_inviter[locale]', options_from_collection_for_select(available_language_options, "second", "first", :selected => current_user.language))
%br
%br
%h4
= t('.personal_message')
= invite.text_area :invite_messages, :rows => 3, :value => t('.check_out_diaspora')
= text_area_tag 'email_inviter[message]',nil, :rows => 3, :value => t('.check_out_diaspora')
%p
= invite.submit t('.send_an_invitation')
= submit_tag t('.send_an_invitation')
.clearfix
.span-7.prepend-3.last
or paste them this link!
= invite_link(@invite_code)
= "#{@invite_code.count} invites left on this code"
%br
%br

View file

@ -0,0 +1,140 @@
<%- self.extend NotifierHelper -%>
<head>
<title><%=invite_email_title %></title>
</head>
<p style="background-color: rgb(255, 255, 255); text-align: center; font-size: 11px;"><%= t('.displaying_correctly', :link => link_to(t('.view_in'), invite_email_url(:invitation_token => @resource.invitation_token), :style => "color: #3F8FBA; text-decoration: none;")).html_safe %> </p>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td style="padding: 30px 15px 0pt; background-color: rgb(221, 221, 221);">
<table style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; font-size: 16px; color: rgb(51, 51, 51);" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);">
<a style="display: block;" href="<%= invite_code_url(@invitation_code) %>" target="_blank">
<img alt="Diaspora" src="http://dl.dropbox.com/u/15865/diaspora%20logo.png" style="border: 0pt none ; display: block;" height="134" width="600">
</a>
</td>
</tr>
<tr>
<td style="padding: 10px 0pt 0px 20px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
<%= t('.finally') %><br>
</td>
</tr>
<tr><td style="padding: 0px 20px 0pt; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" width="600" height='389'>
<a href="<%= invite_code_url(@invitation_code)%>" target="_blank"><img src="http://dl.dropbox.com/u/15865/diaspora_shots.jpg" style="border: 0pt none ; display: block;" width="560">
</a></td></tr>
<tr><td style="padding: 0pt 30px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; line-height: 20px;">
<%= t('.arrived', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
<br>
<br>
<%= link_to(t('.sign_up_now').html_safe, invite_code_url(@invitation_code), :style => "color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;", :target => "_blank").html_safe %>
</td></tr>
<% if @inviter.present? %>
<%= @inviter.inspect %>
<% end %>
<tr><td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
1. <%= t('.get_connected') %></td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody><tr>
<td width="200">
<a href="<%=invite_code_url(@invitation_code) %>" target="_blank"><img style="border: 0pt none ; padding: 0pt 10px 0px 5px; display: block;" src="https://joindiaspora.s3.amazonaws.com/uploads/images/scaled_full_c7506ec0b3ae6694c64d.gif" height="156" width="200"></a>
</td>
<td style="line-height: 20px; width: 360px;">
<%= t('.get_connected_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
<br>
<!-- <a style="color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;" href="https://joindiaspora.com/channels" target="_blank">Tune in to your favorite Channels</a>-->
</td>
</tr>
</tbody></table>
</td></tr>
<tr><td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
2. <%= t('.be_yourself') %></td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody><tr>
<td style="line-height: 20px; width: 360px;">
<%= t('.be_yourself_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
<br>
<!-- <a style="color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;" href="#" target="_blank">Watch all the bumpers</a>-->
</td>
<td width="200">
<a href="<%= invite_code_url(@invitation_code)%>" target="_blank"><img style="border: 0pt none ; padding: 0pt 5px 0px 10px; display: block;" src="http://dl.dropbox.com/u/15865/apolonisaphrodisia.png" height="150" width="170"></a>
</td>
</tr>
</tbody></table>
</td></tr>
<tr><td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
3. <%= t('.have_fun') %></td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody><tr>
<td width="200">
<a href="<%= invite_code_url(@invitation_code)%>" target="_blank"><img style="border: 0pt none ; padding: 0pt 5px; display: block;" src="http://joindiaspora.com/images/cubbies_screenshot2.png" height="151" width="200"></a>
</td>
<td style="line-height: 20px; width: 360px;">
<%= t('.have_fun_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*"), :link => link_to(t('.cubbies'), "https://cubbi.es", :style => "color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;", :target => "_blank")).html_safe %>
<!-- <a style="color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;" href="#" target="_blank">Watch all the bumpers</a>-->
</td>
</tr>
</tbody></table>
</td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody>
<tr>
<td style="padding: 40px 20px 20px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
<%= link_to(t('.sign_up_now').html_safe, invite_code_url(@invitation_code), :style => "color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;", :target => "_blank").html_safe %>
</td>
</tr>
</tbody>
</table>
</td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody>
<tr>
<td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
<%= t('.made_by_people', :strong_diaspora => content_tag(:strong, "DIASPORA*"), :jointeam => link_to(t('.join_team'), "https://github.com/diaspora/diaspora/wiki/Become-a-Contributor", :style =>"color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 18px;", :target => "_blank"), :helpfund => link_to(t('.help_fund'), "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QG4L6VYD8YGPU", :style =>"color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 18px;", :target => "_blank")).html_safe %>
</td>
</tr>
</tbody>
</table>
</td></tr>
<tr><td style="padding: 35px 20px 20px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
<%= t('.love') %><br>
<%= t('.team_diaspora') %><br>
</td></tr>
<tr><td style="padding: 35px 40px; font-size: 11px; color: rgb(102, 102, 102); line-height: 16px;">
<% if AppConfig[:pod_uri].host.match(/joindiaspora.com/) %>
<%= t('.unsubscribe', :link => link_to(t('.here'), "http://joindiaspora.us1.list-manage.com/unsubscribe?u=d759919b94f9cdcf39d204f3f&id=7b5ceb2f8b", :style => "color: #3F8FBA; text-decoration: none;")).html_safe %>
<% end %>
<%= t('.email_us', :email => link_to(t('.email_address'), "mailto:questions@joindiaspora.com", :style => "color: #3F8FBA; text-decoration: none;")).html_safe %>
</td></tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,140 @@
<%- self.extend NotifierHelper -%>
<head>
<title><%=invite_email_title %></title>
</head>
<p style="background-color: rgb(255, 255, 255); text-align: center; font-size: 11px;"><%= t('.displaying_correctly', :link => link_to(t('.view_in'), invite_email_url(:invitation_token => @resource.invitation_token), :style => "color: #3F8FBA; text-decoration: none;")).html_safe %> </p>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td style="padding: 30px 15px 0pt; background-color: rgb(221, 221, 221);">
<table style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; font-size: 16px; color: rgb(51, 51, 51);" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody>
<tr>
<td style="background-color: rgb(0, 0, 0);">
<a style="display: block;" href="<%= invite_code_url(@invitation_code) %>" target="_blank">
<img alt="Diaspora" src="http://dl.dropbox.com/u/15865/diaspora%20logo.png" style="border: 0pt none ; display: block;" height="134" width="600">
</a>
</td>
</tr>
<tr>
<td style="padding: 10px 0pt 0px 20px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
<%= t('.finally') %><br>
</td>
</tr>
<tr><td style="padding: 0px 20px 0pt; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" width="600" height='389'>
<a href="<%= invite_code_url(@invitation_code)%>" target="_blank"><img src="http://dl.dropbox.com/u/15865/diaspora_shots.jpg" style="border: 0pt none ; display: block;" width="560">
</a></td></tr>
<tr><td style="padding: 0pt 30px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; line-height: 20px;">
<%= t('.arrived', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
<br>
<br>
<%= link_to(t('.sign_up_now').html_safe, invite_code_url(@invitation_code), :style => "color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;", :target => "_blank").html_safe %>
</td></tr>
<% if @inviter.present? %>
<%= @inviter.inspect %>
<% end %>
<tr><td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
1. <%= t('.get_connected') %></td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody><tr>
<td width="200">
<a href="<%=invite_code_url(@invitation_code) %>" target="_blank"><img style="border: 0pt none ; padding: 0pt 10px 0px 5px; display: block;" src="https://joindiaspora.s3.amazonaws.com/uploads/images/scaled_full_c7506ec0b3ae6694c64d.gif" height="156" width="200"></a>
</td>
<td style="line-height: 20px; width: 360px;">
<%= t('.get_connected_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
<br>
<!-- <a style="color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;" href="https://joindiaspora.com/channels" target="_blank">Tune in to your favorite Channels</a>-->
</td>
</tr>
</tbody></table>
</td></tr>
<tr><td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
2. <%= t('.be_yourself') %></td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody><tr>
<td style="line-height: 20px; width: 360px;">
<%= t('.be_yourself_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
<br>
<!-- <a style="color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;" href="#" target="_blank">Watch all the bumpers</a>-->
</td>
<td width="200">
<a href="<%= invite_code_url(@invitation_code)%>" target="_blank"><img style="border: 0pt none ; padding: 0pt 5px 0px 10px; display: block;" src="http://dl.dropbox.com/u/15865/apolonisaphrodisia.png" height="150" width="170"></a>
</td>
</tr>
</tbody></table>
</td></tr>
<tr><td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; font-size: 44px; font-weight: bold; color: rgb(0, 0, 0);">
3. <%= t('.have_fun') %></td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody><tr>
<td width="200">
<a href="<%= invite_code_url(@invitation_code)%>" target="_blank"><img style="border: 0pt none ; padding: 0pt 5px; display: block;" src="http://joindiaspora.com/images/cubbies_screenshot2.png" height="151" width="200"></a>
</td>
<td style="line-height: 20px; width: 360px;">
<%= t('.have_fun_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*"), :link => link_to(t('.cubbies'), "https://cubbi.es", :style => "color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;", :target => "_blank")).html_safe %>
<!-- <a style="color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;" href="#" target="_blank">Watch all the bumpers</a>-->
</td>
</tr>
</tbody></table>
</td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody>
<tr>
<td style="padding: 40px 20px 20px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
<%= link_to(t('.sign_up_now').html_safe, invite_code_url(@invitation_code), :style => "color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;", :target => "_blank").html_safe %>
</td>
</tr>
</tbody>
</table>
</td></tr>
<tr><td>
<table style="padding: 0pt 20px; background: rgb(255, 255, 255) none repeat scroll 0%; font-size: 16px; color: rgb(51, 51, 51); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" align="center" border="0" cellpadding="0" cellspacing="0" width="600">
<tbody>
<tr>
<td style="padding: 20px 20px 0px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
<%= t('.made_by_people', :strong_diaspora => content_tag(:strong, "DIASPORA*"), :jointeam => link_to(t('.join_team'), "https://github.com/diaspora/diaspora/wiki/Become-a-Contributor", :style =>"color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 18px;", :target => "_blank"), :helpfund => link_to(t('.help_fund'), "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QG4L6VYD8YGPU", :style =>"color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 18px;", :target => "_blank")).html_safe %>
</td>
</tr>
</tbody>
</table>
</td></tr>
<tr><td style="padding: 35px 20px 20px; background: rgb(255, 255, 255) none repeat scroll 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">
<%= t('.love') %><br>
<%= t('.team_diaspora') %><br>
</td></tr>
<tr><td style="padding: 35px 40px; font-size: 11px; color: rgb(102, 102, 102); line-height: 16px;">
<% if AppConfig[:pod_uri].host.match(/joindiaspora.com/) %>
<%= t('.unsubscribe', :link => link_to(t('.here'), "http://joindiaspora.us1.list-manage.com/unsubscribe?u=d759919b94f9cdcf39d204f3f&id=7b5ceb2f8b", :style => "color: #3F8FBA; text-decoration: none;")).html_safe %>
<% end %>
<%= t('.email_us', :email => link_to(t('.email_address'), "mailto:questions@joindiaspora.com", :style => "color: #3F8FBA; text-decoration: none;")).html_safe %>
</td></tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,12 @@
Hello!
You have been invited to join Diaspora*!
Click this link to get started
<%= invitation_code_url(@invitation_code)%>
Love,
The Diaspora* email robot!

View file

@ -0,0 +1,5 @@
.alert-message.block-message.success
you were invited by
= person_image_link inviter
= person_link inviter
= aspect_membership_dropdown(contact, inviter, false)

View file

@ -11,16 +11,19 @@
= t('welcome')
%h3.accept_invitation_text
= t('.sign_up_message')
- flash.each do |name, msg|
%p{:class => "login_#{name}"}= msg
= image_tag 'diaspora_collage.png', :style => "margin-left:-50px;"
.span-10
%br
%br
%br
%br
= invite_welcome_message
= form_for(resource, :as => resource_name, :html => {:class => 'new_user_form'}, :url => registration_path(resource_name), :validate => true) do |f|
%fieldset
.clearfix
@ -42,6 +45,10 @@
= t('password_confirmation')
= f.password_field :password_confirmation, :title => t('registrations.new.enter_password_again')
.clearfix
= invite_hidden_tag(invite)
.submit_field
= f.submit t('registrations.new.create_my_account'), :class => 'in_aspects'

View file

@ -14,6 +14,8 @@
%p.center
= t(".community_welcome")
= invited_by_message
.clearfix
%br
%br

View file

@ -319,6 +319,8 @@ en:
simplicity_explanation: "Diaspora makes sharing clean and easy and this goes for privacy too. Inherently private, Diaspora doesnt make you wade through pages of settings and options just to keep your profile secure."
learn_about_host: "Learn about how to host your own Diaspora server."
invitation_codes:
excited: "%{name} is excited to see you here."
invitations:
create:
sent: "Invitations have been sent to: "
@ -332,6 +334,7 @@ en:
invite_someone_to_join: "Invite someone to join Diaspora!"
if_they_accept_info: "if they accept, they will be added to the aspect you invited them."
comma_seperated_plz: "You can enter multiple email addresses separated by commas."
check_out_diaspora: "Hey! You should check out Diaspora*"
to: "To"
personal_message: "Personal message"
send_an_invitation: "Send an invitation"

View file

@ -3,9 +3,7 @@
# the COPYRIGHT file.
Diaspora::Application.routes.draw do
# Posting and Reading
resources :reshares
resources :status_messages, :only => [:new, :create]
@ -33,6 +31,7 @@ Diaspora::Application.routes.draw do
get "liked" => "streams#liked", :as => "liked_stream"
get "commented" => "streams#commented", :as => "commented_stream"
get "aspects" => "streams#aspects", :as => "aspects_stream"
resources :aspects do
put :toggle_contact_visibility
@ -97,11 +96,13 @@ Diaspora::Application.routes.draw do
devise_for :users, :controllers => {:registrations => "registrations",
:password => "devise/passwords",
:sessions => "sessions",
:invitations => "invitations"} do
get 'invitations/resend/:id' => 'invitations#resend', :as => 'invitation_resend'
get 'invitations/email' => 'invitations#email', :as => 'invite_email'
end
:sessions => "sessions"}
#legacy routes to support old invite routes
get 'users/invitations/accept' => 'invitations#edit'
get 'users/invitations/email' => 'invitations#email', :as => 'invite_email'
get 'users/invitations' => 'invitations#new', :as => 'new_user_invitation'
post 'users/invitations' => 'invitations#create', :as => 'new_user_invitation'
get 'login' => redirect('/users/sign_in')
@ -122,7 +123,7 @@ Diaspora::Application.routes.draw do
resources :share_visibilities, :only => [:update]
resources :blocks, :only => [:create, :destroy]
get 'community_spotlight' => "contacts#spotlight", :as => 'community_spotlight'
get 'i/:id' => 'invitation_codes#show', :as => 'invite_code'
get 'people/refresh_search' => "people#refresh_search"
resources :people, :except => [:edit, :update] do
@ -189,7 +190,7 @@ Diaspora::Application.routes.draw do
end
end
get 'community_spotlight' => "contacts#spotlight", :as => 'community_spotlight'
# Mobile site
get 'mobile/toggle', :to => 'home#toggle_mobile', :as => 'toggle_mobile'

View file

@ -0,0 +1,15 @@
class CreateInvitationCodes < ActiveRecord::Migration
def self.up
create_table :invitation_codes do |t|
t.string :token
t.integer :user_id
t.integer :count
t.timestamps
end
end
def self.down
drop_table :invitation_codes
end
end

View file

@ -109,6 +109,14 @@ ActiveRecord::Schema.define(:version => 20120301143226) do
add_index "conversations", ["author_id"], :name => "conversations_author_id_fk"
create_table "invitation_codes", :force => true do |t|
t.string "token"
t.integer "user_id"
t.integer "count"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "invitations", :force => true do |t|
t.text "message"
t.integer "sender_id"

View file

@ -0,0 +1,10 @@
@javascript
Feature: Invitations
Scenario: Accepting an invitation
When I visit alice's invitation code url
Then I should see the "alice is excited" message
When I fill in the new user form
And I press "Create my account!"
Then I should see the "welcome to diaspora" message
And I should be able to friend Alice

View file

@ -11,6 +11,7 @@ Then /^I should see the "(.*)" message$/ do |message|
I18n.translate('profiles.edit.you_are_nsfw')
else
raise "muriel, you don't have that message key, add one here"
end
end
page.should have_content(text)
end
end

View file

@ -167,3 +167,22 @@ When /^I view "([^\"]*)"'s first post$/ do |email|
post = user.posts.first
visit post_path(post)
end
Given /^I visit alice's invitation code url$/ do
@alice ||= Factory(:user, :username => 'alice', :getting_started => false)
invite_code = InvitationCode.find_or_create_by_user_id(@alice.id)
visit invite_code_path(invite_code)
end
When /^I fill in the new user form$/ do
step 'I fill in "user_username" with "ohai"'
step 'I fill in "user_email" with "ohai@example.com"'
step 'I fill in "user_password" with "secret"'
step 'I fill in "user_password_confirmation" with "secret"'
end
And /^I should be able to friend Alice$/ do
alice = User.find_by_username 'alice'
step 'I should see "Add contact"'
step "I should see \"#{alice.name}\""
end

34
lib/email_inviter.rb Normal file
View file

@ -0,0 +1,34 @@
class EmailInviter
attr_accessor :emails, :message, :inviter, :locale
def initialize(emails, options={})
self.message = options[:message]
self.inviter = options[:inviter]
self.locale = options.fetch(:locale, 'en')
self.emails = emails
end
def emails=(list)
emails = list.split(%r{[,\s]+})
emails.reject!{|x| x == inviter.email } unless inviter.nil?
@emails = emails
end
def invitation_code
@invitation_code ||= inviter.nil? ? self.admin_code : inviter.invitation_code
end
def self.admin_code
"foo"
end
def send!
self.emails.each{ |email| mail(email)}
end
private
def mail(email)
Notifier.invite(email, message, inviter, invitation_code, locale)
end
end

View file

@ -5,16 +5,11 @@
require 'spec_helper'
describe InvitationsController do
include Devise::TestHelpers
before do
AppConfig[:open_invitations] = true
@user = alice
@aspect = @user.aspects.first
@invite = {:invite_message=>"test", :aspects=> @aspect.id.to_s, :email=>"abc@example.com"}
request.env["devise.mapping"] = Devise.mappings[:user]
Webfinger.stub_chain(:new, :fetch).and_return(Factory(:person))
@invite = {'email_inviter' => {'message' => "test", 'emails' => "abc@example.com"}}
end
describe "#create" do
@ -24,121 +19,28 @@ describe InvitationsController do
request.env["HTTP_REFERER"]= 'http://test.host/cats/foo'
end
it 'saves an invitation' do
expect {
post :create, :user => @invite
}.should change(Invitation, :count).by(1)
it 'creates an EmailInviter' do
inviter = stub(:emails => ['mbs@gmail.com'])
EmailInviter.should_receive(:new).with(@invite['email_inviter']['emails'], @invite['email_inviter']).
and_return(inviter)
post :create, @invite
end
it 'handles a comma-separated list of emails' do
expect{
post :create, :user => @invite.merge(
:email => "foofoofoofoo@example.com, mbs@gmail.com")
}.should change(Invitation, :count).by(2)
end
it 'handles a comma-separated list of emails with whitespace' do
expect {
post :create, :user => @invite.merge(
:email => "foofoofoofoo@example.com , mbs@gmail.com")
}.should change(Invitation, :count).by(2)
end
it "allows invitations without if invitations are open" do
it "redirects if invitations are closed" do
open_bit = AppConfig[:open_invitations]
AppConfig[:open_invitations] = true
AppConfig[:open_invitations] = false
expect{
post :create, :user => @invite
}.to change(Invitation, :count).by(1)
post :create, @invite
response.should be_redirect
AppConfig[:open_invitations] = open_bit
end
it 'returns to the previous page on success' do
post :create, :user => @invite
post :create, @invite
response.should redirect_to("http://test.host/cats/foo")
end
it 'strips out your own email' do
lambda {
post :create, :user => @invite.merge(:email => @user.email)
}.should_not change(Invitation, :count)
expect{
post :create, :user => @invite.merge(:email => "hello@example.org, #{@user.email}")
}.should change(Invitation, :count).by(1)
end
end
describe "#email" do
before do
invites = Invitation.batch_invite(["foo@example.com"], :message => "hi", :sender => @user, :aspect => @user.aspects.first, :service => 'email', :language => "en-US")
invites.first.send!
@invited_user = User.find_by_email("foo@example.com")
end
it "succeeds" do
get :email, :invitation_token => @invited_user.invitation_token
response.should be_success
end
it "shows an error if there's no such invitation token" do
get :email, :invitation_token => "12345"
response.should render_template(:token_not_found)
end
end
describe "#update" do
before do
invite = Factory(:invitation, :sender => @user, :service => 'email', :identifier => "a@a.com")
@invited_user = invite.attach_recipient!
@accept_params = {:user=>
{:password_confirmation =>"password",
:email => "a@a.com",
:username=>"josh",
:password=>"password",
:invitation_token => @invited_user.invitation_token}}
end
context 'success' do
let(:invited) {User.find_by_username(@accept_params[:user][:username])}
it 'creates a user' do
put :update, @accept_params
invited.should_not be_nil
end
it 'seeds the aspects' do
put :update, @accept_params
invited.aspects.count.should == 4
end
it 'adds a contact' do
lambda {
put :update, @accept_params
}.should change(@user.contacts, :count).by(1)
end
end
context 'failure' do
before do
@fail_params = @accept_params
@fail_params[:user][:username] = @user.username
end
it 'stays on the invitation accept form' do
put :update, @fail_params
response.location.include?(accept_user_invitation_path).should be_true
end
it 'keeps the invitation token' do
put :update, @fail_params
response.location.include?("invitation_token=#{@invited_user.invitation_token}").should be_true
end
end
end
describe '#new' do
it 'renders' do
@ -146,43 +48,4 @@ describe InvitationsController do
get :new
end
end
describe '#resend' do
before do
sign_in :user, @user
@controller.stub!(:current_user).and_return(@user)
request.env["HTTP_REFERER"]= 'http://test.host/cats/foo'
invite = Factory(:invitation, :sender => @user, :service => 'email', :identifier => "a@a.com")
@invited_user = invite.attach_recipient!
end
it 'calls resend invitation if one exists' do
@user.reload.invitations_from_me.count.should == 1
invitation = @user.invitations_from_me.first
Resque.should_receive(:enqueue)
put :resend, :id => invitation.id
end
it 'does not send an invitation for a different user' do
invitation2 = Factory(:invitation, :sender => bob, :service => 'email', :identifier => "a@a.com")
Resque.should_not_receive(:enqueue)
put :resend, :id => invitation2.id
end
end
describe '#extract_messages' do
before do
sign_in alice
end
it 'displays a message that tells the user how many invites were sent, and which REJECTED' do
post :create, :user => @invite.merge(
:email => "mbs@gmail.com, foo@bar.com, foo.com, lala@foo, cool@bar.com")
flash[:notice].should_not be_blank
flash[:notice].should =~ /foo\.com/
flash[:notice].should =~ /lala@foo/
end
end
end

View file

@ -39,6 +39,17 @@ describe RegistrationsController do
flash[:error].should == I18n.t('registrations.closed')
response.should redirect_to new_user_session_path
end
it 'does not redirect if there is a valid invite token' do
i = InvitationCode.create(:user => bob)
get :new, :invite => {:token => i.token}
response.should_not be_redirect
end
it 'does redirect if there is an invalid invite token' do
get :new, :invite => {:token => 'fssdfsd'}
response.should be_redirect
end
end
describe "#create" do

View file

@ -130,6 +130,12 @@ FactoryGirl.define do
end
end
factory :invitation_code do
sequence(:token){|n| "sdfsdsf#{n}"}
association :user
count 0
end
factory :service do |service|
nickname "sirrobertking"
type "Services::Twitter"
@ -239,4 +245,4 @@ FactoryGirl.define do
end
factory(:status, :parent => :status_message)
end
end

View file

@ -0,0 +1,15 @@
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# the InvitationCodesHelper. For example:
#
# describe InvitationCodesHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# helper.concat_strings("this","that").should == "this that"
# end
# end
# end
describe InvitationCodesHelper do
pending "add some examples to (or delete) #{__FILE__}"
end

View file

@ -0,0 +1,68 @@
require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'email_inviter')
describe EmailInviter do
before do
@user = stub(:invitation_code => 'coolcodebro', :present? => true,
:email => 'foo@bar.com')
@emails = "mbs333@gmail.com, foo@bar.com maxwell@dude.com"
end
it 'has a list of emails' do
inviter = EmailInviter.new(@emails)
inviter.emails.should_not be_empty
end
it 'should parse three emails' do
inviter = EmailInviter.new(@emails)
inviter.emails.count.should == 3
end
it 'an optional inviter' do
inviter = EmailInviter.new(@emails, :inviter => @user)
inviter.inviter.should_not be_nil
end
it 'can have a message' do
message = "you guys suck hard"
inviter = EmailInviter.new("emails", :message => message)
inviter.message.should == message
end
describe '#emails' do
it 'rejects the inviter email if present' do
inviter = EmailInviter.new(@emails + " #{@user.email}", :inviter => @user)
inviter.emails.should_not include(@user.email)
end
end
describe 'language' do
it 'defaults to english' do
inviter = EmailInviter.new(@emails)
inviter.locale.should == 'en'
end
it 'listens to the langauge option' do
inviter = EmailInviter.new(@emails, :locale => 'es')
inviter.locale.should == 'es'
end
end
describe '#invitation_code' do
it 'delegates to the user if it exists' do
inviter = EmailInviter.new(@emails, :inviter => @user)
inviter.invitation_code.should == @user.invitation_code
end
it 'calls admin_code if it does not' do
inviter = EmailInviter.new(@emails)
inviter.should_receive(:admin_code).and_return("foo")
inviter.invitation_code.should == "foo"
end
end
describe 'admin code' do
it 'is hella pending' do
pending
end
end
end

View file

@ -0,0 +1,7 @@
require 'spec_helper'
describe InvitationCode do
it 'has a valid factory' do
Factory(:invitation_code).should be_valid
end
end

View file

@ -48,44 +48,6 @@ describe Invitation do
@invitation.message.should == "!"
end
describe 'the invite process' do
before do
end
it 'works for a new user' do
invite = Invitation.new(:sender => alice, :aspect => alice.aspects.first, :service => 'email', :identifier => 'foo@bar.com', :language => alice.language)
lambda {
invite.save
invite.send!
}.should change(User, :count).by(1)
end
it 'works for a current user(with the right email)' do
invite = Invitation.create(:sender => alice, :aspect => alice.aspects.first, :service => 'email', :identifier => bob.email, :language => alice.language)
lambda {
invite.send!
}.should_not change(User, :count)
end
it 'works for a current user(with the same fb id)' do
bob.services << Factory.build(:service, :type => "Services::Facebook")
invite = Invitation.create(:sender => alice, :aspect => alice.aspects.first, :service => 'facebook', :identifier => bob.services.first.uid)
lambda {
invite.send!
}.should_not change(User, :count)
end
end
describe '#convert_to_admin!' do
it 'reset sender and aspect to nil, and sets admin flag to true' do
invite = Factory(:invitation)
invite.convert_to_admin!
invite.reload
invite.admin?.should be_true
invite.sender_id.should be_nil
invite.aspect_id.should be_nil
end
end
describe '.batch_invite' do
before do
@ -109,63 +71,4 @@ describe Invitation do
end
end
describe 'send' do
before do
@invitation = Factory(:invitation, :sender => alice, :aspect => alice.aspects.first, :service => 'email', :identifier => 'a@a.com' , :language => alice.language)
end
it 'sends an email' do
lambda {
@invitation.send!
}.should change(Devise.mailer.deliveries, :count).by(1)
end
it 'sends an email with from header' do
@invitation.send!
Devise.mailer.deliveries.first.from.should_not be_blank
end
it 'sends an email with from header' do
@invitation.send!
Devise.mailer.deliveries.first.to.should == ["a@a.com"]
end
context "re-send" do
it 'sends another email' do
lambda {
@invitation.resend
}.should change(Devise.mailer.deliveries, :count).by(1)
end
end
end
describe '#recipient_identifier' do
it 'calls email if the invitation_service is email' do
email = 'abc@abc.com'
invitation = Factory(:invitation, :sender => alice, :service => 'email', :identifier => email, :aspect => alice.aspects.first, :language => alice.language)
invitation.recipient_identifier.should == email
end
context 'facebook' do
before do
@uid = '23526464'
@service = "facebook"
alice.services << Services::Facebook.new(:uid => "13234895")
alice.reload.services(true).first.service_users.create(:uid => @uid, :photo_url => 'url', :name => "Remote User")
end
it 'gets the name if the invitation_service is facebook' do
invitation = Factory(:invitation, :sender => alice, :identifier => @uid, :service => @service, :aspect => alice.aspects.first)
invitation.recipient_identifier.should == "Remote User"
end
it 'does not error if the facebook user is not recorded' do
invitation = Factory(:invitation, :sender => alice, :identifier => @uid, :service => @service, :aspect => alice.aspects.first)
alice.services.first.service_users.delete_all
invitation.recipient_identifier.should == "A Facebook user"
end
end
end
end
end

View file

@ -33,28 +33,6 @@ describe User do
alice.save
end
end
describe '#infer_email_from_invitation_provider' do
it 'sets corresponding email if invitation_service is email' do
addr = '12345@alice.com'
alice.invitation_service = 'email'
alice.invitation_identifier = addr
lambda {
alice.infer_email_from_invitation_provider
}.should change(alice, :email)
end
it 'does not set an email if invitation_service is not email' do
addr = '1233123'
alice.invitation_service = 'facebook'
alice.invitation_identifier = addr
lambda {
alice.infer_email_from_invitation_provider
}.should_not change(alice, :email)
end
end
end
describe 'hidden_shareables' do
@ -400,70 +378,13 @@ describe User do
end
end
describe '.find_by_invitation' do
let(:invited_user) {
inv = Factory.build(:invitation, :recipient => @recipient, :service => @type, :identifier => @identifier)
User.find_by_invitation(inv)
}
context 'send a request to an existing' do
before do
@recipient = alice
end
context 'active user' do
it 'by service' do
@type = 'facebook'
@identifier = '123456'
@recipient.services << Services::Facebook.new(:uid => @identifier)
@recipient.save
invited_user.should == @recipient
end
it 'by email' do
@type = 'email'
@identifier = alice.email
invited_user.should == @recipient
end
end
context 'invited user' do
it 'by service and identifier' do
@identifier = alice.email
@type = 'email'
invited_user.should == alice
end
end
context 'not on server (not yet invited)' do
it 'returns nil' do
@recipient = nil
@identifier = 'foo@bar.com'
@type = 'email'
invited_user.should be_nil
end
end
end
end
describe '.find_or_create_by_invitation'
describe '.create_from_invitation!' do
before do
@identifier = 'max@foobar.com'
@inv = Factory.build(:invitation, :admin => true, :service => 'email', :identifier => @identifier)
@user = User.create_from_invitation!(@inv)
end
it 'creates a persisted user' do
@user.should be_persisted
end
it 'sets the email if the service is email' do
@user.email.should == @inv.identifier
describe '#process_invite_acceptence' do
it 'sets the inviter on user' do
inv = InvitationCode.create(:user => bob)
user = Factory(:user)
user.process_invite_acceptence(inv)
user.invited_by_id.should == bob.id
end
end
@ -842,54 +763,6 @@ describe User do
end
end
describe "#accept_invitation!" do
before do
fantasy_resque do
@invitation = Factory(:invitation, :sender => eve, :identifier => 'invitee@example.org', :aspect => eve.aspects.first)
end
@invitation.reload
@form_params = {
:invitation_token => "abc",
:email => "a@a.com",
:username => "user",
:password => "secret",
:password_confirmation => "secret",
:person => {
:profile => {:first_name => "Bob", :last_name => "Smith"}
}
}
end
context 'after invitation acceptance' do
it 'destroys the invitations' do
user = @invitation.recipient.accept_invitation!(@form_params)
user.invitations_to_me.count.should == 0
end
it "should create the person with the passed in params" do
lambda {
@invitation.recipient.accept_invitation!(@form_params)
}.should change(Person, :count).by(1)
end
it 'resolves incoming invitations into contact requests' do
user = @invitation.recipient.accept_invitation!(@form_params)
eve.contacts.where(:person_id => user.person.id).count.should == 1
end
end
context 'from an admin' do
it 'should work' do
i = nil
fantasy_resque do
i = Invitation.create!(:admin => true, :service => 'email', :identifier => "new_invitee@example.com")
end
i.reload
i.recipient.accept_invitation!(@form_params)
end
end
end
describe '#retract' do
before do