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
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
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
$c->add_dataset_field( "user",
{
name => 'deposit_division',
type => 'subject',
top => 'divisions',
# NB This is NOT a multiple field.
}
);
Add phrases for user field
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
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 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
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
Configuration of metafields
- 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 ~/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
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
Update the database how you normally do it (web interface or commandline) and reload the server config. Test it works :o)
Adding a default
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>