Altering the 'Request a copy' function

From EPrints Documentation
Revision as of 08:47, 6 August 2018 by Libjlrs (talk | contribs) (Method A: Editing the 'requester' citation)
Jump to: navigation, search

The Request a copy function allows for some restricted items to be requested by a visitor to the repository.

If you want someone requesting an item to provide more information that the default email address and reason, you can add additional fields to the request form using the methods outlined below.

Adding additional fields to the request dataset

The 'requests' are dataobjects - very similar to an eprint, or a user, so you can add fields in the same way.

Add configuration for new fields

In a config file e.g. [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/cfg.d/

## Additional fields for 'Request a copy'
push @{$c->{fields}->{request}},
        name => "contact_num",
        type => "text",
        name => "id_num",
        type => "text",

After adding this file, test the config is OK (avoid syntax errors):

> [EPRINTS_ROOT]/bin/epadmin test [ARCHIVE_ID]

Add phrases for new fields

Add the phrases to e.g. [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/lang/en/phrases/z_request_fields.xml:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE phrases SYSTEM "entities.dtd">
<epp:phrases xmlns="" xmlns:epp="" xmlns:epc="">
  <epp:phrase id="request_fieldname_contact_num">Contact number</epp:phrase>
  <epp:phrase id="request_fieldhelp_contact_num">A number that we can contact you on to discuss your request if necessary </epp:phrase>

  <epp:phrase id="request_fieldname_id_num">ID number</epp:phrase>
  <epp:phrase id="request_fieldhelp_id_num">The identification number from your staff/student card</epp:phrase>

Then run:

> [EPRINTS_ROOT]/bin/epadmin update [ARCHIVE_ID]

This will add the columns to the database.

Adding fields to the workflow

By default the workflow is in the global configuration. It can be customised by copying the default request workflow to the repository config:

> mkdir [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/workflows/request
> cp [EPRINTS_ROOT]/lib/workflows/request/default.xml [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/workflows/request

Reload Apache

Test the config again:

> [EPRINTS_ROOT]/bin/epadmin test [ARCHIVE_ID]

Restart Apache (this command depends on which operating system you use - you may need to do something slightly different!) > sudo service httpd graceful

This should have added the fields to the 'Request a copy' workflow.

Altering the email sent to the contact_email address

There are two ways this can be achieved - depending on your version of EPrints.

Method A: Editing the 'requester' citation (For EPrints v3.3.12 and above)

If you are using a recent version of EPrints, and the file [EPRINTS_ROOT]/lib/citations/request/requester.xml exists, there is a simple way to include the new fields in the email to the contact_email address. Your version of EPrints uses a citation to include some information from the request dataobject in the request email.

Copy requester citation to local configuration

By default the request/requester citation is defined in the global configuration. Don't edit that version (as it will be overwritten when EPrints is upgraded). Make a copy:

> mkdir [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/citations/request/
> cp [EPRINTS_ROOT]/lib/citations/reuqest/requester.xml [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/citations/request/

Edit requester citation

Add the new fields to the requester citation:

<?xml version="1.0" ?>
<cite:citation xmlns="" xmlns:cite="" xmlns:epc="">
  <epc:print expr="requester_email"/>
  <epc:if test="contact_num"><br /><epc:phrase ref="request_fieldname_contact_num" />: <epc:print expr="contact_num"/></epc:if>
  <epc:if test="id_num"><br /><epc:phrase ref="request_fieldname_id_num" />: <epc:print expr="id_num"/></epc:if>

Test the config, restart Apache

Run the epadmin test to check everything is OK, and then restart Apache.

EPrints will pick up changes within an existing XML file when you edit it, but it will not detect a new XML file (such as the local requester.xml citation) by default - so a restart (or a reload) is needed.

Method B: Overriding EPrints::Plugin::Screen::Public::RequestCopy

If your version of EPrints doesn't have the above file, or you need to do something more complex than just adding the fields, follow these instructions!

The screen that processes the request being made (not the response to the request) is EPrints::Plugin::Screen::Public::RequestCopy. To include the additional data in the email sent to the contact_email address, we need to change the way this behaves - specifying the additional details to be added.

The correct 'EPrints' way to do this for a plugin is outlined here:

Understand how the current script works

Take a look at EPrints::Plugin::Screen::Public::RequestCopy and try to understand it (a bit at least).

Work out which of the methods you need to work differently.

Make a local copy of the plugin

mkdir -p [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/plugins/EPrints/Plugins/Screen/Public/RequestCopy/
cp [EPRINTS_ROOT]/perl_lib/EPrints/Plugins/Screen/Public/ [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/plugins/EPrints/Plugins/Screen/Public/RequestCopy/

Edit the local copy of the plugin

The package name and 'isa' need to be updated as this is a subclass of the existing plugin.

Any methods that you don't need to change can also be removed (as they'll be inherited from the main RequestCopy module).

PLEASE NOTE the example code below may have been taken from a different version of EPrints to the one you are running. DO NOT just copy and paste it. Please follow the process above to take a copy of RequestCopy from your server, and edit it!

The changes are indicated with ### INSERTED CODE ### comments.

# Example taken from

package EPrints::Plugin::Screen::Public::RequestCopy::LocalRequestCopy;

@ISA = ( 'EPrints::Plugin::Screen::Public::RequestCopy' );

use strict;

sub action_request
	my( $self ) = @_;

	my $session = $self->{session};

	my $request = $self->{processor}->{dataobj};

	my $rc = $self->workflow->update_from_form( $self->{processor} );
	return if !$rc; # validation failed

	my $email = $request->value( "requester_email" );

	my $use_pin_security = $session->config( 'use_request_copy_pin_security' );

	my $eprint = $self->{processor}->{eprint};
	my $doc = $self->{processor}->{document};
	my $contact_email = $self->{processor}->{contact_email};

	my $user = EPrints::DataObj::User::user_with_email( $session, $contact_email );
	if( defined $user )
		$request->set_value( "userid", $user->id );

	$request = $self->{processor}->{dataset}->create_dataobj( $request->get_data );

	my $history_data = {
	if( defined $self->{processor}->{user} )
		$history_data->{userid} = $self->{processor}->{user}->get_id;
		$history_data->{actor} = $email;

	# Log request creation event
	my $history_ds = $session->dataset( "history" );
	$history_ds->create_object( $session, $history_data );

	# Send request email
	my $subject = $session->phrase( "request/request_email:subject", eprint => $eprint->get_value( "title" ) );
	my $mail = $session->make_element( "mail" );
	$mail->appendChild( $session->html_phrase(
		eprint => $eprint->render_citation_link_staff,
		document => defined $doc ? $doc->render_value( "main" ) : $session->make_doc_fragment,
		requester => $request->render_citation( "requester" ),
# this checks whether the value is set, and returns either the rendered value, or an empty document fragment
# the pins for a phrase must be XML fragments - not scalar values.
# The corresponding phrase (request/request_email:body) must also be updated to expect the new data.
		contact_num => $request->is_set( "contact_num" ) ? $request->render_value( "contact_num" ) : $session->make_doc_fragment,
		id_num => $request->is_set( "id_num" ) ? $request->render_value( "id_num" ) : $session->make_doc_fragment,
		reason => $request->is_set( "reason" ) ? $request->render_value( "reason" )
			: $session->html_phrase( "Plugin/Screen/EPrint/RequestRemoval:reason" ) ) );

	my $result;
	if( ( defined $user || $use_pin_security ) && defined $doc )
		# Contact is a registered user or it doesn't matter
		# because we're using the pin security model, and
		# EPrints holds the requested document

		# Send email to contact with accept/reject links

		my $url;
		if ( $use_pin_security )
			# Handle the response via a non-authenticated CGI script
			$url = $session->get_url( host => 1, path => "cgi", "respond_to_doc_request" );
					pin => $request->get_value( 'pin' ),
			# Handle the response via cgi/users/home which is authenticated
			$url = $session->get_url( host => 1, path => "cgi", "users/home" );
					screen => "Request::Respond",
					requestid => $request->id,

		$mail->appendChild( $session->html_phrase( "request/request_email:links",
			accept => $session->render_link( "$url&action=accept" ),
			reject => $session->render_link( "$url&action=reject" ) ) );

		my $to_name;
		if ( defined $user )
			$to_name = EPrints::Utils::tree_to_utf8( $user->render_description );
			$to_name = $contact_email;

		$result = EPrints::Email::send_mail(
			session => $session,
			langid => $session->get_langid,
			to_name => $to_name,
			to_email => $contact_email,
			subject => $subject,
			message => $mail,
			sig => $session->html_phrase( "mail_sig" ),
			cc_list => EPrints::Utils::is_set( $session->config( "request_copy_cc" ) ) ? $session->config( "request_copy_cc" ) : [],
		# Contact is non-registered user or EPrints holds no documents
		# Send email to contact with 'replyto'
		$result = EPrints::Email::send_mail(
			session => $session,
			langid => $session->get_langid,
			to_name => defined $user ? EPrints::Utils::tree_to_utf8( $user->render_description ) : "",
			to_email => $contact_email,
			subject => $subject,
			message => $mail,
			sig => $session->html_phrase( "mail_sig" ),
			replyto_email => $email,
			cc_list => EPrints::Utils::is_set( $session->config( "request_copy_cc" ) ) ? $session->config( "request_copy_cc" ) : [],

	if( !$result )
		$self->{processor}->add_message( "error", $session->html_phrase( "general:email_failed" ) );
	# Send acknowledgement to requester
	$mail = $session->make_element( "mail" );
	$mail->appendChild( $session->html_phrase(
		document => defined $doc ? $doc->render_value( "main" ) : $session->make_doc_fragment,
		eprint	=> $eprint->render_citation_link ) );

	$result = EPrints::Email::send_mail(
		session => $session,
		langid => $session->get_langid,
		to_email => $email,
		subject => $session->phrase( "request/ack_email:subject", eprint=>$eprint->get_value( "title" ) ), 
		message => $mail,
		sig => $session->html_phrase( "mail_sig" )

	if( !$result )
		$self->{processor}->add_message( "error", $session->html_phrase( "general:email_failed" ) );
	$self->{processor}->add_message( "message", $session->html_phrase( "request/ack_page", link => $session->render_link( $eprint->get_url ) ) );
	$self->{processor}->{request_sent} = 1;


Add phrase

The changes to the perl module add two new pins to the phrase. We have to update a local copy of the phrase and add places for these pins to be inserted. In the file [EPRINTS_ROOT]/lib/lang/en/phrases/system.xml locate the phrase request/request_email:body (see:

Copy this phrase into an XML phrase file e.g. [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/lang/en/phrases/z_request_fields.xml - used above. Edit the phrase, defining places for the new pins to appear:

<epp:phrase id="request/request_email:body">
  <p>This item has been requested from <epc:phrase ref="archive_name" /> by <epc:pin name="requester"/>.</p>
  <p>Contact number: <epc:pin name="contact_num"/><br />
     ID number: <epc:pin name="id_num"/></p>
  <p>Please can you respond.</p>

  <p><epc:pin name="eprint"/><br/><epc:pin name="document"/></p>
  <p>The following reason was given:</p>
  <epc:pin name="reason"/>

  <p>Please consider removing restrictions or uploading the full text to the archive so that it will be available immediately to future searchers.</p>

Enable plugin (map)

Finally, we have to tell EPrints to use our new plugin in place of the existing one.

Read the details in [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/cfg.d/

Once you understand what need to be done, add the plugin enabling code in a suitable configuration file e.g. [EPRINTS_ROOT]/archives/[ARCHIVE_ID]/cfg/cfg.d/

$c->{plugin_alias_map}->{"Screen::Public::RequestCopy"} = "Screen::Public::RequestCopy::LocalRequestCopy";
$c->{plugin_alias_map}->{"Screen::Public::RequestCopy::LocalRequestCopy"} = undef;

# If this doesn't seem to work, try uncommenting this:
# $c->{plugins}->{"Screen::Public::RequestCopy::LocalRequestCopy"}->{params}->{disable} = 0;

Test everything and restart apache

Using the same procedure as after adding the fields.

If the epadmin test returns no errors, restart Apache, and try requesting something!