From 7bac6339878b8ed40972e4f9a7bf1001a645c3d3 Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Mon, 12 Dec 2011 11:24:52 -0800 Subject: [PATCH 1/5] invite_link functionailty mostly works --- Gemfile | 1 - Gemfile.lock | 4 - .../invitation_codes_controller.rb | 16 ++ app/controllers/invitations_controller.rb | 99 ++--------- app/controllers/registrations_controller.rb | 15 +- app/controllers/services_controller.rb | 20 +-- app/helpers/invitation_codes_helper.rb | 28 +++ app/mailers/notifier.rb | 15 ++ app/models/invitation_code.rb | 17 ++ app/models/user.rb | 78 +++------ app/views/invitations/new.html.haml | 25 +-- app/views/notifier/invite.erb | 140 +++++++++++++++ app/views/notifier/invite.html.erb | 140 +++++++++++++++ app/views/notifier/invite.text.erb | 12 ++ app/views/people/_add_contact.html.haml | 5 + app/views/registrations/new.html.haml | 9 +- app/views/users/getting_started.haml | 2 + config/locales/diaspora/en.yml | 3 + config/routes.rb | 19 ++- .../20111211213438_create_invitation_codes.rb | 15 ++ db/schema.rb | 8 + features/invitations.feature | 10 ++ features/step_definitions/message_steps.rb | 5 +- features/step_definitions/user_steps.rb | 19 +++ lib/email_inviter.rb | 34 ++++ .../invitations_controller_spec.rb | 159 ++---------------- .../registrations_controller_spec.rb | 11 ++ spec/factories.rb | 8 +- spec/helpers/invitation_codes_helper_spec.rb | 15 ++ spec/lib/email_inviter_spec.rb | 68 ++++++++ spec/models/invitation_code_spec.rb | 7 + spec/models/invitation_spec.rb | 99 +---------- spec/models/user_spec.rb | 139 +-------------- 33 files changed, 674 insertions(+), 571 deletions(-) create mode 100644 app/controllers/invitation_codes_controller.rb create mode 100644 app/helpers/invitation_codes_helper.rb create mode 100644 app/models/invitation_code.rb create mode 100644 app/views/notifier/invite.erb create mode 100644 app/views/notifier/invite.html.erb create mode 100644 app/views/notifier/invite.text.erb create mode 100644 app/views/people/_add_contact.html.haml create mode 100644 db/migrate/20111211213438_create_invitation_codes.rb create mode 100644 features/invitations.feature create mode 100644 lib/email_inviter.rb create mode 100644 spec/helpers/invitation_codes_helper_spec.rb create mode 100644 spec/lib/email_inviter_spec.rb create mode 100644 spec/models/invitation_code_spec.rb diff --git a/Gemfile b/Gemfile index d7b5bfd7d..20f656985 100644 --- a/Gemfile +++ b/Gemfile @@ -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' diff --git a/Gemfile.lock b/Gemfile.lock index 42943b247..b4b489c8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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 diff --git a/app/controllers/invitation_codes_controller.rb b/app/controllers/invitation_codes_controller.rb new file mode 100644 index 000000000..e79b4f868 --- /dev/null +++ b/app/controllers/invitation_codes_controller.rb @@ -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 diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb index 1b4561972..9ca07d839 100644 --- a/app/controllers/invitations_controller.rb +++ b/app/controllers/invitations_controller.rb @@ -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] 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 \ No newline at end of file diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index bcb7cad5b..d55cbb2ec 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -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 diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index 25df66366..c67f609bb 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -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 \ No newline at end of file diff --git a/app/helpers/invitation_codes_helper.rb b/app/helpers/invitation_codes_helper.rb new file mode 100644 index 000000000..83ac8ddd5 --- /dev/null +++ b/app/helpers/invitation_codes_helper.rb @@ -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 diff --git a/app/mailers/notifier.rb b/app/mailers/notifier.rb index f9c4ad044..5b5ea9ee6 100644 --- a/app/mailers/notifier.rb +++ b/app/mailers/notifier.rb @@ -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 diff --git a/app/models/invitation_code.rb b/app/models/invitation_code.rb new file mode 100644 index 000000000..ba31b74c9 --- /dev/null +++ b/app/models/invitation_code.rb @@ -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 diff --git a/app/models/user.rb b/app/models/user.rb index e35314d50..f03cf6ebf 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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}" diff --git a/app/views/invitations/new.html.haml b/app/views/invitations/new.html.haml index 5bfa3e319..448876030 100644 --- a/app/views/invitations/new.html.haml +++ b/app/views/invitations/new.html.haml @@ -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 diff --git a/app/views/notifier/invite.erb b/app/views/notifier/invite.erb new file mode 100644 index 000000000..7093e499f --- /dev/null +++ b/app/views/notifier/invite.erb @@ -0,0 +1,140 @@ +<%- self.extend NotifierHelper -%> + + <%=invite_email_title %> + +

<%= 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 %>

