From 859b79d0dcd53c85bb57e3db888a1af702802987 Mon Sep 17 00:00:00 2001 From: Azul Date: Fri, 30 Aug 2013 11:20:04 +0200 Subject: Account: Composition to handle User and its identities We have a lot of things that act upon a user record and one or more of it's identities at the same time: * Sing up: Create a user and it's initial identity * Rename: Change the username and create a new identity, turn old into an alias * Cancel Account: Remove user and all their identities. In order to keep the User and Identity behaviour isolated but still have a this logic represented in a sinle place the Account model deals with all these things. We could have overwritten the User#create, User#update and User#destroy methods instead. But then we would always create identities, even if we only need a user (for example in tests). --- users/app/controllers/v1/users_controller.rb | 11 ++--- users/app/models/account.rb | 57 +++++++++++++++++++++++ users/app/models/account_settings.rb | 36 -------------- users/app/models/signup_service.rb | 9 ---- users/app/models/user.rb | 4 ++ users/test/functional/v1/users_controller_test.rb | 8 ++-- users/test/unit/account_test.rb | 45 ++++++++++++++++++ 7 files changed, 114 insertions(+), 56 deletions(-) create mode 100644 users/app/models/account.rb delete mode 100644 users/app/models/account_settings.rb delete mode 100644 users/app/models/signup_service.rb create mode 100644 users/test/unit/account_test.rb diff --git a/users/app/controllers/v1/users_controller.rb b/users/app/controllers/v1/users_controller.rb index f380c19..b271152 100644 --- a/users/app/controllers/v1/users_controller.rb +++ b/users/app/controllers/v1/users_controller.rb @@ -18,23 +18,20 @@ module V1 end def create - @user = signup_service.register(params[:user]) + @user = Account.create(params[:user]) respond_with @user # return ID instead? end def update - account_settings.update params[:user] + account.update params[:user] respond_with @user end protected - def account_settings - AccountSettings.new(@user) + def account + Account.new(@user) end - def signup_service - SignupService.new - end end end diff --git a/users/app/models/account.rb b/users/app/models/account.rb new file mode 100644 index 0000000..5368a1b --- /dev/null +++ b/users/app/models/account.rb @@ -0,0 +1,57 @@ +# +# A Composition of a User record and it's identity records. +# +class Account + + attr_reader :user + + def initialize(user = nil) + @user = user + end + + # Returns the user record so it can be used in views. + def self.create(attrs) + @user = User.create(attrs).tap do |user| + Identity.create_for user + end + end + + def update(attrs) + if attrs[:password_verifier].present? + update_login(attrs[:login]) + @user.update_attributes attrs.slice(:password_verifier, :password_salt) + end + # TODO: move into identity controller + update_pgp_key(attrs[:public_key]) if attrs.has_key? :public_key + @user.save && save_identities + @user.refresh_identity + end + + def destroy + return unless @user + Identity.by_user_id.key(@user.id).each do |identity| + identity.destroy + end + @user.destroy + end + + protected + + def update_login(login) + return unless login.present? + @old_identity = Identity.for(@user) + @user.login = login + @new_identity = Identity.for(@user) # based on the new login + @old_identity.destination = @user.email_address # alias old -> new + end + + def update_pgp_key(key) + @new_identity ||= Identity.for(@user) + @new_identity.set_key(:pgp, key) + end + + def save_identities + @new_identity.try(:save) && @old_identity.try(:save) + end + +end diff --git a/users/app/models/account_settings.rb b/users/app/models/account_settings.rb deleted file mode 100644 index 27fa227..0000000 --- a/users/app/models/account_settings.rb +++ /dev/null @@ -1,36 +0,0 @@ -class AccountSettings - - def initialize(user) - @user = user - end - - def update(attrs) - if attrs[:password_verifier].present? - update_login(attrs[:login]) - @user.update_attributes attrs.slice(:password_verifier, :password_salt) - end - # TODO: move into identity controller - update_pgp_key(attrs[:public_key]) if attrs.has_key? :public_key - @user.save && save_identities - end - - protected - - def update_login(login) - return unless login.present? - @old_identity = Identity.for(@user) - @user.login = login - @new_identity = Identity.for(@user) # based on the new login - @old_identity.destination = @user.email_address # alias old -> new - end - - def update_pgp_key(key) - @new_identity ||= Identity.for(@user) - @new_identity.set_key(:pgp, key) - end - - def save_identities - @new_identity.try(:save) && @old_identity.try(:save) - end - -end diff --git a/users/app/models/signup_service.rb b/users/app/models/signup_service.rb deleted file mode 100644 index f316ca9..0000000 --- a/users/app/models/signup_service.rb +++ /dev/null @@ -1,9 +0,0 @@ -class SignupService - - def register(attrs) - User.create(attrs).tap do |user| - Identity.create_for user - end - end - -end diff --git a/users/app/models/user.rb b/users/app/models/user.rb index 8874966..310eecd 100644 --- a/users/app/models/user.rb +++ b/users/app/models/user.rb @@ -86,6 +86,10 @@ class User < CouchRest::Model::Base @identity ||= Identity.for(self) end + def refresh_identity + @identity = Identity.for(self) + end + protected ## diff --git a/users/test/functional/v1/users_controller_test.rb b/users/test/functional/v1/users_controller_test.rb index a330bf3..7cd9b0c 100644 --- a/users/test/functional/v1/users_controller_test.rb +++ b/users/test/functional/v1/users_controller_test.rb @@ -7,7 +7,7 @@ class V1::UsersControllerTest < ActionController::TestCase changed_attribs = record_attributes_for :user_with_settings account_settings = stub account_settings.expects(:update).with(changed_attribs) - AccountSettings.expects(:new).with(user).returns(account_settings) + Account.expects(:new).with(user).returns(account_settings) login user put :update, :user => changed_attribs, :id => user.id, :format => :json @@ -22,7 +22,7 @@ class V1::UsersControllerTest < ActionController::TestCase changed_attribs = record_attributes_for :user_with_settings account_settings = stub account_settings.expects(:update).with(changed_attribs) - AccountSettings.expects(:new).with(user).returns(account_settings) + Account.expects(:new).with(user).returns(account_settings) login :is_admin? => true put :update, :user => changed_attribs, :id => user.id, :format => :json @@ -41,7 +41,7 @@ class V1::UsersControllerTest < ActionController::TestCase test "should create new user" do user_attribs = record_attributes_for :user user = User.new(user_attribs) - User.expects(:create).with(user_attribs).returns(user) + Account.expects(:create).with(user_attribs).returns(user) post :create, :user => user_attribs, :format => :json @@ -55,7 +55,7 @@ class V1::UsersControllerTest < ActionController::TestCase user_attribs.slice!('login') user = User.new(user_attribs) assert !user.valid? - User.expects(:create).with(user_attribs).returns(user) + Account.expects(:create).with(user_attribs).returns(user) post :create, :user => user_attribs, :format => :json diff --git a/users/test/unit/account_test.rb b/users/test/unit/account_test.rb new file mode 100644 index 0000000..39969c0 --- /dev/null +++ b/users/test/unit/account_test.rb @@ -0,0 +1,45 @@ +require 'test_helper' + +class AccountTest < ActiveSupport::TestCase + + test "create a new account" do + user = Account.create(FactoryGirl.attributes_for(:user)) + assert user.valid? + assert user.persisted? + assert id = user.identity + assert_equal user.email_address, id.address + assert_equal user.email_address, id.destination + id.destroy + user.destroy + end + + test "create and remove a user account" do + assert_no_difference "Identity.count" do + assert_no_difference "User.count" do + user = Account.create(FactoryGirl.attributes_for(:user)) + Account.new(user).destroy + end + end + end + + test "change username and create alias" do + user = Account.create(FactoryGirl.attributes_for(:user)) + old_id = user.identity + old_email = user.email_address + Account.new(user).update(FactoryGirl.attributes_for(:user)) + user.reload + old_id.reload + assert user.valid? + assert user.persisted? + assert id = user.identity + assert id.persisted? + assert_equal user.email_address, id.address + assert_equal user.email_address, id.destination + assert_equal user.email_address, old_id.destination + assert_equal old_email, old_id.address + old_id.destroy + id.destroy + user.destroy + end + +end -- cgit v1.2.3