Displaying unique title and volume count on the Koha staff client

An upgrade-friendly way to show unique title and copies’ count using Koha’s SQL reports in tandem with Koha’s Reports web service API, JSON formatted data and some Javascript.

Kia ora!

Last week my good friend Dr. Gautam Sarma, Asst Librarian, K.K. Handique State Open University in Assam posed an question on the Koha Users forum on Facebook. He wanted to know what was the easiest way to view the total count of unique titles as well as total number of copies (item holdings) in his Koha catalog.

Given that he comes to us from a SOUL user’s background, this is a reasonable demand. SOUL developed and marketed by Inflibnet does show this information at a glance, especially when using the cataloging module. Similarly, so does e-Granthalaya, another LMS developed by NIC, Govt of India. The following screenshot snippets show how this information is displayed for SOUL v2.0 and e-Granthalaya 4.0 respectively.

soul

egrant

In Gautam’s own words he was looking for something that would allow him to:

hurriedly say that how much data we have by entering our ILS

While Koha’s SQL reporting facility makes finding this information a breeze, thanks to this ready-made SQL report by Nicole C. Baratta, it does not immediately allow the users to have the sort of heads-up view that SOUL and e-Granthalaya allows. A library staffer have to go to Reports -> Guided Reports -> Use Saved and then finally manually select the actual report and run it to see the unique title and copy count statistics.

At L2C2 Technologies we have been doing some things like these for our client-partners. So I promised Gautam that I will soon post about it. And as it would happen, yesterday Mr. Kalipada Jana, Librarian, Basanti Devi College and a client partner wanted the same facility for his hosted instance’s staff client. We decided to use the Basanti Devi College library as a live use-case (since they are currently doing retro-conversion) and document the same so that other users may also be able to benefit from the same.

Concepts – or what makes it all work

Koha since long have provided a set of HTTP based web service API. According to the World Wide Web Consortium (W3C) – the global standards body that defines anything and everything related to the web, a web service is “a software system designed to support inter-operable machine-to-machine interaction over a network”.

Among the various things Koha’s web services API allow includes the Reports web service, which allows an SQL report’s data to be made available in JSON format, as long as the report is marked as “public“. A public report is accessible via a URL that looks like this: http://MYOPAC/cgi-bin/koha/svc/report?id=REPORTID.

basanti-stats1

In this case, we called the report as a public report using the reports web service via https://bdcl-staff.l2c2.co.in/cgi-bin/koha/svc/report?id=6&annotated=1.

The SQL query being executed by the call was :

SELECT homebranch, count(DISTINCT biblionumber) AS bibs, 
       count(itemnumber) AS items 
FROM items 
GROUP BY homebranch 
ORDER BY homebranch ASC

The JSON data (which thanks to the annotated=1 querystring parameter) was returned as the following key-value pairs : [{"bibs":"1374","homebranch":"BDCL","items":"2359"}].

The solution

