</actions>
</permacrud>
</class>
+ <class id="aupsd" controller="open-ils.cstore" oils_obj:fieldmapper="action::usr_password_set_date" reporter:label="User Password Set Date" oils_persist:readonly="true">
+ <oils_persist:source_definition><![CDATA[
+ SELECT usr,create_date,edit_date FROM actor.passwd
+ ]]></oils_persist:source_definition>
+ <fields oils_persist:primary="id">
+ <field reporter:label="User ID" name="usr" reporter:datatype="id" />
+ <field reporter:label="Create Date" name="create_date" reporter:datatype="timestamp"/>
+ <field reporter:label="Last Edit Date" name="edit_date" reporter:datatype="timestamp"/>
+ </fields>
+ <links>
+ <link field="usr" reltype="has_a" key="id" map="" class="au"/>
+ </links>
+ </class>
<class id="aupr" controller="open-ils.cstore" oils_obj:fieldmapper="actor::usr_password_reset" oils_persist:tablename="actor.usr_password_reset" reporter:label="User password reset requests">
<fields oils_persist:primary="id" oils_persist:sequence="actor.usr_password_reset_id_seq">
<field reporter:label="Request ID" name="id" reporter:datatype="id"/>
my $old_patron;
my $barred_hook = '';
my $renew_hook = '';
+ my $password_hook = '';
if($patron->isnew()) {
( $new_patron, $evt ) = _add_patron($e, _clone_patron($patron));
modify_migrated_user_password($e, $patron->id, $patron->passwd);
$new_patron->passwd(''); # subsequent update will set
# actor.usr.passwd to MD5('')
+ #$U->create_events_for_hook('au.passwd_changed', $db_user, $e->requestor->ws_ou);
+ $password_hook = 'au.passwd_changed';
}
}
$tses->request('open-ils.trigger.event.autocreate', $barred_hook,
$new_patron, $new_patron->home_ou) if $barred_hook;
+
+ $tses->request('open-ils.trigger.event.autocreate', $password_hook,
+ $new_patron, $new_patron->home_ou) if $password_hook;
}
$e->xact_begin; # $e->rollback is called in new_flesh_user
# NOTE: with access to the plain text password we could crypt
# the password without the extra MD5 pre-hashing. Other changes
# would be required. Noting here for future reference.
- modify_migrated_user_password($e, $db_user->id, $new_val);
+ modify_migrated_user_password($e, $db_user->id, $new_val);
$db_user->passwd('');
-
+ $U->create_events_for_hook('au.passwd_changed', $db_user, $e->requestor->ws_ou);
} else {
# if we don't clear the password, the user will be updated with
# All is well; update the password
modify_migrated_user_password($e, $user->id, $password);
-
+ $U->create_events_for_hook('au.passwd_changed', $user, $user->home_ou);
+
# And flag that this password reset request has been honoured
$aupr->[0]->has_been_reset('t');
$e->update_actor_usr_password_reset($aupr->[0]);
return $db_result;
}
}
+
+__PACKAGE__->register_method(
+ method => "get_password_last_edit_age",
+ api_name => "open-ils.actor.get_password_age"
+);
+
+sub get_password_last_edit_age {
+ my( $self, $client, $auth, $patron_id ) = @_;
+ my $e = new_editor(authtoken => $auth);
+ return $e->event unless $e->checkauth;
+ my $patron = $e->retrieve_actor_user($patron_id);
+
+ #return unless the requestor is either the patron in question, or can view users at that patron's home ou
+ unless($patron && ($patron_id == $e->requestor->id || $e->allowed('VIEW_USER', $patron->home_ou))) {
+ return $e->event;
+ }
+
+ #get the password dates from the virtual table
+ my $aupsds = $e->json_query({
+ select => {aupsd => ['create_date','edit_date']},
+ from => 'aupsd',
+ where => {
+ usr => $patron_id
+ }
+ });
+
+ if(defined $aupsds){
+ my $pwd = $aupsds->[0];
+ #convert the dates with the DateTime module
+ if($pwd){
+ my $edit_datetime = DateTime::Format::ISO8601->parse_datetime(clean_ISO8601($pwd->{'edit_date'}));
+ #get time in days since last password update
+ #my $now = DateTime->today()->iso8601();
+ my $now = DateTime->now();
+
+ my $duration = $now->subtract_datetime_absolute($edit_datetime)->delta_seconds / (24*60*60);
+ return int($duration);
+ }
+ }
+ #no password entry, return -1 days
+ return -1;
+}
+
__PACKAGE__->register_method(
method => 'address_alert_test',
api_name => 'open-ils.actor.address_alert.test',
use OpenSRF::Utils::Cache;
use OpenILS::Event;
use DateTime::Format::ISO8601;
+use Data::Dumper;
use CGI qw(:all -utf8);
use Time::HiRes;
$ctx->{authtoken} = $e->authtoken;
$ctx->{authtime} = $e->authtime;
$ctx->{user} = $e->requestor;
+ $ctx->{password_age} = int($U->simplereq(
+ 'open-ils.actor',
+ 'open-ils.actor.get_password_age', $e->authtoken, $ctx->{user}->id));
my $card = $self->editor->retrieve_actor_card($ctx->{user}->card);
$ctx->{active_card} = (ref $card) ? $card->barcode : undef;
$ctx->{place_unfillable} = 1 if $e->requestor->wsid && $e->allowed('PLACE_UNFILLABLE_HOLD', $e->requestor->ws_ou);
<div id="acct_sum_block" class="container">
<h3>[% l('My Account Summary') %]</h3>
<div class="row">
+ <br>
+ [% IF ctx.password_age && ctx.password_age_reminder && ctx.disable_password_change != 'true' %]
+ [% need_password_change = ctx.password_age == -1 || ctx.password_age >= ctx.password_age_reminder %]
+ <div class="col-12">
+ [% IF ctx.password_age == -1 %]
+ You have never changed your password. Please consider updating your password.
+ [% ELSIF ctx.password_age >= (ctx.password_age_reminder - 7) %]
+ Your password is <b>[% ctx.password_age %]</b> days old[%- IF !need_password_change %], you will be asked to change it soon.[%- ELSE %]. We recommend passwords be updated every <b>[% ctx.password_age_reminder %]</b> days. Please consider updating your password.[% END %]
+ [% END %]
+ [% IF need_password_change %]
+ <br>
+ <a class="btn btn-sm btn-action" href='update_password'
+ title="[% l('Change Password') %]"><i class="fas fa-user-cog"></i> [% l("Change Password") %]</a>
+ <br>
+ [% END %]
+ </div>
+ <br>
+ [% END %]
<div class="col-12">
<span [% IF ctx.expired_card %]class="danger"[% END %]>
[% l("Account Expiration Date - ") %]
</span>
[% END %]
</div>
- <br>
+ <br>
<div class="col-12">
<a href="[% mkurl(ctx.opac_root _ '/myopac/circs') %]"
title="[% l('View My Checked Out Items') %]">
##############################################################################
ctx.show_reservations_tab = 'false';
+##############################################################################
+# Password Reminder Settings
+##############################################################################
+
+# days since last password change to start reminding a patron to change their password
+# commenting out this line will disable the reminder
+ctx.password_age_reminder = 15;
%]
# Edit parts/record/contents.tt2 to designate character length on a field-by-
# field basis for notes.
+
+##############################################################################
+# Password Reminder Settings
+##############################################################################
+
+# days since last password change to start reminding a patron to change their password
+# commenting out this line will disable the reminder
+ctx.password_age_reminder = ctx.get_org_setting(ctx.physical_loc || 1, 'global.password_reset_age');
%]
[% l('Generate Password') %]</button>
</div>
</div>
-
+<div class="row reg-field-row">
+ <div class="col-md-3">
+ </div>
+ <div class="col-md-9">
+ <div ng-show="password_age !== undefined && password_age !== '' && password_age !== '-1'"><i>Password last changed <b>{{password_age}}</b> day(s) ago</i></div>
+ <div ng-show="password_age === '-1'"><i>User has never changed their password</i></div>
+ </div>
+</div>
<div class="row reg-field-row">
<div class="col-md-6">
<ul class="nav nav-pills nav-pills-like-tabs">
<h1 class="sr-only" i18n>Evergreen Staff Client Home Page</h1>
</div>
</div>
+ <div ng-if="password_reset_age && password_age >= password_reset_age" class="alert alert-danger row">Your password is <b>{{password_age}} days</b> old. It is recommended that passwords be updated every <b>{{password_reset_age}} days</b>.
+ <p ng-if="!can_self_update">
+ Please contact an adminstrator to have your password changed.
+ </p>
+ <div ng-if="can_self_update">
+ <br>
+ <a class="btn btn-warning btn-block" target="_top" href="{{self_update_link}}">
+ Update Password
+ </a>
+ </div>
+ </div>
<br/>
<div class="row" id="splash-nav">
function($scope, $window,egCore) {
$scope.focus_search = true;
-
+ $scope.can_self_update = false;
+
egCore.strings.setPageTitle(
egCore.strings['PAGE_TITLE_SPLASH']);
-
+ egCore.org.settingsFromServer(['global.password_reset_age','global.password_regex']).then(function(settings) {
+ $scope.password_reset_age = parseInt(settings['global.password_reset_age']);
+ });
+ egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.get_password_age',
+ egCore.auth.token(),
+ egCore.auth.user().id()
+ ).then(function(age) {
+ $scope.password_age = parseInt(age);
+ });
+ egCore.perm.hasPermHere('EDIT_SELF_IN_CLIENT')
+ .then(function(bool){
+ $scope.can_self_update = bool;
+ $scope.self_update_link = './circ/patron/' + egCore.auth.user().id() + '/edit'
+ });
$scope.catalog_search = function($event) {
$scope.focus_search = true;
if (!$scope.cat_query) return;
// These are fetched with every instance of the page.
var page_data = [
service.get_user_settings(),
+ service.get_user_password_age(),
service.get_clone_user(),
service.get_stage_user()
];
});
}
+ service.get_user_password_age = function() {
+ return egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.get_password_age',
+ egCore.auth.token(),
+ service.patron_id
+ ).then(function(age) {
+ console.log("retrieved from AUSPD: "+age)
+ service.password_age = age;
+ });
+ }
+
service.invalidate_field = function(patron, field) {
console.log('Invalidating patron field ' + field);
$scope.stat_cat_entry_maps = prs.stat_cat_entry_maps;
$scope.stage_user = prs.stage_user;
$scope.stage_user_requestor = prs.stage_user_requestor;
+ $scope.password_age = prs.password_age;
$scope.user_settings = prs.user_settings;
prs.user_settings = {};