Merge dummy users into real ones when assigning api tokens
parent
2ceea32cc4
commit
1be5538e5c
@ -1,30 +1,14 @@
|
||||
class ApiTokensController < ApplicationController
|
||||
|
||||
before_filter :ensure_authenticated!
|
||||
|
||||
def create
|
||||
claimed_num = api_token_creator.create(current_user, params[:api_token])
|
||||
|
||||
if claimed_num
|
||||
redirect_to_profile(claimed_num)
|
||||
else
|
||||
render :error
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redirect_to_profile(claimed_num)
|
||||
if claimed_num > 0
|
||||
notice = "Claimed #{claimed_num} asciicasts, yay!"
|
||||
else
|
||||
notice = "Authenticated successfully, yippie!"
|
||||
end
|
||||
|
||||
redirect_to profile_path(current_user), :notice => notice
|
||||
end
|
||||
current_user.assign_api_token(params[:api_token])
|
||||
redirect_to profile_path(current_user),
|
||||
notice: "Successfully registered your API token. ^5"
|
||||
|
||||
def api_token_creator
|
||||
@api_token_creator ||= ApiTokenCreator.new
|
||||
rescue ActiveRecord::RecordInvalid, ApiToken::ApiTokenTakenError
|
||||
render :error
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,5 +1,29 @@
|
||||
class ApiToken < ActiveRecord::Base
|
||||
|
||||
ApiTokenTakenError = Class.new(StandardError)
|
||||
|
||||
belongs_to :user
|
||||
|
||||
validates :user, :token, :presence => true
|
||||
validates :user, :token, presence: true
|
||||
validates :token, uniqueness: true
|
||||
|
||||
attr_accessible :token
|
||||
|
||||
def self.for_token(token)
|
||||
ApiToken.where(token: token).first
|
||||
end
|
||||
|
||||
def reassign_to(target_user)
|
||||
return if target_user == user
|
||||
raise ApiTokenTakenError if taken?
|
||||
|
||||
user.merge_to(target_user)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def taken?
|
||||
!user.dummy?
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,25 +0,0 @@
|
||||
class ApiTokenCreator
|
||||
|
||||
def initialize(clock = DateTime)
|
||||
@clock = clock
|
||||
end
|
||||
|
||||
def create(user, token)
|
||||
api_token = user.add_api_token(token)
|
||||
|
||||
if api_token.persisted?
|
||||
update_asciicasts(api_token.token, user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :clock
|
||||
|
||||
def update_asciicasts(token, user)
|
||||
Asciicast.where(:user_id => nil, :api_token => token).
|
||||
update_all(:user_id => user.id, :api_token => nil,
|
||||
:updated_at => clock.now)
|
||||
end
|
||||
|
||||
end
|
@ -1,7 +1,76 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ApiToken do
|
||||
it "has valid factory" do
|
||||
expect(build(:api_token)).to be_valid
|
||||
|
||||
it { should validate_presence_of(:user) }
|
||||
it { should validate_presence_of(:token) }
|
||||
|
||||
describe "uniqueness validation" do
|
||||
before do
|
||||
create(:api_token)
|
||||
end
|
||||
|
||||
it { should validate_uniqueness_of(:token) }
|
||||
end
|
||||
|
||||
describe '.for_token' do
|
||||
subject { described_class.for_token(token) }
|
||||
|
||||
context "when ApiToken with given token exists" do
|
||||
let(:token) { attributes_for(:api_token)[:token] }
|
||||
let!(:api_token) { create(:api_token, token: token) }
|
||||
|
||||
it { should eq(api_token) }
|
||||
end
|
||||
|
||||
context "when ApiToken with given token doesn't exist" do
|
||||
let(:token) { 'no-no' }
|
||||
|
||||
it { should be(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reassign_to' do
|
||||
subject { api_token.reassign_to(target_user) }
|
||||
|
||||
let(:api_token) { described_class.new }
|
||||
let(:user) { User.new }
|
||||
let(:target_user) { User.new }
|
||||
|
||||
before do
|
||||
api_token.user = user
|
||||
allow(user).to receive(:merge_to)
|
||||
end
|
||||
|
||||
context "when source user is a dummy user" do
|
||||
before do
|
||||
user.dummy = true
|
||||
end
|
||||
|
||||
it "merges user to target user" do
|
||||
subject
|
||||
expect(user).to have_received(:merge_to).with(target_user)
|
||||
end
|
||||
end
|
||||
|
||||
context "when target user is the same user" do
|
||||
let(:target_user) { user }
|
||||
|
||||
it "doesn't do anything" do
|
||||
subject
|
||||
expect(user).to_not have_received(:merge_to)
|
||||
end
|
||||
end
|
||||
|
||||
context "when source user is a real user" do
|
||||
before do
|
||||
user.dummy = false
|
||||
end
|
||||
|
||||
it "raises ApiTokenTakenError" do
|
||||
expect { subject }.to raise_error(ApiToken::ApiTokenTakenError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,75 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ApiTokenCreator do
|
||||
|
||||
let(:api_token_creator) { described_class.new(clock) }
|
||||
let(:clock) { double('clock', now: now) }
|
||||
let(:now) { Time.now }
|
||||
|
||||
describe '#create' do
|
||||
let(:user) { create(:user) }
|
||||
let(:token) { 'a-toh-can' }
|
||||
let(:api_token) { double('api_token', token: token,
|
||||
persisted?: persisted) }
|
||||
|
||||
subject { api_token_creator.create(user, token) }
|
||||
|
||||
before do
|
||||
allow(user).to receive(:add_api_token) { api_token }
|
||||
end
|
||||
|
||||
context "when token was persisted" do
|
||||
let(:persisted) { true }
|
||||
let(:old_updated_at) { 3.days.ago }
|
||||
|
||||
let!(:asciicast_1) { create(:asciicast, :user => nil,
|
||||
:api_token => token,
|
||||
:updated_at => old_updated_at) }
|
||||
let!(:asciicast_2) { create(:asciicast, :user => nil,
|
||||
:api_token => 'please',
|
||||
:updated_at => old_updated_at) }
|
||||
let!(:asciicast_3) { create(:asciicast, :user => create(:user),
|
||||
:api_token => 'nonono',
|
||||
:updated_at => old_updated_at) }
|
||||
|
||||
it { should be(1) }
|
||||
|
||||
it 'assigns the user to all matching asciicasts' do
|
||||
subject
|
||||
|
||||
asciicast_1.reload; asciicast_2.reload; asciicast_3.reload
|
||||
|
||||
expect(asciicast_1.user).to eq(user)
|
||||
expect(asciicast_2.user).not_to eq(user)
|
||||
expect(asciicast_3.user).not_to eq(user)
|
||||
end
|
||||
|
||||
it 'resets the token on all matching asciicasts' do
|
||||
subject
|
||||
|
||||
asciicast_1.reload; asciicast_2.reload; asciicast_3.reload
|
||||
|
||||
expect(asciicast_1.api_token).to be(nil)
|
||||
expect(asciicast_2.api_token).not_to be(nil)
|
||||
expect(asciicast_3.api_token).not_to be(nil)
|
||||
end
|
||||
|
||||
it 'updates the updated_at field on all matching asciicasts' do
|
||||
subject
|
||||
|
||||
asciicast_1.reload; asciicast_2.reload; asciicast_3.reload
|
||||
|
||||
expect(asciicast_1.updated_at.to_i).to eq(now.to_i)
|
||||
expect(asciicast_2.updated_at.to_i).to eq(old_updated_at.to_i)
|
||||
expect(asciicast_3.updated_at.to_i).to eq(old_updated_at.to_i)
|
||||
end
|
||||
end
|
||||
|
||||
context "when token wasn't persisted " do
|
||||
let(:persisted) { false }
|
||||
|
||||
it { should be(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue