Skip to content

Commit

Permalink
Add basic CRUD operations for the proxy user feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
renspr committed Jan 16, 2024
1 parent 76bd052 commit 90dc6ad
Show file tree
Hide file tree
Showing 16 changed files with 323 additions and 7 deletions.
175 changes: 175 additions & 0 deletions app/controllers/account/proxy_users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
class Account::ProxyUsersController < Account::ApplicationController

before_action -> { add_breadcrumb t("account.proxy_users.breadcrumb.index"), account_proxy_users_path }
before_action -> { add_breadcrumb t("account.proxy_users.breadcrumb.new"), new_account_proxy_user_path }, only: [:new, :create]
before_action -> { add_breadcrumb t("account.proxy_users.breadcrumb.edit"), edit_account_proxy_user_path }, only: [:edit, :update]

def index
@proxy_users = current_user.proxy_users
end

def new
if params[:barcode].present?
ils_user = Ils.get_user(params[:barcode])

unless ils_user
flash[:error] = t(".lookup.no_user_found_error", barcode: params[:barcode])
redirect_to new_account_proxy_user_path and return
end

ensure_proxy_is_not_self(ils_user.id) or return
ensure_proxy_is_unique(ils_user.id) or return

@proxy_user = current_user.proxy_users.build(
ils_primary_id: ils_user.id,
name: ils_user.full_name
)
else
@proxy_user = current_user.proxy_users.build
end
end

def create
ProxyUser.transaction do
@proxy_user = current_user.proxy_users.build(proxy_user_params)

ensure_proxy_is_not_self(@proxy_user.ils_primary_id) or return
ensure_proxy_is_unique(@proxy_user.ils_primary_id) or return

if @proxy_user.save
if create_proxy_user_in_alma(@proxy_user)
flash[:success] = t(".success")
redirect_to account_proxy_users_path
else
flash[:error] = t(".error")
redirect_to account_proxy_users_path
raise ActiveRecord::Rollback
end
else
render :new, status: :unprocessable_entity
end
end
end

def edit
@proxy_user = current_user.proxy_users.find(params[:id])
end

def update
@proxy_user = current_user.proxy_users.find(params[:id])

if @proxy_user.update(proxy_user_params)
flash[:success] = t(".success")
redirect_to account_proxy_users_path
else
render :edit, status: :unprocessable_entity
end
end

def destroy
ProxyUser.transaction do
@proxy_user = current_user.proxy_users.find(params[:id])

if @proxy_user.destroy
if delete_proxy_user_in_alma(@proxy_user)
flash[:success] = t(".success")
redirect_to account_proxy_users_path
else
flash[:error] = t(".error")
redirect_to account_proxy_users_path
raise ActiveRecord::Rollback
end
end
end
end

private

def proxy_user_params
params.require(:proxy_user).permit(:ils_primary_id, :name, :note, :expired_at)
end

def create_proxy_user_in_alma(proxy_user)
user_id = proxy_user.ils_primary_id
user_details = get_user_details_from_alma(user_id)
return false unless user_details

# Get the existing proxies, or initialize an empty array
# in case there are no proxies yet
proxies = user_details["proxy_for_user"] ||= []

# Check if the proxy user already exists in Alma. This can happen if the
# proxy user was created in Alma directly
return true if proxies.any? { |p| p["primary_id"].downcase == current_user.ils_primary_id.downcase }

# Add the proxy user for the current user
proxies << {
primary_id: current_user.ils_primary_id
}
user_details["proxy_for_user"] = proxies

# Update the user in Alma
update_user_details_in_alma(user_id, user_details)
end

def delete_proxy_user_in_alma(proxy_user)
user_id = proxy_user.ils_primary_id
user_details = get_user_details_from_alma(user_id)
return false unless user_details

# Get the existing proxies, or initialize an empty array
# in case there are no proxies yet
proxies = user_details["proxy_for_user"] ||= []

# Check if the proxy user exists in Alma. This can happen if the
# proxy user was deleted in Alma directly
return true if proxies.none? { |p| p["primary_id"].downcase == current_user.ils_primary_id.downcase }

# Remove the proxy user for the current user
user_details["proxy_for_user"] = proxies.reject do |p|
p["primary_id"].downcase == current_user.ils_primary_id.downcase
end

# Update the user in Alma
update_user_details_in_alma(user_id, user_details)
end

# Note: We use the Alma API directly in #get_user_details_from_alma and
# #update_user_details_in_alma, rather than the Ils adapter. This
# creates a direct dependecy on the Alma API. This is not ideal, but the
# the proxy user feature is an Alma specific feature anyway, so we skip the
# abstraction for now.