With the report (in this case report id #6) returning the branch-wise unique title and copies information in JSON format, it was now only a small matter of putting together some JavaScript so that the information could be displayed in a more human-friendly format on the staff client. The following JQuery snippet was all that was required to be placed into BDCL’s IntranetUserJS system preference to get our desired result.

$(document).ready(function() {
    if ( $('#main_intranet-main').length ) {
    $.getJSON("https://bdcl-staff.l2c2.co.in/cgi-bin/koha/svc/report?id=6&annotated=1", function(data) {
        var branches = data[0].homebranch;
        var bibs = data[0].bibs;
        var items = data[0].items;
        $('div.newsitem').prepend('<div class="newsitem" id="mystats"><table class="table table-striped" style="width: 100%; background: none;"><thead><th colspan="3" style="text-align: center; font-weight: bold; padding: 8px; line-height: 1.42857143; vertical-align: middle; text-transform: uppercase;">Library Statistics</thead><tbody><tr><td><strong>Branch</strong></td><td><strong>Unique titles</strong></td><td><strong>Total Copies</strong></td></tr><tr><td class="text-center">'+branches+'</td><td class="text-center">'+bibs+'</td><td class="text-center">'+items+'</td></tr></tbody></table></div>');
    });
    }
});

And voila! Houston! We have touchdown! ๐Ÿ™‚

koha-count

Hope this post helps you at your library. Happy hacking!

Koha and the โ€œmagicโ€ of XSLT – Part 2 : Show accession no. in OPAC results page

How to add 952$p (typically the accession no.) to your OPAC’s Results page display.

About 6 months back, we had posted about “Koha and the โ€œmagicโ€ of XSLT : displaying new MARC fields on the OPAC“. This post can be thought of as its Part 2 as it introduces a couple of new concepts – (a) looping through a list of repeatable values and (b) punctuating these values for correct display. If XSLT or Koha with XSLT sound like something you are hearing for the first time, we strongly suggest that you first read the Part 1 first (see above).

The Backstory

Our tutorial style blog posts are usually the result of addressing some sort of user demand. In this case, this post came about because of Mr. Kalipada Jana, Librarian at Basanti Devi College, Kolkata. Yesterday he had filed a ticket on our helpdesk saying that he would like accession number(s) attached to each bibliographic record to be displayed on the OPAC results page. This is something that Koha does not do by default. But having seen such a display elsewhere he wanted to have the same.

The default Results page

chrome_2017-11-28_22-58-45

What the user wanted

chrome_2017-11-28_22-57-56

The Process

Koha stores it holdings item identification in MARC21 tag 952$p. The user here was using this field to store the individually unique accession numbers of their items in holdings. Now a bibliographic record may quite easily have multiple copies with separate accession numbers. So the XSLT snipped we needed must do the following:

  1. Handle looping over to display repeated 952$p (when there were multiple copies of the same book.
  2. Separate the accn nos. with “commas” if there where multiple copies of a book and after the final accession number terminate the line with a period instead of a comma. And if there was only a single copy, then instead of comma use a period.
  3. .

  4. Suppress this accession no. display for bibliographic records that do not have any holdings.

The code

<!-- L2C2 - 2017-11-28 adding accn no to results page 952$p -->
<xsl:if test="marc:datafield[@tag=952]/marc:subfield[@code='p']">
<span class="results_summary accn_no">
<span class="label">Accession number(s): </span>
    <xsl:for-each select="marc:datafield[@tag=952]">
        <xsl:value-of select="marc:subfield[@code='p']"/>
        <xsl:choose>
            <xsl:when test="position()=last()">
                <xsl:text>.</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>, </xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</span>
</xsl:if>

In the first line (not the comment) we check if the MARC record has a 952$p field and sub-tag. If it does only then the rest of the code is executed. This is what helps us to suppress this new display for records without any accession numbers in its 952$p. The next couple of lines push out the necessary HTML code since the record has at least one accession number i.e. 952$p. In the subsequent two lines immediately after, we set up two loops. The first one loops through all the 952 (holdings) field in the bib record, while the inner loop looks up the $p sub-field. The inner most bit i.e. <xsl:choose><xsl:when test="position()=last()"> handled the punctuation. First if it checks if the currect MARCXML 952$p sub-node is the last one, if so it places a period and terminates the line. Otherwise, it places a comma as punctuation between the multiple accession numbers.

This code was added into the custom file which we named as MARC21slim2OPACResults-bdcl.xsl. This file is same as the default MARC21slim2OPACResults.xsl file, the only addition being the snippet given above. In order to get Koha to start using our file instead of the default, we placed the full path of our new file into the OPAC system preference – OPACXSLTResultsDisplay.

See it in action

If you want to see this XSLT in action, click here.

Managing patrons with same permanent & local address

Setting your borrower’s local address same as their permanent address with just a single click during patron entry into Koha ILS.

Often folks when unable to find some nifty feature that was present in their erstwhile LMS but not there in Koha, is found to be exclaiming – “But we can’t do that with Koha!”. Well, we have news for you – Koha is open source and that means, you can build / modify the parts that you need or are missing. But you do not know how to do that. Well… *that* is not really Koha’s problem. But fear not, if you are willing and have the aptitude for poking around code you can do it too. There are plenty of open access resources that show you how to do so, just waiting for you to pick up and start working on your skills. After all, it is said:

If you give a hungry man a fish, you feed him for a day, but if you teach him how to fish, you feed him for a lifetime.

Why this post

At L2C2 Technologies, we work with a lot of academic libraries where they need to record both the permanent as well as local address of their students. Koha allows for recording more than a single address for a patron since donkey’s years. If you look at the schema of the borrowers table in the Koha database, you will see that there are fields to record both the primary address as well as alternate address. These two set of fields fit nicely into our permanent and local address requirement.

2017-06-19_01

However, the library staff often complain that it is useless extra work to re-enter the same data over in both set of fields as many users often have one and the same address for both. As a result, we are sometimes asked how to cut down this extra work. In this post, we are going to share one of the ways by which you too can do the same, should you need to do this.

Choosing our tools

All we use are snippets of JavaScript, jquery and css to achieve our objective. All of which go in into the Koha database as part of the IntranetUserJS system preference. We do not touch any template file or change any underlying PERL code. This way our tweak is guaranteed to survive Koha version upgrades without any further effort on our part.

The steps… as easy as 1-2-3

Since we do not want to re-type the same information, the only option is to copy it from first set of fields and that what we do by adding a checkbox HTML form input element. We give this checkbox the id copypermaddress and insert this into the DOM just before the first li element belonging to the parent fieldset memberentry_address on the Add Patron screen.

$('<li><input type="checkbox" name="copypermaddress" id="copypermaddress" value=""><label for="copypermaddress">Same as permanent address:</label><div class="hint">Click to copy permanent address data</div></li>').insertBefore(' #memberentry_address > ol > li:first-child ');

While the above insertion gets us the following screen, it still does not do anything i.e. if you clicked the checkbox, nothing would happen yet. In the next step we cover that.

2017-06-19_02

So we add a listener that will wait for state-change of the checkbox. In plain English, that means it will detect when a user clicks that checkbox and then based on whether it was selected or unchecked, appropriate action would be taken. And that exactly what happens below. The first part goes into action if the checkbox was checked and the part coming after the else kicks in when it is unchecked. In the first instance we copy over the values from the permanent address field and in the second part we undo the copy and blank out the local address fields.

$(document).ready(function(){
$('#copypermaddress').change(function() {
  if(this.checked) {
    $('#B_address').val($('#address').val());
    $('#B_address2').val($('#address2').val());
    $('#B_city').val($('#city').val());
    $('#B_state').val($('#state').val());
    $('#B_zipcode').val($('#zipcode').val());
    $('#B_country').val($('#country').val());
  } else {
    $('#B_address').val('');
    $('#B_address2').val('');
    $('#B_city').val('');
    $('#B_state').val('West Bengal');
    $('#B_zipcode').val('');
    $('#B_country').val('India');
  }
});
});

In the two following screenshots we get to see how exactly this works. In the first one, only the permanent address has been added. While in the second screenshot, we see how the data has been copied over when the checkbox is clicked.

2017-06-19_03

2017-06-19_04

References

  1. .insertBefore()http://api.jquery.com/insertbefore/
  2. :first-child Selectorhttps://api.jquery.com/first-child-selector/
  3. .change()https://api.jquery.com/change/
  4. .val()http://api.jquery.com/val/
  5. Koha DB Schema – http://schema.koha-community.org/master/

JQuery quicktip : Using Patron Attribute fields without double rowed textarea boxes

A JQuery quick tip for Koha ILS

Often we are have clients who want to capture additional data for their patrons. For schools and colleges, this typically includes demographic details, roll numbers, program enrolled etc. The Koha-friendly way to do is by using Extended Patron Attributes aka custom fields for patron data.`

2017-06-17_03-30-18

The thing about these patron attribute fields is that if these are expecting textual data input, Koha uses the textarea HTML element for them. Which is fine, except the textarea elements are sized to 2 rows by default. This something that confuses some users who expect to see an input element instead. So, we decided to adopt a middle way solution – to reduce the textarea element’s rows attribute from 2 to 1.

JQuery to the rescue

As always we turn to trusty jquery which makes this something ridiculously easy thing to do. Here is the code snippet:

$(document).ready(function(){
  if ($('#pat_memberentrygen').length) {
    var tareas = $('textarea[id^=patron_attr_]');
    for (var i=0; i < tareas.length; i++) {
      var t = $(tareas[i]);
      var tarea_reset_rows = t.attr('rows',1);
    }
  }
});

We plug that code into our IntranetUserJS system preference and we are good to go! ๐Ÿ™‚ The screenshot below shows the change it brings to the patron data entry UI.

2017-06-17_03-31-01

Code explained

In the first line (i.e. the one starting with if) we check if we are actually on the patron member entry page. Next we create a JS array of only the textarea element on *that* page, *which* have an id that begins with patron_attr_. And finally we loop through that array and change the rows attribute of each textarea fields whose reference is stored in the array.

Using Google Drive to upload files into directory under Koha OPAC DocumentRoot

Almost a year back, we had shared a post about how to use google drive as a remote backup storage. If you are unfamiliar with it and wish to understand the concepts presented here, we suggest that you first read it and then proceed with this.

Why did we do this?

Our client partner Bangabasi College is putting up a collection of their college questions papers from previous years as PDF files. You can have a glimpse of it by clicking here. The page that is being presented to the visitor to the OPAC is generated using a facility called “Koha as a CMS“. Now here is the thing, while the HTML required to display the scanned question paper PDF files is handled well by the “Koha as a CMS” functionality, it does not handle the part where we need to actually upload the PDF files into Bangabasi College’s Koha instance’s Apache2 DocumentRoot path.

So here is what we did. A normal SCP user account was created on the server hosting Bangabasi college account, into which the PDF files were uploaded into by the library staff users. However, after this, it required manual intervention from us, in order to move these files into the correct DocumentRoot path. We had created a folder QB for the question back under the DocumentRoot as /usr/share/koha/opac/htdocs/bangabasi/qb. And into this QB folder the uploaded PDF files were moved into by us.

But this created one problem, a big one. Our client was dependent on us at all times to move / sync the uploaded files into their final destination the QB folder. Also, if they needed to correct and re-upload a PDF file, they would again need us to help them move the corrected file into the DocumentRoot location. So, basically if we were not available for any reason, we would be holding them up from updating / uploading their own files into their hosted Koha. While our client was happy with how things were happening, to us, this was clearly not at all a desirable situation.

Our client was already using Google Drive and that’s when we figured than instead of simply using the Google Drive for backup, we could also use it to allow our client to do direct, independent uploads – their data in their own hands at all times. And thus this experiment.

Setting it all up

1) We created a folder named “qb” on Bangabasi College’s Google drive.

2) Next on the server within the folder /usr/share/koha/opac/htdocs/bangabasi we ran the command drive init. This asked us to authorize the google drive command line client and fetch the API key, which is what we did after logging in into Bangabasi college library’s gmail account. The API key was copied from the browser and pasted back into the command line. Basically what this did was to create a hidden directory named .gd under /usr/share/koha/opac/htdocs/bangabasi and create a file there called credentials.json. This completed the authentication setup with bangabasi’s google drive account.

3) Lastly, we set up the following cron job as the root user:

*/5 * * * *  cd /usr/share/koha/opac/htdocs/bangabasi && /usr/bin/drive pull -quiet qb

to execute on our server once every 5 minutes.

How it works

Now whenever a library staff user uploads a PDF file into their Google drive’s qb folder, every 5 minutes the cron job on our server will check if there is a new file on the remote Google drive. If there is, then the new file(s) are pulled down automatically onto the /usr/share/koha/opac/htdocs/bangabasi/qb. In this case for instance 125 .pdf files totaling in at about 19 MB were pulled down in ~18 seconds.

Similarly in case of a modification or removal of a file from Bangabasi’s Google drive “qb” it would be similarly synced or removed from the /usr/share/koha/opac/htdocs/custinc/bangabasi/qb folder on our server.

How to reference the files

Since the PDF files are stored under /bangabasi/qb folder under the Koha OPAC’s DocumentRoot i.e. /usr/share/koha/opac/htdocs/, we simply need to refer to the files with the following href attribute value set to /bangabasi/qb/<filename> in our HTML code.

Pros and cons of this approach

First the cons:

1) Google’s AI algorithms gets to read all your PDF files. But since our client is already using Google’s services, this is apparently not a major concern to them. And anyway our client is allowing public dissemination of these files, so Google is going to read it one way or another.

2) If the library staff user accidentally or maliciously deletes the Google drive folder or files in it, then the very next run of the pull command will remove the same off our server. But same would have been the case if the staff users had root / sudo access to the Koha DocumentRoot (i.e. /usr/share/koha/opac/htdocs). In fact, in the latter case, they can even rm -rf the entire server, removing *everything* from it.

The Pros

1) You can now allow your staff users to freely upload the processed files without having to give everyone the access to the actual Koha server’s filesystem. The chances of accidental or malicious deletion of files off the Koha server is largely minimized.

2) The speed! Simply put uploading files to Google drive is usually faster then directly uploading to the Koha server hosted on the Internet. The transfers between Google servers and the hosted Koha server also happens at a high rate of transfer.

3) You basically have *two* online copies of your PDF files – (a) on the Google Drive folder and (b) on the Koha server, which is good in terms of redundancy.

Koha and the “magic” of XSLT : displaying new MARC fields on the OPAC.

A short tutorial on using XSLT to make MARC fields in your data visible on the OPAC.

Earlier today, Suresh Kumar Tejomurtula, a member of the venerable LIS-Forum mailing list being run out of IISc Bangalore, posted a question on that list:

Under language codes of 008/35-37 and also under 041$a I added language code. for eg: tel for Telugu language. But I do not see any difference to the view of the record, except that the marc tags contains that values. Adding these fields data will enable library team to understand the language of the material. My question is, How will the users of the OPAC, who do not know about marc language codes will understand the item language [from just the 3-letter code sequence].

Short answer : Using XSLT

Much of Koha’s superpowers on the OPAC (as also on the staff client) side comes from its judicious use of XSLT. When we search for documents in Koha, the result that is returned from the database by way of the various perl modules that perform much of Koha’s internal plumbing, comes in as an XML (eXtensible Markup Language) document. More precisely it is returned as a MARCXML record. Readers of this blog who are familiar with the MarcEdit software may have often encountered a MARCXML record. Those who are not so familiar may well like to read up a bit from here before proceeding with this post.

So what is XSLT?

Wikipedia gives the definition of XSLT as –

“XSLT (Extensible Stylesheet Language Transformations) is a language for transforming XML documents into other XML documents, or other formats such as HTML for web pages, plain text or XSL Formatting Objects, which may subsequently be converted to other formats, such as PDF, PostScript and PNG.”

Where to start?

At the OPAC level, the XSLT magic is primarily driven by two files i.e. (a) MARC21slim2OPACResults.xsl and (b) MARC21slim2OPACDetail.xsl. Koha’s default settings of how we see the search results on the OPAC and the document specific details in the Normal view, are defined in these two files.

N.B. Directly editing these two files is strictly not advised unless you are a XSLT guru.

Lucky for us that Koha’s system preferences provide options to override the defaults by creating new XSLT files and telling Koha to use the new ones instead. The screenshot below shows the default setting.

2017-05-04_03-05-15

The two files are available inside a folder named xslt under the locale of the selected theme you are using e.g. /usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/en/xslt/ on a package-based installation. By default most of us in India would be using the English locale i.e. “en”. The default Koha theme is “bootstrap”. Thus if you are using a custom theme and/or different locale look for the files under that.

Step #1 : Copying the XSLT files

We will be fetching the 3-letter language code from MARC 008/35-37 of each marc record. Since our Koha instance here is named as “demo”, we’ll make a copy of the file MARC21slim2OPACResults.xsl as MARC21slim2OPACResults-demo.xsl and the MARC21slim2OPACDetail.xsl as MARC21slim2OPACDetail-demo.xsl.

N.B. You can give any name to the copies you make, but it is suggested that the less adventurous you are with the names, easier it will be for you to trace your steps back if you make a mistake while editing them. And trust me you will make mistakes, at least initially.

Step #2 : Editing MARC21slim2OPACResults-demo.xsl

The MARC21slim2OPACResults.xsl is what drives the display of results of a search on the Koha OPAC. And it does not show the value of 008/35-37 i.e. MARC language code, while displaying the search result. To add this facility, we need to do the following to our copy i.e. MARC21slim2OPACResults-demo.xsl. Around line no. 70 or there about, there will be this line <xsl:variable name="controlField008-30-31" select="substring($controlField008,31,2)"/>. Add the following line after it – <xsl:variable name="controlField008_35-37" select="substring($controlField008,36,3)"/>.

Explanation: we’re defining a new variable named controlField008_35-37 and in it we are storing the 3-digit value found at 008/35-37 from another variable – controlField008.

The second step in editing this file is to add the code to check if (a) 008/35-37 actually exists (e.g. if you have a blank 008 field, 008/35-37 won’t exist) and (b) it is set as something other than “und(i.e. undefined). The following code does that first and proceeds to match the value found in 008/35-37 against 23 different languages. These languages are English and the 22 official languages of India as per the Eighth Schedule of the Indian Constitution. You can add or remove any language from this list as you require. However, when you do, please make sure that the codes you setup in this list here are coming from the Code Sequence document of the MARC Code list for languages as published by the US Library of Congress.

This means that you must also be using these same exact codes in your MARC records in Koha.

2017-05-04_05-40-55

Where we place this code will depend on where we want this language to listed in the results. In our case, we decided to add it between Material type and Format. And thus in our case, the code was added at line no 637. If you too want language to be displayed between the Material Type and Format, then look out for this line <xsl:if test="string-length(normalize-space($physicalDescription))"> and add this block before.

Saved the file and moved on to the next section.

Step #3 : Editing MARC21slim2OPACDetail-demo.xsl

The process is similar to what we just did above. Open the file MARC21slim2OPACDetail-demo.xsl for editing and go to line no. 51 (or there about) and look for this line <xsl:variable name="controlField008" select="marc:controlfield[@tag=008]"/>. Add the following line immediately after that: <xsl:variable name="controlField008_35-37" select="substring($controlField008,36,3)"/>.

2017-05-04_06-02-17

Since we wanted the “Language of document” to come after Material type, we added the code immediate after the node <xsl:if test="$DisplayOPACiconsXSLT!='0'"> is closed but before <!--Series: Alternate Graphic Representation (MARC 880) -->; in our case, this worked out to be around line no. 195. Finally, we saved and closed the file.

Getting Koha to use the new XSLT files

The Koha system preference OPACXSLTResultsDisplay was changed from its original setting (i.e. “default”) and set to the path of our new file MARC21slim2OPACResults-demo.xsl i.e. /usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/en/xslt/MARC21slim2OPACResults-demo.xsl. Likewise the other system preference OPACXSLTDetailsDisplay was changed to /usr/share/koha/opac/htdocs/opac-tmpl/bootstrap/en/xslt/MARC21slim2OPACDetail-demo.xsl. It was time to test our XSLT modifications.

And it works!

Since pictures are said to be worth a 1000 words, we will let before and after screen grabs do the talking here. Also if anyone wants to see directly how it actually looks after applying the changed XSLT, visit the URL http://demo-opac.l2c2academy.co.in/cgi-bin/koha/opac-detail.pl?biblionumber=18

Before : Using the default MARC21slim2OPACResults.xsl

chrome_2017-05-04_07-05-24

After : Using the new MARC21slim2OPACResults-demo.xsl

chrome_2017-05-04_07-17-09

Before : Using the default MARC21slim2OPACDetail.xsl

chrome_2017-05-04_07-48-28

After : Using the new MARC21slim2OPACDetail-demo.xsl

chrome_2017-05-04_07-49-09

Koha quick tip : Duplicating a bibliographic record for a multi-volume book

Yesterday a young colleague called up with a query. She wanted to know how she could create separate bib records for a multiple volume book (e.g. “The Complete Works of Swami Vivekananda” which comes in 8 volumes) by editing the following volume specific info:

  1. ISBN;
  2. page count and physical description;
  3. price;
  4. date of copyright / publication;

while keeping other common information same across the records.

I told her that do this, she would first need to catalog at least *one* volume (preferably the first volume) of the book and then simply duplicating the record and changing the fields she needed to change in each case. This feature is well-documented in the Koha Manual under “Duplicating Records” inside the chapter on Cataloging. Continue reading “Koha quick tip : Duplicating a bibliographic record for a multi-volume book”

When “sex” prevents a Koha ILS installation

This is a true story from a recently concluded Koha workshop. There were roughly ~30+ participants and about 15 – 18 computers for their “hands-on” sessions. The instructor-led “how to install Koha 16.11 on Ubuntu 14.04.5” was going along smoothly. However, suddenly all hell broke loose! Everyone, including the instructor were stumped right at nearly the last leg of ‘sudo apt-get install koha-common‘. The install would not complete due to three missing files. First the repos were changed and re-tried. Well… no go! That’s when I noticed that the error was 403 forbidden. Woah! I tried to manually download the files off the repos using a browser and all it said was an “Access denied!” error coming from the Squid proxy.

A closer look at the files gave the game away. The university’s content filtering rules on the Squid proxy was the cause. Apparently the files: (a) libmoosex-markasmethods-perl (b) libmoosex-nonmoose-perl and (c) libwww-youtube-download-perl were being blocked from being fetched. The first two were triggering a false positive on the pornographic filter (the “sex” in libmoosex) and the third was hitting the keyword filter “youtube”, since Youtube was blocked on campus!!!

With no easy way to work around the proxy for connectivity, I manually downloaded the three files using a standby unfiltered link on a single computer. Next I transferred the files on to a pen drive and manually copied them over into each system’s /var/cache/apt/archives and thus fooling apt-get into thinking the files were already downloaded by it. And that is how we saved the day! ๐Ÿ˜‰

Lesson

If you are planning a Koha installfest at an educational institution, please ensure that their content filtering proxy rules are tweaked before actually going ahead with the workshop.

Installing SMS::Send::IN::eSMS send driver for Koha ILS

An easy peasy HOWTO along with a few under-the-hood details explained.

Step #1 : Installing the SMS::Send::IN::eSMS module from CPAN

Login as a sudo user and start the CPAN shell using the command sudo perl -MCPAN -e shell. Install the driver by typing in install SMS::Send::IN::eSMS. If everything works OK, you should see output on screen similar to this:

cpan[1]> install SMS::Send:IN::eSMS
Reading '/root/.cpan/Metadata'
  Database was generated on Thu, 09 Feb 2017 09:41:03 GMT
Running install for module 'SMS::Send::IN::eSMS'
Checksum for /root/.cpan/sources/authors/id/I/IN/INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz ok
Scanning cache /root/.cpan/build for sizes
............................................................................DONE
Configuring I/IN/INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz with Makefile.PL
Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for SMS::Send::IN::eSMS
Writing MYMETA.yml and MYMETA.json
  INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz
  /usr/bin/perl Makefile.PL INSTALLDIRS=site -- OK
Running make for I/IN/INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz
cp lib/SMS/Send/IN/eSMS.pm blib/lib/SMS/Send/IN/eSMS.pm
Manifying blib/man3/SMS::Send::IN::eSMS.3pm
  INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz
  /usr/bin/make -- OK
Running make test
PERL_DL_NONLAZY=1 PERL_USE_UNSAFE_INC=1 /usr/bin/perl "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/checkloginpass.t .. ok
t/checkmsgdest.t .... ok
t/compile.t ......... ok
t/liveaccttest.t .... skipped: No login information available, skipping all tests.
t/pod-coverage.t .... ok
t/pod.t ............. ok
All tests successful.
Files=6, Tests=16,  1 wallclock secs ( 0.09 usr  0.00 sys +  0.99 cusr  0.07 csys =  1.15 CPU)
Result: PASS
  INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz
  /usr/bin/make test -- OK
Running make install
Installing /usr/local/share/perl/5.20.2/SMS/Send/IN/eSMS.pm
Installing /usr/local/man/man3/SMS::Send::IN::eSMS.3pm
Appending installation info to /usr/local/lib/x86_64-linux-gnu/perl/5.20.2/perllocal.pod
  INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz
  /usr/bin/make install  -- OK

cpan[2]>

With the SMS::Send::IN::eSMS module installed, we’ll now set up the Koha side of things.

Step #2 : Making a one-line change to Koha’s SMS.pm

Assumption : That you are using a .deb package based installation. If you are using a git or a tarball installation you probably do not need this guide. ๐Ÿ™‚

The code in file /usr/share/koha/lib/C4/SMS.pm is what Koha uses to communicate with the SMS provider (in this case eSMS Kerala from KSITM) via the send driver. This code is capable of accepting two parameters i.e. (a) username and (b) password of the user with the SMS service provider via whom the user wants to send out the messages. However due to Telecom Regulatory Authority of India (TRAI) rules, in India we need to use three parameters, the third one being a mandatory, 6-character, nationally unique senderid allotted to every bulk transactional SMS sender in India. As of version 16.11 Koha can not handle this AS-IS.

Therefore, to make SMS work with Koha in India, we need to make a one-line change to the code. Look for the following code around line no. 80 of the file /usr/share/koha/lib/C4/SMS.pm:

# Create a sender
$sender = SMS::Send->new( $driver,
                          _login    => C4::Context->preference('SMSSendUsername'),
                          _password => C4::Context->preference('SMSSendPassword'),
                    );

Add the following line : _senderid => C4::Context->preference('SMSSendSenderID'),, so that the code looks like this:

# Create a sender
$sender = SMS::Send->new( $driver,
                          _login    => C4::Context->preference('SMSSendUsername'),
                          _password => C4::Context->preference('SMSSendPassword'),
                          _senderid => C4::Context->preference('SMSSendSenderID'),
                    );

Save and close the file. Now login into the staff client and add the four necessary system preferences – (a) SMSSendDriver, (b) SMSSendUsername, (c) SMSSendPassword and (d) SMSSendSenderID. Now, if you are on Koha 3.22 or higher version (i.e. 16.05 or 16.11), you will find the first three under Patron preferences and you only need to create the last one i.e. SMSSendSenderID to complete the setup.

eSMS_02

eSMS_03

However, if you are still using Koha 3.18.x or 3.20.x series then you will need to create three Local use preferences i.e. SMSSendUsername, SMSSendPassword and SMSSendSenderID. Either way, set these four parameters to your actual settings and you are ready to go start using the installed driver.

N.B.This behaviour will change from Koha 17.05 onward (estimated release date May 2017) when the bug number 13029 – “Allow to pass additional parameters to SMS::Send drivers” becomes generally available as part of the stable releases.

Troubleshooting #1 – Missing ‘make’

‘Make’ is required to configure and install the driver. So, if you see an error that reads as

Running make for I/IN/INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz
Can't exec "/usr/bin/make": No such file or directory at /usr/local/share/perl/5                                                                                                             .20.2/CPAN/Distribution.pm line 2197.
  INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz
  /usr/bin/make -- NOT OK
  No such file or directory
Failed during this command:
 INDRADG/SMS-Send-IN-eSMS-0.01.tar.gz         : make NO

Exit from cpan by using the command exit and from the command line install make by entering the command sudo apt-get install make. Once make is installed, run sudo perl -MCPAN -e shell and then proceed with driver installation using the command install SMS::Send::IN::eSMS.

Troubleshooting #2 – CPAN index is out of date

After typing in the command ‘install SMS::Send::IN::eSMS‘ if you find yourself facing the error Warning: Cannot install SMS::Send::IN::eSMS, don’t know what it is., DO NOT panic! It happened to us on one of our test servers too ๐Ÿ™‚

It simply means your CPAN index metadata is out-of-date, and you need to refresh the index by running the command ‘reload index‘. After the updated index is fetched, re-run the command install SMS::Send::IN::eSMS. It will work this time.

Adding autocomplete support to MARC21 260 / 264 (imprint) fields in Koha

Adding auto-complete feature to Koha’s MARC21 260 / 264 field (Imprint – place, name of publisher, distributor etc) as a cataloging aid.

As per LC’s AACR2 (as well as RDA) instructions, the imprint information as captured in MARC21 field 260 (AACR2) and 264 (RDA) should be *transcribed* and not *recorded* using the principle – “Take What You See and Accept What You Get” [1]. As a result, the 260$a (place) and 260$b (publisher, distributor etc) are usually not handled as fields whose values are controlled using authorized values.

Up until 2001, the 260 field was a NR field. It was made repeatable to accomodate frequent publisher name changes.

Since the 260$a and 260$b are not usually guided by authorized values, it is noted (at least in the Indian sub continent context) that catalogers often make typographical errors while transcribing the data, e.g. “Pearson Education” may be inadvertantly added as “Peerson Education” or as even as “Pearshon education”, while “Kolkata” may have been entered both as “Kolkata” as well as “Kolkatta” or even as “Kolkhata”. Without authority control of the field, this cataloging quality check is often overlooked. Errors like this often end up affecting the result of advanced searches or custom SQL reports.

Luckily for us, Koha ILS uses jquery extensively while (via jquery-ui) provides for nice autocomplete widgets, like the ones we see in action when we type in part of the borrower’s name in patron search (checkout) or in the authoritiy headings search, where entering 3 characters triggers the AJAX based lookup with the option to select one of the offered list *OR* to type in our own.

AJAX stands for “Asynchronous Javascript and XML”. In simple terms it encompasses a set of web development technique that allows us to fetch and load data from a remote server into our currently open page, without requiring us to refresh / reload the page. [2]

Recently a client requested that we offer them a way to look up publisher names and place names (for field 260) already entered into their Koha instance, without having to type it all in every time. For example in their database they already had the following publisher names entered – “Pearson Education, Prentice Hall India, PacktPub, Press Trust of India” etc. Now they if they encountered an item that was from these publishers they should be able to pull up a list just by entering “P” into the 260$b field and then be able to select the one applicable. And if they encountered a publisher name say “Penguin Books”, they should be able to type it in as well.

Koha 16.11 ships with 3 (three) different ysearch.pl scripts that show us how to achieve this. You can find out which ones these are by using the command `locate ysearch.pl`. NOTE: You may be required to run `sudo updatedb` once before locate finds the files. For our requirement we modeled our script which we’ll call 260search.pl on /usr/share/koha/intranet/cgi-bin/cataloguing/ysearch.pl. You can grab a copy of 260search.pl from L2C2’s github repo here [3]. The script returns a JSON based result set if results matching your input is found.

Remember that **every** script that Koha executes, needs it executable bit set, and so does this one. Therefore, do *not* forget to set the executable bit for the script with `sudo chmod a+x /usr/share/koha/intranet/cgi-bin/cataloguing/260search.pl` before you proceed to the next step.

Step #2 : Enabling the fields

With the script in place, we now need to turn to IntranetUserJS system preference and enter the following jquery snippet to enable autocomplete in 260$a and 260$b :

$(document).ready(function(){
  $( '[id^="tag_260_subfield_a"]' ).autocomplete({
    source: function(request, response) {
      $.ajax({
        url: "/cgi-bin/koha/cataloguing/260search.pl",
        dataType: "json",
        data: {
          term: request.term,
          table: "biblioitems",
          field: "place"
        },
        success: function(data) {
          response( $.map( data, function( item ) {
            return {
              label: item.fieldvalue,
              value: item.fieldvalue
            }
          }));
        }
      });
    },
    minLength: 1,
  });
  $( '[id^="tag_260_subfield_b"]' ).autocomplete({
    source: function(request, response) {
      $.ajax({
        url: "/cgi-bin/koha/cataloguing/260search.pl",
        dataType: "json",
        data: {
          term: request.term,
          table: "biblioitems",
          field: "publishercode"
        },
        success: function(data) {
          response( $.map( data, function( item ) {
            return {
              label: item.fieldvalue,
              value: item.fieldvalue
            }
          }));
        }
      });
    },
    minLength: 1,
  });
});

A video of autocomplete in action

Conclusion

By tweaking the 260search.pl script or even by completely re-writing it to use the various search functions shipped by Koha inside its /usr/share/koha/lib directory on a .deb package based installation, you can do so much more than possible with this simple hack. Happy hacking! ๐Ÿ™‚ [4]

References:

[1] http://www.loc.gov/catworkshop/RDA%20training%20materials/LC%20RDA%20Training/Module1IntroManifestItemsSept12.doc

[2] https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started

[3] https://gist.github.com/l2c2technologies/7d0449dcb80c90880381ef4571003d1d

[4] http://catb.org/jargon/html/H/hack.html