Browse Source

CLDC-1091: User Account URLs (#448)

* Works but relies on routes ordering

* Add helper test

* Actually work

* Test edit password auth even though we don't have a route for it

* Add spec description

* Consistency
pull/451/head
baarkerlounger 3 years ago committed by GitHub
parent
commit
8b5be1925c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      app/controllers/users_controller.rb
  2. 9
      app/helpers/user_helper.rb
  3. 2
      app/views/layouts/application.html.erb
  4. 4
      app/views/users/edit.html.erb
  5. 4
      app/views/users/new.html.erb
  6. 28
      app/views/users/show.html.erb
  7. 9
      config/routes.rb
  8. 20
      spec/controllers/users_controller_spec.rb
  9. 16
      spec/features/user_spec.rb
  10. 38
      spec/helpers/user_helper_spec.rb
  11. 15
      spec/requests/users_controller_spec.rb

6
app/controllers/users_controller.rb

@ -10,8 +10,10 @@ class UsersController < ApplicationController
if @user == current_user if @user == current_user
bypass_sign_in @user bypass_sign_in @user
flash[:notice] = I18n.t("devise.passwords.updated") if user_params.key?("password") flash[:notice] = I18n.t("devise.passwords.updated") if user_params.key?("password")
redirect_to account_path
else
redirect_to user_path(@user)
end end
redirect_to user_path(@user)
elsif user_params.key?("password") elsif user_params.key?("password")
format_error_messages format_error_messages
@minimum_password_length = User.password_length.min @minimum_password_length = User.password_length.min
@ -87,7 +89,7 @@ private
end end
def find_resource def find_resource
@user = User.find_by(id: params[:id]) @user = params[:id] ? User.find_by(id: params[:id]) : current_user
end end
def authenticate_scope! def authenticate_scope!

9
app/helpers/user_helper.rb

@ -0,0 +1,9 @@
module UserHelper
def aliased_user_edit(user, current_user)
current_user == user ? edit_account_path : edit_user_path(user)
end
def pronoun(user, current_user)
current_user == user ? "you" : "they"
end
end

2
app/views/layouts/application.html.erb

@ -52,7 +52,7 @@
elsif elsif
component.navigation_item(text: 'Logs', href: case_logs_path) component.navigation_item(text: 'Logs', href: case_logs_path)
component.navigation_item(text: 'Your organisation', href: "/organisations/#{current_user.organisation.id}") component.navigation_item(text: 'Your organisation', href: "/organisations/#{current_user.organisation.id}")
component.navigation_item(text: 'Your account', href: user_path(current_user)) component.navigation_item(text: 'Your account', href: account_path)
component.navigation_item(text: 'Sign out', href: destroy_user_session_path) component.navigation_item(text: 'Sign out', href: destroy_user_session_path)
end end
end end

4
app/views/users/edit.html.erb

@ -36,7 +36,7 @@
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{current_user == @user ? "you" : "they"} a data protection officer?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a data protection officer?", size: "m" }
%> %>
<%= f.govuk_collection_radio_buttons :is_key_contact, <%= f.govuk_collection_radio_buttons :is_key_contact,
@ -44,7 +44,7 @@
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{current_user == @user ? "you" : "they"} a key contact?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a key contact?", size: "m" }
%> %>
<% end %> <% end %>

4
app/views/users/new.html.erb

@ -37,7 +37,7 @@
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{current_user == @user ? "you" : "they"} a data protection officer?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a data protection officer?", size: "m" }
%> %>
<%= f.govuk_collection_radio_buttons :is_key_contact, <%= f.govuk_collection_radio_buttons :is_key_contact,
@ -45,7 +45,7 @@
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{current_user == @user ? "you" : "they"} a key contact?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a key contact?", size: "m" }
%> %>
<% end %> <% end %>

28
app/views/users/show.html.erb

@ -12,66 +12,66 @@
<%= govuk_summary_list do |summary_list| %> <%= govuk_summary_list do |summary_list| %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { 'Name' } row.key { "Name" }
row.value { @user.name } row.value { @user.name }
if current_user == @user || current_user.data_coordinator? if current_user == @user || current_user.data_coordinator?
row.action(visually_hidden_text: 'name', href: edit_user_path, html_attributes: { 'data-qa': 'change-name' }) row.action(visually_hidden_text: "name", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-name" })
else else
row.action() row.action()
end end
end %> end %>
<%= summary_list.row() do |row| <%= summary_list.row() do |row|
row.key { 'Email address' } row.key { "Email address" }
row.value { @user.email } row.value { @user.email }
if current_user == @user || current_user.data_coordinator? if current_user == @user || current_user.data_coordinator?
row.action(visually_hidden_text: 'email address', href: edit_user_path, html_attributes: { 'data-qa': 'change-email' }) row.action(visually_hidden_text: "email address", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-email-address" })
else else
row.action() row.action()
end end
end %> end %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { 'Password' } row.key { "Password" }
row.value { '••••••••' } row.value { "••••••••" }
if current_user == @user if current_user == @user
row.action(visually_hidden_text: 'password', href: password_edit_user_path, html_attributes: { 'data-qa': 'change-password' }) row.action(visually_hidden_text: "password", href: edit_password_account_path, html_attributes: { "data-qa": "change-password" })
else else
row.action() row.action()
end end
end %> end %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { 'Organisation' } row.key { "Organisation" }
row.value { @user.organisation.name } row.value { @user.organisation.name }
row.action() row.action()
end %> end %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { 'Role' } row.key { "Role" }
row.value { @user.role.humanize } row.value { @user.role.humanize }
if current_user.data_coordinator? if current_user.data_coordinator?
row.action(visually_hidden_text: "role", href: edit_user_path, html_attributes: { "data-qa": "role" }) row.action(visually_hidden_text: "role", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-role" })
else else
row.action() row.action()
end end
end %> end %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { 'Data protection officer' } row.key { "Data protection officer" }
row.value { @user.is_data_protection_officer? ? "Yes" : "No" } row.value { @user.is_data_protection_officer? ? "Yes" : "No" }
if current_user.data_coordinator? if current_user.data_coordinator?
row.action(visually_hidden_text: "are #{current_user == @user ? "you" : "they"} a data protection officer?", href: edit_user_path, html_attributes: { "data-qa": "change-are-#{current_user == @user ? "you" : "they"}-a-data-protection-officer" }) row.action(visually_hidden_text: "are #{pronoun(@user, current_user)} a data protection officer?", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-are-#{pronoun(@user, current_user)}-a-data-protection-officer" })
else else
row.action() row.action()
end end
end %> end %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { 'Key contact' } row.key { "Key contact" }
row.value { @user.is_key_contact? ? "Yes" : "No" } row.value { @user.is_key_contact? ? "Yes" : "No" }
if current_user.data_coordinator? if current_user.data_coordinator?
row.action(visually_hidden_text: "are #{current_user == @user ? "you" : "they"} a key contact?", href: edit_user_path, html_attributes: { "data-qa": "change-are-#{current_user == @user ? "you" : "they"}-a-key-contact" }) row.action(visually_hidden_text: "are #{pronoun(@user, current_user)} a key contact?", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-are-#{pronoun(@user, current_user)}-a-key-contact" })
else else
row.action() row.action()
end end

9
config/routes.rb

@ -36,6 +36,7 @@ Rails.application.routes.draw do
devise_scope :user do devise_scope :user do
get "account/password/reset-confirmation", to: "auth/passwords#reset_confirmation" get "account/password/reset-confirmation", to: "auth/passwords#reset_confirmation"
put "account", to: "users#update"
end end
get "/health", to: ->(_) { [204, {}, [nil]] } get "/health", to: ->(_) { [204, {}, [nil]] }
@ -48,12 +49,12 @@ Rails.application.routes.draw do
get "/privacy-notice", to: "content#privacy_notice" get "/privacy-notice", to: "content#privacy_notice"
get "/data-sharing-agreement", to: "content#data_sharing_agreement" get "/data-sharing-agreement", to: "content#data_sharing_agreement"
resources :users do resource :account, only: %i[show edit], controller: "users" do
member do get "edit/password", to: "users#edit_password"
get "password/edit", to: "users#edit_password"
end
end end
resources :users
resources :organisations do resources :organisations do
member do member do
get "details", to: "organisations#details" get "details", to: "organisations#details"

20
spec/controllers/users_controller_spec.rb

@ -0,0 +1,20 @@
require "rails_helper"
RSpec.describe UsersController, type: :controller do
let(:params) { { id: other_user.id } }
let(:user) { FactoryBot.create(:user, :data_coordinator) }
let(:other_user) { FactoryBot.create(:user, organisation: user.organisation) }
before do
sign_in user
end
describe "GET #edit_password" do
context "when trying to view the edit page for another user in your organisation" do
it "does not let you and returns not found" do
get :edit_password, params: params
expect(response).to have_http_status(:not_found)
end
end
end
end

16
spec/features/user_spec.rb

@ -182,13 +182,13 @@ RSpec.describe "User Features" do
end end
it "does not have change links for dpo and key contact" do it "does not have change links for dpo and key contact" do
visit("/users/#{user.id}") visit("/account")
expect(page).not_to have_selector('[data-qa="change-are-you-a-data-protection-officer"]') expect(page).not_to have_selector('[data-qa="change-are-you-a-data-protection-officer"]')
expect(page).not_to have_selector('[data-qa="change-are-you-a-key-contact"]') expect(page).not_to have_selector('[data-qa="change-are-you-a-key-contact"]')
end end
it "does not have dpo and key contact as editable fields" do it "does not have dpo and key contact as editable fields" do
visit("/users/#{user.id}/edit") visit("/account/edit")
expect(page).not_to have_field("user[is_dpo]") expect(page).not_to have_field("user[is_dpo]")
expect(page).not_to have_field("user[is_key_contact]") expect(page).not_to have_field("user[is_key_contact]")
end end
@ -210,31 +210,31 @@ RSpec.describe "User Features" do
visit("/logs") visit("/logs")
expect(page).to have_link("Your account") expect(page).to have_link("Your account")
click_link("Your account") click_link("Your account")
expect(page).to have_current_path("/users/#{user.id}") expect(page).to have_current_path("/account")
end end
it "can navigate to change your password page from main account page" do it "can navigate to change your password page from main account page" do
visit("/users/#{user.id}") visit("/account")
find('[data-qa="change-password"]').click find('[data-qa="change-password"]').click
expect(page).to have_content("Change your password") expect(page).to have_content("Change your password")
fill_in("user[password]", with: "Password123!") fill_in("user[password]", with: "Password123!")
fill_in("user[password_confirmation]", with: "Password123!") fill_in("user[password_confirmation]", with: "Password123!")
click_button("Update") click_button("Update")
expect(page).to have_current_path("/users/#{user.id}") expect(page).to have_current_path("/account")
end end
it "allow user to change name" do it "allow user to change name" do
visit("/users/#{user.id}") visit("/account")
find('[data-qa="change-name"]').click find('[data-qa="change-name"]').click
expect(page).to have_content("Change your personal details") expect(page).to have_content("Change your personal details")
fill_in("user[name]", with: "Test New") fill_in("user[name]", with: "Test New")
click_button("Save changes") click_button("Save changes")
expect(page).to have_current_path("/users/#{user.id}") expect(page).to have_current_path("/account")
expect(page).to have_content("Test New") expect(page).to have_content("Test New")
end end
it "has dpo and key contact as editable fields" do it "has dpo and key contact as editable fields" do
visit("/users/#{user.id}") visit("/account")
expect(page).to have_selector('[data-qa="change-are-you-a-data-protection-officer"]') expect(page).to have_selector('[data-qa="change-are-you-a-data-protection-officer"]')
expect(page).to have_selector('[data-qa="change-are-you-a-key-contact"]') expect(page).to have_selector('[data-qa="change-are-you-a-key-contact"]')
end end

38
spec/helpers/user_helper_spec.rb

@ -0,0 +1,38 @@
require "rails_helper"
RSpec.describe UserHelper do
let(:current_user) { FactoryBot.create(:user, :data_coordinator) }
let(:user) { FactoryBot.create(:user, :data_coordinator) }
describe "aliased_user_edit" do
context "when the current logged in user is the same as the user being viewed" do
let(:user) { current_user }
it "returns the edit account path" do
expect(aliased_user_edit(user, current_user)).to eq(edit_account_path)
end
end
context "when the current logged in user is not the same as the user being viewed" do
it "returns the edit user path" do
expect(aliased_user_edit(user, current_user)).to eq(edit_user_path(user))
end
end
end
describe "pronoun" do
context "when the current logged in user is the same as the user being viewed" do
let(:user) { current_user }
it "returns 'you'" do
expect(pronoun(user, current_user)).to eq("you")
end
end
context "when the current logged in user is not the same as the user being viewed" do
it "returns 'they'" do
expect(pronoun(user, current_user)).to eq("they")
end
end
end
end

15
spec/requests/users_controller_spec.rb

@ -34,7 +34,7 @@ RSpec.describe UsersController, type: :request do
describe "#password" do describe "#password" do
it "does not let you edit user passwords" do it "does not let you edit user passwords" do
get "/users/#{user.id}/password/edit", headers: headers, params: {} get "/account/edit/password", headers: headers, params: {}
expect(response).to redirect_to("/account/sign-in") expect(response).to redirect_to("/account/sign-in")
end end
end end
@ -63,7 +63,7 @@ RSpec.describe UsersController, type: :request do
before do before do
sign_in user sign_in user
put "/users/#{user.id}", headers: headers, params: params put "/account", headers: headers, params: params
end end
it "shows an error if passwords don't match" do it "shows an error if passwords don't match" do
@ -204,7 +204,7 @@ RSpec.describe UsersController, type: :request do
context "when the current user matches the user ID" do context "when the current user matches the user ID" do
before do before do
sign_in user sign_in user
get "/users/#{user.id}/password/edit", headers: headers, params: {} get "/account/edit/password", headers: headers, params: {}
end end
it "shows the edit password page" do it "shows the edit password page" do
@ -453,7 +453,7 @@ RSpec.describe UsersController, type: :request do
context "when the current user matches the user ID" do context "when the current user matches the user ID" do
before do before do
sign_in user sign_in user
get "/users/#{user.id}/password/edit", headers: headers, params: {} get "/account/edit/password", headers: headers, params: {}
end end
it "shows the edit password page" do it "shows the edit password page" do
@ -468,11 +468,12 @@ RSpec.describe UsersController, type: :request do
context "when the current user does not matches the user ID" do context "when the current user does not matches the user ID" do
before do before do
sign_in user sign_in user
get "/users/#{other_user.id}/password/edit", headers: headers, params: {}
end end
it "returns not found 404" do it "there is no route" do
expect(response).to have_http_status(:not_found) expect {
get "/users/#{other_user.id}/password/edit", headers: headers, params: {}
}.to raise_error(ActionController::RoutingError)
end end
end end
end end

Loading…
Cancel
Save