======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: Enter new username: 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. The ''Request'' object is defined in ''Open-ILS/web/opac/common/js/opac_utils.js''. - The first parameter in the ''Request'' object initializer is a variable defined in ''Open-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 final ''return 0;'' to ''return 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''.