# ---------------------------------------------------------------
# Copyright (C) 2010 Equinox Software, Inc
# Author: Joe Atzberger <jatzberger@esilibrary.com>
+# Portions Copyright (C) 2011 Merrimack Valley Library Consortium
+# Author: Jason Stephenson <jstephenson@mvlc.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
use OpenILS::Utils::Fieldmapper;
use OpenILS::Utils::Lockfile;
use OpenILS::Utils::CStoreEditor q/:funcs/;
+use OpenILS::Application::AppUtils;
use File::Basename qw/fileparse/;
our $debug = 0;
+my $apputils = 'OpenILS::Application::AppUtils';
+
sub _default_self {
return {
# opts => {},
my $self = shift or return;
$self->{bootstrapped} or $self->bootstrap();
@_ or croak "session() called without required argument (app_name, e.g. 'open-ils.acq')";
- return ($self->{session} ||= OpenSRF::AppSession->create(@_));
+ return OpenSRF::AppSession->create(@_);
}
sub bootstrap {
return new_editor(@_);
}
+# Die on an event. Takes an optional third parameter for the textcode
+# of an event to die on. If the event textcode does not match the
+# third parameter, will warn on the event instead of dying.
+sub die_event {
+ my $self = shift;
+ my $e = shift;
+ my $name = shift;
+ if ($apputils->event_code($e)) {
+ if (!defined($name) || $apputils->event_equals($e,$name)) {
+ croak(Dumper $e);
+ } else {
+ carp(Dumper $e);
+ }
+ }
+}
+
+# Prints warning on an even. Takes an optional third parameter for the
+# textcode of an event to warn on.
+sub warn_event {
+ my $self = shift;
+ my $e = shift;
+ my $name = shift;
+ if ($apputils->event_code($e)
+ && (!defined($name) || $apputils->event_equals($e, $name))) {
+ carp(Dumper $e);
+ }
+}
+
# Authenticate with the open-ils.auth module.
# Takes a hash ref of arguments:
# {
my $self = shift or return;
my $args = shift or return;
if ($args && ref($args) eq 'HASH') {
- $self->{bootstrapped} or $self->bootstrap();
+ # Default to staff in case the back end ever stops doing so.
+ $args->{type} = 'staff' unless (defined($args->{type}));
- my $session = OpenSRF::AppSession->create('open-ils.auth');
+ my $session = $self->session('open-ils.auth');
my $seed = $session->request(
'open-ils.auth.authenticate.init', $args->{'username'}
)->gather(1);
} else {
$self->{authtoken} = undef;
$self->{authtime} = undef;
+ carp("Authentication failed");
}
$session->disconnect();
return $self->authtoken;
}
}
+# Deletes the session for our authtoken if we have logged in with the
+# authenticate method.
+sub logout {
+ my $self = shift or return;
+ my $token = shift || $self->{authtoken};
+ if ($token) {
+ my $session = $self->session('open-ils.auth');
+ if ($session->request('open-ils.auth.session.delete', $token)->gather(1)) {
+ if ($token eq $self->{authtoken}) {
+ $self->{authtoken} = undef;
+ $self->{authtime} = undef;
+ }
+ } else {
+ carp("Not authenticated");
+ }
+ $session->disconnect();
+ } else {
+ carp("No authtoken");
+ }
+}
+
sub authtoken {
my $self = shift;
return $self->{authtoken};
=head1 NAME
-OpenILS::Utils::Cronscript - Consolidated options handling for any script (not just cron, really)
+OpenILS::Utils::Cronscript - Consolidated options handling and utility
+methods for any script (not just cron, really)
=head1 SYNOPSIS
'user=s' => 'admin',
'password=s' => '',
'nolockfile' => 1,
- };
+ );
my $core = OpenILS::Utils::Cronscript->new(\%defaults);
my $opts = $core->MyGetOptions(); # options now in, e.g.: $opts->{max}
$core->bootstrap;
-Or if you don't need any additional options and just want to get a session going:
-
+You can skip alot of the above if you're happy with the defaults:
+
+ my $script = OpenILS::Utils::Cronscript->new();
+
+If you just don't want a lock file:
+
+ my $core = OpenILS::Utils::Cronscript->new({nolockfile=>1});
+
+Or if you don't need any additional options and just want to get a
+session going:
+
use OpenILS::Utils::Cronscript;
my $session = OpenILS::Utils::Cronscript->new()->session('open-ils.acq');
+Cronscript gives you access to many useful methods:
+
+You can login if necessary:
+
+ my $account = {
+ username => 'admin',
+ password => 'password',
+ workstation => 'workstation_name', # optional
+ type => 'staff' # optional, but staff is the default
+ };
+ my $authtoken = $core->authenticate($account);
+
+You can logout a session given its authtoken:
+
+ $core->logout($authtoken);
+
+Or, if you've authenticated with the authenticate method, you can
+logout the most recently authenticated session:
+
+ $core->logout();
+
+If you have logged in with the authenticate method, you can retrieve
+your current authtoken or authtime values:
+
+ my $token = $core->authtoken;
+ my $authtime = $core->authtime;
+
+You can create a CStoreEdtor object:
+
+ my $editor = $core->editor(); # With defaults.
+ my $editor = $core->editor(authtoken=>$authtoken); # with a given
+ # session
+ my $editor = $core->editor(xact=>1); # With transactions or any
+ # other CStoreEditor options.
+
+You can create OpenSRF AppSesions to run commands:
+
+ my $pcrud = $core->session('open-ils.pcrud');
+ #...Do some pcrud stuff here.
+
+You can print warnings or die on events:
+
+ my $evt ...;
+ $core->warn_event($evt);
+ $core->die_event($evt);
+
+Or only on certain events:
+
+ $core->warn_event($evt, 'PERM_FAILURE');
+ $core->die_event($evt, 'PERM_FAILURE');
+
+Includes a shared debug flag so you can turn debug mode on and off:
+
+ $OpenILS::Utils::Cronscript::debug = 1; # Debugging on
+ $OpenILS::Utils::Cronscript::debug = 0; # Debugging off
+
+Includes OpenILS::Application::Apputils so using AppUtils methods is
+as simple as:
+
+ my $apputils = 'OpenILS::Application::AppUtils';
+ $apputils->event_code($evt);
+
+Uses and imports the OpenILS::Utils::Fieldmapper so you don't have to.
+
+Includes Data::Dumper, so you don't have to.
+
=head1 DESCRIPTION
-There are a few main problems when writing a new script for Evergreen.
+There are a few main problems when writing a new script for Evergreen.
=head2 Initialization
-The runtime
-environment for the application requires a lot of initialization, but during normal operation it
-has already occured (when Evergreen was started). So most of the EG code never has to deal with
-this problem, but standalone scripts do. The timing and sequence of requisite events is important and not obvious.
+The runtime environment for the application requires a lot of
+initialization, but during normal operation it has already occured
+(when Evergreen was started). So most of the EG code never has to
+deal with this problem, but standalone scripts do. The timing and
+sequence of requisite events is important and not obvious.
=head2 Common Options, Consistent Options
-We need several common options for each script that accesses the database or
-uses EG data objects and methods. Logically, these options often deal with initialization. They
-should take the B<exact> same form(s) for each script and should not be
-dependent on the local author to copy and paste them from some reference source. We really don't want to encourage (let alone force)
-admins to use C<--config>, C<--osrf-confg>, C<-c>, and C<@ARGV[2]> for the same purpose in different scripts, with different
-default handling, help descriptions and error messages (or lack thereof).
+We need several common options for each script that accesses the
+database or uses EG data objects and methods. Logically, these
+options often deal with initialization. They should take the B<exact>
+same form(s) for each script and should not be dependent on the local
+author to copy and paste them from some reference source. We really
+don't want to encourage (let alone force) admins to use C<--config>,
+C<--osrf-confg>, C<-c>, and C<@ARGV[2]> for the same purpose in
+different scripts, with different default handling, help descriptions
+and error messages (or lack thereof).
-This suggests broader problem of UI consistency and uniformity, also partially addressed by this module.
+This suggests broader problem of UI consistency and uniformity, also
+partially addressed by this module.
=head2 Lockfiles
-A lockfile is necessary for a script that wants to prevent possible simultaneous execution. For example, consider a script
-that is scheduled to run frequently, but that experiences occasional high load: you wouldn't want crontab to start running
-it again if the first instance had not yet finished.
+A lockfile is necessary for a script that wants to prevent possible
+simultaneous execution. For example, consider a script that is
+scheduled to run frequently, but that experiences occasional high
+load: you wouldn't want crontab to start running it again if the first
+instance had not yet finished.
-But the code for creating, writing to, checking for, reading and cleaning up a lockfile for the script bloats what might otherwise be a terse
-method call. Conscript handles lockfile generation and removal automatically.
+But the code for creating, writing to, checking for, reading and
+cleaning up a lockfile for the script bloats what might otherwise be a
+terse method call. Conscript handles lockfile generation and removal
+automatically.
=head1 OPTIONS
'verbose+' => 0,
'help' => 0,
-=head1 TODO
-
-More docs here.
-
=head1 SEE ALSO
Getopt::Long
+ OpenILS::Application::AppUtils
+ OpenILS::Utils::Fieldmapper
OpenILS::Utils::Lockfile
- oils_header.pl
-=head1 AUTHOR
+=head1 AUTHORS
-Joe Atzberger <jatzberger@esilibrary.com>
+ Joe Atzberger <jatzberger@esilibrary.com>
+ Jason Stephenson <jstephenson@mvlc.org>
=cut