Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#161789] Access List Enhancements #3983

Merged
merged 15 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 40 additions & 36 deletions app/assets/javascripts/_common.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,69 @@
function submitAjaxForm(e) {
e.preventDefault(); //Prevent the normal submission action
var form = $(this);
var submit = $("input[type='submit']", form);
var submit_val = submit.val();
submit.val("Please Wait...");
submit.attr("disabled", true);
jQuery.ajax({
type: "get",
data: form.serialize(),
url: form.attr("action"),
timeout: 25000,
success: function (r) {
$("#result").html(r);
submit.val(submit_val);
submit.attr("disabled", false);
},
error: function () {
$("#result").html(
"<p>There was an error retrieving results. Please try again.</p>"
);
submit.val(submit_val);
submit.attr("disabled", false);
},
});
};

$(document).ready(function() {
if ($('#login') && $('#username')) {
$('#username').focus();
if ($("#login") && $("#username")) {
$("#username").focus();
}

$('.link_select').change(function(e) {
$(".link_select").change(function(e) {
window.location = this.value;
});

$('form#ajax_form').submit(function(e){
e.preventDefault(); //Prevent the normal submission action
var form = $(this);
var submit = $("input[type='submit']",form);
var submit_val = submit.val();
submit.val("Please Wait...");
submit.attr("disabled", true);
jQuery.ajax({
type: "get",
data: form.serialize(),
url: form.attr('action'),
timeout: 25000,
success: function(r) {
$('#result').html(r);
submit.val(submit_val);
submit.attr("disabled", false);
},
error: function() {
$('#result').html('<p>There was an error retrieving results. Please try again.</p>');
submit.val(submit_val);
submit.attr("disabled", false);
}
});
});
$("form#ajax_form").submit(submitAjaxForm);

$('#content').click(function(e){
$("#content").click(function(e){
var element = $(e.target);
if (element.is('a') && element.parents('div.ajax_links').length == 1) {
if (element.is("a") && element.parents("div.ajax_links").length == 1) {
e.preventDefault(); //Prevent the normal action
jQuery.ajax({
url: element.attr('href'),
url: element.attr("href"),
timeout: 25000,
success: function(r) {
$('#result').html(r);
$("#result").html(r);
},
error: function() {
$('#result').html('<p>There was an error retrieving results. Please try again.</p>');
$("#result").html("<p>There was an error retrieving results. Please try again.</p>");
}
});
} else {
return;
}
});

$('.sync_select').change(function(e) {
$(".sync_select").change(function(e) {
var selected_value = this.value;
$('.sync_select[name='+this.name+']').each(function(e) {
$(`.sync_select[name=${this.name}]`).each(function(e) {
this.value = selected_value;
});
});

$('#filter_toggle').click(function(){
$('#filter_container').toggle('fast');
$("#filter_toggle").click(function(){
$("#filter_container").toggle("fast");
});

});
Expand Down
4 changes: 4 additions & 0 deletions app/assets/stylesheets/app/user_product_access_list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
margin-bottom: 0px;
}
}

.inline {
display: inline;
}
35 changes: 28 additions & 7 deletions app/controllers/product_users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class ProductUsersController < ApplicationController

layout "two_column"

USERS_PER_PAGE = 50

def initialize
@active_tab = "admin_products"
super
Expand All @@ -24,12 +26,6 @@ def initialize
# GET /facilities/:facility_id/services/service_id/users
def index
if @product.requires_approval?
all_product_users = @product
.product_users
.includes(:user)
.includes(:product_access_group)
.order("users.last_name ASC", "users.first_name ASC")

respond_to do |format|
format.csv do
# used for "Export as CSV" link
Expand All @@ -40,7 +36,7 @@ def index
end

format.html do
@product_users = all_product_users.paginate(page: params[:page])
@product_users = all_product_users.paginate(page: params[:page], per_page: USERS_PER_PAGE)
end
end
else
Expand All @@ -49,6 +45,18 @@ def index
end
end

# GET /facilities/:facility_id/bundles/bundle_id/users/search
# GET /facilities/:facility_id/instruments/instrument_id/users/search
# GET /facilities/:facility_id/items/item_id/users/search
# GET /facilities/:facility_id/services/service_id/users/search
def search
@product_users = all_product_users(params[:search]).paginate(page: params[:page], per_page: USERS_PER_PAGE)

@search_term = params[:search]

render layout: false
end

# GET /facilities/:facility_id/bundles/bundle_id/users/new
# GET /facilities/:facility_id/instruments/instrument_id/users/new
# GET /facilities/:facility_id/items/item_id/users/new
Expand Down Expand Up @@ -105,6 +113,19 @@ def update_restrictions

private

def all_product_users(search_term = nil)
product_users = @product
.product_users
.includes(:user)
.includes(:product_access_group)

if search_term.present?
product_users = product_users.where("LOWER(users.last_name) LIKE :search OR LOWER(users.first_name) LIKE :search OR LOWER(users.username) LIKE :search", search: search_term)
end

product_users.order("users.last_name ASC", "users.first_name ASC")
end

def downcase_product_type
@product.class.model_name.human.downcase
end
Expand Down
4 changes: 3 additions & 1 deletion app/lib/facility_product_routing_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ module FacilityProductRoutingConcern

def facility_product_routing_concern
get :manage, on: :member
resources :users, controller: "product_users", except: [:show, :edit, :create]
resources :users, controller: "product_users", except: [:show, :edit, :create] do
get "search", on: :collection
end
resources :file_uploads, path: "files", only: [:index, :create, :destroy]
get "/files/:file_type/:id", to: "file_uploads#download", as: "download_product_file"
end
Expand Down
5 changes: 5 additions & 0 deletions app/views/product_users/_export_csv.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
= form_tag polymorphic_path([current_facility, @product, :users], format: :csv), method: :get, class: "search_form inline" do
= hidden_field_tag :email, current_user.email, disabled: true
= hidden_field_tag :format, params[:format], disabled: true

= link_to t("reports.product_users.export"), url_for(format: :csv), class: "js--exportSearchResults pull-right", data: { form: ".search_form" }
2 changes: 2 additions & 0 deletions app/views/product_users/_table.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@
= pu.select :product_access_group_id,
options_from_collection_for_select(@product.product_access_groups, "id", "name", product_user.product_access_group_id),
include_blank: true

= will_paginate(@product_users)
33 changes: 33 additions & 0 deletions app/views/product_users/_users_results.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
:javascript
$(document).ready(function() {
$("form#ajax_form").submit(submitAjaxForm);
})

#result
- if @product_users.present? || @search_term
-# There are users to search for or the search action was performed
= form_tag polymorphic_path([:search, current_facility, @product, :users]), id: "ajax_form", class: "inline", method: :get do
= label_tag :access_list_search, text("search_form.label")
= text_field_tag :search, nil, size: 50, class: "search-query", id: "access_list_search", value: @search_term
= submit_tag text("search_form.button"), class: "btn"

- if @product_users.nil?
- # Access list not required for this product
- elsif @product_users.empty? && @search_term
- # search results returned empty
%p.notice= text("no_results")
- elsif @product_users.empty?
- # no users have access to this product, no search was performed
%p.notice= text("empty_access_list")
- else
- if @search_term.blank?
-# Search action wasn't performed or it was performed with the empty string
= render "export_csv"

- if @product.has_product_access_groups?
= form_for @product, url: [current_facility, @product, :update_restrictions], method: :put do |f|
= render "table", f: f
= f.submit text("update", plural_label: ProductAccessGroup.model_name.human.pluralize),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this translation still work in the new partial?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

class: ["btn", "btn-primary"]
- else
= render "table"
20 changes: 1 addition & 19 deletions app/views/product_users/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,4 @@
= text("import_button")
%span{ style:"display:none" }= f.file_field :file, onchange: "form.submit()"

- if @product_users.nil?
- elsif @product_users.empty?
%p.notice= text("none")
giladshanan marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's an entry for this in config/locales/views/admin/en.product_users.yml:7 that can be removed now

- else
= form_tag polymorphic_path([current_facility, @product, :users], format: :csv), method: :get, class: "search_form" do
= hidden_field_tag :email, current_user.email, disabled: true
= hidden_field_tag :format, params[:format], disabled: true

= link_to t("reports.product_users.export"), url_for(format: :csv), class: "js--exportSearchResults pull-right", data: { form: ".search_form" }

- if @product.has_product_access_groups?
= form_for @product, url: [current_facility, @product, :update_restrictions], method: :put do |f|
= render "table", f: f
= f.submit text("update", plural_label: ProductAccessGroup.model_name.human.pluralize),
class: ["btn", "btn-primary"]
- else
= render "table"

= will_paginate(@product_users)
= render "users_results"
1 change: 1 addition & 0 deletions app/views/product_users/search.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
= render "users_results"
16 changes: 10 additions & 6 deletions config/locales/views/admin/en.product_users.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ en:
index:
header: Approved Users
add: Add Approved User
none: No users are currently approved.
update: Update %{plural_label}
import_button: Import Approved Users
import_hint: |
This %{product_type} requires a user to be approved before they can make a
reservation or purchase. Users can be approved individually or a list can be imported.
When importing, create a CSV file with a single column titled ‘Username’
This %{product_type} requires a user to be approved before they can make a
reservation or purchase. Users can be approved individually or a list can be imported.
When importing, create a CSV file with a single column titled ‘Username’
(!sso_id_downcase! or email). New users are added to the existing access list.
users_results:
no_results: No users found.
empty_access_list: No users are currently approved.
search_form:
button: Search
label: Search by name, or username
update: Update %{plural_label}

table:
confirm_removal: |
Are you sure you wish to remove this user from this %{product_type}?

46 changes: 46 additions & 0 deletions spec/system/admin/access_list_tab_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,44 @@

require "rails_helper"

RSpec.shared_examples_for "search for a user" do
context "search for a user", :js do
let(:user_searchable) { create(:user, first_name: "John", last_name: "Doe", username: "jdoe") }
let(:user_not_found) { create(:user, first_name: "Jane", last_name: "Holmes", username: "jholmes") }

before do
create(:product_user, product:, user: user_not_found)
create(:product_user, product:, user: user_searchable)
visit polymorphic_path([:manage, facility, product])
click_link "Access List"
end

it "searches for users by first name" do
fill_in "access_list_search", with: "John"
click_button "Search"
wait_for_ajax
expect(page).to have_content(user_searchable.last_first_name)
expect(page).to_not have_content(user_not_found.last_first_name)
end

it "searches for users by last name" do
fill_in "access_list_search", with: "Doe"
click_button "Search"
wait_for_ajax
expect(page).to have_content(user_searchable.last_first_name)
expect(page).to_not have_content(user_not_found.last_first_name)
end

it "searches for users by username" do
fill_in "access_list_search", with: "jdoe"
click_button "Search"
wait_for_ajax
expect(page).to have_content(user_searchable.last_first_name)
expect(page).to_not have_content(user_not_found.last_first_name)
end
end
end

RSpec.describe "Access List Tab for various product types", :js do
let(:facility) { create(:setup_facility) }
let(:director) { create(:user, :facility_director, facility: facility) }
Expand All @@ -24,6 +62,8 @@
it "renders the page" do
expect(page.current_path).to eq polymorphic_path([facility, product, :users])
end

it_behaves_like "search for a user"
end

context "with an item" do
Expand All @@ -36,6 +76,8 @@
it "renders the page" do
expect(page.current_path).to eq polymorphic_path([facility, product, :users])
end

it_behaves_like "search for a user"
end

context "with a service" do
Expand All @@ -48,6 +90,8 @@
it "renders the page" do
expect(page.current_path).to eq polymorphic_path([facility, product, :users])
end

it_behaves_like "search for a user"
end

context "with a timed service" do
Expand All @@ -60,5 +104,7 @@
it "renders the page" do
expect(page.current_path).to eq polymorphic_path([facility, product, :users])
end

it_behaves_like "search for a user"
end
end
Loading