From 3a1a6fde9a1fc2ea2a8f081a9d2578ec718bdd32 Mon Sep 17 00:00:00 2001
From: Azul <azul@riseup.net>
Date: Tue, 24 Oct 2017 12:12:26 +0200
Subject: [PATCH] fix: also remove invite codes used for tmp users

fixes #8807
---
 app/models/account.rb     | 26 +++++++++++++++-----------
 test/unit/account_test.rb | 11 +++++++++++
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/app/models/account.rb b/app/models/account.rb
index 4442a683..4db69e8f 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -34,31 +34,25 @@ class Account
     user.save
 
     # this is not very atomic, but we do the best we can:
-    if !user.is_tmp? && user.persisted?
+    return user unless user.persisted?
+    if !user.is_tmp?
       identity = user.identity
       identity.user_id = user.id
       identity.save
       identity.errors.each do |attr, msg|
         user.errors.add(attr, msg)
       end
-      if user.invite_required?
-        user_invite_code = InviteCode.find_by_invite_code user.invite_code
-        if user.is_test? && user_invite_code.max_uses == 1
-          user_invite_code.destroy
-        else
-          user_invite_code.invite_count += 1
-          user_invite_code.save
-        end
-      end
     end
+    consume_invite_code_for_user(user) if user.invite_required?
+    return user
   rescue VALIDATION_FAILED => ex
     user.errors.add(:base, ex.to_s) if user
+    return user
   ensure
     if creation_problem?(user, identity)
       user.destroy     if user     && user.persisted?
       identity.destroy if identity && identity.persisted?
     end
-    return user
   end
 
   def update(attrs)
@@ -113,6 +107,16 @@ class Account
 
   protected
 
+  def self.consume_invite_code_for_user(user)
+    invite_code = InviteCode.find_by_invite_code user.invite_code
+    if user.is_test? && invite_code.max_uses == 1
+      invite_code.destroy
+    else
+      invite_code.invite_count += 1
+      invite_code.save
+    end
+  end
+
   def update_login(login)
     return unless login.present?
     @old_identity = Identity.for(@user)
diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb
index f81764db..61b40b5f 100644
--- a/test/unit/account_test.rb
+++ b/test/unit/account_test.rb
@@ -153,6 +153,17 @@ class AccountTest < ActiveSupport::TestCase
     end
   end
 
+  test "Single use invite code is destroyed when used by tmp user" do
+    with_config invite_required: true do
+      attrs = user_attributes invite_code: @testcode.invite_code
+      attrs[:login] = 'tmp_user_' + attrs[:login]
+      user = Account.create(attrs)
+      user.save
+      assert user.persisted?, user.errors.inspect
+      assert_nil InviteCode.find_by_invite_code user.invite_code
+    end
+  end
+
   test "Invite code stays zero when invite code is not used" do
     #user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
     invalid_user = FactoryGirl.build(:user, :invite_code => @testcode.invite_code)
-- 
GitLab