How to control eprint workflow based on a user field
NOTE: This was originally written based on experience of an EPrints 3.3.10 install. It has been updated following a post on the EP-Tech list Restrict sepcific editor only upload in specific divisions (May 2026), and seems to work against a v3.4.6 archive.
Task[edit]
How to control the EPrint workflow, only show options (e.g. divisions/collections) that a user can deposit into? e.g.
- A user belongs to a specific division and can only assign sub-divisions from their division
- We have many 'collections'. Each EPrint belongs to one collection. Users can only deposit items into specific collections.
Divisions example[edit]
This is based on the default 'divisions', and is suitable for a user that belongs to one division. This approach won't work if you need to restrict to multiple divisions.
Add field to user, to control the division (or sub-divisions) they can deposit to[edit]
$c->add_dataset_field( "user",
{
name => 'deposit_division',
type => 'subject',
top => 'divisions',
# NB This is NOT a multiple field.
}
);Add phrases for user field[edit]
These should be added to a suitable phrase file within the archive configuration
<epp:phrase id="user_fieldname_deposit_division">Deposit division</epp:phrase>
<epp:phrase id="user_fieldhelp_deposit_division">If the user should only be allowed to deposit under one division, please add it here.</epp:phrase>Add new user field to the 'user admin' workflow[edit]
E.g. workflows/user/default.xml, in the 'usertype' stage, which is only visible to admins
<component><field ref="deposit_division"/></component>Update eprint workflow[edit]
Edit the eprint workflow (workflows/eprint/default.xml) to check whether the user has a deposit_division set. If they do, use that as the 'top' attribute for the divisions component. The 'as_string' is needed, otherwise the rendered version of the division will be used instead of the underlying value.
<!--
comment-out old divisions:
<component><field ref="divisions" /></component>
and use the following instead
-->
<epc:choose>
<epc:when test="$current_user{deposit_division}.is_set()">
<component><field ref="divisions" top="{$current_user{deposit_division}.as_string()}" /></component>
</epc:when>
<epc:otherwise>
<component><field ref="divisions" /></component>
</epc:otherwise>
</epc:choose>Test, deploy[edit]
Run ~/bin/epadmin test ARCHIVEID and if all OK, restart Apache. Now (as an admin user), you should be able to set a 'deposit division' for a user. Once set, that user should only see the section of 'divisions' below the value you have set for them.
If you just want to add a specific division to an EPrint, based on the value in the user profile, this can be achieved via eprint_fields_default or eprint_fields_automatic using something similar to this (see the 'Adding a default' section below):
my $repo = $eprint->repository;
if( defined $repo->current_user )
{
my $user = $repo->current_user;
if( $user->exists_and_set( "deposit_division" ) )
{
my $division = $user->value( "deposit_division" );
$eprint->set_value( "divisions", [ $division ] );
}
}Collections example[edit]
Configuration of metafields[edit]
- Create a namedset with the collections in it:
~/archives/ARCHIVEID/cfg/namedsets/collections
# A list of collections - remember to add the relevant phrases!
library
art_gallery
university_newspapers
lab_equipment- Add the metafield to both the eprint and the user. This can be done in a few different ways, this is one:
Edit ~/archives/ARCHIVEID/cfg/cfg.d/eprint_fields.pl, adding:
{
name => 'collection',
type => 'namedset',
set_name => "collections",
},Edit ~/archives/ARCHIVEID/cfg/cfg.d/user_fields.pl, adding:
{
name => 'collection',
type => 'namedset',
set_name => "collections",
multiple => 1, #Allows a user to have rights to more than one collection
},Add to user workflow[edit]
Edit ~/archives/ARCHIVEID/cfg/workflows/user/default.xml. We only want admin staff to be able to assign collections, so the field is added to the 'usertype' stage:
<stage name="usertype">
<component><field ref="usertype"/></component>
<component><field ref="username"/></component>
<component><field ref="collection"/></component>
<component><field ref="roles"/></component>
</stage>This allows one or more collections to be assigned to a user.
Add to EPrint workflow[edit]
To render only the collections that have been assigned to a user, we need to get the 'collection's from the owning user, join them into a comma-separated string and use that as the 'options' for the eprint collection field.
<component><field ref="collection" options="{join($item{userid}.as_item(){collection},',')}"/></component>We could also have used $current_user - which would be OK if the $current_user will have rights to more collections than the owning user.
Update database and restart webserver[edit]
Update the database how you normally do it (web interface or commandline) and reload the server config. Test it works :o)
Adding a default[edit]
If a user has no collections assigned in their profile, what should happen? We could either:
- always set a default collection in user_fields_default.pl
- use eprint_fields_default.pl to set a default collection for the eprint.
$c->{set_eprint_defaults} = sub
{
my( $data, $repository ) = @_;
my $user = $repository->current_user();
if( defined $user && $user->is_set( "collection" ) )
{
my $collections = $user->get_value( "collection" );
if( scalar @$collections == 1 ){
$data->{collection} = @$collections[0];
#We may also want to set some default metadata on items in this collection?
#Do it here - as we know we've got one collection!
if( $data->{collection} eq 'university_newspapers' ){
$data->{type} = "newspaper";
...
}
}
}
}If a user only has access to one collection, the value should be set automatically and the field not shown in the workflow.
<flow>
<epc:choose>
<epc:when test="$STAFF_ONLY = 'TRUE'">
<!-- Allow editors to choose any collection -->
<stage ref="collection"/>
</epc:when>
<epc:otherwise test="length( $item{userid}.as_item(){collection} ) gt 1">
<!-- If someone has access to more than one collection, offer their collections -->
<stage ref="collection"/>
</epc:otherwise>
</epc:choose>
...
</flow>
<stage name="collection">
<epc:if test="$STAFF_ONLY = 'TRUE'">
<component><field ref="collection" required="yes" /></component>
</epc:if>
<epc:if test="$STAFF_ONLY != 'TRUE'">
<component><field ref="collection" required="yes" options="{join($item{userid}.as_item(){collection},',')}"/></component>
</epc:if>
</stage>