implement the sign_up auth action

did committed Jun 16, 2017
commit 7535097a8b6508b6600d17be749824c6feb9c0e4
Showing 41 changed files with 389 additions and 44 deletions
locomotive/steam/middlewares/auth.rb b/lib/locomotive/steam/middlewares/auth.rb +26 -2
@@ @@ -2,6 +2,7 @@ module Locomotive::Steam
module Middlewares
# Process all the authentication actions:
+ # - sign up
# - sign in
# - new reset password
# - reset password
@@ @@ -26,6 +27,21 @@ module Locomotive::Steam
private
+ def sign_up(options)
+ return if authenticated?
+
+ status, entry = services.auth.sign_up(options, default_liquid_context)
+
+ if status == :entry_created
+ store_authenticated(entry)
+ redirect_to options.callback || mounted_on
+ else
+ liquid_assigns['auth_entry'] = entry
+ end
+
+ append_message(status)
+ end
+
def sign_in(options)
return if authenticated?
@@ @@ -102,7 +118,7 @@ module Locomotive::Steam
class AuthOptions
- ACTIONS = %w(sign_in sign_out forgot_password reset_password)
+ ACTIONS = %w(sign_up sign_in sign_out forgot_password reset_password)
attr_reader :site, :params
@@ @@ -131,7 +147,7 @@ module Locomotive::Steam
end
def id
- params[:auth_id]
+ params[:auth_entry].try(:[], id_field) || params[:auth_id]
end
def password
@@ @@ -162,6 +178,14 @@ module Locomotive::Steam
params[:auth_email_handle]
end
+ def disable_email
+ [1, 'true', true].include?(params[:auth_disable_email])
+ end
+
+ def entry
+ params[:auth_entry]
+ end
+
def smtp
name = params[:auth_email_smtp_namespace] || 'smtp'
namespace = site.metafields.try(:[], name)
locomotive/steam/services/auth_service.rb b/lib/locomotive/steam/services/auth_service.rb +72 -5
@@ @@ -12,6 +12,22 @@ module Locomotive
entries.find(type, id)
end
+ def sign_up(options, context)
+ entry = entries.create(options.type, options.entry) do |_entry|
+ _entry.extend(ContentEntryAuth)
+ _entry[:_password_field] = options.password_field.to_sym
+ end
+
+ if entry.errors.empty?
+ ActiveSupport::Notifications.instrument('steam.auth.signup', entry: entry)
+
+ context[options.type.singularize] = entry
+ send_welcome_email(options, context)
+ end
+
+ [entry.errors.empty? ? :entry_created : :invalid_entry, entry]
+ end
+
def sign_in(options)
entry = entries.all(options.type, options.id_field => options.id).first
@@ @@ -73,17 +89,31 @@ module Locomotive
private
+ def send_welcome_email(options, context)
+ return if options.disable_email
+
+ send_email options, context, <<-EMAIL
+ Hi,
+ You've been successfully registered.
+ Thanks!
+ EMAIL
+ end
+
def send_reset_password_instructions(options, context)
+ send_email options, context, <<-EMAIL
+ Hi,
+ To reset your password please follow the link below: #{context['reset_password_url']}.
+ Thanks!
+ EMAIL
+ end
+
+ def send_email(options, context, default_body)
email_options = { from: options.from, to: options.id, subject: options.subject, smtp: options.smtp }
if options.email_handle
email_options[:page_handle] = options.email_handle
else
- email_options[:body] = <<-EMAIL
- Hi,
- To reset your password please follow the link below: #{context['reset_password_url']}.
- Thanks!
- EMAIL
+ email_options[:body] = default_body
end
email_service.send_email(email_options, context)
@@ @@ -99,6 +129,43 @@ EMAIL
res == 0
end
+ # Module inject to the content entry to enable
+ # related authentication methods.
+ #
+ module ContentEntryAuth
+
+ def valid?
+ super
+
+ name = self[:_password_field]
+ password = self[name]
+ confirmation = self["#{name}_confirmation"]
+
+ if password.to_s.size < Locomotive::Steam::AuthService::MIN_PASSWORD_LENGTH
+ self.errors.add(name, :password_too_short)
+ end
+
+ if !password.blank? && password != confirmation
+ self.errors.add(name, :password_different_from_confirmation)
+ end
+
+ set_password(password) if self.errors.empty?
+
+ self.errors.empty?
+ end
+
+ private
+
+ def set_password(password)
+ self[:"#{self[:_password_field]}_hash"] = BCrypt::Password.create(password)
+
+ name = self.attributes.delete(:_password_field)
+
+ self.attributes.delete_if { |_name| _name == name || _name == "#{name}_confirmation" }
+ end
+
+ end
+
end
end
locomotive/steam/services/content_entry_service.rb b/lib/locomotive/steam/services/content_entry_service.rb +3 -0
@@ @@ -28,6 +28,9 @@ module Locomotive
def create(type_slug, attributes, as_json = false)
with_repository(type_slug) do |_repository|
entry = _repository.build(clean_attributes(attributes))
+
+ yield(entry) if block_given?
+
decorated_entry = i18n_decorate { entry }
if validate(_repository, decorated_entry)
spec/fixtures/default/app/content_types/accounts.yml +2 -1
@@ @@ -47,7 +47,8 @@ fields:
- email: # The lowercase, underscored name of the field
label: Email # Human readable name of the field
type: email
- required: false
+ required: true
+ unique: true
hint: Explanatory text displayed in the back office
localized: false
spec/fixtures/default/app/content_types/songs.yml +2 -2
@@ @@ -14,8 +14,8 @@ fields:
- cover:
label: Cover
type: file
- required: true
- # localized: true # required when pushing the site with Wagon
+ required: false
+ #localized: true # required when pushing the site with Wagon
- short_description:
type: text
text_formatting: html
spec/fixtures/default/app/views/pages/account/sign_up.liquid +49 -0
@@ @@ -0,0 +1,49 @@
+ ---
+ title: Sign up
+ listed: false
+ published: true
+ handle: sign_up
+ ---
+ {% extends 'index' %}
+
+ {% block content %}
+
+ <h1>Sign up</h1>
+
+ {% if current_account %}
+ <div class="alert alert-warning">
+ You're already authenticated!
+ </div>
+ {% else %}
+
+ <form action="{% path_to 'sign_up' %}" method="POST">
+ <input type="hidden" name="auth_action" value="sign_up" />
+ <input type="hidden" name="auth_content_type" value="accounts" />
+ <input type="hidden" name="auth_id_field" value="email" />
+ <input type="hidden" name="auth_password_field" value="password" />
+ <input type="hidden" name="auth_callback" value="{% path_to sign_in %}" />
+
+ <div class="form-group">
+ <label for="auth-name">Your name</label>
+ <input type="text" name="auth_entry[name]" class="form-control" id="auth-name" placeholder="Name">
+ </div>
+ <div class="form-group">
+ <label for="auth-email">Your E-mail</label>
+ <input type="email" name="auth_entry[email]" class="form-control" id="auth-email" placeholder="Email">
+ </div>
+ <div class="form-group">
+ <label for="auth-password">Password</label>
+ {% if auth_entry.errors.password.size > 0 %}
+ <span class="inline-error">{{ 'auth_' | append: auth_entry.errors.password.first | translate }}</span>
+ {% endif %}
+ <input type="password" name="auth_entry[password]" class="form-control" id="auth-password" placeholder="Password">
+ </div>
+ <div class="form-group">
+ <label for="auth-password">Password confirmation</label>
+ <input type="password" name="auth_entry[password_confirmation]" class="form-control" id="auth-password" placeholder="Password confirmation">
+ </div>
+ <button type="submit" class="btn btn-default">Create account</button>
+ </form>
+ {% endif %}
+
+ {% endblock %}
spec/fixtures/default/config/translations.yml +4 -0
@@ @@ -25,3 +25,7 @@ auth_invalid_token:
auth_password_too_short:
en: "Your password is too short"
fr: "Votre mot de passe est trop court"
+
+ auth_password_different_from_confirmation:
+ en: "Your password doesn't match the confirmation"
+ fr: "Votre mot de passe ne correspond à la confirmation"
spec/fixtures/default/data/accounts.yml +1 -1
@@ @@ -3,7 +3,7 @@
password: 'easyone'
- "Jane":
- email: 'john@doe.net'
+ email: 'jane@doe.net'
password: 'anotherone'
_auth_reset_token: '420000000000000'
_auth_reset_sent_at: '2020-01-01T15:00:00.000Z'
spec/fixtures/default/data/songs.yml +1 -0
@@ @@ -11,6 +11,7 @@
cover:
en: /samples/asset_collections/cover.jpg
fr: /samples/photo_2.jpg
+ nb: /samples/photo_2.jpg
band: pearl-jam
- "Song #3":
duration: "6:28"
locomotive_accounts.bson b/spec/fixtures/mongodb/locomotive_accounts.bson +0 -0
locomotive_accounts.metadata.json b/spec/fixtures/mongodb/locomotive_accounts.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_accounts"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_accounts"}]}
\ No newline at end of file
locomotive_activities.bson b/spec/fixtures/mongodb/locomotive_activities.bson +0 -0
locomotive_activities.metadata.json b/spec/fixtures/mongodb/locomotive_activities.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_activities"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_activities"}]}
\ No newline at end of file
locomotive_content_assets.bson b/spec/fixtures/mongodb/locomotive_content_assets.bson +0 -0
locomotive_content_assets.metadata.json b/spec/fixtures/mongodb/locomotive_content_assets.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_content_assets"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_content_assets"}]}
\ No newline at end of file
locomotive_content_entries.bson b/spec/fixtures/mongodb/locomotive_content_entries.bson +0 -0
locomotive_content_entries.metadata.json b/spec/fixtures/mongodb/locomotive_content_entries.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_content_entries"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_content_entries"}]}
\ No newline at end of file
locomotive_content_types.bson b/spec/fixtures/mongodb/locomotive_content_types.bson +0 -0
locomotive_content_types.metadata.json b/spec/fixtures/mongodb/locomotive_content_types.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_content_types"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_content_types"}]}
\ No newline at end of file
locomotive_pages.bson b/spec/fixtures/mongodb/locomotive_pages.bson +0 -0
locomotive_pages.metadata.json b/spec/fixtures/mongodb/locomotive_pages.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_pages"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_pages"}]}
\ No newline at end of file
locomotive_sites.bson b/spec/fixtures/mongodb/locomotive_sites.bson +0 -0
locomotive_sites.metadata.json b/spec/fixtures/mongodb/locomotive_sites.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_sites"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_sites"}]}
\ No newline at end of file
locomotive_snippets.bson b/spec/fixtures/mongodb/locomotive_snippets.bson +0 -0
locomotive_snippets.metadata.json b/spec/fixtures/mongodb/locomotive_snippets.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_snippets"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_snippets"}]}
\ No newline at end of file
locomotive_theme_assets.bson b/spec/fixtures/mongodb/locomotive_theme_assets.bson +0 -0
locomotive_theme_assets.metadata.json b/spec/fixtures/mongodb/locomotive_theme_assets.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_theme_assets"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_theme_assets"}]}
\ No newline at end of file
locomotive_translations.bson b/spec/fixtures/mongodb/locomotive_translations.bson +0 -0
locomotive_translations.metadata.json b/spec/fixtures/mongodb/locomotive_translations.metadata.json +1 -1
@@ @@ -1 +1 @@
- {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_dev.locomotive_translations"}]}
\ No newline at end of file
+ {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"locomotive_engine_wagon_dev.locomotive_translations"}]}
\ No newline at end of file
spec/integration/repositories/content_entry_repository_spec.rb +1 -1
@@ @@ -116,7 +116,7 @@ describe Locomotive::Steam::ContentEntryRepository do
let(:site_id) { mongodb_site_id }
let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
- let(:entry_id) { BSON::ObjectId.from_string('5829ffa087f6435971756881') }
+ let(:entry_id) { BSON::ObjectId.from_string('5943b4dd87f6430cf23b814d') }
end
spec/integration/repositories/page_repository_spec.rb +2 -2
@@ @@ -14,7 +14,7 @@ describe Locomotive::Steam::PageRepository do
describe '#all' do
let(:conditions) { {} }
subject { repository.all(conditions) }
- it { expect(subject.size).to eq 33 }
+ it { expect(subject.size).to eq 34 }
context 'with conditions' do
let(:conditions) { { fullpath: 'index', 'slug.ne' => '404' } }
@@ @@ -34,7 +34,7 @@ describe Locomotive::Steam::PageRepository do
describe '#only_handle_and_fullpath' do
subject { repository.only_handle_and_fullpath }
- it { expect(subject.size).to eq 8 }
+ it { expect(subject.size).to eq 9 }
end
describe '#by_fullpath' do
spec/integration/repositories/theme_asset_repository_spec.rb +1 -1
@@ @@ -26,7 +26,7 @@ describe Locomotive::Steam::ThemeAssetRepository do
describe '#checksums' do
subject { repository.checksums }
it { expect(subject.size).to eq 16 }
- it { expect(subject['stylesheets/application.css']).to eq 'f431407c21db339b7759c2d7ded2553f' }
+ it { expect(subject['stylesheets/application.css']).to eq 'f06835e254f0d1b8363aae754525c723' }
end
end
spec/integration/repositories/translation_repository_spec.rb +1 -1
@@ @@ -13,7 +13,7 @@ describe Locomotive::Steam::TranslationRepository do
describe '#all' do
subject { repository.all }
- it { expect(subject.size).to eq 7 }
+ it { expect(subject.size).to eq 8 }
end
describe '#by_key' do
spec/integration/server/auth_spec.rb +70 -0
@@ @@ -8,6 +8,76 @@ describe 'Authentication' do
run_server
end
+ describe 'sign up action' do
+
+ it 'renders the form' do
+ get '/account/sign-up'
+ expect(last_response.body).to include '/account/sign-up'
+ end
+
+ describe 'press the sign up button' do
+
+ let(:params) { {
+ auth_action: 'sign_up',
+ auth_content_type: 'accounts',
+ auth_id_field: 'email',
+ auth_password_field: 'password',
+ auth_callback: '/account/me',
+ auth_entry: {
+ name: 'Chris Cornell',
+ email: 'chris@soundgarden.band',
+ password: 'easyone',
+ password_confirmation: 'easyone'
+ }
+ } }
+
+ it 'redirects to the callback' do
+ sign_up(params)
+ expect(last_response.status).to eq 301
+ expect(last_response.location).to eq '/account/me'
+ end
+
+ it 'displays the profile page as described in the params' do
+ params[:auth_entry][:email] = 'chris.cornell@soundgarden.band'
+ sign_up(params, true)
+ expect(last_response.body).to include "My name is Chris Cornell and I'm logged in!"
+ end
+
+ context 'wrong parameters' do
+
+ let(:params) { {
+ auth_action: 'sign_up',
+ auth_content_type: 'accounts',
+ auth_id_field: 'email',
+ auth_password_field: 'password',
+ auth_callback: '/account/me',
+ auth_entry: {
+ name: 'Chris Cornell',
+ email: 'chris@soundgarden.band',
+ password: 'easyone',
+ password_confirmation: 'easyone2'
+ }
+ } }
+
+ it 'renders the sign up page with an error message' do
+ sign_up(params)
+ expect(last_response.status).to eq 200
+ expect(last_response.body).to include '/account/sign-up'
+ expect(last_response.body).to include "Your password doesn't match the confirmation"
+ end
+
+ end
+
+ def sign_up(params, follow_redirect = false)
+ post '/account/sign-up', params
+ follow_redirect! if follow_redirect
+ last_response
+ end
+
+ end
+
+ end
+
describe 'sign in action' do
it 'renders the form' do
spec/integration/services/content_entry_service_spec.rb +1 -1
@@ @@ -45,7 +45,7 @@ describe Locomotive::Steam::ContentEntryService do
let(:site_id) { mongodb_site_id }
let(:adapter) { Locomotive::Steam::MongoDBAdapter.new(database: 'steam_test', hosts: ['127.0.0.1:27017']) }
- let(:entry_id) { BSON::ObjectId.from_string('5829ffa087f6435971756881') }
+ let(:entry_id) { BSON::ObjectId.from_string('5943b4dd87f6430cf23b814d') }
describe '#create' do
subject { service.create('messages', { name: 'John', email: 'john@doe.net', message: 'Hello world!' }) }
spec/support/helpers.rb +1 -1
@@ @@ -4,7 +4,7 @@ module Spec
module Helpers
def mongodb_site_id
- BSON::ObjectId.from_string('5829ff6487f64359474164a1')
+ BSON::ObjectId.from_string('5943b49287f6430cadd748a3')
end
def reset!
spec/unit/adapters/filesystem/yaml_loaders/content_entry_spec.rb +1 -1
@@ @@ -84,7 +84,7 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::ContentEntry do
end
it 'stores the size of the file in multiple locales' do
- expect(subject[1][:cover_size]).to eq('en' => 14768, 'fr' => 165883)
+ expect(subject[1][:cover_size]).to eq('en' => 14768, 'fr' => 165883, 'nb' => 165883)
end
spec/unit/adapters/filesystem/yaml_loaders/page_spec.rb +7 -7
@@ @@ -15,14 +15,14 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Page do
subject { loader.load(scope).sort { |a, b| a[:_fullpath] <=> b[:_fullpath] } }
it 'tests various stuff' do
- expect(subject.size).to eq 33
+ expect(subject.size).to eq 34
expect(subject.first[:title]).to eq(en: 'Page not found', fr: 'Page non trouvée')
- expect(subject[22][:is_layout]).to eq true
- expect(subject[22][:listed]).to eq false
- expect(subject[22][:published]).to eq false
- expect(subject[23][:slug]).to eq(en: 'music', fr: 'notre-musique')
- expect(subject[24][:_fullpath]).to eq 'songs'
- expect(subject[24][:template_path]).to eq(en: false)
+ expect(subject[23][:is_layout]).to eq true
+ expect(subject[23][:listed]).to eq false
+ expect(subject[23][:published]).to eq false
+ expect(subject[24][:slug]).to eq(en: 'music', fr: 'notre-musique')
+ expect(subject[25][:_fullpath]).to eq 'songs'
+ expect(subject[25][:template_path]).to eq(en: false)
end
end
spec/unit/adapters/filesystem/yaml_loaders/translation_spec.rb +1 -1
@@ @@ -15,7 +15,7 @@ describe Locomotive::Steam::Adapters::Filesystem::YAMLLoaders::Translation do
subject { loader.load(scope) }
it 'tests various stuff' do
- expect(subject.size).to eq 7
+ expect(subject.size).to eq 8
expect(subject.first[:key]).to eq('powered_by')
expect(subject.first[:values]).to eq({ 'en' => 'Powered by', 'fr' => 'Propulsé par' })
end
spec/unit/entities/content_entry_spec.rb +9 -0
@@ @@ -116,6 +116,15 @@ describe Locomotive::Steam::ContentEntry do
it { expect(subject['picture']['url']).to eq '/assets/foo.png' }
+ context 'includes a non dynamic attribute' do
+
+ it "doesn't add it to the output" do
+ content_entry['author'] = 'John Doe'
+ expect(subject['author']).to eq nil
+ end
+
+ end
+
end
describe 'dynamic attributes' do
spec/unit/services/auth_service_spec.rb +124 -7
@@ @@ -2,9 +2,10 @@ require 'spec_helper'
describe Locomotive::Steam::AuthService do
- let(:entries) { instance_double('ContentService') }
- let(:emails) { instance_double('EmailService') }
- let(:service) { described_class.new(entries, emails) }
+ let(:entries) { instance_double('ContentService') }
+ let(:emails) { instance_double('EmailService') }
+ let(:service) { described_class.new(entries, emails) }
+ let(:liquid_context) { {} }
let(:default_auth_options) { {
type: 'accounts',
@@ @@ -22,6 +23,126 @@ describe Locomotive::Steam::AuthService do
let(:auth_options) { instance_double('AuthOptions', default_auth_options) }
+ describe '#sign_up' do
+
+ let(:errors) { [] }
+ let(:entry_attributes) { { fullname: 'Chris Cornell', band: 'Soundgarden', email: 'chris@soundgarden.band', password: 'easyone', password_confirmation: 'easyone' } }
+ let(:entry) { instance_double('Account', errors: errors) }
+ let(:email_disabled) { false }
+ let(:default_auth_options) { {
+ type: 'accounts',
+ id_field: 'email',
+ id: 'chris@soundgarden.band',
+ password_field: 'password',
+ from: 'no-reply@acme.org',
+ subject: 'Your account has been created',
+ email_handle: 'account-created',
+ smtp: {},
+ disable_email: email_disabled,
+ entry: entry_attributes
+ } }
+
+ subject { service.sign_up(auth_options, liquid_context) }
+
+ context 'the entry has errors' do
+
+ let(:errors) { [:invalid_password] }
+
+ it 'returns invalid_entry and the entry' do
+ expect(entries).to receive(:create).with('accounts', {
+ fullname: 'Chris Cornell',
+ band: 'Soundgarden',
+ email: 'chris@soundgarden.band',
+ password: 'easyone',
+ password_confirmation: 'easyone'
+ }).and_return(entry)
+ is_expected.to eq [:invalid_entry, entry]
+ end
+
+ end
+
+ it "returns both :created and the entry if it was able to create it (+ send email)" do
+ expect(entries).to receive(:create).with('accounts', {
+ fullname: 'Chris Cornell',
+ band: 'Soundgarden',
+ email: 'chris@soundgarden.band',
+ password: 'easyone',
+ password_confirmation: 'easyone'
+ }).and_return(entry)
+ expect(emails).to receive(:send_email).with({
+ from: 'no-reply@acme.org',
+ to: 'chris@soundgarden.band',
+ subject: 'Your account has been created',
+ page_handle: 'account-created',
+ smtp: {} }, liquid_context)
+ is_expected.to eq [:entry_created, entry]
+ end
+
+ context 'email is disabled' do
+
+ let(:email_disabled) { true }
+
+ it "doesn't send a notification email" do
+ allow(entries).to receive(:create).and_return(entry)
+ expect(emails).to_not receive(:send_email)
+ is_expected.to eq [:entry_created, entry]
+ end
+
+ end
+
+ describe Locomotive::Steam::AuthService::ContentEntryAuth do
+
+ let(:repository) { instance_double('FieldRepository', all: nil, required: []) }
+ let(:type) { instance_double('ContentType', slug: 'accounts', label_field_name: :title, fields: repository, fields_by_name: {}) }
+ let(:attributes) { { password: 'easyone', password_confirmation: 'easyone' } }
+ let(:content_entry) { Locomotive::Steam::ContentEntry.new(attributes).tap { |e| e.content_type = type } }
+
+ before { content_entry.extend(described_class) }
+
+ describe '#valid?' do
+
+ before { content_entry[:_password_field] = 'password' }
+
+ subject { content_entry.valid? }
+
+ it { is_expected.to eq true }
+
+ it 'encrypts the password since there is no error' do
+ expect(BCrypt::Password).to receive(:create).with('easyone').and_return('42a')
+ subject
+ expect(content_entry[:password_hash]).to eq '42a'
+ expect(content_entry.attributes[:password]).to eq nil
+ expect(content_entry.attributes[:password_confirmation]).to eq nil
+ end
+
+ context 'the password is less than 6 characters' do
+
+ let(:attributes) { { password: 'easy', password_confirmation: 'easy' } }
+
+ it 'returns false' do
+ is_expected.to eq false
+ expect(content_entry.errors[:password]).to eq([:password_too_short])
+ end
+
+ end
+
+ context "the password doesn't match the confirmation" do
+
+ let(:attributes) { { password: 'easyone', password_confirmation: 'oneeasy' } }
+
+ it 'returns false' do
+ is_expected.to eq false
+ expect(content_entry.errors[:password]).to eq([:password_different_from_confirmation])
+ end
+
+ end
+
+ end
+
+ end
+
+ end
+
describe '#sign_in' do
subject { service.sign_in(auth_options) }
@@ @@ -47,8 +168,6 @@ describe Locomotive::Steam::AuthService do
describe '#forgot_password' do
- let(:liquid_context) { {} }
-
subject { service.forgot_password(auth_options, liquid_context) }
it 'returns :wrong_email if no entry matches the email' do
@@ @@ -57,7 +176,6 @@ describe Locomotive::Steam::AuthService do
end
it 'sends the instructions by email if an entry matches the email' do
- allow(SecureRandom).to receive(:hex).and_return('42a')
entry = build_account('easyone', '42a')
expect(entries).to receive(:all).with('accounts', { 'email' => 'john@doe.net' }).and_return([entry])
expect(entries).to receive(:update_decorated_entry)
@@ @@ -77,7 +195,6 @@ describe Locomotive::Steam::AuthService do
let(:auth_options) { instance_double('AuthOptions', _auth_options) }
it 'also sends the instructions by email with a default email template' do
- allow(SecureRandom).to receive(:hex).and_return('42a')
entry = build_account('easyone', '42a')
expect(entries).to receive(:all).with('accounts', { 'email' => 'john@doe.net' }).and_return([entry])
expect(entries).to receive(:update_decorated_entry)