def get_user_details_from_alma(user_id)
Ils.adapter.api.get("users/#{user_id}")
rescue AlmaApi::Error
nil
end

def update_user_details_in_alma(user_id, user_details)
Ils.adapter.api.put("users/#{user_id}", body: user_details.to_json)
true
rescue AlmaApi::Error => e
Rails.logger.error(["Error updating user in Alma [#{e.code}]: #{e.message}", *e.backtrace].join($/))
false
end

def ensure_proxy_is_not_self(user_id)
if user_id&.downcase == current_user.ils_primary_id.downcase
flash[:error] = t(".cannot_proxy_self_error")
redirect_to new_account_proxy_user_path and return
end

true
end

def ensure_proxy_is_unique(user_id)
if current_user.proxy_users.exists?(ils_primary_id: user_id)
flash[:error] = t(".already_exists_error", barcode: user_id)
redirect_to new_account_proxy_user_path and return
end

true
end

end
9 changes: 6 additions & 3 deletions app/models/proxy_user.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
class ProxyUser < ApplicationUser
class ProxyUser < ApplicationRecord

belongs_to :user

validates :ils_primary_id, presence: true
validates :label, presence: true
validates :ils_primary_id, presence: true, uniqueness: {scope: :user_id} # rubocop:disable Rails/UniqueValidationWithoutIndex
validates :name, presence: true

# Not stored in the database, but used to lookup the proxy user in the ILS
attribute :barcode, :string

end
3 changes: 3 additions & 0 deletions app/views/account/application/_nav.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@
= link_to account_pin_path, class: "list-group-item list-group-item-action" do
i.fa-solid.fa-fw.fa-shield-halved.me-2
= t(".pin")
= link_to account_proxy_users_path, class: "list-group-item list-group-item-action" do
i.fa-solid.fa-fw.fa-people-arrows.me-2
= t(".proxy_users")
7 changes: 7 additions & 0 deletions app/views/account/proxy_users/_form.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
= simple_form_for [:account, @proxy_user] do |f|
= f.hidden_field :ils_primary_id
= f.input :name, input_html: { readonly: true }
= f.input :note
= f.input :expired_at, as: :date, html5: true, start_year: Date.today.year, prompt: true
= f.button :submit, t("save"), class: "btn btn-primary"
= link_to t("cancel"), account_proxy_users_path, class: "btn btn-link"
16 changes: 16 additions & 0 deletions app/views/account/proxy_users/_proxy_user.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
li.list-group-item.d-flex.justify-content-between.align-items-center
.fw-bold
= proxy_user.name
= " (#{proxy_user.ils_primary_id})"

- if proxy_user.expired_at.present?
span.badge.bg-info.ms-2 = t(".expired_at", date: l(proxy_user.expired_at))

- if proxy_user.note.present?
em: .text_muted = proxy_user.note
div
= link_to edit_account_proxy_user_path(proxy_user), class: "btn btn-primary btn-sm me-2" do
i.fa-solid.fa-edit.fa-fw
= link_to account_proxy_user_path(proxy_user), class: "btn btn-danger btn-sm", \
data: { turbo_method: :delete, turbo_confirm: t(".confirm_delete") } do
i.fa-solid.fa-trash.fa-fw
6 changes: 6 additions & 0 deletions app/views/account/proxy_users/edit.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.card.card-shadowed
.card-header
h5.m-0 = t(".header")
.card-body
= render "alerts"
= render "form"
18 changes: 18 additions & 0 deletions app/views/account/proxy_users/index.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.card.card-shadowed
.card-header.d-flex.align-items-center
h5.m-0
=> t(".header")
.ms-auto = link_to new_account_proxy_user_path, class: "btn btn-primary" do
i.fa-solid.fa-plus.fa-fw.me-1
= t(".new_proxy_user")
.card-body
.callout.callout-info
i.fa-solid.fa-info-circle.fa-fw.fa-lg.me-1
= t(".info")

- if @proxy_users.present?
ol.list-group
= render partial: "proxy_user", collection: @proxy_users
- else
.alert.alert-info.mb-0.text-center
= t(".no_proxy_users")
24 changes: 24 additions & 0 deletions app/views/account/proxy_users/new.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
- if @proxy_user.ils_primary_id.blank?
/ Lookup Form
.card.card-shadowed
.card-header
h5.m-0 = t(".lookup.header")
.card-body
= render "alerts"

