/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.eperson;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.commons.cli.*;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
import org.dspace.storage.rdbms.DatabaseManager;
import org.dspace.storage.rdbms.TableRow;
import org.dspace.storage.rdbms.TableRowIterator;
/**
* Tools for manipulating EPersons and Groups.
*
* @author mwood
*/
public class Groomer
{
private static final DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
/**
* Command line tool for "grooming" the EPerson collection.
*/
static public void main(String[] argv)
throws SQLException
{
final String USAGE = "Groomer -verb [option...]";
OptionGroup verbs = new OptionGroup();
verbs.setRequired(true);
verbs.addOption(new Option("h", "help", false, "explain this tool"));
verbs.addOption(new Option("a", "aging", false, "discover accounts not used recently"));
verbs.addOption(new Option("u", "unsalted", false, "list accounts with unsalted password hashes"));
Options options = new Options();
options.addOptionGroup(verbs);
options.addOption("b", "last-used-before", true,
"date of last login was before this (for example: "
+ dateFormat.format(Calendar.getInstance().getTime())
+ ')');
options.addOption("d", "delete", false, "delete matching epersons");
PosixParser parser = new PosixParser();
CommandLine command = null;
try {
command = parser.parse(options, argv);
} catch (ParseException ex) {
System.err.println(ex.getMessage());
if (! (ex instanceof MissingOptionException))
new HelpFormatter().printHelp(USAGE, options);
System.exit(1);
}
// Help the user
if (null == command || command.hasOption('h') || command.hasOption('?'))
{
new HelpFormatter().printHelp(USAGE, options);
System.exit(0);
}
// Scan for disused accounts
else if (command.hasOption('a'))
{
aging(command);
}
// List accounts with unsalted passwords
else if (command.hasOption('u'))
{
findUnsalted();
}
// Should not happen: verb option defined but no code!
else
System.err.println("Unimplemented verb: " + verbs.getSelected());
}
/**
* Find and optionally delete accounts not logged in recently.
*
* @param command a parsed command line.
* @throws SQLException from callees.
*/
private static void aging(CommandLine command) throws SQLException
{
if (!command.hasOption('b'))
{
System.err.println("A last login date is required.");
System.exit(1);
}
Date before = null;
try {
before = dateFormat.parse(command.getOptionValue('b'));
} catch (java.text.ParseException ex) {
System.err.println(ex.getMessage());
System.exit(1);
}
boolean delete = command.hasOption('d');
Context myContext = new Context();
final TableRowIterator tri = DatabaseManager.queryTable(myContext,
"EPerson",
"SELECT eperson_id, email, netid FROM EPerson WHERE last_active < ?",
new java.sql.Date(before.getTime()));
myContext.turnOffAuthorisationSystem();
while (tri.hasNext())
{
TableRow row = tri.next();
if (null == row)
break;
int id = row.getIntColumn("eperson_id");
EPerson account = EPerson.find(myContext, id);
System.out.print(id);
System.out.print('\t');
System.out.print(account.getLastActive());
System.out.print('\t');
System.out.print(account.getEmail());
System.out.print('\t');
System.out.print(account.getNetid());
System.out.print('\t');
System.out.print(account.getFullName());
System.out.println();
if (delete)
{
List<String> whyNot = account.getDeleteConstraints();
if (!whyNot.isEmpty())
{
System.out.print("\tCannot be deleted; referenced in");
for (String table : whyNot)
{
System.out.print(' ');
System.out.print(table);
}
System.out.println();
}
else
try {
account.delete();
} catch (AuthorizeException | EPersonDeletionException ex) {
System.err.println(ex.getMessage());
}
}
}
myContext.restoreAuthSystemState();
myContext.complete();
}
/**
* List accounts having no password salt.
*
* @throws SQLException
*/
private static void findUnsalted()
throws SQLException
{
Context myContext = new Context();
final TableRowIterator tri = DatabaseManager.query(myContext,
"SELECT email FROM EPerson WHERE password IS NOT NULL AND digest_algorithm IS NULL");
for (TableRow row = tri.next(); tri.hasNext(); row = tri.next())
System.out.println(row.getStringColumn("email"));
myContext.abort(); // No changes to commit
}
}