From 0591d5be11051efae50516211384cc24618dd813 Mon Sep 17 00:00:00 2001
From: Brian Plexico <brian.plexico@gmail.com>
Date: Thu, 30 May 2013 11:33:11 -0400
Subject: [PATCH] Extract InviteRedeemer from Invite

---
 app/models/invite.rb          | 42 +-------------------
 app/models/invite_redeemer.rb | 74 +++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 41 deletions(-)
 create mode 100644 app/models/invite_redeemer.rb

diff --git a/app/models/invite.rb b/app/models/invite.rb
index d95baebb8..9a5acc73b 100644
--- a/app/models/invite.rb
+++ b/app/models/invite.rb
@@ -41,47 +41,7 @@ class Invite < ActiveRecord::Base
   end
 
   def redeem
-    result = nil
-    Invite.transaction do
-      # Avoid a race condition
-      row_count = Invite.update_all('redeemed_at = CURRENT_TIMESTAMP',
-                                    ['id = ? AND redeemed_at IS NULL AND created_at >= ?', id, SiteSetting.invite_expiry_days.days.ago])
-
-      if row_count == 1
-
-        # Create the user if we are redeeming the invite and the user doesn't exist
-        result = User.where(email: email).first
-        result ||= User.create_for_email(email, trust_level: SiteSetting.default_invitee_trust_level)
-        result.send_welcome_message = false
-
-        # If there are topic invites for private topics
-        topics.private_messages.each do |t|
-          t.topic_allowed_users.create(user_id: result.id)
-        end
-
-        # Check for other invites by the same email. Don't redeem them, but approve their
-        # topics.
-        Invite.where('invites.email = ? and invites.id != ?', email, id).includes(:topics).where(topics: { archetype: Archetype::private_message }).each do |i|
-          i.topics.each do |t|
-            t.topic_allowed_users.create(user_id: result.id)
-          end
-        end
-
-        if Invite.update_all(['user_id = ?', result.id], ['email = ?', email]) == 1
-          result.send_welcome_message = true
-        end
-
-          # Notify the invitee
-          invited_by.notifications.create(notification_type: Notification.types[:invitee_accepted],
-                                          data: { display_username: result.username }.to_json)
-
-      else
-        # Otherwise return the existing user
-        result = User.where(email: email).first
-      end
-    end
-
-    result
+    InviteRedeemer.new(self).redeem unless expired? || destroyed?
   end
 
 end
diff --git a/app/models/invite_redeemer.rb b/app/models/invite_redeemer.rb
new file mode 100644
index 000000000..64533fa73
--- /dev/null
+++ b/app/models/invite_redeemer.rb
@@ -0,0 +1,74 @@
+InviteRedeemer = Struct.new(:invite) do
+
+  def redeem
+    Invite.transaction do
+      process_invitation if invite_was_redeemed?
+    end
+
+    invited_user
+  end
+
+  private
+
+  def invited_user
+    @invited_user ||= get_invited_user
+  end
+
+  def process_invitation
+    add_to_private_topics_if_invited
+    add_user_to_invited_topics
+    send_welcome_message
+    notify_invitee
+  end
+
+  def invite_was_redeemed?
+    # Return true if a row was updated
+    mark_invite_redeemed == 1
+  end
+
+  def mark_invite_redeemed
+    Invite.update_all('redeemed_at = CURRENT_TIMESTAMP',
+                      ['id = ? AND redeemed_at IS NULL AND created_at >= ?',
+                       invite.id, SiteSetting.invite_expiry_days.days.ago])
+  end
+
+  def get_invited_user
+    result = get_existing_user
+    result ||= create_new_user
+    result.send_welcome_message = false
+    result
+  end
+
+  def get_existing_user
+    User.where(email: invite.email).first
+  end
+
+  def create_new_user
+    User.create_for_email(invite.email, trust_level: SiteSetting.default_invitee_trust_level)
+  end
+
+  def add_to_private_topics_if_invited
+    invite.topics.private_messages.each do |t|
+      t.topic_allowed_users.create(user_id: invited_user.id)
+    end
+  end
+
+  def add_user_to_invited_topics
+    Invite.where('invites.email = ? and invites.id != ?', invite.email, invite.id).includes(:topics).where(topics: {archetype: Archetype::private_message}).each do |i|
+      i.topics.each do |t|
+        t.topic_allowed_users.create(user_id: invited_user.id)
+      end
+    end
+  end
+
+  def send_welcome_message
+    if Invite.update_all(['user_id = ?', invited_user.id], ['email = ?', invite.email]) == 1
+      invited_user.send_welcome_message = true
+    end
+  end
+
+  def notify_invitee
+    invite.invited_by.notifications.create(notification_type: Notification.types[:invitee_accepted],
+                                           data: {display_username: invited_user.username}.to_json)
+  end
+end
\ No newline at end of file