From 9813b2a4a9bf43ccc36930f4eae3db7f9085400a Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Tue, 4 Feb 2020 22:46:23 +0100 Subject: [PATCH] Add frontend controllers and views for user account management. Needs to be enabled via # config/initializers/alchemy.rb Alchemy::Devise.enable_user_accounts = true --- .../alchemy/accounts_controller.rb | 18 +++ .../alchemy/confirmations_controller.rb | 11 ++ .../alchemy/passwords_controller.rb | 11 ++ .../alchemy/sessions_controller.rb | 11 ++ app/mailers/alchemy/notifications.rb | 20 ++- app/models/alchemy/user.rb | 9 ++ app/views/alchemy/accounts/show.html.erb | 3 + .../alchemy/devise/shared/_links.html.erb | 15 ++ .../confirmation_instructions.de.text.erb | 5 + .../confirmation_instructions.en.text.erb | 5 + ...er_reset_password_instructions.de.text.erb | 8 ++ ...er_reset_password_instructions.en.text.erb | 8 ++ ...er_reset_password_instructions.es.text.erb | 8 ++ ...er_reset_password_instructions.ru.text.erb | 8 ++ app/views/alchemy/passwords/edit.html.erb | 27 ++++ app/views/alchemy/passwords/new.html.erb | 18 +++ app/views/alchemy/sessions/new.html.erb | 32 +++++ config/routes.rb | 32 +++++ lib/alchemy/devise.rb | 23 ++- spec/controllers/accounts_controller_spec.rb | 45 ++++++ .../confirmations_controller_spec.rb | 46 ++++++ spec/controllers/passwords_controller_spec.rb | 34 +++++ spec/controllers/sessions_controller_spec.rb | 64 +++++++++ spec/mailers/notifications_spec.rb | 38 +++++ spec/routing/account_routing_spec.rb | 132 ++++++++++++++++++ spec/routing/admin_password_routing_spec.rb | 43 ++++++ .../admin_user_session_routing_spec.rb | 32 +++++ spec/routing/password_routing_spec.rb | 114 ++++++++++----- spec/routing/session_routing_spec.rb | 87 ++++++++---- 29 files changed, 846 insertions(+), 61 deletions(-) create mode 100644 app/controllers/alchemy/accounts_controller.rb create mode 100644 app/controllers/alchemy/confirmations_controller.rb create mode 100644 app/controllers/alchemy/passwords_controller.rb create mode 100644 app/controllers/alchemy/sessions_controller.rb create mode 100644 app/views/alchemy/accounts/show.html.erb create mode 100644 app/views/alchemy/devise/shared/_links.html.erb create mode 100644 app/views/alchemy/notifications/confirmation_instructions.de.text.erb create mode 100644 app/views/alchemy/notifications/confirmation_instructions.en.text.erb create mode 100644 app/views/alchemy/notifications/member_reset_password_instructions.de.text.erb create mode 100644 app/views/alchemy/notifications/member_reset_password_instructions.en.text.erb create mode 100644 app/views/alchemy/notifications/member_reset_password_instructions.es.text.erb create mode 100644 app/views/alchemy/notifications/member_reset_password_instructions.ru.text.erb create mode 100644 app/views/alchemy/passwords/edit.html.erb create mode 100644 app/views/alchemy/passwords/new.html.erb create mode 100644 app/views/alchemy/sessions/new.html.erb create mode 100644 spec/controllers/accounts_controller_spec.rb create mode 100644 spec/controllers/confirmations_controller_spec.rb create mode 100644 spec/controllers/passwords_controller_spec.rb create mode 100644 spec/controllers/sessions_controller_spec.rb create mode 100644 spec/routing/account_routing_spec.rb create mode 100644 spec/routing/admin_password_routing_spec.rb create mode 100644 spec/routing/admin_user_session_routing_spec.rb diff --git a/app/controllers/alchemy/accounts_controller.rb b/app/controllers/alchemy/accounts_controller.rb new file mode 100644 index 0000000..13bf743 --- /dev/null +++ b/app/controllers/alchemy/accounts_controller.rb @@ -0,0 +1,18 @@ +module Alchemy + class AccountsController < ::Devise::RegistrationsController + helper 'Alchemy::Pages' + + def show + authorize! :show, current_alchemy_user + @user = current_alchemy_user + end + + private + + def permission_denied(*) + store_location_for(:user, account_path) + flash[:warning] = t(:unauthenticated, scope: 'devise.failure') + redirect_to alchemy.login_path + end + end +end diff --git a/app/controllers/alchemy/confirmations_controller.rb b/app/controllers/alchemy/confirmations_controller.rb new file mode 100644 index 0000000..daefa26 --- /dev/null +++ b/app/controllers/alchemy/confirmations_controller.rb @@ -0,0 +1,11 @@ +module Alchemy + class ConfirmationsController < ::Devise::ConfirmationsController + helper 'Alchemy::Pages' + + private + + def new_session_path(*) + alchemy.login_path + end + end +end diff --git a/app/controllers/alchemy/passwords_controller.rb b/app/controllers/alchemy/passwords_controller.rb new file mode 100644 index 0000000..52f87bb --- /dev/null +++ b/app/controllers/alchemy/passwords_controller.rb @@ -0,0 +1,11 @@ +module Alchemy + class PasswordsController < ::Devise::PasswordsController + helper 'Alchemy::Pages' + + private + + def new_session_path(*) + alchemy.login_path + end + end +end diff --git a/app/controllers/alchemy/sessions_controller.rb b/app/controllers/alchemy/sessions_controller.rb new file mode 100644 index 0000000..d119f16 --- /dev/null +++ b/app/controllers/alchemy/sessions_controller.rb @@ -0,0 +1,11 @@ +module Alchemy + class SessionsController < ::Devise::SessionsController + helper 'Alchemy::Pages' + + private + + def after_sign_in_path_for(user) + stored_location_for(user) || alchemy.account_path + end + end +end diff --git a/app/mailers/alchemy/notifications.rb b/app/mailers/alchemy/notifications.rb index 33327df..cd27825 100644 --- a/app/mailers/alchemy/notifications.rb +++ b/app/mailers/alchemy/notifications.rb @@ -1,5 +1,5 @@ module Alchemy - class Notifications < ActionMailer::Base + class Notifications < ::Devise::Mailer default(from: Config.get(:mailer)['mail_from']) @@ -21,6 +21,15 @@ def alchemy_user_created(user) ) end + def member_reset_password_instructions(user, token, opts={}) + @user = user + @token = token + mail( + to: user.email, + subject: Alchemy.t("Reset password instructions") + ) + end + def reset_password_instructions(user, token, opts={}) @user = user @token = token @@ -29,5 +38,14 @@ def reset_password_instructions(user, token, opts={}) subject: Alchemy.t("Reset password instructions") ) end + + def confirmation_instructions(user, token, opts={}) + @user = user + @token = token + mail( + to: user.email, + subject: Alchemy.t("Account confirmation instructions") + ) + end end end diff --git a/app/models/alchemy/user.rb b/app/models/alchemy/user.rb index bd574c8..7c042fe 100644 --- a/app/models/alchemy/user.rb +++ b/app/models/alchemy/user.rb @@ -157,6 +157,15 @@ def deliver_welcome_mail end end + # Overwritten to send a different email to members + def send_reset_password_instructions_notification(token) + if has_role?('member') + send_devise_notification(:member_reset_password_instructions, token, {}) + else + send_devise_notification(:reset_password_instructions, token, {}) + end + end + private def logged_in_timeout diff --git a/app/views/alchemy/accounts/show.html.erb b/app/views/alchemy/accounts/show.html.erb new file mode 100644 index 0000000..a5c0a17 --- /dev/null +++ b/app/views/alchemy/accounts/show.html.erb @@ -0,0 +1,3 @@ +

