parent
6cf1cd5d76
commit
66b7b7e27a
14 changed files with 29 additions and 406 deletions
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
class InvitationsController < ApplicationController
|
||||
|
||||
before_action :authenticate_user!, :only => [:new, :create]
|
||||
before_action :authenticate_user!
|
||||
|
||||
def new
|
||||
@invite_code = current_user.invitation_code
|
||||
|
|
@ -19,36 +19,6 @@ class InvitationsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# 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
|
||||
redirect_to invite_code_path(invitation_code)
|
||||
end
|
||||
|
||||
def email
|
||||
@invitation_code =
|
||||
if params[:invitation_token]
|
||||
# this is for legacy invites.
|
||||
user = User.find_by_invitation_token(params[:invitation_token])
|
||||
|
||||
user.ugly_accept_invitation_code if user
|
||||
else
|
||||
params[:invitation_code]
|
||||
end
|
||||
@inviter = user || InvitationCode.where(id: params[:invitation_code]).first.try(:user)
|
||||
if @invitation_code.present?
|
||||
render 'notifier/invite', :layout => false
|
||||
else
|
||||
flash[:error] = t('invitations.check_token.not_found')
|
||||
|
||||
redirect_to root_url
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
emails = inviter_params[:emails].split(',').map(&:strip).uniq
|
||||
|
||||
|
|
@ -78,15 +48,8 @@ class InvitationsController < ApplicationController
|
|||
redirect_to :back
|
||||
end
|
||||
|
||||
def check_if_invites_open
|
||||
unless AppConfig.settings.invitations.open?
|
||||
flash[:error] = I18n.t 'invitations.create.no_more'
|
||||
|
||||
redirect_to :back
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid_email?(email)
|
||||
User.email_regexp.match(email).present?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
helper_method :invite
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:username, :email, :getting_started, :password, :password_confirmation, :language, :disable_mail, :invitation_service, :invitation_identifier, :show_community_spotlight_in_stream, :auto_follow_back, :auto_follow_back_aspect_id, :remember_me, :captcha, :captcha_key)
|
||||
params.require(:user).permit(
|
||||
:username, :email, :getting_started, :password, :password_confirmation, :language, :disable_mail,
|
||||
:show_community_spotlight_in_stream, :auto_follow_back, :auto_follow_back_aspect_id,
|
||||
:remember_me, :captcha, :captcha_key
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,151 +0,0 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
#TODO: kill me
|
||||
class Invitation < ActiveRecord::Base
|
||||
|
||||
belongs_to :sender, :class_name => 'User'
|
||||
belongs_to :recipient, :class_name => 'User'
|
||||
belongs_to :aspect
|
||||
|
||||
before_validation :set_email_as_default_service
|
||||
|
||||
# before_create :share_with_exsisting_user, :if => :recipient_id?
|
||||
validates :identifier, :presence => true
|
||||
validates :service, :presence => true
|
||||
validate :valid_identifier?
|
||||
validate :recipient_not_on_pod?
|
||||
validates_presence_of :sender, :aspect, :unless => :admin?
|
||||
validate :ensure_not_inviting_self, :on => :create, :unless => :admin?
|
||||
validate :sender_owns_aspect?, :unless => :admin?
|
||||
validates_uniqueness_of :sender_id, :scope => [:identifier, :service], :unless => :admin?
|
||||
|
||||
|
||||
# @note options hash is passed through to [Invitation.new]
|
||||
# @see [Invitation.new]
|
||||
#
|
||||
# @param [Array<String>] emails
|
||||
# @option opts [User] :sender
|
||||
# @option opts [Aspect] :aspect
|
||||
# @option opts [String] :service
|
||||
# @return [Array<Invitation>] An array of [Invitation] models
|
||||
# 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)
|
||||
|
||||
#share with anyone whose email you entered who is on the pod
|
||||
users_on_pod.each{|u| opts[:sender].share_with(u.person, opts[:aspect])}
|
||||
|
||||
emails.map! do |e|
|
||||
user = users_on_pod.find{|u| u.email == e}
|
||||
Invitation.create(opts.merge(:identifier => e, :recipient => user))
|
||||
end
|
||||
emails
|
||||
end
|
||||
|
||||
|
||||
# Downcases the incoming service identifier and assigns it
|
||||
#
|
||||
# @param ident [String] Service identifier
|
||||
# @see super
|
||||
def identifier=(ident)
|
||||
ident.downcase! if ident
|
||||
super
|
||||
end
|
||||
|
||||
# Determine if we want to skip emailing the recipient.
|
||||
#
|
||||
# @return [Boolean]
|
||||
# @return [void]
|
||||
def skip_email?
|
||||
!email_like_identifer
|
||||
end
|
||||
|
||||
# Find or create user, and send that resultant User an
|
||||
# invitation.
|
||||
#
|
||||
# @return [Invitation] self
|
||||
def send!
|
||||
if email_like_identifer
|
||||
EmailInviter.new(self.identifier, sender).send!
|
||||
else
|
||||
puts "broken facebook invitation_token"
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
|
||||
# converts a personal invitation to an admin invite
|
||||
# used in account deletion
|
||||
# @return [Invitation] self
|
||||
def convert_to_admin!
|
||||
self.admin = true
|
||||
self.sender = nil
|
||||
self.aspect = nil
|
||||
self.save
|
||||
self
|
||||
end
|
||||
# @return [Invitation] self
|
||||
def resend
|
||||
self.send!
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
def recipient_identifier
|
||||
case self.service
|
||||
when 'email'
|
||||
self.identifier
|
||||
when'facebook'
|
||||
I18n.t('invitations.a_facebook_user')
|
||||
end
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
def email_like_identifer
|
||||
case self.service
|
||||
when 'email'
|
||||
self.identifier
|
||||
when 'facebook'
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# @note before_save
|
||||
def set_email_as_default_service
|
||||
self.service ||= 'email'
|
||||
end
|
||||
|
||||
# @note Validation
|
||||
def ensure_not_inviting_self
|
||||
if self.identifier == self.sender.email
|
||||
errors[:base] << 'You can not invite yourself.'
|
||||
end
|
||||
end
|
||||
|
||||
# @note Validation
|
||||
def sender_owns_aspect?
|
||||
if self.sender_id != self.aspect.user_id
|
||||
errors[:base] << 'You do not own that aspect.'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def recipient_not_on_pod?
|
||||
return true if self.recipient.nil?
|
||||
if self.recipient.username?
|
||||
errors[:recipient] << "The user '#{self.identifier}' (#{self.recipient.diaspora_handle}) is already on this pod, so we sent them a share request"
|
||||
end
|
||||
end
|
||||
|
||||
# @note Validation
|
||||
def valid_identifier?
|
||||
return false unless self.identifier
|
||||
if self.service == 'email'
|
||||
unless self.identifier.match(Devise.email_regexp)
|
||||
errors[:base] << 'invalid email'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -14,7 +14,7 @@ class User < ActiveRecord::Base
|
|||
scope :daily_actives, ->(time = Time.now) { logged_in_since(time - 1.day) }
|
||||
scope :yearly_actives, ->(time = Time.now) { logged_in_since(time - 1.year) }
|
||||
scope :halfyear_actives, ->(time = Time.now) { logged_in_since(time - 6.month) }
|
||||
scope :active, -> { joins(:person).where(people: {closed_account: false}).where.not(username: nil) }
|
||||
scope :active, -> { joins(:person).where(people: {closed_account: false}) }
|
||||
|
||||
devise :token_authenticatable, :database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable,
|
||||
|
|
@ -34,7 +34,7 @@ class User < ActiveRecord::Base
|
|||
|
||||
validate :unconfirmed_email_quasiuniqueness
|
||||
|
||||
validates_presence_of :person, :unless => proc {|user| user.invitation_token.present?}
|
||||
validates :person, presence: true
|
||||
validates_associated :person
|
||||
validate :no_person_with_same_username
|
||||
|
||||
|
|
@ -48,8 +48,6 @@ class User < ActiveRecord::Base
|
|||
:first_name, :last_name, :gender, :participations, to: :person
|
||||
delegate :id, :guid, to: :person, prefix: true
|
||||
|
||||
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'
|
||||
|
|
@ -99,15 +97,6 @@ class User < ActiveRecord::Base
|
|||
ConversationVisibility.where(person_id: self.person_id).sum(:unread)
|
||||
end
|
||||
|
||||
#@deprecated
|
||||
def ugly_accept_invitation_code
|
||||
begin
|
||||
self.invitations_to_me.first.sender.invitation_code
|
||||
rescue Exception => e
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def process_invite_acceptence(invite)
|
||||
self.invited_by = invite.user
|
||||
invite.use!
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
|
||||
module Workers
|
||||
class ResendInvitation < Base
|
||||
sidekiq_options queue: :low
|
||||
|
||||
def perform(invitation_id)
|
||||
inv = Invitation.find(invitation_id)
|
||||
inv.resend
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -571,9 +571,6 @@ en:
|
|||
zero: "No invites left on this code"
|
||||
one: "One invite left on this code"
|
||||
other: "%{count} invites left on this code"
|
||||
check_token:
|
||||
not_found: "Invitation token not found"
|
||||
a_facebook_user: "A Facebook user"
|
||||
|
||||
layouts:
|
||||
header:
|
||||
|
|
|
|||
|
|
@ -122,11 +122,8 @@ Diaspora::Application.routes.draw do
|
|||
post "/users" => "registrations#create", :as => :user_registration
|
||||
end
|
||||
|
||||
#legacy routes to support old invite routes
|
||||
get 'users/invitation/accept' => 'invitations#edit'
|
||||
get 'invitations/email' => 'invitations#email', :as => 'invite_email'
|
||||
get 'users/invitations' => 'invitations#new', :as => 'new_user_invitation'
|
||||
post 'users/invitations' => 'invitations#create', :as => 'user_invitation'
|
||||
get "users/invitations" => "invitations#new", :as => "new_user_invitation"
|
||||
post "users/invitations" => "invitations#create", :as => "user_invitation"
|
||||
|
||||
get 'login' => redirect('/users/sign_in')
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ class AccountDeleter
|
|||
#user deletion methods
|
||||
remove_share_visibilities_on_contacts_posts
|
||||
delete_standard_user_associations
|
||||
disassociate_invitations
|
||||
disconnect_contacts
|
||||
tombstone_user
|
||||
end
|
||||
|
|
@ -45,12 +44,12 @@ class AccountDeleter
|
|||
|
||||
#user deletions
|
||||
def normal_ar_user_associates_to_delete
|
||||
%i(tag_followings invitations_to_me services aspects user_preferences
|
||||
%i(tag_followings services aspects user_preferences
|
||||
notifications blocks authorizations o_auth_applications pairwise_pseudonymous_identifiers)
|
||||
end
|
||||
|
||||
def special_ar_user_associations
|
||||
%i(invitations_from_me person profile contacts auto_follow_back_aspect)
|
||||
%i(person profile contacts auto_follow_back_aspect)
|
||||
end
|
||||
|
||||
def ignored_ar_user_associations
|
||||
|
|
@ -70,12 +69,6 @@ class AccountDeleter
|
|||
end
|
||||
end
|
||||
|
||||
def disassociate_invitations
|
||||
user.invitations_from_me.each do |inv|
|
||||
inv.convert_to_admin!
|
||||
end
|
||||
end
|
||||
|
||||
def disconnect_contacts
|
||||
user.contacts.destroy_all
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class EmailInviter
|
|||
options = options.symbolize_keys
|
||||
self.message = options[:message]
|
||||
self.locale = options.fetch(:locale, 'en')
|
||||
self.inviter = inviter
|
||||
self.inviter = inviter
|
||||
self.emails = emails
|
||||
end
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ class EmailInviter
|
|||
end
|
||||
|
||||
def invitation_code
|
||||
@invitation_code ||= inviter.invitation_code
|
||||
@invitation_code ||= inviter.invitation_code
|
||||
end
|
||||
|
||||
def send!
|
||||
|
|
@ -26,6 +26,6 @@ class EmailInviter
|
|||
private
|
||||
|
||||
def mail(email)
|
||||
Notifier.invite(email, message, inviter, invitation_code, locale).deliver_now!
|
||||
Notifier.invite(email, message, inviter, invitation_code, locale).deliver_now
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -126,37 +126,6 @@ describe InvitationsController, :type => :controller do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#email' do
|
||||
|
||||
it 'succeeds' do
|
||||
get :email, :invitation_code => "anycode"
|
||||
expect(response).to be_success
|
||||
end
|
||||
|
||||
context 'legacy invite tokens' do
|
||||
def get_email
|
||||
get :email, :invitation_token => @invitation_token
|
||||
end
|
||||
|
||||
context 'invalid token' do
|
||||
@invitation_token = "invalidtoken"
|
||||
|
||||
it 'redirects and flashes if the invitation token is invalid' do
|
||||
get_email
|
||||
|
||||
expect(response).to be_redirect
|
||||
expect(response).to redirect_to root_url
|
||||
end
|
||||
|
||||
it 'flashes an error if the invitation token is invalid' do
|
||||
get_email
|
||||
|
||||
expect(flash[:error]).to eq(I18n.t("invitations.check_token.not_found"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#new' do
|
||||
it 'renders' do
|
||||
sign_in @user, scope: :user
|
||||
|
|
|
|||
|
|
@ -16,18 +16,18 @@ describe AccountDeleter do
|
|||
end
|
||||
|
||||
describe '#perform' do
|
||||
user_removal_methods = %i(
|
||||
delete_standard_user_associations
|
||||
remove_share_visibilities_on_contacts_posts
|
||||
disconnect_contacts tombstone_user
|
||||
)
|
||||
|
||||
|
||||
user_removal_methods = [:delete_standard_user_associations,
|
||||
:disassociate_invitations,
|
||||
:remove_share_visibilities_on_contacts_posts,
|
||||
:disconnect_contacts,
|
||||
:tombstone_user]
|
||||
|
||||
person_removal_methods = [:delete_contacts_of_me,
|
||||
:delete_standard_person_associations,
|
||||
:tombstone_person_and_profile,
|
||||
:remove_conversation_visibilities]
|
||||
person_removal_methods = %i(
|
||||
delete_contacts_of_me
|
||||
delete_standard_person_associations
|
||||
tombstone_person_and_profile
|
||||
remove_conversation_visibilities
|
||||
)
|
||||
|
||||
context "user deletion" do
|
||||
after do
|
||||
|
|
@ -110,15 +110,6 @@ describe AccountDeleter do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#disassociate_invitations" do
|
||||
it "sets invitations_from_me to be admin invitations" do
|
||||
invites = [double]
|
||||
allow(bob).to receive(:invitations_from_me).and_return(invites)
|
||||
expect(invites.first).to receive(:convert_to_admin!)
|
||||
@account_deletion.disassociate_invitations
|
||||
end
|
||||
end
|
||||
|
||||
context 'person associations' do
|
||||
describe '#disconnect_contacts' do
|
||||
it "deletes all of user's contacts" do
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Invitation, :type => :model do
|
||||
let(:user) { alice }
|
||||
|
||||
before do
|
||||
@email = 'maggie@example.com'
|
||||
Devise.mailer.deliveries = []
|
||||
end
|
||||
describe 'validations' do
|
||||
before do
|
||||
@invitation = FactoryGirl.build(:invitation, :sender => user, :recipient => nil, :aspect => user.aspects.first, :language => "de")
|
||||
end
|
||||
|
||||
it 'is valid' do
|
||||
expect(@invitation.sender).to eq(user)
|
||||
expect(@invitation.recipient).to eq(nil)
|
||||
expect(@invitation.aspect).to eq(user.aspects.first)
|
||||
expect(@invitation.language).to eq("de")
|
||||
expect(@invitation).to be_valid
|
||||
end
|
||||
|
||||
it 'ensures the sender is placing the recipient into one of his aspects' do
|
||||
@invitation.aspect = FactoryGirl.build(:aspect)
|
||||
expect(@invitation).not_to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe '#language' do
|
||||
it 'returns the correct language if the language is set' do
|
||||
@invitation = FactoryGirl.build(:invitation, :sender => user, :recipient => eve, :aspect => user.aspects.first, :language => "de")
|
||||
expect(@invitation.language).to eq("de")
|
||||
end
|
||||
|
||||
it 'returns en if no language is set' do
|
||||
@invitation = FactoryGirl.build(:invitation, :sender => user, :recipient => eve, :aspect => user.aspects.first)
|
||||
expect(@invitation.language).to eq("en")
|
||||
end
|
||||
end
|
||||
|
||||
it 'has a message' do
|
||||
@invitation = FactoryGirl.build(:invitation, :sender => user, :recipient => eve, :aspect => user.aspects.first, :language => user.language)
|
||||
@invitation.message = "!"
|
||||
expect(@invitation.message).to eq("!")
|
||||
end
|
||||
|
||||
|
||||
describe '.batch_invite' do
|
||||
before do
|
||||
@emails = ['max@foo.com', 'bob@mom.com']
|
||||
@opts = {:aspect => eve.aspects.first, :sender => eve, :service => 'email', :language => eve.language}
|
||||
end
|
||||
|
||||
it 'returns an array of invites based on the emails passed in' do
|
||||
invites = Invitation.batch_invite(@emails, @opts)
|
||||
expect(invites.count).to be 2
|
||||
expect(invites.all?{|x| x.persisted?}).to be true
|
||||
end
|
||||
|
||||
it 'shares with people who are already on the pod' do
|
||||
FactoryGirl.create(:user, :email => @emails.first)
|
||||
invites = nil
|
||||
expect{
|
||||
invites = Invitation.batch_invite(@emails, @opts)
|
||||
}.to change(eve.contacts, :count).by(1)
|
||||
expect(invites.count).to be 2
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -566,20 +566,6 @@ describe User, :type => :model do
|
|||
|
||||
describe 'account deletion' do
|
||||
describe '#destroy' do
|
||||
it 'removes invitations from the user' do
|
||||
FactoryGirl.create(:invitation, :sender => alice)
|
||||
expect {
|
||||
alice.destroy
|
||||
}.to change {alice.invitations_from_me(true).count }.by(-1)
|
||||
end
|
||||
|
||||
it 'removes invitations to the user' do
|
||||
Invitation.new(:sender => eve, :recipient => alice, :identifier => alice.email, :aspect => eve.aspects.first).save(:validate => false)
|
||||
expect {
|
||||
alice.destroy
|
||||
}.to change {alice.invitations_to_me(true).count }.by(-1)
|
||||
end
|
||||
|
||||
it 'removes all service connections' do
|
||||
Services::Facebook.create(:access_token => 'what', :user_id => alice.id)
|
||||
expect {
|
||||
|
|
@ -960,10 +946,8 @@ describe User, :type => :model do
|
|||
describe "#clearable_attributes" do
|
||||
it 'returns the clearable fields' do
|
||||
user = FactoryGirl.create :user
|
||||
expect(user.send(:clearable_fields).sort).to eq(%w{
|
||||
expect(user.send(:clearable_fields).sort).to eq(%w(
|
||||
language
|
||||
invitation_token
|
||||
invitation_sent_at
|
||||
reset_password_sent_at
|
||||
reset_password_token
|
||||
remember_created_at
|
||||
|
|
@ -973,11 +957,7 @@ describe User, :type => :model do
|
|||
current_sign_in_ip
|
||||
hidden_shareables
|
||||
last_sign_in_ip
|
||||
invitation_service
|
||||
invitation_identifier
|
||||
invitation_limit
|
||||
invited_by_id
|
||||
invited_by_type
|
||||
authentication_token
|
||||
auto_follow_back
|
||||
auto_follow_back_aspect_id
|
||||
|
|
@ -985,7 +965,7 @@ describe User, :type => :model do
|
|||
confirm_email_token
|
||||
last_seen
|
||||
color_theme
|
||||
}.sort)
|
||||
).sort)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1110,9 +1090,6 @@ describe User, :type => :model do
|
|||
|
||||
describe "active" do
|
||||
before do
|
||||
invited_user = FactoryGirl.build(:user, username: nil)
|
||||
invited_user.save(validate: false)
|
||||
|
||||
closed_account = FactoryGirl.create(:user)
|
||||
closed_account.person.lock_access!
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Workers::ResendInvitation do
|
||||
describe '#perfom' do
|
||||
it 'should call .resend on the object' do
|
||||
invite = FactoryGirl.build(:invitation, :service => 'email', :identifier => 'foo@bar.com')
|
||||
|
||||
allow(Invitation).to receive(:find).and_return(invite)
|
||||
expect(invite).to receive(:resend)
|
||||
Workers::ResendInvitation.new.perform(invite.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue