From 06d05e099e7f3b5d4d770db80081cd51c9eb6eb0 Mon Sep 17 00:00:00 2001
From: root <root@dsv.su.se>
Date: Thu, 3 Jun 2021 13:46:19 +0200
Subject: [PATCH 1/9] Fixed a bug with saving templates

---
 script.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/script.js b/script.js
index 4ac5bfe..a708d23 100644
--- a/script.js
+++ b/script.js
@@ -357,7 +357,7 @@ function loadTemplate(event) {
 function saveTemplate(event) {
     event.preventDefault()
     var datalist = productDataList(document.querySelector('#product-data'))
-    datalist.push(['template', event.currentTarget.form.template.value])
+    datalist.append('template', event.currentTarget.form.template.value)
     ajaxRequest('savetemplate', datalist, showResult)
 }
 

From 3c8a0485dea4e545838ac35a1a34645d73f2689f Mon Sep 17 00:00:00 2001
From: root <root@dsv.su.se>
Date: Tue, 14 Sep 2021 22:45:28 +0200
Subject: [PATCH 2/9] Testing a hopefully faster ldap lookup

---
 include/Ajax.php         | 2 +-
 include/CheckoutPage.php | 2 +-
 include/Cron.php         | 6 ++++--
 include/Page.php         | 6 +++---
 include/Responder.php    | 2 ++
 include/User.php         | 9 ++++-----
 include/UserPage.php     | 2 +-
 7 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/include/Ajax.php b/include/Ajax.php
index 8ddadd3..4ede200 100644
--- a/include/Ajax.php
+++ b/include/Ajax.php
@@ -112,7 +112,7 @@ class Ajax extends Responder {
             $user = $loan->get_user();
             $userlink = replace(array('page' => 'users',
                                       'id'   => $user->get_id(),
-                                      'name' => $user->get_displayname()),
+                                      'name' => $user->get_displayname($this->ldap)),
                                 $this->fragments['item_link']);
             $productlink = replace(array('page' => 'products',
                                          'id'   => $product->get_id(),
diff --git a/include/CheckoutPage.php b/include/CheckoutPage.php
index e07f199..1da4759 100644
--- a/include/CheckoutPage.php
+++ b/include/CheckoutPage.php
@@ -33,7 +33,7 @@ class CheckoutPage extends Page {
         $disabled = 'disabled';
         if($this->user !== null) {
             $username = $this->user->get_name();
-            $displayname = $this->user->get_displayname();
+            $displayname = $this->user->get_displayname($this->ldap);
             $notes = $this->user->get_notes();
             $enddate = format_date(default_loan_end(time()));
             $disabled = '';
diff --git a/include/Cron.php b/include/Cron.php
index 50682f7..7ca58e8 100644
--- a/include/Cron.php
+++ b/include/Cron.php
@@ -4,11 +4,13 @@ class Cron {
     private $sender = '';
     private $error = '';
     private $kvs;
+    private $ldap;
     public function __construct($sender, $error) {
         $this->now = time();
         $this->sender = $sender;
         $this->error = $error;
         $this->kvs = new Kvs();
+        $this->ldap = new Ldap();
     }
 
     public function run() {
@@ -89,7 +91,7 @@ EOF;
 
         $subject = replace(array('count' => $overdue_count,
                                  'late'  => $late), $subject_template);
-        $message = replace(array('name'       => $user->get_displayname(),
+        $message = replace(array('name'       => $user->get_displayname($this->ldap),
                                  'list_sv'    => $reminder_list_sv,
                                  'product_sv' => $product_sv,
                                  'it_sv'      => $it_sv,
@@ -101,7 +103,7 @@ EOF;
                            $message_template);
 
         try {
-            mb_send_mail($user->get_email(),
+            mb_send_mail($user->get_email($this->ldap),
                          $subject,
                          $message,
                          'From: '.$this->sender);
diff --git a/include/Page.php b/include/Page.php
index b783547..696bed7 100644
--- a/include/Page.php
+++ b/include/Page.php
@@ -103,7 +103,7 @@ abstract class Page extends Responder {
                 $replacements['has_notes'] = '*';
             }
             $userlink = replace(array('id' => $user->get_id(),
-                                      'name' => $user->get_displayname(),
+                                      'name' => $user->get_displayname($this->ldap),
                                       'page' => 'users'),
                                 $this->fragments['item_link']);
             $replacements['item_link'] = $userlink;
@@ -151,7 +151,7 @@ abstract class Page extends Responder {
                 case 'overdue':
                     $loan = $product->get_active_loan();
                     $user = $loan->get_user();
-                    $replacements = array('name' => $user->get_displayname(),
+                    $replacements = array('name' => $user->get_displayname($this->ldap),
                                           'id'   => $user->get_id(),
                                           'page' => 'users');
                     $userlink = replace($replacements,
@@ -237,7 +237,7 @@ abstract class Page extends Responder {
                 }
             } else if($event instanceof Loan) {
                 $user = $event->get_user();
-                $userlink = replace(array('name' => $user->get_displayname(),
+                $userlink = replace(array('name' => $user->get_displayname($this->ldap),
                                           'id' => $user->get_id(),
                                           'page' => 'users'),
                                     $this->fragments['item_link']);
diff --git a/include/Responder.php b/include/Responder.php
index 6d05f51..ff621cd 100644
--- a/include/Responder.php
+++ b/include/Responder.php
@@ -1,9 +1,11 @@
 <?php
 abstract class Responder {
     protected $fragments = array();
+    protected $ldap = null;
     
     public function __construct() {
         $this->fragments = get_fragments('./html/fragments.html');
+        $this->ldap = new Ldap();
     }
     
     final protected function escape_tags($tags) {
diff --git a/include/User.php b/include/User.php
index 80ed297..658fea7 100644
--- a/include/User.php
+++ b/include/User.php
@@ -33,7 +33,6 @@ class User {
         }
         $this->id = $id;
         $this->update_fields();
-        $this->ldap = new Ldap();
     }
     
     private function update_fields() {
@@ -68,17 +67,17 @@ class User {
         return true;
     }
 
-    public function get_displayname() {
+    public function get_displayname($ldap) {
         try {
-            return $this->ldap->get_user($this->name);
+            return $ldap->get_user($this->name);
         } catch(Exception $e) {
             return 'Ej i SUKAT';
         }
     }
 
-    public function get_email() {
+    public function get_email($ldap, $format = true) {
         try {
-            return $this->ldap->get_user_email($this->name);
+            return $ldap->get_user_email($this->name);
         } catch(Exception $e) {
             return 'Mailadress saknas';
         }
diff --git a/include/UserPage.php b/include/UserPage.php
index ab1b544..c5ff4e1 100644
--- a/include/UserPage.php
+++ b/include/UserPage.php
@@ -56,7 +56,7 @@ class UserPage extends Page {
                              'inactive_loans' => $table_inactive,
                              'id' => $this->user->get_id(),
                              'name' => $this->user->get_name(),
-                             'displayname' => $this->user->get_displayname(),
+                             'displayname' => $this->user->get_displayname($this->ldap),
                              'notes' => $this->user->get_notes()),
                        $this->fragments['user_details']);
     }

From 6cc74873b221cfbb455ab36c30da5144f13dd3f5 Mon Sep 17 00:00:00 2001
From: Erik Thuning <boooink@gmail.com>
Date: Wed, 15 Sep 2021 10:53:13 +0200
Subject: [PATCH 3/9] Fixed the last palces where ldap object must be passed

---
 include/Product.php    | 4 +++-
 include/SearchPage.php | 2 +-
 include/User.php       | 7 +++----
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/include/Product.php b/include/Product.php
index 7c0a0e6..9ea76ad 100644
--- a/include/Product.php
+++ b/include/Product.php
@@ -109,7 +109,9 @@ class Product {
         return true;
     }
 
-    public function matches($terms) {
+    // Ldap object must be passed to keep the arglist in sync
+    // with User->matches()
+    public function matches($terms, $ldap) {
         foreach($terms as $field => $values) {
             $matchvalues = array();
             if(property_exists($this, $field)) {
diff --git a/include/SearchPage.php b/include/SearchPage.php
index e89111f..0eb095c 100644
--- a/include/SearchPage.php
+++ b/include/SearchPage.php
@@ -132,7 +132,7 @@ class SearchPage extends Page {
         $items = get_items($type);
         $out = array();
         foreach($items as $item) {
-            if($item->matches($terms)) {
+            if($item->matches($terms, $this->ldap)) {
                 $out[] = $item;
             }
         }
diff --git a/include/User.php b/include/User.php
index 658fea7..f2cbfe0 100644
--- a/include/User.php
+++ b/include/User.php
@@ -3,7 +3,6 @@ class User {
     private $id = 0;
     private $name = '';
     private $notes = '';
-    private $ldap = null;
     
     public static function create_user($name) {
         $ins_user = prepare('insert into `user`(`name`) values (?)');
@@ -45,17 +44,17 @@ class User {
         return true;
     }
 
-    public function matches($terms) {
+    public function matches($terms, $ldap) {
         foreach($terms as $field => $values) {
             $matchvalues = array();
             if($field == 'name') {
                 $matchvalues[] = $this->name;
-                $matchvalues[] = $this->get_displayname();
+                $matchvalues[] = $this->get_displayname($ldap);
             } else if(property_exists($this, $field)) {
                 $matchvalues[] = $this->$field;
             } else if($field == 'fritext') {
                 $matchvalues[] = $this->name;
-                $matchvalues[] = $this->get_displayname();
+                $matchvalues[] = $this->get_displayname($ldap);
                 $matchvalues[] = $this->notes;
             } else {
                 return false;

From 5e215672045db73f25127283dac3ee25fc2cd65f Mon Sep 17 00:00:00 2001
From: Erik Thuning <boooink@gmail.com>
Date: Wed, 22 Sep 2021 15:14:35 +0200
Subject: [PATCH 4/9] Implemented picking users based on email on the checkout
 page

---
 html/fragments.html      | 14 ++++++++--
 include/CheckoutPage.php | 56 ++++++++++++++++++++++++++++++++++------
 include/Ldap.php         | 19 +++++++-------
 3 files changed, 70 insertions(+), 19 deletions(-)

diff --git a/html/fragments.html b/html/fragments.html
index b09a101..409dc08 100644
--- a/html/fragments.html
+++ b/html/fragments.html
@@ -534,12 +534,22 @@
              list="user_suggest"
              autocomplete="off"
              placeholder="Användarnamn"
-             value="¤user¤"
-             required />
+             value="¤user¤" />
       <button type="submit" >
         Välj
       </button>
     </div>
+    <div>
+      <label for="email">
+        E-post:
+      </label>
+      <input type="text"
+             name="email"
+             id="email"
+             autocomplete="off"
+             placeholder="E-post"
+             value="¤email¤" />
+    </div>
     <div>
       <label for="displayname">
         Namn:
diff --git a/include/CheckoutPage.php b/include/CheckoutPage.php
index 1da4759..e779b1c 100644
--- a/include/CheckoutPage.php
+++ b/include/CheckoutPage.php
@@ -1,30 +1,68 @@
 <?php
 class CheckoutPage extends Page {
     private $userstr = '';
+    private $emailstr = '';
     private $user = null;
 
     public function __construct() {
         parent::__construct();
         if(isset($_GET['user'])) {
             $this->userstr = trim(strtolower($_GET['user']));
+        }
+        if(isset($_GET['email'])) {
+            $this->emailstr = trim(strtolower($_GET['email']));
+        }
+        try {
+            $this->user = $this->user_init($this->userstr,
+                                           $this->emailstr);
+        } catch(Exception $e) {
+            $this->error = $e->getMessage();
+        }
+    }
+
+    protected function user_init($name, $email) {
+        $nameuser = null;
+        $emailuser = null;
+        if($name) {
             try {
-                $this->user = new User($this->userstr, 'name');
+                $nameuser = new User($this->userstr, 'name');
             } catch(Exception $ue) {
+                # The user wasn't found locally
                 try {
-                    $ldap = new Ldap();
-                    $ldap->get_user($this->userstr);
-                    $this->user = User::create_user($this->userstr);
+                    $this->ldap->get_user($this->userstr);
+                    $nameuser = User::create_user($this->userstr);
                 } catch(Exception $le) {
-                    $this->error = "Användarnamnet '";
-                    $this->error .= $this->userstr;
-                    $this->error .= "' kunde inte hittas.";
+                    $err = "Användarnamnet '$name' kunde inte hittas.";
+                    throw new Exception($err);
                 }
             }
         }
+        if($email) {
+            try {
+                # Lookup email directly in ldap since we don't store it
+                $emailuser = new User($this->ldap->search_email($email),
+                                      'name');
+            } catch(Exception $ue) {
+                $err = "E-postadressen '$emailuser' kunde inte hittas.";
+                throw new Exception($err);
+            }
+        }
+        if($nameuser && $emailuser) {
+            if($nameuser != $emailuser) {
+                $err = "Användarnamn och e-post matchar olika användare.";
+                throw new Exception($err);
+            }
+            return $nameuser;
+        }
+        if($nameuser) {
+            return $nameuser;
+        }
+        return $emailuser;
     }
 
     protected function render_body() {
         $username = '';
+        $email = '';
         $displayname = '';
         $notes = '';
         $loan_table = '';
@@ -33,6 +71,7 @@ class CheckoutPage extends Page {
         $disabled = 'disabled';
         if($this->user !== null) {
             $username = $this->user->get_name();
+            $email = $this->user->get_email($this->ldap);
             $displayname = $this->user->get_displayname($this->ldap);
             $notes = $this->user->get_notes();
             $enddate = format_date(default_loan_end(time()));
@@ -45,7 +84,8 @@ class CheckoutPage extends Page {
             $subhead = replace(array('title' => 'Lånade artiklar'),
                                $this->fragments['subtitle']);
         }
-        print(replace(array('user' => $this->userstr,
+        print(replace(array('user' => $username,
+                            'email' => $email,
                             'displayname' => $displayname,
                             'notes' => $notes,
                             'end' => $enddate,
diff --git a/include/Ldap.php b/include/Ldap.php
index 91c7c84..00e17b4 100644
--- a/include/Ldap.php
+++ b/include/Ldap.php
@@ -17,7 +17,8 @@ class Ldap {
     public function get_user($uid) {
         $data = $this->search("uid=$uid", 'cn', 'uid');
         if($data['count'] !== 1) {
-            throw new Exception("LDAP search for '$uid' did not return exactly one result");
+            $err = "LDAP search for '$uid' did not return exactly one result";
+            throw new Exception($err);
         }
         return $data[0]['cn'][0];
     }
@@ -25,20 +26,20 @@ class Ldap {
     public function get_user_email($uid) {
         $data = $this->search("uid=$uid", 'mail', 'uid');
         if($data['count'] !== 1) {
-            throw new Exception("LDAP search for '$uid' did not return exactly one result");
+            $err = "LDAP search for '$uid' did not return exactly one result";
+            throw new Exception($err);
         }
         return $data[0]['mail'][0];
     }
 
-    public function search_user($uid) {
-        $data = $this->search("uid=$uid", 'cn', 'uid');
+    public function search_email($email) {
+        $data = $this->search("mail=$email", 'mail', 'uid');
         $out = array();
-        foreach($data as $result) {
-            if(isset($result['uid'])) {
-                $out[$result['uid'][0]] = $result['cn'][0];
-            }
+        if($data['count'] !== 1) {
+            $err = "LDAP search for '$email' did not return exactly one result.";
+            throw new Exception($err);
         }
-        return $out;
+        return $data[0]['uid'][0];
     }
 }
 ?>

From 5ace3ea42e77843008da6cb66bbcc72ec76534ee Mon Sep 17 00:00:00 2001
From: Erik Thuning <boooink@gmail.com>
Date: Wed, 22 Sep 2021 15:34:33 +0200
Subject: [PATCH 5/9] Changed checkoutPage email search behaviour Now a default
 domain is appended on email string that don't contain an @ character

---
 include/CheckoutPage.php | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/include/CheckoutPage.php b/include/CheckoutPage.php
index e779b1c..e209b81 100644
--- a/include/CheckoutPage.php
+++ b/include/CheckoutPage.php
@@ -25,12 +25,12 @@ class CheckoutPage extends Page {
         $emailuser = null;
         if($name) {
             try {
-                $nameuser = new User($this->userstr, 'name');
+                $nameuser = new User($name, 'name');
             } catch(Exception $ue) {
                 # The user wasn't found locally
                 try {
-                    $this->ldap->get_user($this->userstr);
-                    $nameuser = User::create_user($this->userstr);
+                    $this->ldap->get_user($name);
+                    $nameuser = User::create_user($name);
                 } catch(Exception $le) {
                     $err = "Användarnamnet '$name' kunde inte hittas.";
                     throw new Exception($err);
@@ -39,11 +39,15 @@ class CheckoutPage extends Page {
         }
         if($email) {
             try {
+                $search = $email;
+                if(strpos($email, '@') === false) {
+                    $search = $email .'@dsv.su.se';
+                }
                 # Lookup email directly in ldap since we don't store it
-                $emailuser = new User($this->ldap->search_email($email),
+                $emailuser = new User($this->ldap->search_email($search),
                                       'name');
             } catch(Exception $ue) {
-                $err = "E-postadressen '$emailuser' kunde inte hittas.";
+                $err = "E-postadressen '$search' kunde inte hittas.";
                 throw new Exception($err);
             }
         }
@@ -61,8 +65,8 @@ class CheckoutPage extends Page {
     }
 
     protected function render_body() {
-        $username = '';
-        $email = '';
+        $username = $this->userstr;
+        $email = $this->emailstr;
         $displayname = '';
         $notes = '';
         $loan_table = '';

From f8e951c215acec6641c5050fa8c118d325b1305d Mon Sep 17 00:00:00 2001
From: Erik Thuning <boooink@gmail.com>
Date: Mon, 26 Feb 2024 14:50:58 +0100
Subject: [PATCH 6/9] Added a missed css class to the user table fragment

---
 html/en/fragments.html | 2 +-
 html/sv/fragments.html | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/html/en/fragments.html b/html/en/fragments.html
index 78d2b3b..4219832 100644
--- a/html/en/fragments.html
+++ b/html/en/fragments.html
@@ -38,7 +38,7 @@
       </th>
     </tr>
   </thead>
-  <tbody>
+  <tbody class="single">
     ¤rows¤
   </tbody>
 </table>
diff --git a/html/sv/fragments.html b/html/sv/fragments.html
index dcaca53..36c2c20 100644
--- a/html/sv/fragments.html
+++ b/html/sv/fragments.html
@@ -38,7 +38,7 @@
       </th>
     </tr>
   </thead>
-  <tbody>
+  <tbody class="single">
     ¤rows¤
   </tbody>
 </table>

From 07128568ca8cf62b1ba2558a699f2a67e786514f Mon Sep 17 00:00:00 2001
From: Erik Thuning <boooink@gmail.com>
Date: Mon, 26 Feb 2024 15:14:41 +0100
Subject: [PATCH 7/9] Renamed the fragment product_form to product_details in
 preparation for readonly public views

---
 html/en/fragments.html  | 2 +-
 html/sv/fragments.html  | 2 +-
 include/NewPage.php     | 2 +-
 include/ProductPage.php | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/html/en/fragments.html b/html/en/fragments.html
index 4219832..da67ed4 100644
--- a/html/en/fragments.html
+++ b/html/en/fragments.html
@@ -152,7 +152,7 @@
   </form>
 </div>
 
-¤¤ product_form ¤¤
+¤¤ product_details ¤¤
 <div id="product-details">
   <h2>Product details</h2>
   <form id="product-data"
diff --git a/html/sv/fragments.html b/html/sv/fragments.html
index 36c2c20..abfafa1 100644
--- a/html/sv/fragments.html
+++ b/html/sv/fragments.html
@@ -152,7 +152,7 @@
   </form>
 </div>
 
-¤¤ product_form ¤¤
+¤¤ product_details ¤¤
 <div id="product-details">
   <h2>Artikeldata</h2>
   <form id="product-data"
diff --git a/include/NewPage.php b/include/NewPage.php
index dd0e15e..ffe6a48 100644
--- a/include/NewPage.php
+++ b/include/NewPage.php
@@ -49,7 +49,7 @@ class NewPage extends Page {
                               'info' => $fields,
                               'label' => '',
                               'hidden' => 'hidden'),
-                        $this->fragments['product_form']);
+                        $this->fragments['product_details']);
         return $out;
     }
 }
diff --git a/include/ProductPage.php b/include/ProductPage.php
index 4edd51d..c1904bf 100644
--- a/include/ProductPage.php
+++ b/include/ProductPage.php
@@ -87,7 +87,7 @@ class ProductPage extends Page {
                 $fields['checkout_hidden'] = '';
             }
         }
-        $out = replace($fields, $this->fragments['product_form']);
+        $out = replace($fields, $this->fragments['product_details']);
         $out .= replace($fields, $this->fragments['product_meta']);
         return $out;
     }

From a91923ad18d8b74f2782ff092e1684147cc9b56b Mon Sep 17 00:00:00 2001
From: Erik Thuning <boooink@gmail.com>
Date: Mon, 26 Feb 2024 16:10:59 +0100
Subject: [PATCH 8/9] Renamed product_detail fragments to product_match in
 order to disambiguate with actual detail views

---
 html/en/fragments.html | 4 ++--
 html/sv/fragments.html | 4 ++--
 include/Page.php       | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/html/en/fragments.html b/html/en/fragments.html
index da67ed4..dcdce7d 100644
--- a/html/en/fragments.html
+++ b/html/en/fragments.html
@@ -105,7 +105,7 @@
   </td>
 </tr>
 
-¤¤ product_detail_row ¤¤
+¤¤ product_match_row ¤¤
 <tr>
   <td class="status ¤status¤">
   </td>
@@ -116,7 +116,7 @@
   </td>
 </tr>
 
-¤¤ product_detail ¤¤
+¤¤ product_match ¤¤
 <dt>
   ¤name¤:
 </dt>
diff --git a/html/sv/fragments.html b/html/sv/fragments.html
index abfafa1..b91f0fb 100644
--- a/html/sv/fragments.html
+++ b/html/sv/fragments.html
@@ -105,7 +105,7 @@
   </td>
 </tr>
 
-¤¤ product_detail_row ¤¤
+¤¤ product_match_row ¤¤
 <tr>
   <td class="status ¤status¤">
   </td>
@@ -116,7 +116,7 @@
   </td>
 </tr>
 
-¤¤ product_detail ¤¤
+¤¤ product_match ¤¤
 <dt>
   ¤name¤:
 </dt>
diff --git a/include/Page.php b/include/Page.php
index 8f79010..00bb7e1 100644
--- a/include/Page.php
+++ b/include/Page.php
@@ -182,7 +182,7 @@ abstract class Page extends Responder {
             $details = $this->build_product_details($product, $matches);
             $out .= replace(array('status'  => $status,
                                   'details' => $details),
-                            $this->fragments['product_detail_row']);
+                            $this->fragments['product_match_row']);
         }
         return $out;
     }
@@ -195,7 +195,7 @@ abstract class Page extends Responder {
             }
             $out .= replace(array('name'   => $product->get_label($name),
                                   'value'  => $value),
-                            $this->fragments['product_detail']);
+                            $this->fragments['product_match']);
         }
         return $out;
     }

From 9410c7bcecc06eb480450f1485739837bfd98e6e Mon Sep 17 00:00:00 2001
From: Erik Thuning <boooink@gmail.com>
Date: Mon, 26 Feb 2024 16:15:15 +0100
Subject: [PATCH 9/9] Fixed a mismatched tag on that broke the search page

---
 html/en/fragments.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/html/en/fragments.html b/html/en/fragments.html
index dcdce7d..d5271fa 100644
--- a/html/en/fragments.html
+++ b/html/en/fragments.html
@@ -814,7 +814,7 @@
   <div class="clear"></div>
 </form>
 <p id="hints">
-  Advanced searches are possible by prefixing a search term with a keyword ending with a colon, for example: <strong>serial:123456</strong> or <strong>tag:computer</tag>
+  Advanced searches are possible by prefixing a search term with a keyword ending with a colon, for example: <strong>serial:123456</strong> or <strong>tag:computer</strong>
 </p>
 <div id="found-products"
      class="¤hidden¤">