Hallo <%= @user.fullname %>

+ +<%= link_to 'Edit account', alchemy.edit_account_path %> diff --git a/app/views/alchemy/devise/shared/_links.html.erb b/app/views/alchemy/devise/shared/_links.html.erb new file mode 100644 index 0000000..cd17113 --- /dev/null +++ b/app/views/alchemy/devise/shared/_links.html.erb @@ -0,0 +1,15 @@ +<%- if controller_name != 'sessions' %> + <%= link_to t('.login', default: 'Log in'), alchemy.login_path %>
+<% end %> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to t('.sign_up', default: 'Sign up'), alchemy.new_account_path %>
+<% end %> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> + <%= link_to t('.forgot_password', default: 'Forgot your password?'), alchemy.new_password_path %>
+<% end %> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to t('.confirmation_instructions', default: "Didn't receive confirmation instructions?"), alchemy.new_confirmation_path %>
+<% end %> diff --git a/app/views/alchemy/notifications/confirmation_instructions.de.text.erb b/app/views/alchemy/notifications/confirmation_instructions.de.text.erb new file mode 100644 index 0000000..d96c9e1 --- /dev/null +++ b/app/views/alchemy/notifications/confirmation_instructions.de.text.erb @@ -0,0 +1,5 @@ +Willkommen <%= @user.fullname %>! + +Bitte bestätigen Sie Ihre E-Mail-Adresse durch klicken auf folgenden Link: + +<%= alchemy.confirmation_url(@user, confirmation_token: @token) %> diff --git a/app/views/alchemy/notifications/confirmation_instructions.en.text.erb b/app/views/alchemy/notifications/confirmation_instructions.en.text.erb new file mode 100644 index 0000000..1aacf31 --- /dev/null +++ b/app/views/alchemy/notifications/confirmation_instructions.en.text.erb @@ -0,0 +1,5 @@ +Welcome <%= @user.fullname %>! + +You can confirm your account email through the link below: + +<%= alchemy.confirmation_url(@user, confirmation_token: @token) %> diff --git a/app/views/alchemy/notifications/member_reset_password_instructions.de.text.erb b/app/views/alchemy/notifications/member_reset_password_instructions.de.text.erb new file mode 100644 index 0000000..f306fa0 --- /dev/null +++ b/app/views/alchemy/notifications/member_reset_password_instructions.de.text.erb @@ -0,0 +1,8 @@ +Hallo <%= @user.fullname %>. + +Sie haben angefordert Ihr Passwort zurückzusetzen. Dies kann durch anklicken des nachfolgenden Links bestätigt werden. + +<%= alchemy.edit_password_url(@user, reset_password_token: @token) %> + +Wenn Sie diese Zurücksetzung nicht angefragt haben, dann können Sie diese E-Mail einfach ignorieren. +Ihr Passwort wird erst dann zurückgesetzt, wenn Sie den Link anklicken. diff --git a/app/views/alchemy/notifications/member_reset_password_instructions.en.text.erb b/app/views/alchemy/notifications/member_reset_password_instructions.en.text.erb new file mode 100644 index 0000000..e1150cb --- /dev/null +++ b/app/views/alchemy/notifications/member_reset_password_instructions.en.text.erb @@ -0,0 +1,8 @@ +Hello <%= @user.name %>. + +You have requested to change your password. Please confirm this by clicking the link below. + +<%= alchemy.edit_password_url(@user, reset_password_token: @token) %> + +If you didn't request this, please ignore this email. +Your password won't change until you access the link above and create a new one. diff --git a/app/views/alchemy/notifications/member_reset_password_instructions.es.text.erb b/app/views/alchemy/notifications/member_reset_password_instructions.es.text.erb new file mode 100644 index 0000000..55d62af --- /dev/null +++ b/app/views/alchemy/notifications/member_reset_password_instructions.es.text.erb @@ -0,0 +1,8 @@ +Hola <%= @user.name %>. + +Has solicitado modificar tu contraseña. Por favor, confírmalo pulsando en el siguiente enlace. + +<%= alchemy.edit_password_url(@user, reset_password_token: @token) %> + +Si no has sido tu el que ha hecho la solicitud, ignora este correo. +Tu contraseña no cambiará hasta que no accedas al enlace de arriba y generes una nueva. diff --git a/app/views/alchemy/notifications/member_reset_password_instructions.ru.text.erb b/app/views/alchemy/notifications/member_reset_password_instructions.ru.text.erb new file mode 100644 index 0000000..c4ecfdc --- /dev/null +++ b/app/views/alchemy/notifications/member_reset_password_instructions.ru.text.erb @@ -0,0 +1,8 @@ +Здравствуйте, <%= @user.name %>. + +Вы сделали запрос на смену пароля. Пожалуйста подтвердите это, нажав на ссылку ниже. + +<%= alchemy.edit_password_url(@user, reset_password_token: @token) %> + +Если вы не делали запрос, просто проигнорируйте это письмо. +Ваш пароль не изменится до тех пор, пока вы не перейдете по ссылке и сами не измените его. diff --git a/app/views/alchemy/passwords/edit.html.erb b/app/views/alchemy/passwords/edit.html.erb new file mode 100644 index 0000000..786a7a8 --- /dev/null +++ b/app/views/alchemy/passwords/edit.html.erb @@ -0,0 +1,27 @@ +

