From 0ee0f810245229fc748526210952fa834824cb1a Mon Sep 17 00:00:00 2001 From: Erik Thuning <boooink@gmail.com> Date: Fri, 29 Apr 2022 15:58:38 +0200 Subject: [PATCH] Changed cron behaviour to warn users 3 days before their loans end --- include/Cron.php | 221 +++++++++++++++++++++++++++++++++-------------- include/Kvs.php | 4 +- include/Ldap.php | 25 +++--- include/Loan.php | 14 ++- include/User.php | 10 +++ 5 files changed, 194 insertions(+), 80 deletions(-) diff --git a/include/Cron.php b/include/Cron.php index 7ca58e8..ad6d26b 100644 --- a/include/Cron.php +++ b/include/Cron.php @@ -6,22 +6,26 @@ class Cron { private $kvs; private $ldap; public function __construct($sender, $error) { - $this->now = time(); + $this->now = new DateTimeImmutable(); $this->sender = $sender; $this->error = $error; + $warn_time = DateInterval::createFromDateString('3 days'); + $this->warn_date = $this->now->add($warn_time); + $this->run_interval = DateInterval::createFromDateString('1 day'); $this->kvs = new Kvs(); $this->ldap = new Ldap(); } public function run() { - $lastrun = $this->kvs->get_value('lastrun'); - $interval = 3600*24; //1 day in seconds - - if($lastrun && $this->now - $lastrun < $interval) { + $lastrun = $this->kvs->get_value('lastrun', 0); + $nextrun = $this->now + ->setTimestamp($lastrun) + ->add($this->run_interval); + if($nextrun > $this->now) { return; } - $this->kvs->set_key('lastrun', $this->now); - + $this->kvs->set_key('lastrun', $this->now->getTimestamp()); + $users = get_items('user'); foreach($users as $user) { $this->check_loans($user); @@ -29,89 +33,174 @@ class Cron { } private function check_loans($user) { + $expiring = $user->get_expiring_loans($this->warn_date); $overdue = $user->get_overdue_loans(); - if($overdue) { - $this->send_reminder($user, $overdue); + if($expiring || $overdue) { + $this->send_reminder($user, $expiring, $overdue); } } - - private function send_reminder($user, $loans) { - $subject_template = "DSV Helpdesk: Du har ¤count¤ ¤late¤ lån"; - $reminder_template_sv = "¤brand¤ ¤name¤, försenad sedan ¤due¤\n"; - $reminder_template_en = "¤brand¤ ¤name¤, late since ¤due¤\n"; - $message_template = <<<EOF -Hej ¤name¤ -Vi vill påminna dig om att ditt lån har gått ut på följande ¤product_sv¤: + private function make_subject($num_expiring, $num_expired) { + $subject = "DSV Helpdesk: "; + $messages = array(); + if($num_expiring > 0) { + $messages[] = $num_expiring." utgående lån"; + } + if($num_expired > 1) { + $messages[] = $num_expired." försenade lån"; + } elseif($num_expired > 0) { + $messages[] = $num_expired." försenat lån"; + } + return $subject.implode(" och ", $messages); + } -¤list_sv¤ + private function make_expiring_notice($lang, $expiring) { + if(!$expiring) { + return ''; + } + $days = $this->warn_date->d; + switch($lang) { + case 'sv': + $msg = "Följande lån går ut om mindre än ".$days." dagar:"; + $itemglue = ", går ut "; + break; + case 'en': + if(count($expiring) == 1) { + $loanstr = "loan expires"; + } else { + $loanstr = "loans expire"; + } + $msg = "The following ".$loanstr." in less than ".$days." days:"; + $itemglue = ", expires on "; + break; + default: + throw new Exception("Invalid language: ".$lang); + } + $msg .= "\n\n"; + foreach($expiring as $loan) { + $product = $loan->get_product(); + $serial = $product->get_serial(); + $brand = $product->get_brand(); + $name = $product->get_name(); + $endtime = format_date($loan->get_endtime()); + $msg .= $serial.": ".$brand." ".$name.$itemglue.$endtime; + } + return $msg; + } -Vänligen återlämna ¤it_sv¤ till Helpdesk så snart som möjligt, alternativt svara på det här meddelandet för att förlänga ¤loan_sv¤. + private function make_overdue_notice($lang, $overdue) { + if(!$overdue) { + return ''; + } + switch($lang) { + case 'sv': + $msg = "Följande lån har gått ut:"; + $itemglue = ", gick ut "; + break; + case 'en': + if(count($overdue) == 1) { + $msg = "The following loan has expired:"; + } else { + $msg = "The following loans have expired:"; + } + $itemglue = ", expired on "; + break; + default: + throw new Exception("Invalid language: ".$lang); + } + $msg .= "\n\n"; + foreach($overdue as $loan) { + $product = $loan->get_product(); + $serial = $product->get_serial(); + $brand = $product->get_brand(); + $name = $product->get_name(); + $endtime = format_date($loan->get_endtime()); + $msg .= $serial.": ".$brand." ".$name.$itemglue.$endtime; + } + return $msg; + } + + private function make_return_info($lang, $count) { + switch($lang) { + case 'sv': + if($count > 1) { + $loan = "lånen"; + $product = "artiklarna"; + } else { + $loan = "lånet"; + $product = "artikeln"; + } + return "Vänligen kontakta Helpdesk för att förlänga $loan eller lämna tillbaka $product."; + break; + case 'en': + if($count > 1) { + $loan = "loans"; + $product = "items"; + } else { + $loan = "loan"; + $product = "item"; + } + return "Please contact Helpdesk in order to extend the $loan or return the $product."; + break; + default: + throw new Exception("Invalid language: ".$lang); + } + + } + + private function send_reminder($user, $expiring, $expired) { + $uid = $user->get_name(); + $name = $this->ldap->get_firstname($uid); + + $subject = $this->make_subject(count($expiring), count($expired)); + + $info_sv = array(); + $info_sv[] = $this->make_expiring_notice('sv', $expiring); + $info_sv[] = $this->make_overdue_notice('sv', $expired); + $info_sv = implode("\n\n", $info_sv); + $returns_sv = $this->make_return_info( + 'sv', count($expiring) + count($expired)); + + $info_en = array(); + $info_en[] = $this->make_expiring_notice('en', $expiring); + $info_en[] = $this->make_overdue_notice('en', $expired); + $info_en = implode("\n\n", $info_en); + $returns_en = $this->make_return_info( + 'en', count($expiring) + count($expired)); + + $message = <<<EOF +Hej $name! + +Det här är en automatisk påminnelse om lånade artiklar från Helpdesk. + +$info_sv + +$returns_sv ---- -We would like to remind you that your loan has expired on the following ¤product_en¤: +This is an automated reminder regarding items on loan from Helpdesk. -¤list_en¤ +$info_en -Please return ¤it_en¤ to the Helpdesk as soon as possible, or reply to this message in order to extend the ¤loan_en¤. +$returns_en Mvh DSV Helpdesk helpdesk@dsv.su.se 08 - 16 16 48 + EOF; - - $overdue_count = count($loans); - $reminder_list_sv = ''; - $reminder_list_en = ''; - $late = 'försenat'; - $product_sv = 'artikel'; - $product_en = 'product'; - $it_sv = 'den'; - $it_en = 'it'; - $loan_sv = 'lånet'; - $loan_en = 'loan'; - if($overdue_count > 1) { - $late = 'försenade'; - $product_sv = 'artiklar'; - $product_en = 'products'; - $it_sv = 'dem'; - $it_en = 'them'; - $loan_sv = 'lånen'; - $loan_en = 'loans'; - } - foreach($loans as $loan) { - $replacements = array('name' => $loan->get_product()->get_name(), - 'brand' => $loan->get_product()->get_brand(), - 'due' => format_date($loan->get_endtime())); - $reminder_list_sv .= replace($replacements, $reminder_template_sv); - $reminder_list_en .= replace($replacements, $reminder_template_en); - } - - $subject = replace(array('count' => $overdue_count, - 'late' => $late), $subject_template); - $message = replace(array('name' => $user->get_displayname($this->ldap), - 'list_sv' => $reminder_list_sv, - 'product_sv' => $product_sv, - 'it_sv' => $it_sv, - 'loan_sv' => $loan_sv, - 'list_en' => $reminder_list_en, - 'product_en' => $product_en, - 'it_en' => $it_en, - 'loan_en' => $loan_en), - $message_template); - try { - mb_send_mail($user->get_email($this->ldap), + mb_send_mail($this->ldap->get_user_email($uid), $subject, $message, 'From: '.$this->sender); } catch(Exception $e) { + error_log($e->message); mb_send_mail($this->error, "Kunde inte skicka påminnelse", - "Påminnelse kunde inte skickas till " - .$user->get_name()); + "Påminnelse kunde inte skickas till ".$uid); } } } diff --git a/include/Kvs.php b/include/Kvs.php index e80edf8..2900dcd 100644 --- a/include/Kvs.php +++ b/include/Kvs.php @@ -16,11 +16,11 @@ class Kvs { return array_keys($this->items); } - public function get_value($key) { + public function get_value($key, $default=null) { if(isset($this->items[$key])) { return $this->items[$key]; } - return null; + return $default; } public function set_key($key, $value) { diff --git a/include/Ldap.php b/include/Ldap.php index 00e17b4..f43d7f9 100644 --- a/include/Ldap.php +++ b/include/Ldap.php @@ -2,7 +2,7 @@ class Ldap { private $conn; private $base_dn = "dc=su,dc=se"; - + public function __construct() { $this->conn = ldap_connect('ldaps://ldap.su.se'); ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3); @@ -13,23 +13,26 @@ class Ldap { $result = ldap_search($this->conn, $this->base_dn, $term, $attributes); return ldap_get_entries($this->conn, $result); } - - public function get_user($uid) { - $data = $this->search("uid=$uid", 'cn', 'uid'); + + public function get_attribute($uid, $attribute) { + $data = $this->search("uid=$uid", $attribute); if($data['count'] !== 1) { $err = "LDAP search for '$uid' did not return exactly one result"; throw new Exception($err); } - return $data[0]['cn'][0]; + return $data[0][strtolower($attribute)][0]; + } + + public function get_user($uid) { + return $this->get_attribute($uid, 'cn'); + } + + public function get_firstname($uid) { + return $this->get_attribute($uid, 'givenName'); } public function get_user_email($uid) { - $data = $this->search("uid=$uid", 'mail', 'uid'); - if($data['count'] !== 1) { - $err = "LDAP search for '$uid' did not return exactly one result"; - throw new Exception($err); - } - return $data[0]['mail'][0]; + return $this->get_attribute($uid, 'mail'); } public function search_email($email) { diff --git a/include/Loan.php b/include/Loan.php index 9bf38c8..08311b7 100644 --- a/include/Loan.php +++ b/include/Loan.php @@ -54,7 +54,7 @@ class Loan extends Event { $this->endtime = $ts; return true; } - + public function end() { $now = time(); $query = prepare('update `event` set `returntime`=? where `id`=?'); @@ -75,6 +75,18 @@ class Loan extends Event { return false; } + public function expires_before($datetime) { + if($this->returntime !== null) { + return false; + } + $endtime = new DateTime(); + $endtime->setTimestamp($this->endtime); + if(!$this->is_overdue() && $endtime < $datetime) { + return true; + } + return false; + } + public function get_status() { if($this->is_overdue()) { return 'overdue_loan'; diff --git a/include/User.php b/include/User.php index d77475f..a34ca03 100644 --- a/include/User.php +++ b/include/User.php @@ -189,5 +189,15 @@ class User extends Entity { } return $overdue; } + + public function get_expiring_loans($end_date) { + $expiring = array(); + foreach($this->get_loans('active') as $loan) { + if($loan->expires_before($end_date)) { + $expiring[] = $loan; + } + } + return $expiring; + } } ?>