OPAC development
I'm writing this as I deconstruct how the current OPAC (as of January 2008) works, largely for my own memory, but perhaps this will be helpful to others.
How the OPAC makes OpenSRF calls
I needed to figure out which OpenSRF call was being made by a function in the OPAC so that I could adjust its behavior. The problem was that an OpenSRF call was returning a string literal of '0' for a "username not found" result, which in JavaScript's type coercion environment could easily be interpreted as a numeric 0, which would map to another user's ID and cause further confusion. We wanted to change the call to return an explicit null
instead. Here's how I figured out what needed to change:
- The problem was occurring on the "My OPAC" page, with a URL of
https://localhost/opac/en-US/skin/default/xml/myopac.xml
. I viewed the source and found the following chunk of code implementing the "change username" widget:<tr id='myopac_update_username_row' class='hide_me'> <td class='myopac_update_cell' colspan='3'> <span class='myopac_update_span'>Enter new username: </span> <input type='text' size='24' id='myopac_new_username' onkeydown='if(userPressedEnter(event)) myOPACUpdateUsername();'></input> <span class='myopac_update_span'> <button onclick='myOPACUpdateUsername();'>Submit</button> </span> <span class='myopac_update_span'> <button onclick='hideMe($("myopac_update_username_row"));'>Cancel</button> </span> </td> </tr>
From this, I was able to determine that the JavaScript method of interest was
myOPACUpdateUsername()
. - Then I grepped for the function definition of that method. There are two main directories containing JavaScript files of interest to the OPAC:
dan@denials:~/source/Evergreen-trunk$ grep "function\s*myOPACUpdateUsername" Open-ILS/web/opac/common/js/*js dan@denials:~/source/Evergreen-trunk$ grep "function\s*myOPACUpdateUsername" Open-ILS/web/opac/skin/default/js/*js Open-ILS/web/opac/skin/default/js/myopac.js:function myOPACUpdateUsername() {
Okay – success, it's in
Open-ILS/web/opac/skin/default/js/myopac.js
! - The pertinent chunk of code in the function definition is as follows:
function myOPACUpdateUsername() { var username = $('myopac_new_username').value; ... /* first see if the requested username is taken */ var req = new Request(CHECK_USERNAME, G.user.session, username); req.send(true); var res = req.result(); if( res && res == G.user.id() ) { alertId('myopac_username_dup'); return; }
Calls to OpenSRF methods from JavaScript are routed through a
Request
object. TheRequest
object is defined inOpen-ILS/web/opac/common/js/opac_utils.js
. - The first parameter in the
Request
object initializer is a variable defined inOpen-ILS/web/common/js/config.js
.var CHECK_USERNAME = 'open-ils.actor:open-ils.actor.username.exists';
This is the OpenSRF method of interest. So now we just have to find it and change its behaviour.
- So we're back to grepping the source code. At this point, most of the OpenSRF methods are defined in Perl, so let's start there:
dan@denials: $ find Open-ILS/src/perlmods/OpenILS/ -name "*.pm" -exec grep -H open-ils.actor.username.exists {} \; Open-ILS/src/perlmods/OpenILS/Application/Actor.pm: api_name => 'open-ils.actor.username.exists'
Bingo!
- The relevant Perl code that implements that method is:
__PACKAGE__->register_method( method => 'usrname_exists', api_name => 'open-ils.actor.username.exists', signature => q/ Returns 1 if the requested username exists, returns 0 otherwise / ); sub usrname_exists { my( $self, $conn, $auth, $usrname ) = @_; my $e = new_editor(authtoken=>$auth); return $e->event unless $e->checkauth; my $a = $e->search_actor_user({usrname => $usrname, deleted=>'f'}, {idlist=>1}); return $$a[0] if $a and @$a; return 0; }
To make this method return
null
if the username does not exist, we change the finalreturn 0;
toreturn undef;
to return an empty payload from the method. We also adjust the method documentation accordingly. - We adjust the code in
myopac.js
to handle the new expectations and sprinkle some comments while we're there:function myOPACUpdateUsername() { var username = $('myopac_new_username').value; ... /* first see if the requested username is taken */ var req = new Request(CHECK_USERNAME, G.user.session, username); req.send(true); var res = req.result(); /* If the username does not already exist, res will be null; * we can move on to updating the username. * * If the username does exist, then res will be the user ID. * G.user.id() gives us the currently authenticated user ID. * If res == G.user.id(), we try to update the username anyways. */ if( res != null && res != G.user.id() ) { alertId('myopac_username_dup'); return; }
Then we test it out – and find that it works successfully. Hurray!
- Now let's find any other places that method is called and repair them accordingly. First we'll check for the OpenSRF method name:
dan@denials: $ find . -exec grep -H "open-ils.actor.username.exists" {} \; | grep -v svn ./Open-ILS/src/perlmods/OpenILS/Application/Actor.pm: api_name => 'open-ils.actor.username.exists', ./Open-ILS/xul/staff_client/build/chrome/content/OpenILS/util/config.js:var CHECK_USERNAME = 'open-ils.actor:open-ils.actor.username.exists';
These are innocuous.
- Now we check for the
CHECK_USERNAME
constant in JavaScript files:dan@denials: $ find . -exec grep -H "CHECK_USERNAME" {} \; | grep -v svn ./Evergreen/xul/staff_client/server/patron/ue_config.js: var req = new Request(CHECK_USERNAME, SESSION, usrname); ./Open-ILS/xul/staff_client/server/patron/ue_config.js: var req = new Request(CHECK_USERNAME, SESSION, usrname); ./Open-ILS/xul/staff_client/build/server/patron/ue_config.js: var req = new Request(CHECK_USERNAME, SESSION, usrname); ./Open-ILS/xul/staff_client/build/chrome/content/OpenILS/util/config.js:var CHECK_USERNAME = 'open-ils.actor:open-ils.actor.username.exists'; ./Open-ILS/web/opac/skin/default/js/myopac.js: var req = new Request(CHECK_USERNAME, G.user.session, username); ./Open-ILS/web/opac/common/js/config.js:var CHECK_USERNAME = 'open-ils.actor:open-ils.actor.username.exists';
So we have a few instances of the call being made from the staff client. We'll modify these the same way as we did
myopac.js
.