<%= t('.title', default: 'Change your password') %>

+ +<%= simple_form_for(@user, as: :user, url: alchemy.password_path, html: { method: :put }) do |f| %> + <%= f.error_notification %> + + <%= f.input :reset_password_token, as: :hidden %> + <%= f.full_error :reset_password_token %> + +
+ <%= f.input :password, + label: t('.password.label', default: 'New password'), + required: true, + autofocus: true, + hint: t('.hint', default: '%{minimum} characters minimum', minimum: @minimum_password_length) if @minimum_password_length, + input_html: { autocomplete: "new-password" } %> + <%= f.input :password_confirmation, + label: t('.password_confirmation.label', default: 'Confirm your new password'), + required: true, + input_html: { autocomplete: "new-password" } %> +
+ +
+ <%= f.button :submit, t('.button.label', default: 'Change my password') %> +
+<% end %> + +<%= render "alchemy/devise/shared/links" %> diff --git a/app/views/alchemy/passwords/new.html.erb b/app/views/alchemy/passwords/new.html.erb new file mode 100644 index 0000000..30090da --- /dev/null +++ b/app/views/alchemy/passwords/new.html.erb @@ -0,0 +1,18 @@ +

<%= t('.title', default: 'Forgot your password?') %>

+ +<%= simple_form_for(@user, as: :user, url: alchemy.password_path, html: { method: :post }) do |f| %> + <%= f.error_notification %> + +
+ <%= f.input :email, + required: true, + autofocus: true, + input_html: { autocomplete: "email" } %> +
+ +
+ <%= f.button :submit, t('.button.label', default: 'Send me reset password instructions') %> +
+<% end %> + +<%= render "alchemy/devise/shared/links" %> diff --git a/app/views/alchemy/sessions/new.html.erb b/app/views/alchemy/sessions/new.html.erb new file mode 100644 index 0000000..5b5954b --- /dev/null +++ b/app/views/alchemy/sessions/new.html.erb @@ -0,0 +1,32 @@ +