+ + + + +
+ + + + + + + + + + + + + + + + + + + <% if @inviter.present? %> + <%= @inviter.inspect %> + <% end %> + + + + + + + + + + + + + + + + + + + + +
+ + Diaspora + +
+ <%= t('.finally') %>
+
+ +
+ <%= t('.arrived', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> +
+
+ <%= 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 %> +
+ 1. <%= t('.get_connected') %>
+ + + + + +
+ + + <%= t('.get_connected_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> +
+ +
+
+ 2. <%= t('.be_yourself') %>
+ + + + + + +
+ + <%= t('.be_yourself_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> + +
+ +
+ +
+
+ 3. <%= t('.have_fun') %>
+ + + + + +
+ + + + <%= 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 %> + +
+
+ + + + + + +
+ <%= 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 %> +
+
+ + + + + + +
+ <%= 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 %> + +
+
+ <%= t('.love') %>
+ <%= t('.team_diaspora') %>
+
+ <% 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 %> +
+
diff --git a/app/views/notifier/invite.html.erb b/app/views/notifier/invite.html.erb new file mode 100644 index 000000000..7093e499f --- /dev/null +++ b/app/views/notifier/invite.html.erb @@ -0,0 +1,140 @@ +<%- self.extend NotifierHelper -%> + + <%=invite_email_title %> + +

<%= 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 %>

+ + + + +
+ + + + + + + + + + + + + + + + + + + <% if @inviter.present? %> + <%= @inviter.inspect %> + <% end %> + + + + + + + + + + + + + + + + + + + + +
+ + Diaspora + +
+ <%= t('.finally') %>
+
+ +
+ <%= t('.arrived', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> +
+
+ <%= 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 %> +
+ 1. <%= t('.get_connected') %>
+ + + + + +
+ + + <%= t('.get_connected_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> +
+ +
+
+ 2. <%= t('.be_yourself') %>
+ + + + + + +
+ + <%= t('.be_yourself_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> + +
+ +
+ +
+
+ 3. <%= t('.have_fun') %>
+ + + + + +
+ + + + <%= 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 %> + +
+
+ + + + + + +
+ <%= 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 %> +
+
+ + + + + + +
+ <%= 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 %> + +
+
+ <%= t('.love') %>
+ <%= t('.team_diaspora') %>
+
+ <% 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 %> +
+
diff --git a/app/views/notifier/invite.text.erb b/app/views/notifier/invite.text.erb new file mode 100644 index 000000000..90cb006df --- /dev/null +++ b/app/views/notifier/invite.text.erb @@ -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! \ No newline at end of file diff --git a/app/views/people/_add_contact.html.haml b/app/views/people/_add_contact.html.haml new file mode 100644 index 000000000..7026e5d47 --- /dev/null +++ b/app/views/people/_add_contact.html.haml @@ -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) diff --git a/app/views/registrations/new.html.haml b/app/views/registrations/new.html.haml index b4a27188e..472a5fdaf 100644 --- a/app/views/registrations/new.html.haml +++ b/app/views/registrations/new.html.haml @@ -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' diff --git a/app/views/users/getting_started.haml b/app/views/users/getting_started.haml index 770b3bb36..7347c2cfc 100644 --- a/app/views/users/getting_started.haml +++ b/app/views/users/getting_started.haml @@ -14,6 +14,8 @@ %p.center = t(".community_welcome") + = invited_by_message + .clearfix %br %br diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index fc3ebca21..a0eb0adde 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -319,6 +319,8 @@ en: simplicity_explanation: "Diaspora makes sharing clean and easy – and this goes for privacy too. Inherently private, Diaspora doesn’t 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" diff --git a/config/routes.rb b/config/routes.rb index 44e6aa3b7..0be9978c6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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' diff --git a/db/migrate/20111211213438_create_invitation_codes.rb b/db/migrate/20111211213438_create_invitation_codes.rb new file mode 100644 index 000000000..f2bdde858 --- /dev/null +++ b/db/migrate/20111211213438_create_invitation_codes.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index cc3532834..f662bf314 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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" diff --git a/features/invitations.feature b/features/invitations.feature new file mode 100644 index 000000000..d3b92045c --- /dev/null +++ b/features/invitations.feature @@ -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 diff --git a/features/step_definitions/message_steps.rb b/features/step_definitions/message_steps.rb index dc8d140ad..004acffca 100644 --- a/features/step_definitions/message_steps.rb +++ b/features/step_definitions/message_steps.rb @@ -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 \ No newline at end of file +end diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index 8fd3f009a..350a3730a 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -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 diff --git a/lib/email_inviter.rb b/lib/email_inviter.rb new file mode 100644 index 000000000..d5ec92b81 --- /dev/null +++ b/lib/email_inviter.rb @@ -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 \ No newline at end of file diff --git a/spec/controllers/invitations_controller_spec.rb b/spec/controllers/invitations_controller_spec.rb index be3ca2447..b2e6afe50 100644 --- a/spec/controllers/invitations_controller_spec.rb +++ b/spec/controllers/invitations_controller_spec.rb @@ -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 diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index c75c379a0..a6b4a2777 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -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 diff --git a/spec/factories.rb b/spec/factories.rb index 56358bb82..4f13b6ec6 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -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 \ No newline at end of file +end diff --git a/spec/helpers/invitation_codes_helper_spec.rb b/spec/helpers/invitation_codes_helper_spec.rb new file mode 100644 index 000000000..c2dfae147 --- /dev/null +++ b/spec/helpers/invitation_codes_helper_spec.rb @@ -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 diff --git a/spec/lib/email_inviter_spec.rb b/spec/lib/email_inviter_spec.rb new file mode 100644 index 000000000..22e216da0 --- /dev/null +++ b/spec/lib/email_inviter_spec.rb @@ -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 \ No newline at end of file diff --git a/spec/models/invitation_code_spec.rb b/spec/models/invitation_code_spec.rb new file mode 100644 index 000000000..142cc2944 --- /dev/null +++ b/spec/models/invitation_code_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' + +describe InvitationCode do + it 'has a valid factory' do + Factory(:invitation_code).should be_valid + end +end diff --git a/spec/models/invitation_spec.rb b/spec/models/invitation_spec.rb index ad19d8b59..c379ee819 100644 --- a/spec/models/invitation_spec.rb +++ b/spec/models/invitation_spec.rb @@ -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 \ No newline at end of file diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f4f286622..1738beda5 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -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 From 6b97b8044ba4bd1ed940b7935b4494892c5694ed Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Thu, 9 Feb 2012 00:02:01 -0800 Subject: [PATCH 2/5] small updates, and it looks like we are mostly working --- app/controllers/admins_controller.rb | 10 +- app/controllers/invitations_controller.rb | 1 + app/controllers/services_controller.rb | 34 ----- app/helpers/notifier_helper.rb | 7 +- app/models/invitation.rb | 48 +------ app/views/notifier/invite.erb | 140 ------------------- app/views/notifier/invite.html.erb | 32 ++--- app/views/notifier/invite.text.erb | 2 +- features/accepts_invitation.feature | 2 +- features/step_definitions/user_steps.rb | 9 +- features/support/paths.rb | 2 +- lib/email_inviter.rb | 5 +- lib/rake_helpers.rb | 2 +- spec/controllers/services_controller_spec.rb | 47 ------- tmp/.gitkeep | 0 15 files changed, 44 insertions(+), 297 deletions(-) delete mode 100644 app/views/notifier/invite.erb delete mode 100644 tmp/.gitkeep diff --git a/app/controllers/admins_controller.rb b/app/controllers/admins_controller.rb index 7b1fafa4d..12d3cdbf9 100644 --- a/app/controllers/admins_controller.rb +++ b/app/controllers/admins_controller.rb @@ -11,12 +11,14 @@ class AdminsController < ApplicationController end def admin_inviter - user = User.find_by_email params[:idenitifer] + email = params[:idenitifer] + user = User.find_by_email(email) + unless user - Invitation.create(:service => 'email', :identifier => params[:identifier], :admin => true) - flash[:notice] = "invitation sent to #{params[:identifier]}" + EmailInviter.new(email).send! + flash[:notice] = "invitation sent to #{email}" else - flash[:notice]= "error sending invite to #{params[:identifier]}" + flash[:notice]= "error sending invite to #{email}" end redirect_to user_search_path, :notice => flash[:notice] end diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb index 9ca07d839..cefd53162 100644 --- a/app/controllers/invitations_controller.rb +++ b/app/controllers/invitations_controller.rb @@ -27,6 +27,7 @@ class InvitationsController < ApplicationController def create inviter = EmailInviter.new(params[:email_inviter][:emails], params[:email_inviter]) + inviter.send! redirect_to :back, :notice => "Great! Invites were sent off to #{inviter.emails.join(', ')}" end diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index c67f609bb..5f44071bf 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -69,38 +69,4 @@ class ServicesController < ApplicationController @service = current_user.services.where(:type => "Services::#{params[:provider].titleize}").first @friends = @service ? @service.finder(:remote => params[:remote]).paginate( :page => params[:page], :per_page => 15) : [] end - - def inviter - @uid = params[:uid] - - if i_id = params[:invitation_id] - invite = Invitation.find(i_id) - invited_user = invite.recipient - else - invite = Invitation.create(:service => params[:provider], :identifier => @uid, :sender => current_user, :aspect => current_user.aspects.find(params[:aspect_id])) - invited_user = invite.attach_recipient! - end - - #to make sure a friend you just invited from facebook shows up as invited - service = current_user.services.where(:type => "Services::Facebook").first - su = ServiceUser.where(:service_id => service.id, :uid => @uid).first - su.attach_local_models - su.save - - respond_to do |format| - format.html{ invite_redirect_url(invite, invited_user, su)} - format.json{ render :json => invite_redirect_json(invite, invited_user, su) } - end - end - - def facebook_message_url(user, facebook_uid) - subject = t('services.inviter.join_me_on_diaspora') - message = < :admin? validates_uniqueness_of :sender_id, :scope => [:identifier, :service], :unless => :admin? - after_create :queue_send! #TODO make this after_commit :queue_saved!, :on => :create - # @note options hash is passed through to [Invitation.new] # @see [Invitation.new] @@ -33,7 +31,7 @@ class Invitation < ActiveRecord::Base # @option opts [Aspect] :aspect # @option opts [String] :service # @return [Array] An array of [Invitation] models - # the valid ones are saved, and the invalid ones are not. + # the valid optsnes are saved, and the invalid ones are not. def self.batch_invite(emails, opts) users_on_pod = User.where(:email => emails, :invitation_token => nil) @@ -66,36 +64,16 @@ class Invitation < ActiveRecord::Base !email_like_identifer end - # Attach a recipient [User] to the [Invitation] unless - # there is one already present. - # - # @return [User] The recipient. - def attach_recipient! - unless self.recipient.present? - self.recipient = User.find_or_create_by_invitation(self) - self.save - end - self.recipient - end - # Find or create user, and send that resultant User an # invitation. # # @return [Invitation] self def send! - self.attach_recipient! - - # Sets an instance variable in User (set by devise invitable) - # This determines whether an email should be sent to the recipient. - recipient.skip_invitation = self.skip_email? - - recipient.invite! - - # Logging the invitation action - log_hash = {:event => :invitation_sent, :to => self[:identifier], :service => self[:service]} - log_hash.merge({:inviter => self.sender.diaspora_handle, :invitier_uid => self.sender.id, :inviter_created_at_unix => self.sender.created_at.to_i}) if self.sender - Rails.logger.info(log_hash) - + if email_like_identifer + EmailInviter.new(self.identifier).send! + else + puts "broken facebook invitation_token" + end self end @@ -135,19 +113,7 @@ class Invitation < ActiveRecord::Base when 'email' self.identifier when 'facebook' - if username = ServiceUser.username_of_service_user_by_uid(self.identifier) - unless username.include?('profile.php?') - "#{username}@facebook.com" - else - nil - end - end - end - end - - def queue_send! - unless self.recipient.present? - Resque.enqueue(Jobs::Mail::InviteUserByEmail, self.id) + false end end diff --git a/app/views/notifier/invite.erb b/app/views/notifier/invite.erb deleted file mode 100644 index 7093e499f..000000000 --- a/app/views/notifier/invite.erb +++ /dev/null @@ -1,140 +0,0 @@ -<%- self.extend NotifierHelper -%> - - <%=invite_email_title %> - -

<%= 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 %>

- - - - -
- - - - - - - - - - - - - - - - - - - <% if @inviter.present? %> - <%= @inviter.inspect %> - <% end %> - - - - - - - - - - - - - - - - - - - - -
- - Diaspora - -
- <%= t('.finally') %>
-
- -
- <%= t('.arrived', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> -
-
- <%= 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 %> -
- 1. <%= t('.get_connected') %>
- - - - - -
- - - <%= t('.get_connected_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> -
- -
-
- 2. <%= t('.be_yourself') %>
- - - - - - -
- - <%= t('.be_yourself_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> - -
- -
- -
-
- 3. <%= t('.have_fun') %>
- - - - - -
- - - - <%= 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 %> - -
-
- - - - - - -
- <%= 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 %> -
-
- - - - - - -
- <%= 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 %> - -
-
- <%= t('.love') %>
- <%= t('.team_diaspora') %>
-
- <% 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 %> -
-
diff --git a/app/views/notifier/invite.html.erb b/app/views/notifier/invite.html.erb index 7093e499f..be58a6716 100644 --- a/app/views/notifier/invite.html.erb +++ b/app/views/notifier/invite.html.erb @@ -2,7 +2,7 @@ <%=invite_email_title %> -

<%= 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 %>

+

<%= t('devise.mailer.invitation_instructions.displaying_correctly', :link => link_to(t('devise.mailer.invitation_instructions.view_in'), invite_email_url(:invitation_code => @invitation_code), :style => "color: #3F8FBA; text-decoration: none;")).html_safe %>

@@ -19,7 +19,7 @@ @@ -29,10 +29,10 @@ @@ -43,7 +43,7 @@ + 1. <%= t('devise.mailer.invitation_instructions.get_connected') %>
- <%= t('.finally') %>
+ <%= t('devise.mailer.invitation_instructions.finally') %>
- <%= t('.arrived', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> + <%= t('devise.mailer.invitation_instructions.arrived', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>

- <%= 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 %> + <%= link_to(t('devise.mailer.invitation_instructions.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 %>
- 1. <%= t('.get_connected') %>
@@ -51,7 +51,7 @@ @@ -60,13 +60,13 @@ + 2. <%= t('devise.mailer.invitation_instructions.be_yourself') %>
- <%= t('.get_connected_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> + <%= t('devise.mailer.invitation_instructions.get_connected_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
- 2. <%= t('.be_yourself') %>
+ 3. <%= t('devise.mailer.invitation_instructions.have_fun') %>
- <%= t('.be_yourself_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %> + <%= t('devise.mailer.invitation_instructions.be_yourself_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*")).html_safe %>
@@ -81,7 +81,7 @@
- 3. <%= t('.have_fun') %>
@@ -90,7 +90,7 @@ @@ -102,7 +102,7 @@ @@ -114,7 +114,7 @@ @@ -123,14 +123,14 @@
- <%= 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 %> + <%= t('devise.mailer.invitation_instructions.have_fun_paragraph', :strong_diaspora => content_tag(:strong, "DIASPORA*"), :link => link_to(t('devise.mailer.invitation_instructions.cubbies'), "https://cubbi.es", :style => "color: #3F8FBA; text-decoration: underline; font-weight: bold; font-size: 20px;", :target => "_blank")).html_safe %>
- <%= 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 %> + <%= link_to(t('devise.mailer.invitation_instructions.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 %>
- <%= 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 %> + <%= t('devise.mailer.invitation_instructions.made_by_people', :strong_diaspora => content_tag(:strong, "DIASPORA*"), :jointeam => link_to(t('devise.mailer.invitation_instructions.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('devise.mailer.invitation_instructions.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 %>
- <%= t('.love') %>
- <%= t('.team_diaspora') %>
+ <%= t('devise.mailer.invitation_instructions.love') %>
+ <%= t('devise.mailer.invitation_instructions.team_diaspora') %>
<% 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 %> + <%= t('devise.mailer.invitation_instructions.unsubscribe', :link => link_to(t('devise.mailer.invitation_instructions.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 %> + <%= t('devise.mailer.invitation_instructions.email_us', :email => link_to(t('devise.mailer.invitation_instructions.email_address'), "mailto:questions@joindiaspora.com", :style => "color: #3F8FBA; text-decoration: none;")).html_safe %>
diff --git a/app/views/notifier/invite.text.erb b/app/views/notifier/invite.text.erb index 90cb006df..947541336 100644 --- a/app/views/notifier/invite.text.erb +++ b/app/views/notifier/invite.text.erb @@ -4,7 +4,7 @@ You have been invited to join Diaspora*! Click this link to get started -<%= invitation_code_url(@invitation_code)%> +<%= invite_code_url(@invitation_code)%> Love, diff --git a/features/accepts_invitation.feature b/features/accepts_invitation.feature index 98635b492..70d9dccad 100644 --- a/features/accepts_invitation.feature +++ b/features/accepts_invitation.feature @@ -40,6 +40,6 @@ Feature: invitation acceptance Given a user with email "bob@bob.bob" When I sign in as "bob@bob.bob" And I follow "By email" - And I fill in "user_email" with "alex@example.com" + And I fill in "email_inviter_emails" with "alex@example.com" And I press "Send an invitation" Then I should have 1 Devise email delivery diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index 350a3730a..e60922edd 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -26,15 +26,14 @@ Given /^a nsfw user with email "([^\"]*)"$/ do |email| end Given /^I have been invited by an admin$/ do - i = Invitation.create!(:admin => true, :service => 'email', :identifier => "new_invitee@example.com") - @me = i.attach_recipient! + i = EmailInviter.new("new_invitee@example.com") + i.send! end Given /^I have been invited by a user$/ do @inviter = Factory(:user) - aspect = @inviter.aspects.create(:name => "Rocket Scientists") - i = Invitation.create!(:aspect => aspect, :sender => @inviter, :service => 'email', :identifier => "new_invitee@example.com", :message =>"Hey, tell me about your rockets!") - @me = i.attach_recipient! + i = EmailInviter.new("new_invitee@example.com", :inviter => @inviter) + i.send! end When /^I click on my name$/ do diff --git a/features/support/paths.rb b/features/support/paths.rb index b6eb520df..318d39f7f 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -20,7 +20,7 @@ module NavigationHelpers when /^my profile page$/ person_path(@me.person) when /^my acceptance form page$/ - accept_user_invitation_path(:invitation_token => @me.invitation_token) + invite_code_path(InvitationCode.first) when /^the requestors profile$/ person_path(Request.where(:recipient_id => @me.person.id).first.sender) when /^"([^\"]*)"'s page$/ diff --git a/lib/email_inviter.rb b/lib/email_inviter.rb index d5ec92b81..0585b866b 100644 --- a/lib/email_inviter.rb +++ b/lib/email_inviter.rb @@ -15,10 +15,11 @@ class EmailInviter end def invitation_code - @invitation_code ||= inviter.nil? ? self.admin_code : inviter.invitation_code + @invitation_code ||= inviter.nil? ? EmailInviter.admin_code : inviter.invitation_code end def self.admin_code + puts "FIX ME" "foo" end @@ -29,6 +30,6 @@ class EmailInviter private def mail(email) - Notifier.invite(email, message, inviter, invitation_code, locale) + Notifier.invite(email, message, inviter, invitation_code, locale).deliver! end end \ No newline at end of file diff --git a/lib/rake_helpers.rb b/lib/rake_helpers.rb index d0f2a5a44..d71fa3e83 100644 --- a/lib/rake_helpers.rb +++ b/lib/rake_helpers.rb @@ -29,7 +29,7 @@ module RakeHelpers unless possible_user puts "#{n}: sending email to: #{backer_name} #{backer_email}" unless Rails.env == 'test' unless test - i = Invitation.new(:service => 'email', :identifier => backer_email, :admin => true) + i = EmailInviter.new(backer_email) i.send! end else diff --git a/spec/controllers/services_controller_spec.rb b/spec/controllers/services_controller_spec.rb index fd11b2150..9017c3959 100644 --- a/spec/controllers/services_controller_spec.rb +++ b/spec/controllers/services_controller_spec.rb @@ -143,51 +143,4 @@ describe ServicesController do Nokogiri(response.body).css('.translation_missing').should be_empty end end - - describe '#inviter' do - before do - @uid = "abc" - fb = Factory(:service, :type => "Services::Facebook", :user => @user) - fb = Services::Facebook.find(fb.id) - @su = Factory(:service_user, :service => fb, :uid => @uid) - @invite_params = {:provider => 'facebook', :uid => @uid, :aspect_id => @user.aspects.first.id} - end - - it 'redirects to a prefilled facebook message url' do - put :inviter, @invite_params - response.location.should match(/https:\/\/www\.facebook\.com\/messages\/.*?msg_prefill=.*/) - end - - it 'creates an invitation' do - lambda { - put :inviter, @invite_params - }.should change(Invitation, :count).by(1) - end - - it 'sets the invitation_id on the service_user' do - post :inviter, @invite_params - @su.reload.invitation.should_not be_nil - end - - it 'does not create a duplicate invitation' do - invited_user = Factory.build(:user, :username =>nil) - invited_user.save(:validate => false) - inv = Invitation.create!(:sender => @user, :recipient => invited_user, :aspect => @user.aspects.first, :identifier => eve.email) - @invite_params[:invitation_id] = inv.id - - lambda { - put :inviter, @invite_params - }.should_not change(Invitation, :count) - end - - it 'disregards the amount of invites if open_invitations are enabled' do - open_bit = AppConfig[:open_invitations] - AppConfig[:open_invitations] = true - - lambda { - put :inviter, @invite_params - }.should change(Invitation, :count).by(1) - AppConfig[:open_invitations] = open_bit - end - end end diff --git a/tmp/.gitkeep b/tmp/.gitkeep deleted file mode 100644 index e69de29bb..000000000 From 319b3c4d3b1b5cdfa86f8e218030e6c3a3bcc46e Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Thu, 15 Mar 2012 13:48:21 -0700 Subject: [PATCH 3/5] fixed rspec tests, more fit and finish around how the invite code works, and improving admin functionality --- app/controllers/admins_controller.rb | 10 ++- app/controllers/invitations_controller.rb | 2 +- app/models/invitation.rb | 2 +- app/models/invitation_code.rb | 24 +++++- app/models/user.rb | 13 +-- app/views/admins/user_search.html.haml | 84 ++++++++----------- app/views/notifier/invite.html.erb | 2 +- config/application.yml.example | 6 ++ config/routes.rb | 1 + .../20110105051803_create_import_tables.rb | 1 - features/step_definitions/user_steps.rb | 6 +- lib/email_inviter.rb | 11 +-- lib/rake_helpers.rb | 5 ++ spec/controllers/admins_controller_spec.rb | 7 +- .../invitations_controller_spec.rb | 5 +- spec/lib/email_inviter_spec.rb | 34 +++----- spec/lib/rake_helper_spec.rb | 18 ++-- spec/models/invitation_code_spec.rb | 35 ++++++++ 18 files changed, 143 insertions(+), 123 deletions(-) diff --git a/app/controllers/admins_controller.rb b/app/controllers/admins_controller.rb index 12d3cdbf9..d433c71ba 100644 --- a/app/controllers/admins_controller.rb +++ b/app/controllers/admins_controller.rb @@ -11,11 +11,12 @@ class AdminsController < ApplicationController end def admin_inviter - email = params[:idenitifer] + inviter = InvitationCode.default_inviter_or(current_user) + email = params[:identifier] user = User.find_by_email(email) unless user - EmailInviter.new(email).send! + EmailInviter.new(email, inviter).send! flash[:notice] = "invitation sent to #{email}" else flash[:notice]= "error sending invite to #{email}" @@ -23,6 +24,11 @@ class AdminsController < ApplicationController redirect_to user_search_path, :notice => flash[:notice] end + def add_invites + InvitationCode.find_by_token(params[:invite_code_id]).add_invites! + redirect_to user_search_path + end + def weekly_user_stats @created_users = User.where("username IS NOT NULL") @created_users_by_week = Hash.new{ |h,k| h[k] = [] } diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb index cefd53162..560b9aeb7 100644 --- a/app/controllers/invitations_controller.rb +++ b/app/controllers/invitations_controller.rb @@ -26,7 +26,7 @@ class InvitationsController < ApplicationController def create - inviter = EmailInviter.new(params[:email_inviter][:emails], params[:email_inviter]) + inviter = EmailInviter.new(params[:email_inviter][:emails], current_user, params[:email_inviter]) inviter.send! redirect_to :back, :notice => "Great! Invites were sent off to #{inviter.emails.join(', ')}" end diff --git a/app/models/invitation.rb b/app/models/invitation.rb index 809872c10..d19b462ae 100644 --- a/app/models/invitation.rb +++ b/app/models/invitation.rb @@ -70,7 +70,7 @@ class Invitation < ActiveRecord::Base # @return [Invitation] self def send! if email_like_identifer - EmailInviter.new(self.identifier).send! + EmailInviter.new(self.identifier, sender).send! else puts "broken facebook invitation_token" end diff --git a/app/models/invitation_code.rb b/app/models/invitation_code.rb index ba31b74c9..33e259642 100644 --- a/app/models/invitation_code.rb +++ b/app/models/invitation_code.rb @@ -3,15 +3,35 @@ class InvitationCode < ActiveRecord::Base validates_presence_of :user - before_create :generate_token + before_create :generate_token, :set_default_invite_count def to_param token end + def add_invites! + self.update_attributes(:count => self.count+100) + end + + def use! + self.update_attributes(:count => self.count-1) + end + def generate_token begin self.token = ActiveSupport::SecureRandom.hex(6) end while InvitationCode.exists?(:token => self[:token]) end -end + + def self.default_inviter_or(user) + if AppConfig[:admin_account].present? + inviter = User.find_by_username(AppConfig[:admin_account]) + end + inviter ||= user + inviter + end + + def set_default_invite_count + self.count = AppConfig[:invite_count] || 25 + end +end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index f03cf6ebf..1f7c9e5a1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -83,7 +83,6 @@ 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 @@ -108,28 +107,18 @@ class User < ActiveRecord::Base ConversationVisibility.sum(:unread, :conditions => "person_id = #{self.person.id}") end - # @return [User] - def self.find_by_invitation(invitation) - service = invitation.service - identifier = invitation.identifier - - if service == 'email' - 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 end def process_invite_acceptence(invite) self.invited_by = invite.user + invite.use! end diff --git a/app/views/admins/user_search.html.haml b/app/views/admins/user_search.html.haml index ff74732ff..8736398e2 100644 --- a/app/views/admins/user_search.html.haml +++ b/app/views/admins/user_search.html.haml @@ -1,65 +1,47 @@ .span-24 = render :partial => 'admins/admin_bar.haml' -%br -%br +.span-24.prepend-4 -%h3 - = form_tag 'admin_inviter', :method => :get do - email to invite: - = text_field_tag 'identifier' - = submit_tag 'invite' + %h3 + you currently have + = current_user.invitation_code.count + invites left + = link_to "add_invites", add_invites_path(current_user.invitation_code) + + = form_tag 'admin_inviter', :method => :get do + email to invite: + = text_field_tag 'identifier' + = submit_tag 'invite' -%h3 - user search -= form_tag 'user_search', :method => :get do - username: - = text_field_tag 'user[username]', params[:user][:username] + %h3 + user search + = form_tag 'user_search', :method => :get do + username: + = text_field_tag 'user[username]', params[:user][:username] - email: - = text_field_tag 'user[email]', params[:user][:email] + email: + = text_field_tag 'user[email]', params[:user][:email] - invitation identifier: - = text_field_tag 'user[invitation_identifier]', params[:user][:invitation_identifier] - - invitation token: - = text_field_tag 'user[invitation_token]', params[:user][:invitation_token] - = submit_tag 'go' + = submit_tag 'go' -= "#{@users.count} users found" -%br -%br -= for user in @users - = user.inspect + = "#{@users.count} users found" %br - - if user.person - = user.person.inspect + %br + - @users.each do |user| + = user.inspect %br - - if user.person.profile - = user.person.profile.inspect + - if user.person + = user.person.inspect + %br + - if user.person.profile + = user.person.profile.inspect + %br + = "invite token: #{invite_code_url(user.invited_by.invite_code)}" if user.invited_by.present? + = link_to "add_invites", add_invites_path(user.invitation_code) %br - = "invite token: #{accept_invitation_url(user, :invitation_token => user.invitation_token)}" if user.invitation_token - %br - %br - %br -%br -= javascript_include_tag 'apiconsole' -#query - %h3 api console - = text_field_tag :api - = submit_tag 'ping this api', :id => 'api_submit' - - response: - %br - %br - #resp - - -%br - post to Diaspora v1 - - - + %br + %br \ No newline at end of file diff --git a/app/views/notifier/invite.html.erb b/app/views/notifier/invite.html.erb index be58a6716..ead22fce2 100644 --- a/app/views/notifier/invite.html.erb +++ b/app/views/notifier/invite.html.erb @@ -1,4 +1,4 @@ -<%- self.extend NotifierHelper -%> + <%- self.extend NotifierHelper -%> <%=invite_email_title %> diff --git a/config/application.yml.example b/config/application.yml.example index d5e318f27..1de63b89a 100644 --- a/config/application.yml.example +++ b/config/application.yml.example @@ -49,6 +49,12 @@ defaults: &defaults # Set this to true if you want users to invite as many people as they want open_invitations: true + #the 'admin' account for your pod... ie for jd.com, this is diasporahq + admin_account: '' + + #the default amount of invitiations for an invite link + invite_count: 25 + # Set this to true if you don't want your users to follow the diasporahq@joindiaspora.com # account on account creation. The diasporahq account helps users start with some # activity in their stream and get news about Diaspora, but if you don't want your server diff --git a/config/routes.rb b/config/routes.rb index 0be9978c6..e22da84f0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -112,6 +112,7 @@ Diaspora::Application.routes.draw do get :weekly_user_stats get :correlations get :stats, :as => 'pod_stats' + get "add_invites/:invite_code_id" => 'admins#add_invites', :as => 'add_invites' end resource :profile, :only => [:edit, :update] diff --git a/db/migrate/20110105051803_create_import_tables.rb b/db/migrate/20110105051803_create_import_tables.rb index f514f3157..0388d2cef 100644 --- a/db/migrate/20110105051803_create_import_tables.rb +++ b/db/migrate/20110105051803_create_import_tables.rb @@ -166,7 +166,6 @@ class CreateImportTables < ActiveRecord::Migration t.string :language t.string :email t.database_authenticatable - t.invitable t.recoverable t.rememberable t.trackable diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index e60922edd..2dbf8c281 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -26,13 +26,15 @@ Given /^a nsfw user with email "([^\"]*)"$/ do |email| end Given /^I have been invited by an admin$/ do - i = EmailInviter.new("new_invitee@example.com") + admin = Factory(:user) + bob.invitation_code + i = EmailInviter.new("new_invitee@example.com", bob) i.send! end Given /^I have been invited by a user$/ do @inviter = Factory(:user) - i = EmailInviter.new("new_invitee@example.com", :inviter => @inviter) + i = EmailInviter.new("new_invitee@example.com", @inviter) i.send! end diff --git a/lib/email_inviter.rb b/lib/email_inviter.rb index 0585b866b..298379c81 100644 --- a/lib/email_inviter.rb +++ b/lib/email_inviter.rb @@ -1,10 +1,10 @@ class EmailInviter attr_accessor :emails, :message, :inviter, :locale - def initialize(emails, options={}) + def initialize(emails, inviter, options={}) self.message = options[:message] - self.inviter = options[:inviter] self.locale = options.fetch(:locale, 'en') + self.inviter = inviter self.emails = emails end @@ -15,12 +15,7 @@ class EmailInviter end def invitation_code - @invitation_code ||= inviter.nil? ? EmailInviter.admin_code : inviter.invitation_code - end - - def self.admin_code - puts "FIX ME" - "foo" + @invitation_code ||= inviter.invitation_code end def send! diff --git a/lib/rake_helpers.rb b/lib/rake_helpers.rb index d71fa3e83..f7a075277 100644 --- a/lib/rake_helpers.rb +++ b/lib/rake_helpers.rb @@ -26,6 +26,11 @@ module RakeHelpers possible_invite = Invitation.find_by_identifier(backer_email) possible_user ||= possible_invite.recipient if possible_invite.present? + admin_account = User.find_by_username(AppConfig[:admin_account]) + raise "no admin_account in application.yml" unless admin_account.present? + admin_account.invitation_code.count += num_to_process + admin_account.invitation_code.save + unless possible_user puts "#{n}: sending email to: #{backer_name} #{backer_email}" unless Rails.env == 'test' unless test diff --git a/spec/controllers/admins_controller_spec.rb b/spec/controllers/admins_controller_spec.rb index 69299f01f..4f269d419 100644 --- a/spec/controllers/admins_controller_spec.rb +++ b/spec/controllers/admins_controller_spec.rb @@ -73,11 +73,6 @@ describe AdminsController do AppConfig[:admins] = [@user.username] end - it 'succeeds' do - get :admin_inviter, :identifier => 'bob@moms.com' - response.should be_redirect - end - it 'does not die if you do it twice' do get :admin_inviter, :identifier => 'bob@moms.com' get :admin_inviter, :identifier => 'bob@moms.com' @@ -85,7 +80,7 @@ describe AdminsController do end it 'invites a new user' do - Invitation.should_receive(:create) + EmailInviter.should_receive(:new).and_return(stub.as_null_object) get :admin_inviter, :identifier => 'bob@moms.com' response.should redirect_to user_search_path flash.notice.should include("invitation sent") diff --git a/spec/controllers/invitations_controller_spec.rb b/spec/controllers/invitations_controller_spec.rb index b2e6afe50..2f551c252 100644 --- a/spec/controllers/invitations_controller_spec.rb +++ b/spec/controllers/invitations_controller_spec.rb @@ -20,8 +20,8 @@ describe InvitationsController do end it 'creates an EmailInviter' do - inviter = stub(:emails => ['mbs@gmail.com']) - EmailInviter.should_receive(:new).with(@invite['email_inviter']['emails'], @invite['email_inviter']). + inviter = stub(:emails => ['mbs@gmail.com'], :send! => true) + EmailInviter.should_receive(:new).with(@invite['email_inviter']['emails'], @user, @invite['email_inviter']). and_return(inviter) post :create, @invite end @@ -41,7 +41,6 @@ describe InvitationsController do end end - describe '#new' do it 'renders' do sign_in :user, @user diff --git a/spec/lib/email_inviter_spec.rb b/spec/lib/email_inviter_spec.rb index 22e216da0..3d423d362 100644 --- a/spec/lib/email_inviter_spec.rb +++ b/spec/lib/email_inviter_spec.rb @@ -4,65 +4,53 @@ 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" + @emails = "mbs333@gmail.com, foo1@bar.com maxwell@dude.com" end it 'has a list of emails' do - inviter = EmailInviter.new(@emails) + inviter = EmailInviter.new(@emails, @user) inviter.emails.should_not be_empty end it 'should parse three emails' do - inviter = EmailInviter.new(@emails) + inviter = EmailInviter.new(@emails, @user) inviter.emails.count.should == 3 end - it 'an optional inviter' do - inviter = EmailInviter.new(@emails, :inviter => @user) + it 'has an inviter' do + inviter = EmailInviter.new(@emails, @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 = EmailInviter.new("emails", @user, :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 = EmailInviter.new(@emails + " #{@user.email}", @user) inviter.emails.should_not include(@user.email) end end describe 'language' do it 'defaults to english' do - inviter = EmailInviter.new(@emails) + inviter = EmailInviter.new(@emails, @user) inviter.locale.should == 'en' end it 'listens to the langauge option' do - inviter = EmailInviter.new(@emails, :locale => 'es') + inviter = EmailInviter.new(@emails, @user, :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) + it 'delegates to the user' do + inviter = EmailInviter.new(@emails, @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 \ No newline at end of file diff --git a/spec/lib/rake_helper_spec.rb b/spec/lib/rake_helper_spec.rb index b2b8de3c4..48b617fc7 100644 --- a/spec/lib/rake_helper_spec.rb +++ b/spec/lib/rake_helper_spec.rb @@ -12,20 +12,18 @@ describe RakeHelpers do describe '#process_emails' do before do Devise.mailer.deliveries = [] - end - it 'should send emails to each backer' do - expect{ - process_emails(@csv, 100, 1, false) - }.to change(User, :count).by(3) + @old_admin = AppConfig[:admin_account] + AppConfig[:admin_account] = Factory(:user).username end - it 'should not send the email to the same email twice' do - process_emails(@csv, 100, 1, false) + after do + AppConfig[:admin_account] = @old_admin + end - Devise.mailer.deliveries.count.should == 3 - process_emails(@csv, 100, 1, false) + it 'should send emails to each email' do - Devise.mailer.deliveries.count.should == 3 + EmailInviter.should_receive(:new).exactly(3).times.and_return(stub.as_null_object) + process_emails(@csv, 100, 1, false) end end end diff --git a/spec/models/invitation_code_spec.rb b/spec/models/invitation_code_spec.rb index 142cc2944..18d949f98 100644 --- a/spec/models/invitation_code_spec.rb +++ b/spec/models/invitation_code_spec.rb @@ -4,4 +4,39 @@ describe InvitationCode do it 'has a valid factory' do Factory(:invitation_code).should be_valid end + + it 'sets the count to a default value' do + code = Factory(:invitation_code) + code.count.should > 0 + end + + describe '#use!' do + it 'decrements the count of the code' do + code = Factory(:invitation_code) + + expect{ + code.use! + }.to change(code, :count).by(-1) + end + end + + describe '.default_inviter_or' do + before do + @old_account = AppConfig[:admin_account] + AppConfig[:admin_account] = 'bob' + end + + after do + AppConfig[:admin_account] = @old_account + end + + it 'grabs the set admin account for the pod...' do + InvitationCode.default_inviter_or(alice).username.should == 'bob' + end + + it '..or the given user' do + AppConfig[:admin_account] = '' + InvitationCode.default_inviter_or(alice).username.should == 'alice' + end + end end From 11505a386c9b58403a9c2ac3726f9d15035bd0af Mon Sep 17 00:00:00 2001 From: Maxwell Salzberg Date: Fri, 16 Mar 2012 14:00:57 -0700 Subject: [PATCH 4/5] adding a test for decremented invites, as, and check the invite is valid in the controller --- app/controllers/invitations_controller.rb | 2 ++ app/controllers/registrations_controller.rb | 10 ++++++++-- app/models/invitation_code.rb | 4 ++++ app/models/user.rb | 2 +- app/views/services/_remote_friend.html.haml | 5 +---- config/locales/diaspora/en.yml | 1 + features/accepts_invitation.feature | 6 +++++- features/step_definitions/user_steps.rb | 8 ++++---- 8 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb index 560b9aeb7..2d66b9f6a 100644 --- a/app/controllers/invitations_controller.rb +++ b/app/controllers/invitations_controller.rb @@ -18,6 +18,8 @@ class InvitationsController < ApplicationController # this is for legacy invites. We try to look the person who sent them the # invite, and use their new invite code + # owe will be removing this eventually + # @depreciated def edit user = User.find_by_invitation_token(params[:invitation_token]) invitation_code = user.ugly_accept_invitation_code diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index d55cbb2ec..544531a6a 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -3,7 +3,7 @@ # the COPYRIGHT file. class RegistrationsController < Devise::RegistrationsController - before_filter :check_registrations_open_or_vaild_invite! + before_filter :check_registrations_open_or_vaild_invite!, :check_valid_invite! def create @user = User.build(params[:user]) @@ -16,7 +16,7 @@ class RegistrationsController < Devise::RegistrationsController Rails.logger.info("event=registration status=successful user=#{@user.diaspora_handle}") else @user.errors.delete(:person) - + flash[:error] = @user.errors.full_messages.join(";") Rails.logger.info("event=registration status=failure errors='#{@user.errors.full_messages.join(', ')}'") render :new @@ -28,6 +28,12 @@ class RegistrationsController < Devise::RegistrationsController end private + def check_valid_invite! + return true if invite.can_be_used? + flash[:error] = t('registrations.invalid_invite') + redirect_to new_user_session_path + end + def check_registrations_open_or_vaild_invite! return true if invite.present? if AppConfig[:registrations_closed] diff --git a/app/models/invitation_code.rb b/app/models/invitation_code.rb index 33e259642..e653648ce 100644 --- a/app/models/invitation_code.rb +++ b/app/models/invitation_code.rb @@ -9,6 +9,10 @@ class InvitationCode < ActiveRecord::Base token end + def can_be_used? + self.count > 0 + end + def add_invites! self.update_attributes(:count => self.count+100) end diff --git a/app/models/user.rb b/app/models/user.rb index 1f7c9e5a1..6d7abfb7c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -107,7 +107,7 @@ class User < ActiveRecord::Base ConversationVisibility.sum(:unread, :conditions => "person_id = #{self.person.id}") end - #should be deprecated + #@deprecated def ugly_accept_invitation_code begin self.invitations_to_me.first.sender.invitation_code diff --git a/app/views/services/_remote_friend.html.haml b/app/views/services/_remote_friend.html.haml index 36e74627e..dd6dfcdcd 100644 --- a/app/views/services/_remote_friend.html.haml +++ b/app/views/services/_remote_friend.html.haml @@ -1,9 +1,6 @@ .stream_element{:id => friend.id} .float-right - - - if friend.already_invited? - = link_to t('.resend'), service_inviter_path(:uid => friend.uid, :provider => 'facebook', :invitation_id => friend.invitation_id), :class => 'button resend' - - elsif friend.on_diaspora? + - if friend.on_diaspora? = aspect_membership_dropdown(contact_proxy(friend), friend.person, 'left') - else = render 'shared/aspect_dropdown', :selected_aspects => contact_proxy(friend).aspects, :person => friend.person, :hang => 'left', :dropdown_class => 'inviter', :service_uid => friend.uid diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index a0eb0adde..f2db7e70e 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -682,6 +682,7 @@ en: update: "Update" cancel_my_account: "Cancel my account" closed: "Signups are closed on this Diaspora pod." + invalid_invite: "The invite link you provided is no longer valid!" requests: manage_aspect_contacts: diff --git a/features/accepts_invitation.feature b/features/accepts_invitation.feature index 70d9dccad..440574e6c 100644 --- a/features/accepts_invitation.feature +++ b/features/accepts_invitation.feature @@ -19,7 +19,7 @@ Feature: invitation acceptance Then I should be on the stream page Scenario: accept invitation from user - Given I have been invited by a user + Given I have been invited by bob And I am on my acceptance form page And I fill in the following: | user_username | ohai | @@ -35,6 +35,10 @@ Feature: invitation acceptance And I preemptively confirm the alert And I follow "awesome_button" Then I should be on the stream page + And I log out + And I sign in as "bob@bob.bob" + And I follow "By email" + Then I should see "9 invites left" Scenario: sends an invitation Given a user with email "bob@bob.bob" diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index 2dbf8c281..1a042f010 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -27,13 +27,13 @@ end Given /^I have been invited by an admin$/ do admin = Factory(:user) - bob.invitation_code - i = EmailInviter.new("new_invitee@example.com", bob) + admin.invitation_code + i = EmailInviter.new("new_invitee@example.com", admin) i.send! end -Given /^I have been invited by a user$/ do - @inviter = Factory(:user) +Given /^I have been invited by bob$/ do + @inviter = Factory(:user, :email => 'bob@bob.bob') i = EmailInviter.new("new_invitee@example.com", @inviter) i.send! end From 852687b31c9600a95cc96c27d50112bc93702488 Mon Sep 17 00:00:00 2001 From: danielgrippi Date: Fri, 16 Mar 2012 17:35:47 -0700 Subject: [PATCH 5/5] MS DG fix a few final tests --- app/controllers/registrations_controller.rb | 3 ++- features/accepts_invitation.feature | 2 +- features/step_definitions/user_steps.rb | 5 +++++ spec/controllers/registrations_controller_spec.rb | 4 ++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 544531a6a..e1483aa71 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -29,7 +29,8 @@ class RegistrationsController < Devise::RegistrationsController private def check_valid_invite! - return true if invite.can_be_used? + return true unless AppConfig[:registrations_closed] #this sucks + return true if invite && invite.can_be_used? flash[:error] = t('registrations.invalid_invite') redirect_to new_user_session_path end diff --git a/features/accepts_invitation.feature b/features/accepts_invitation.feature index 440574e6c..f10dcc827 100644 --- a/features/accepts_invitation.feature +++ b/features/accepts_invitation.feature @@ -38,7 +38,7 @@ Feature: invitation acceptance And I log out And I sign in as "bob@bob.bob" And I follow "By email" - Then I should see "9 invites left" + Then I should see one less invite Scenario: sends an invitation Given a user with email "bob@bob.bob" diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index 1a042f010..b7c62a60b 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -34,10 +34,15 @@ end Given /^I have been invited by bob$/ do @inviter = Factory(:user, :email => 'bob@bob.bob') + @inviter_invite_count = @inviter.invitation_code.count i = EmailInviter.new("new_invitee@example.com", @inviter) i.send! end +When /^I should see one less invite$/ do + step "I should see \"#{@inviter_invite_count -1} invites left\"" +end + When /^I click on my name$/ do click_link("#{@me.first_name} #{@me.last_name}") end diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index a6b4a2777..f1ff07342 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -54,6 +54,10 @@ describe RegistrationsController do describe "#create" do context "with valid parameters" do + before do + AppConfig[:registrations_closed] = false + end + before do user = Factory.build(:user) User.stub!(:build).and_return(user)