= form_tag new_account_proxy_user_path, method: :get do
.input-group
span.input-group-text
i.fa-solid.fa-id-card
=< text_field_tag :barcode, params[:barcode], placeholder: t(".lookup.form.barcode_placeholder"), \
class: "form-control", autofocus: true, autocomplete: "off"
= submit_tag t(".lookup.form.submit"), class: "btn btn-primary"
= link_to t("cancel"), account_proxy_users_path, class: "btn btn-outline-primary"
- else
/ New Form
.card.card-shadowed
.card-header
h5.m-0 = t(".header")
.card-body
= render "alerts"
= render "form"
1 change: 1 addition & 0 deletions config/locales/de/account/application/nav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ de:
profile: Meine Daten
loans_history: Ausleihhistorie
pin: "PIN verwalten"
proxy_users: "Proxy-Users"
44 changes: 44 additions & 0 deletions config/locales/de/account/proxy_users.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
de:
account:
proxy_users:
already_exists_error: "Es existiert bereits ein Proxy-User mit der Bibliotheksausweisnummer '%{barcode}'."
cannot_proxy_self_error: "Sie können sich nicht selbst als Proxy-User einrichten."

proxy_user:
expired_at: "Gültig bis %{date}"
confirm_delete: "Möchten Sie diesen Proxy-User wirklich löschen?"

breadcrumb:
index: "Proxy-Users"
new: "Neuer Proxy-User"
edit: "Proxy-User bearbeiten"

index:
header: "Proxy-Users"
new_proxy_user: "Neuer Proxy-User"
info: >
Sie können hier andere Nutzer berechtigen, in Ihrem Namen bzw. auf Ihr Konto Medien auszuleihen.
no_proxy_users: "Sie haben noch keine Proxy-User eingerichtet."

new:
header: "Neuer Proxy-User"
lookup:
header: "Nutzer suchen"
form:
submit: "Suchen"
barcode_placeholder: "Bibliotheksausweisnummer"
no_user_found_error: "Kein Nutzer mit der Bibliotheksausweisnummer '%{barcode}' gefunden."

create:
error: "Proxy-User konnte nicht eingerichtet werden. Es ist ein Fehler aufgetreten."
success: "Proxy-User wurde erfolgreich eingerichtet."

edit:
header: "Proxy-User bearbeiten"

update:
success: "Proxy-User wurde erfolgreich aktualisiert."

destroy:
error: "Proxy-User konnte nicht gelöscht werden. Es ist ein Fehler aufgetreten."
success: "Proxy-User wurde erfolgreich gelöscht."
11 changes: 11 additions & 0 deletions config/locales/de/simple_form.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ de:
required:
text: 'Erforderliche Angabe'
mark: '*'

labels:
defaults:
user_id: "Ausweisnummer"
Expand All @@ -24,6 +25,11 @@ de:
new_pin: "Neue PIN"
new_pin_confirmation: "Neue PIN wiederholen"

proxy_user:
name: "Name"
note: "Notiz"
expired_at: "Gültig bis"

placeholders:
defaults:
user_id: "Ihre Bibliotheksausweisnummer"
Expand Down Expand Up @@ -61,4 +67,9 @@ de:
Ihre aktuelle PIN ist erforderlich, um die PIN ändern zu können. Wenn Sie Ihre
aktuelle PIN vergessen haben, wenden Sie sich bitte an die Kolleginnen und Kollegen der Ortsleihe.
proxy_user:
note: "Sie können hier eine Notiz hinterlegen, warum Sie diesen Proxy-User eingerichtet haben."
expired_at: >
Wenn Sie hier ein Datum angeben (z.B. Semesterende), wird der Proxy-User automatisch nach diesem Tag gelöscht.
1 change: 1 addition & 0 deletions config/locales/en/account/application/nav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ en:
profile: My Account
loans_history: Lending History
pin: Manage PIN
proxy_users: "Proxy-User"
1 change: 1 addition & 0 deletions config/locales/en/simple_form.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ en:
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
match "authorize", via: [:get, :post], on: :member
end
resource :pin, except: [:destroy]
resources :proxy_users, path: "proxy-users", except: [:show]
end

# Closed stack orders
Expand Down
7 changes: 5 additions & 2 deletions db/migrate/20240110160545_create_proxy_users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ def change
create_table :proxy_users do |t|
t.belongs_to :user, null: false, foreign_key: true
t.string :ils_primary_id, null: false
t.string :label, null: false
t.date :expiry_date
t.string :name, null: false
t.string :note, null: true
t.date :expired_at
t.timestamps
end

add_index :proxy_users, [:user_id, :ils_primary_id], unique: true
end
end
Loading

0 comments on commit 90dc6ad

Please sign in to comment.