<%= t('.title', default: 'Log in') %>

+ +<% if flash[:alert] %> +
+ <%= flash[:alert] %> +
+<% end %> + +<% if flash[:notice] %> +
+ <%= flash[:notice] %> +
+<% end %> + +<%= simple_form_for(@user, as: :user, url: alchemy.login_path) do |f| %> +
+ <%= f.input :email, + required: false, + autofocus: true, + input_html: { autocomplete: "email" } %> + <%= f.input :password, + required: false, + input_html: { autocomplete: "current-password" } %> + <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %> +
+ +
+ <%= f.button :submit, t('.button.label', default: 'Log in') %> +
+<% end %> + +<%= render "alchemy/devise/shared/links" %> diff --git a/config/routes.rb b/config/routes.rb index 055cce5..313d553 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,36 @@ Alchemy::Engine.routes.draw do + if Alchemy::Devise.enable_user_accounts? + devise_for :user, + class_name: 'Alchemy::User', + singular: :user, + skip: :all, + controllers: { + registrations: Alchemy::Devise.registrations_enabled? ? 'alchemy/accounts' : nil, + confirmations: Alchemy::Devise.confirmations_enabled? ? 'alchemy/confirmations' : nil, + sessions: 'alchemy/sessions', + passwords: 'alchemy/passwords' + }, + path: :account, + router_name: :alchemy + + scope :account do + devise_scope :user do + get '/login' => 'sessions#new' + post '/login' => 'sessions#create' + match '/logout' => 'sessions#destroy', via: Devise.sign_out_via + + if Alchemy::Devise.confirmations_enabled? + resource :confirmation, only: %i[new create show] + end + resource :password, only: %i[new create edit update] + end + end + + devise_scope :user do + resource :account, except: Alchemy::Devise.registrations_enabled? ? [] : %i[new create] + end + end + namespace :admin, { path: Alchemy.admin_path, constraints: Alchemy.admin_constraints diff --git a/lib/alchemy/devise.rb b/lib/alchemy/devise.rb index 65eb8a2..658e1dd 100644 --- a/lib/alchemy/devise.rb +++ b/lib/alchemy/devise.rb @@ -6,12 +6,12 @@ module Alchemy # === Default modules # # [ - #. :database_authenticatable, + # :database_authenticatable, # :trackable, # :validatable, # :timeoutable, # :recoverable - #. ] + # ] # # If you want to add additional modules into the Alchemy user class append # them to this collection in an initializer in your app. @@ -36,6 +36,25 @@ def self.devise_modules ] end + def self.devise_modules=(modules) + @devise_modules = modules + end + module Devise + def self.enable_user_accounts? + @enable_user_accounts ||= false + end + + def self.enable_user_accounts=(val) + @enable_user_accounts = val + end + + def self.registrations_enabled? + Alchemy.devise_modules.include?(:registerable) + end + + def self.confirmations_enabled? + Alchemy.devise_modules.include?(:confirmable) + end end end diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb new file mode 100644 index 0000000..f8c4457 --- /dev/null +++ b/spec/controllers/accounts_controller_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +describe Alchemy::AccountsController do + routes { Alchemy::Engine.routes } + + context 'with user accounts enabled' do + before do + allow(Alchemy::Devise).to receive(:enable_user_accounts?) { true } + Rails.application.reload_routes! + @request.env["devise.mapping"] = Devise.mappings[:user] + end + + describe '#show' do + let(:user) { create(:alchemy_member_user) } + + context 'with authorized user' do + before { authorize_user(user) } + + render_views + + it 'shows account' do + get :show + is_expected.to render_template(:show) + end + end + + context 'with unauthorized user' do + it 'redirects to login' do + get :show + is_expected.to redirect_to(login_path) + end + + it 'stores current location' do + get :show + expect(session[:user_return_to]).to eq(account_path) + end + + it 'shows warning message' do + get :show + expect(flash[:warning]).to eq I18n.t(:unauthenticated, scope: 'devise.failure') + end + end + end + end +end diff --git a/spec/controllers/confirmations_controller_spec.rb b/spec/controllers/confirmations_controller_spec.rb new file mode 100644 index 0000000..c34af7b --- /dev/null +++ b/spec/controllers/confirmations_controller_spec.rb @@ -0,0 +1,46 @@ +require 'rails_helper' + +describe Alchemy::ConfirmationsController do + routes { Alchemy::Engine.routes } + + context 'with user accounts enabled' do + before do + allow(Alchemy::Devise).to receive(:enable_user_accounts?) { true } + end + + context 'with confirmations enabled' do + let(:user) { double(email: 'mail@example.com') } + + before do + allow(Alchemy::Devise).to receive(:confirmations_enabled?) { true } + Rails.application.reload_routes! + @request.env["devise.mapping"] = Devise.mappings[:user] + expect(Alchemy::User).to receive(:send_confirmation_instructions) { user } + end + + describe '#create' do + context 'with valid params' do + before do + expect(user).to receive(:errors) { [] } + end + + it "redirects to account" do + post :create, params: {user: {email: user.email}} + expect(response).to redirect_to(login_path) + end + end + + context 'without valid params' do + before do + expect(user).to receive(:errors).twice { ['Email not found'] } + end + + it "renders form" do + post :create, params: {user: {email: 'not@found'}} + is_expected.to render_template(:new) + end + end + end + end + end +end diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb new file mode 100644 index 0000000..e8108b1 --- /dev/null +++ b/spec/controllers/passwords_controller_spec.rb @@ -0,0 +1,34 @@ +require 'rails_helper' + +describe Alchemy::PasswordsController do + routes { Alchemy::Engine.routes } + + context 'with user accounts enabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = true + Rails.application.reload_routes! + end + + before do + @request.env["devise.mapping"] = Devise.mappings[:user] + end + + let!(:user) { create(:alchemy_user) } + + describe '#create' do + context 'with valid params' do + it "redirects to login" do + post :create, params: {user: {email: user.email}} + expect(response).to redirect_to(login_path) + end + end + + context 'without valid params' do + it "renders form" do + post :create, params: {user: {email: 'not@found'}} + is_expected.to render_template(:new) + end + end + end + end +end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb new file mode 100644 index 0000000..751d423 --- /dev/null +++ b/spec/controllers/sessions_controller_spec.rb @@ -0,0 +1,64 @@ +require 'rails_helper' + +describe Alchemy::SessionsController do + routes { Alchemy::Engine.routes } + + context 'with user accounts enabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = true + Rails.application.reload_routes! + end + + before do + @request.env["devise.mapping"] = Devise.mappings[:user] + end + + let(:user) { create(:alchemy_user) } + + describe '#create' do + context 'with valid user' do + let(:user_params) do + { + login: user.login, + password: 's3cr3t' + } + end + + before { user } + + context 'without redirect path in session' do + it "redirects to account" do + post :create, params: {user: user_params} + expect(response).to redirect_to(account_path) + end + end + + context 'with redirect path in session' do + it "redirects to these params" do + session[:user_return_to] = '/secret_page' + post :create, params: {user: user_params} + expect(response).to redirect_to('/secret_page') + end + end + + context 'without valid params' do + it "renders login form" do + post :create, params: {user: {login: ''}} + is_expected.to render_template(:new) + end + end + end + end + + describe "#destroy" do + before do + authorize_user(user) + end + + it "redirects to root" do + delete :destroy + is_expected.to redirect_to(root_path) + end + end + end +end diff --git a/spec/mailers/notifications_spec.rb b/spec/mailers/notifications_spec.rb index 377735b..6ebfffd 100644 --- a/spec/mailers/notifications_spec.rb +++ b/spec/mailers/notifications_spec.rb @@ -78,5 +78,43 @@ module Alchemy expect(mail.body.raw_source).to match /#{Regexp.escape(admin_edit_password_url(user, reset_password_token: token, only_path: true))}/ end end + + context 'with user accounts and confirmations enabled' do + before do + allow(Alchemy::Devise).to receive(:enable_user_accounts?) { true } + allow(Alchemy::Devise).to receive(:confirmations_enabled?) { true } + Rails.application.reload_routes! + end + + describe '#confirmation_instructions' do + let(:user) do + mock_model 'User', + alchemy_roles: %w(member), + email: 'jon@doe.com', + name: 'John Doe', + login: 'jon.doe', + fullname: 'John Doe' + end + + let(:token) { '123456789' } + + let(:mail) do + Notifications.confirmation_instructions(user, token) + end + + it "delivers a mail to user" do + expect(mail.to).to eq([user.email]) + expect(mail.subject).to eq('Account confirmation instructions') + end + + it "mail body includes users name" do + expect(mail.body.raw_source).to match /#{user.fullname}/ + end + + it "mail body includes reset instructions" do + expect(mail.body.raw_source).to match /#{Regexp.escape(confirmation_url(user, confirmation_token: token, only_path: true))}/ + end + end + end end end diff --git a/spec/routing/account_routing_spec.rb b/spec/routing/account_routing_spec.rb new file mode 100644 index 0000000..2152781 --- /dev/null +++ b/spec/routing/account_routing_spec.rb @@ -0,0 +1,132 @@ +require 'rails_helper' + +describe "Account Routing" do + context 'if user accounts are enabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = true + Rails.application.reload_routes! + end + + it "routes to show account" do + expect({ + get: "/account" + }).to route_to( + controller: "alchemy/accounts", + action: "show" + ) + end + + it "routes to edit account" do + expect({ + get: "/account/edit" + }).to route_to( + controller: "alchemy/accounts", + action: "edit" + ) + end + + it "routes to update account" do + expect({ + patch: "/account" + }).to route_to( + controller: "alchemy/accounts", + action: "update" + ) + end + + it "routes to destroy account" do + expect({ + delete: "/account" + }).to route_to( + controller: "alchemy/accounts", + action: "destroy" + ) + end + + context 'when registrations are enabled' do + before do + allow(Alchemy::Devise).to receive(:registrations_enabled?) { true } + Rails.application.reload_routes! + end + + it "routes to new account" do + expect({ + get: "/account/new" + }).to route_to( + controller: "alchemy/accounts", + action: "new" + ) + end + + it "routes to create account" do + expect({ + post: "/account" + }).to route_to( + controller: "alchemy/accounts", + action: "create" + ) + end + end + end + + context 'if user accounts are disabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = false + Rails.application.reload_routes! + end + + it "does not route to show account" do + expect({ + get: "/account" + }).to_not route_to( + controller: "alchemy/accounts", + action: "show" + ) + end + + it "does not route to edit account" do + expect({ + get: "/account/edit" + }).to_not route_to( + controller: "alchemy/accounts", + action: "edit" + ) + end + + it "does not route to update account" do + expect({ + patch: "/account" + }).to_not route_to( + controller: "alchemy/accounts", + action: "update" + ) + end + + it "does not route to destroy account" do + expect({ + delete: "/account" + }).to_not route_to( + controller: "alchemy/accounts", + action: "destroy" + ) + end + + it "does not route to new account" do + expect({ + get: "/account/new" + }).to_not route_to( + controller: "alchemy/accounts", + action: "new" + ) + end + + it "does not route to create account" do + expect({ + post: "/account" + }).to_not route_to( + controller: "alchemy/accounts", + action: "create" + ) + end + end +end diff --git a/spec/routing/admin_password_routing_spec.rb b/spec/routing/admin_password_routing_spec.rb new file mode 100644 index 0000000..4ac1c23 --- /dev/null +++ b/spec/routing/admin_password_routing_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +describe "Admin Password Routing" do + routes { Alchemy::Engine.routes } + + it "routes to new password" do + expect({ + get: "/admin/passwords" + }).to route_to( + controller: "alchemy/admin/passwords", + action: "new" + ) + end + + it "routes to reset password" do + expect({ + post: "/admin/passwords" + }).to route_to( + controller: "alchemy/admin/passwords", + action: "create" + ) + end + + it "routes to edit password" do + expect({ + get: "/admin/passwords/123/edit/12345" + }).to route_to( + controller: "alchemy/admin/passwords", + action: "edit", + id: "123", + reset_password_token: "12345" + ) + end + + it "routes to update password" do + expect({ + patch: "/admin/passwords" + }).to route_to( + controller: "alchemy/admin/passwords", + action: "update" + ) + end +end diff --git a/spec/routing/admin_user_session_routing_spec.rb b/spec/routing/admin_user_session_routing_spec.rb new file mode 100644 index 0000000..826fb8c --- /dev/null +++ b/spec/routing/admin_user_session_routing_spec.rb @@ -0,0 +1,32 @@ +require 'rails_helper' + +describe "Admin User Session Routing" do + routes { Alchemy::Engine.routes } + + it "routes to login" do + expect({ + get: "/admin/login" + }).to route_to( + controller: "alchemy/admin/user_sessions", + action: "new" + ) + end + + it "routes to create session" do + expect({ + post: "/admin/login" + }).to route_to( + controller: "alchemy/admin/user_sessions", + action: "create" + ) + end + + it "routes to logout" do + expect({ + delete: "/admin/logout" + }).to route_to( + controller: "alchemy/admin/user_sessions", + action: "destroy" + ) + end +end diff --git a/spec/routing/password_routing_spec.rb b/spec/routing/password_routing_spec.rb index 008e577..851c576 100644 --- a/spec/routing/password_routing_spec.rb +++ b/spec/routing/password_routing_spec.rb @@ -1,43 +1,89 @@ require 'rails_helper' describe "Password Routing" do - routes { Alchemy::Engine.routes } - - it "routes to new password" do - expect({ - get: "/admin/passwords" - }).to route_to( - controller: "alchemy/admin/passwords", - action: "new" - ) - end + context 'if user accounts are enabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = true + Rails.application.reload_routes! + end - it "routes to reset password" do - expect({ - post: "/admin/passwords" - }).to route_to( - controller: "alchemy/admin/passwords", - action: "create" - ) - end + it "routes to new password" do + expect({ + get: "/account/password/new" + }).to route_to( + controller: "alchemy/passwords", + action: "new" + ) + end + + it "routes to reset password" do + expect({ + post: "/account/password" + }).to route_to( + controller: "alchemy/passwords", + action: "create" + ) + end + + it "routes to edit password" do + expect({ + get: "/account/password/edit" + }).to route_to( + controller: "alchemy/passwords", + action: "edit" + ) + end - it "routes to edit password" do - expect({ - get: "/admin/passwords/123/edit/12345" - }).to route_to( - controller: "alchemy/admin/passwords", - action: "edit", - id: "123", - reset_password_token: "12345" - ) + it "routes to update password" do + expect({ + patch: "/account/password" + }).to route_to( + controller: "alchemy/passwords", + action: "update" + ) + end end - it "routes to update password" do - expect({ - patch: "/admin/passwords" - }).to route_to( - controller: "alchemy/admin/passwords", - action: "update" - ) + context 'if user accounts are disabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = false + Rails.application.reload_routes! + end + + it "does not route to new password" do + expect({ + get: "/account/password/new" + }).to_not route_to( + controller: "alchemy/passwords", + action: "new" + ) + end + + it "does not route to reset password" do + expect({ + post: "/account/password" + }).to_not route_to( + controller: "alchemy/passwords", + action: "create" + ) + end + + it "does not route to edit password" do + expect({ + get: "/account/password/edit" + }).to_not route_to( + controller: "alchemy/passwords", + action: "edit" + ) + end + + it "does not route to update password" do + expect({ + patch: "/account/password" + }).to_not route_to( + controller: "alchemy/passwords", + action: "update" + ) + end end end diff --git a/spec/routing/session_routing_spec.rb b/spec/routing/session_routing_spec.rb index 0d6b9a9..58b0801 100644 --- a/spec/routing/session_routing_spec.rb +++ b/spec/routing/session_routing_spec.rb @@ -1,32 +1,71 @@ require 'rails_helper' describe "Session Routing" do - routes { Alchemy::Engine.routes } - - it "routes to login" do - expect({ - get: "/admin/login" - }).to route_to( - controller: "alchemy/admin/user_sessions", - action: "new" - ) - end + context 'if user accounts are enabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = true + Rails.application.reload_routes! + end + + it "routes to login" do + expect({ + get: "/account/login" + }).to route_to( + controller: "alchemy/sessions", + action: "new" + ) + end + + it "routes to create session" do + expect({ + post: "/account/login" + }).to route_to( + controller: "alchemy/sessions", + action: "create" + ) + end - it "routes to create session" do - expect({ - post: "/admin/login" - }).to route_to( - controller: "alchemy/admin/user_sessions", - action: "create" - ) + it "routes to logout" do + expect({ + delete: "/account/logout" + }).to route_to( + controller: "alchemy/sessions", + action: "destroy" + ) + end end - it "routes to logout" do - expect({ - delete: "/admin/logout" - }).to route_to( - controller: "alchemy/admin/user_sessions", - action: "destroy" - ) + context 'if user accounts are disabled' do + before(:all) do + Alchemy::Devise.enable_user_accounts = false + Rails.application.reload_routes! + end + + it "does not route to login" do + expect({ + get: "/account/login" + }).to_not route_to( + controller: "alchemy/sessions", + action: "new" + ) + end + + it "does not route to create session" do + expect({ + post: "/account/login" + }).to_not route_to( + controller: "alchemy/sessions", + action: "create" + ) + end + + it "does not route to logout" do + expect({ + delete: "/account/logout" + }).to_not route_to( + controller: "alchemy/sessions", + action: "destroy" + ) + end end end