Tuesday, July 21, 2015

ArchivesSpace Donor Details Plugin

In a previous post about our ArchivesSpace implementation, Max detailed some of the things that ArchivesSpace is not (or, at least, is not yet), including some of the desired and/or required features for our local implementation of ArchivesSpace that are not currently present in the out-of-the-box ArchivesSpace distribution. One of the lacking features that Max mentions relates to information that we track for people and organizations who donate collections to the Bentley. 

Each of our donors has a unique donor number that we use to track accessions, organize case files, detail provenance in our finding aids and catalog records, and to conduct other fundamental archival functions. For example, the donor number of the source of a collection is indicated in the 500 field of that collection's MARC record and in the acquisition information section of that collection's finding aid. Donor numbers are essential components of our legacy data, and will continue to play a significant role in our day-to-day operations going forward. The ability to store and generate donor numbers in ArchivesSpace is necessary functionality for us that is currently not supported in the stock application.

ArchivesSpace Agents

In ArchivesSpace, each person, family, corporate entity, or software that relates to a resource or accession as a creator, source, or subject is linked to that resource or accession from an agent record. This will provide some really great functionality in that we will only need to create an agent record for a unique entity once and will thereafter simply add that agent as an agent link, saving us the hassle of looking up a name in LoC, our MARC records, or our finding aids to ensure consistent use across collections each time we add it as a source, creator, or subject. The way this currently works for us does, despite our best efforts, occasionally lead to slight variations in spelling or forms of names and subjects across collections or typos in our finding aids due to the fact that we must type each subject or agent rather than select an existing subject or agent from a controlled value list (we're working on fixing those problems, though; more to come on that from Max and Walker soon!)

While having a controlled list of agents in ArchivesSpace will in many ways be an improvement over our current practice, it also means that our ArchivesSpace agent records will need to include all of the information we might need to track about an agent in one place. ArchivesSpace agent records contain many universally applicable fields that permit a wide range of users to generate agent records with links to authority records, various name forms, contact information, notes, and so on. We realize that not every institution will use donor numbers in the same way as us and, as Max notes in his blog post, "it wouldn't make sense for us to request ArchivesSpace to develop functionality that only works for one user," which means that it's up to us to find a solution that will meet our local needs.

Our first thought was to try to identify some field in the existing ArchivesSpace agent records that we could use to store donor numbers. We took a look at the options in agent name forms, contact details, and so on to determine if any of the existing fields would work.

ArchivesSpace person name form

We briefly considered adding multiple name forms for each donor -- one name form using the fields as they were intended in the proper DACS, RDA, or other fashion and another name form using a field, such as "Number" or "Qualifier" to store the donor number. We ultimately decided, however, that this would be a hacky approach, and it would be better to come up with a more sophisticated solution.

ArchivesSpace Plugins

One of the great things about ArchivesSpace that we have mentioned on this blog before, and will undoubtedly mention again, is the fact that ArchivesSpace is open source, allowing users to take a complete look at the inner workings of ArchivesSpace and modify or extend it to meet their needs. Even more significant is that the ArchivesSpace team has made it easy for users to add plugins to "customize ArchivesSpace by overriding or extending functions without changing the core codebase." Making changes to the core codebase could cause unintended issues down the road when upgrading to new version of ArchivesSpace, but plugins are modular extensions of the application that can be quickly copied over to a new version of ArchivesSpace, easily tweaked to accommodate any changes, and readily shared with others to allow other users who desire the same functionality to drop the plugin into their local ArchivesSpace instance.

The ArchivesSpace distribution includes a few exemplar plugins that demonstrate the power of plugins and the relative ease with which they can be implemented. This plugin, for example, generates a new unique accession number, following a predefined format, each time a new accession record is created. Additionally, Hudson Molonglo makes numerous plugins available on their GitHub, including the excellent container management plugin that we intend to use in our ArchivesSpace instance. Among the plugins that they have developed is a plugin to add additional contact details to an agent record. Browsing the existing ArchivesSpace plugins, combined with some existing understanding of how to create a plugin based on our experiences adding a custom EAD importer and from reading the blog posts "Writing an ArchivesSpace Plugin" by Mark Triggs and "Customizing your ArchivesSpace EAD importers and exporters" by Chris Fitzpatrick, inspired me to attempt to create a plugin to extend the existing ArchivesSpace agent model to include donor numbers (and other necessary but lacking fields).

Donor Details Plugin

After just a few days of occasional work on the plugin, I developed a functioning prototype that adds a Donor Details option to each agent record, including a field to enter a donor number and a check box that, when selected, will automatically generate a new donor number by iterating the current maximum donor number by one. The plugin also ensures that each donor number is unique, will only display the donor details field in an existing agent record if donor details exist for that agent, and will only allow users to select the auto-generate check box if there is not an existing donor number for the selected agent. The current code for the plugin, including slight variations for ArchivesSpace versions 1.1.2, 1.2.0, and 1.3.0, is on our GitHub. Here's how it works:

The donor details plugin currently consists of four directories: backend, frontend, migrations, and schema, each of which follow the naming conventions and functions detailed in the ArchivesSpace plugin README.


The backend directory contains one subdirectory, model, which is where the new backend modules and classes used in the donor details plugin are defined. Within the model directory are five files and another subdirectory, mixins. 

The four files ending in _ext.rb (agent_corporate_entity_ext.rb, agent_family_ext.rb, agent_person_ext.rb, agent_software_ext.rb) are extensions of existing components of the ArchivesSpace backend model. Each file contains only one line that extends the model for each agent type by including the donor details module. The donor details module itself is defined in the mixins directory, in the file donor_details.rb


Currently, the relationship between the donor details module and each donor detail record is one-to-many; each agent can have one array of donor details, which itself may have one or more donor detail records associated with it. This may change at some point (the relationship between agent and donor number should really be one-to-one), but I used existing components of agent records, such as contact details, that have a one-to-many relationship with agents as models for the donor details plugin, which is why it is designed as such (it also is not really a problem, since it will never matter that we can add multiple donor numbers to an agent as long as we don't). 

What this means in terms of the functionality of the plugin is that each agent record includes the donor details (plural) module, which itself contains records of the type donor detail (singular). This is an important distinction to note, as a good deal of the functionality of the plugin (not to mention the functionality of ArchivesSpace and other Ruby on Rails applications) is dependent upon using consistent naming conventions across all components. Throughout the entire plugin, including within the backend models, the database tables, the frontend displays, and the ArchiveSpace JSONModel schema definitions, the plural and singular forms of donor_detail are used consistently and deliberately following the required naming conventions. The DonorDetails module includes records corresponding to the donor_detail JSONModel, which are stored in the donor_detail table in the database, which are displayed using the donor_detail form template in the frontend, and so on. 

The remaining file in the backend/model directory, donor_detail.rb, is where the backend components of each singular donor detail record is defined, including where the links between the model and the relevant table in the ArchivesSpace database and the relationship between the model and the relevant JSONModel schema defintion are made. It's also where the bits of code that automatically generate a new donor number and that validate the uniqueness of donor numbers are located.


The code in backend/model/donor_detail.rb is another really great example of how extensible ArchivesSpace is when plugins are used in conjunction with the existing ArchivesSpace codebase. Functions in this file, such as auto_generate and validates_unique, are used throughout the ArchivesSpace application to automatically generate numbers and display strings and to enforce uniqueness constraints (see both in use here, for example). I didn't actually have to write any code to define the auto_generate or validates_unique functions. All I had to do was find existing applications of those functions in the ArchivesSpace code to figure out how to put them to my own use. There are plenty of examples of this kind of reusable, modular code across the ArchivesSpace application, and it is what really makes it possible to easily add new features and functionality to ArchivesSpace (that is, provided you have the time to search and browse through the code in the ArchivesSpace GitHub in to find those functions).


The schemas directory in the donor details plugin includes only two files, abstract_agent_ext.rb and donor_detail.rb.

The file abstract_agent_ext.rb works in much the same way as the previously discussed _ext.rb files: it extends the existing abstract_agent schema, specifically by adding a donor details array, containing one or many donor detail items, to each agent record.


The file donor_detail.rb is where the donor_detail JSONModel schema is defined:


This is where the properties of each singular donor detail record are defined. Currently, there are only a few properties: number (a string), number_auto_generate (a boolean), and dart_id (another string that Max and I just added this morning to explore linking our donors to the University's Development office donor database). "Number" and "dart_id" are fairly self-explanatory, and number_auto_generate is the property that will be set to true or false, in the ArchivesSpace staff interface, using a check box to indicate whether or not the donor number should be automatically generated by the system. Appending _auto_generate to a property is another one of those already-existing ArchivesSpace features (see it used elsewhere to indicate whether a sort name ought to be auto-generated) that can be used to later make use of yet another existing ArchivesSpace function when implementing the frontend check box. There really are a lot of useful reusable things in the ArchivesSpace code if you look for them!


Since we'll actually need these donor numbers to be stored somewhere in the ArchivesSpace database, we include a file, 001_donor_detail.rb, in the donor details plugin's migrations directory that creates a table with the necessary fields in the ArchivesSpace database. Here we also follow the proper naming conventions: the table we create is called donor_detail (same as the JSONModel schema and backend model) and the columns in that table are number, number_auto_generate, and dart_id (same as the names of properties in the donor_detail JSONModel schema). The table also includes columns for agent_person_id, agent_family_id, agent_corporate_entity_id, and agent_software_id, which will be populated with the unique identifier for an agent when it is created, to establish the relationship between the agent and donor detail tables.


The frontend directory contains all of the code that displays a donor detail form in the ArchivesSpace staff interface, so that staff can add donor details when creating or editing an agent and see any existing donor information when viewing an agent. The frontend directory contains three subdirectories: assets, locales, and views.

The assets directory contains only one file: donor_detail.crud.js, which includes the JavaScript that controls the check box and text field in the donor detail form. Essentially what it does is make the donor number text field read only and display the text "System generates when saved." This is another bit of code that I "borrowed" from the existing ArchivesSpace application, specifically from the bit of code that controls the check box for agent sort names.

The locales directory also contains only one file: en.yml, which is where the English language translations for each part of the donor details plugin are located. It's the file that ArchivesSpace uses to know what to display to staff using the frontend interface for things like "number," "dart_id," and so on. An en.yml file in a locales directory is another really helpful feature of ArchivesSpace (see the entire ArchivesSpace en.yml file). It allows you to centrally maintain, modify, or override the language that will be used in the ArchivesSpace public and staff interfaces and to then refer to the entry in the en.yml file using a variable name, rather than requiring you to change every instance of English language text that you or the ArchivesSpace developers would have used throughout numerous html files. 

The html files that integrate the donor details plugin into the staff interface are located in the views subdirectory, which in this plugin contains only an agents subdirectory. The views directory (and corresponding subdirectories) are where the code is located that actually makes a form or a field display in the ArchivesSpace web interface. The views/agents directory contains three files: _donor_details.html.erb, _form.html.erb, and show.html.erb

The only unique-to-this-plugin file in this directory is _donor_details.html.erb. The other two files override the stock ArchivesSpace agents _form.html.erb and show.html.erb files to make them display the form template defined in _donor_details.html.erb in addition to all of the already-existing agent forms.


The template in _donor_details.html.erb will display a label and text box for donor number along with an automatable check box if the donor number is blank, otherwise it will display only the donor number label and text box. As with a lot of components of this plugin, this code follows the standard form of other ArchivesSpace templates, such as the contact details template. 

The change that I made to _form.html.erb can be found on line 27, and the changes made to show.html.erb on lines 93-121. The form and show files essentially replicate the function of surrounding bits of code that do things like display the templates for name forms and contact details, and uses that code to display the template for donor details, including a label and text field for donor number, including a check box to automatically generate the number, and a label and text field for DART ID. 

The final product in the staff interface looks like this:

That may look like a small achievement considering all of the bits and pieces that went into making a tiny, two-fields and a check box form appear in ArchivesSpace agent records, But, when you consider that our local implementation of ArchivesSpace can now include core functionality that it did not have before, that tiny form is really quite significant, and learning how to develop a plugin and spending time troubleshooting all of the errors that arose due to me being an archivist, not a programmer, was well worth the effort. Working on this plugin was also a really useful lesson in just how extensible and modifiable ArchivesSpace is by design, and it opens up a world of possibilities for us as we start to dive into migrating our legacy accession records (plenty more on that to come), develop new conventions for using ArchivesSpace, and think about how we can use the system to its fullest extent.


We've said it on this blog before, but it's worth stressing again: we are archivists, not programmers. While this plugin has been fully functional and has not had any issues, yet, I would not be surprised if there are bits of the code that could have been written in a more understandable, concise, sophisticated, or otherwise programmatically correct way. I would be very appreciative of any feedback, criticism, pointers, etc. that any more experienced programmers reading this blog might have!

No comments:

Post a Comment