User Tools

Site Tools


opac-devel:catalog_development

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:

  1. 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($(&quot;myopac_update_username_row&quot;));'>Cancel</button>
        </span>
      </td>
    </tr>

    From this, I was able to determine that the JavaScript method of interest was myOPACUpdateUsername().

  2. 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!

  3. 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.

  4. 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.

  5. 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!

  6. 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.

  7. 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!

  8. 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.

  9. 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.

opac-devel/catalog_development.txt · Last modified: 2008/02/02 06:50 by dbs

© 2008-2017 GPLS and others. Evergreen is open source software, freely licensed under GNU GPLv2 or later.
The Evergreen Project is a member of Software Freedom Conservancy.