]> 91.132.146.200 Git - bibliotheca-php.git/commitdiff
new search field. Work in progress
authorBanana <mail@bananas-playground.net>
Sun, 28 Jan 2024 07:56:18 +0000 (08:56 +0100)
committerBanana <mail@bananas-playground.net>
Sun, 28 Jan 2024 07:56:18 +0000 (08:56 +0100)
14 files changed:
CHANGELOG
TODO
documentation/upgrade.txt
sources/updatecheck.txt
upgrade/from-version-1.5.txt
webclient/index.php
webclient/lib/managecollectionfields.class.php
webclient/lib/managecollections.class.php
webclient/lib/possessed.class.php
webclient/lib/summoner.class.php
webclient/lib/trite.class.php
webclient/view/default/managecolletions/managecolletions.html
webclient/view/default/managecolletions/managecolletions.php
webclient/view/default/managegroups/managegroups.html

index f543a846da9755ae087d70c770ea7096042c7c33..4aaf9a8be5b378a0345411cb84c15e82a4021212 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 1.x - Chizra
     * Config change. Added new entries. See upgrade/from-version-1.5.txt. It won't work if it is missing.
     * Config change: Added new theme config. See upgrade/from-version-1.5.txt. It won't work if it is missing.
+    * Added: A new entry field for better global search. Read upgrade/from-version-1.5.txt for more details.
     * Added: #6 Feature: Duplicate search
       This is a very limited like search based on the title field. Needs improvement and better search data.
     * Licence change to GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
diff --git a/TODO b/TODO
index 9e84de3685e70c665399d915540375e854ee8b57..9de748f1a8c599ba39e1a708a1fc598ddffe665d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,7 @@
 * change the search data. Maybe an extra search field in which all the searchable information of an entry will be
   saved.
+* query optimization and default indexes on columns
+* make documentation markdown to be nicer
 * change multiple-attachment to a field which tells it is used for a image gallery
 * update JS and remove deprecations
 * complete profile view. Groups still missing.
@@ -8,8 +10,6 @@
 * create a real fallback theme, which does not depend on any styling/css
 ** change the css and js lookup too in main file
 * i18n support
-* Automatic upgrades of DB
-* drop in updates
 * Definition of fields in "card view"
 * User and groupmanagement: Check where a user or group is used!
 * Better error handling and display while adding / update and delete
index 5270c898a8d7270071f7eb9c7fe43f2d88243751..26199c3fb0e740f1142bf7c8f2eb7720e0e04d51 100644 (file)
@@ -1,5 +1,6 @@
 Each release has its own file in the upgrade folder.
 Basic flow would be to extract the new release and copy over the following files and directories:
+
 ```
 webclient/config/
 webclient/lib/
@@ -9,8 +10,14 @@ webclient/api.php
 webclient/index.php
 ```
 
-In those files there are the steps needed to make an upgrade.
+and follow the upgrade file(s). After the first launch, visit `/index.php?p=managesystem` and check if there any
+further changes to be done.
 
-If you upgrade multiple versions make sure to read all the files in the correct order.
+In those files there are the steps needed to make an upgrade. If you upgrade multiple versions make sure to read
+all the files in the correct order. Within the upgrade files itself there is an order. Make sure to follow.
 
-Within the upgrade files itself there is an order. Make sure to follow.
+# Why no automatic updates
+Doing so, the process serving the application needs write access to the files. Which can be a security risk.
+Providing write access only to storage or temporary files and not the application files itself, it is more
+secure (there is no complete security).
+The downside are manual updates.
index 9c05c5a583dd6e686385ad225229711c52f1a8c0..88a97e0aec6c28154a5988210f17713b4766264e 100644 (file)
@@ -11,7 +11,7 @@ upgrade file with correct placeholders
 
 correct placeholders in sql file for manual setup
 
-correct version info in VERSION and index.php
+correct version info in VERSION and index.php and cyberdemon, if needed
 
 correct tag
 
index 85a0b80731a88d7cd71de50c7597095be55fdaae..4c1f7166fa304ca72759561640946b603fddeb3e 100644 (file)
@@ -1,18 +1,26 @@
-## Added new constants to config.php file.
+# Added a new global search field
+As of version 1.6, the field 'Combined Search' provides a much better default search base.
+If you want to use it make sure you update its contents for all the existing entries in
+your collection. After that and for all new entries the data will be created automatically.
+The update and creation of the field is done by using the new option "Update combined search field data"
+in collection management. It needs to be done for each if your collections but only once.
+
+# Added new constants to config.php file.
 Use config.php.default as a help. The new lines are:
+```
 const LOGFILE = PATH_SYSTEMOUT.'/bibliotheca.log';
-
 # CURL browser settings
 const BROWSER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0';
 const BROWSER_ACCEPT = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
 const BROWSER_ACCEPT_LANG = 'en-US,en;q=0.5';
+```
 
-## Updated tools configs
-Please compare the default config files for googlebooks, imdbweb and musicbrainz and make the required
-changes.
+# Updated tools configs
+Please compare the default config files for googlebooks, imdbweb and musicbrainz and make the required  changes.
 
 # Added new theme config to config.php file
 Use config.php.default as a help. The new setting is:
+```
 # additional config for each theme with fallback
 const UI_THEME_CONFIG = array(
     'default' => array(
@@ -22,3 +30,4 @@ const UI_THEME_CONFIG = array(
         'coverImageMaxWidth' => 500 // in pixel. Supports image/jpeg, image/png, image/webp
     )
 );
+```
index 8465a868bdadd6113c0d011bfad1a42cf1fb03e2..920190d61c363d542f07a576b2bca55422e27419 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * Bibliotheca
  *
- * Copyright 2018-2023 Johannes Keßler
+ * Copyright 2018-2024 Johannes Keßler
  *
  * This program is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index c51db5fc3df579ef2bfcbdca014090c1a4b02efe..a3d19168e7e87363033e294f4d7f109365757cde 100644 (file)
@@ -260,8 +260,12 @@ class ManageCollectionFields {
 
                $this->_cacheExistingSysFields = array();
 
-               $queryStr = "SELECT `cf`.`fk_field_id` AS id, `sf`.`type`, `sf`.`displayname`, `sf`.`identifier`,
-                                                       `sf`.`createstring`, `sf`.`searchtype`
+               $queryStr = "SELECT `cf`.`fk_field_id` AS id, 
+                        `sf`.`type`, 
+                        `sf`.`displayname`, 
+                        `sf`.`identifier`,
+                                               `sf`.`createstring`, 
+                                               `sf`.`searchtype`
                                                FROM `".DB_PREFIX."_collection_fields_".$this->_collectionId."` AS cf
                                                LEFT JOIN `".DB_PREFIX."_sys_fields` AS sf ON `cf`.`fk_field_id` = `sf`.`id`";
                if($sortAZ === true) {
@@ -307,11 +311,12 @@ class ManageCollectionFields {
                        }
                }
 
+        // add systemfields
                $def['created'] = array('identifier' => 'created', 'displayname' => 'Created', 'type' => 'systemfield');
                $def['modified'] = array('identifier' => 'modified', 'displayname' => 'Modified', 'type' => 'systemfield');
-               $ret = $def + $ret;
+               $def['search'] = array('identifier' => 'search', 'displayname' => 'Combined Search', 'type' => 'systemfield');
 
-               return $ret;
+               return $def + $ret;
        }
 
        /**
index 0b630eec8cf10c5db3b7c1f5608855e096c64612..ac52dfa8231c64da6729ebd5a56ccce3edfa9632 100644 (file)
@@ -226,7 +226,9 @@ class ManageCollections {
                                                                                 `owner` int NOT NULL,
                                                                                 `group` int NOT NULL,
                                                                                 `rights` char(9) COLLATE utf8mb4_bin NOT NULL,
-                                                                                PRIMARY KEY (`id`)
+                                                                                `search` text COLLATE utf8mb4_unicode_ci NOT NULL,
+                                                                                PRIMARY KEY (`id`),
+                                                                                FULLTEXT KEY `search` (`search`)
                                                                                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci";
                                if(QUERY_DEBUG) Summoner::sysLog("[QUERY] ".__METHOD__." query: ".Summoner::cleanForLog($queryCollectionEntry));
                                $this->_DB->query($queryCollectionEntry);
@@ -338,7 +340,17 @@ class ManageCollections {
                                        // optimize does a recreation and the column collation
                                        // is considered
                                        $this->_DB->query("OPTIMIZE TABLE `".DB_PREFIX."_collection_entry_".$data['id']."`");
-                               }
+                               } elseif($data['defaultSearchField'] === "search") {
+                    // Special case. 1.6 adds the search field. Needs to be checked if there
+                    // It is a new default column which is added at creation of a collection
+                    // but needs to be added manually for existing ones.
+                    // could be removed in future version...
+                    $queryStr = "ALTER TABLE `".DB_PREFIX."_collection_entry_".$data['id']."` 
+                                    ADD `search` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci 
+                                    NOT NULL AFTER `rights`, ADD FULLTEXT (`search`)";
+                    if(QUERY_DEBUG) Summoner::sysLog("[QUERY] ".__METHOD__." query: ".Summoner::cleanForLog($queryStr));
+                    $this->_DB->query($queryStr);
+                }
                        } catch (Exception $e) {
                                if($e->getCode() == "1061") {
                                        // duplicate key message if the index is already there.
@@ -438,6 +450,72 @@ class ManageCollections {
                return  $ret;
        }
 
+    /**
+     * Selects the text entry fields, gets their data, combines the words and writes it into the search field
+     * for every entry in the current loaded collection
+     *
+     * @param string $collectionId The id of the collection
+     * @param array $searchFields The available search fields of the given collection
+     * @return bool
+     */
+    public function updateSearchData(string $collectionId, array $searchFields): bool {
+        $ret = false;
+
+        // simple search fields for loaded collection
+        // Every field witch has a column in the entry table is a simple search field.
+        // Name starts with entry. Here we want only the text fields
+        // Those fields are the data for the combined search field
+        $dataFields = array();
+        if(!empty($searchFields)) {
+            foreach($searchFields as $k=>$v) {
+                if(isset($v['searchtype']) && strpos($v['searchtype'],'Text') !== false) {
+                    $dataFields[$k] = $v['identifier'];
+                }
+            }
+        }
+
+        // get the search data for every entry in the collection
+        $entryData = array();
+        if(!empty($dataFields)) {
+            $fieldStr = implode(",",$dataFields);
+            $queryStr = "SELECT id,".$fieldStr." FROM `".DB_PREFIX."_collection_entry_".$collectionId."`";
+            if(QUERY_DEBUG) Summoner::sysLog("[QUERY] ".__METHOD__." query: ".Summoner::cleanForLog($queryStr));
+            try {
+                $query = $this->_DB->query($queryStr);
+                if($query !== false && $query->num_rows > 0) {
+                    $entryData = $query->fetch_all(MYSQLI_ASSOC);
+                }
+            }
+            catch (Exception $e) {
+                Summoner::sysLog("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+            }
+        }
+
+        // build the search data and update the entries
+        if(!empty($entryData)) {
+            foreach($entryData as $d) {
+                $entryid = $d['id'];
+                unset($d['id']);
+                $searchData = implode(" ",$d);
+                $searchData = implode(" ", Summoner::words($searchData));
+
+                $queryStr = "UPDATE `".DB_PREFIX."_collection_entry_".$collectionId."`
+                            SET `search` = '".$this->_DB->real_escape_string($searchData)."'
+                            WHERE `id` = '".$entryid."'";
+                if(QUERY_DEBUG) Summoner::sysLog("[QUERY] ".__METHOD__." query: ".Summoner::cleanForLog($queryStr));
+                try {
+                    $this->_DB->query($queryStr);
+                    $ret = true;
+                }
+                catch (Exception $e) {
+                    Summoner::sysLog("[ERROR] ".__METHOD__." mysql catch: ".$e->getMessage());
+                }
+            }
+        }
+
+        return $ret;
+    }
+
        /**
         * Check if given name can be used as a new one
         *
@@ -505,7 +583,6 @@ class ManageCollections {
        private function _updateToolRelation(string $id, array $tool): bool {
                $ret = false;
 
-
                $queryStr = "DELETE FROM `".DB_PREFIX."_tool2collection`
                                                                WHERE `fk_collection_id` = '".$this->_DB->real_escape_string($id)."'";
                if(QUERY_DEBUG) Summoner::sysLog("[QUERY] ".__METHOD__." query: ".Summoner::cleanForLog($queryStr));
index 09184b27b8b31a551b73097272174c1230ea3d4c..a5550968277a70b083bd27fd4f6dd82d004f27c0 100644 (file)
@@ -24,7 +24,6 @@
  * Some groups are protected and should not be removed.
  *
  * passwords used here: password_hash("somePassword", PASSWORD_DEFAULT);
- *
  */
 class Possessed {
        /**
index 70b3a800582b432e053d14d759dd8ba279ec791c..8ab6f3f01ccf48925b6f3088afe1f3e4e96d6b92 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 /**
+ * Class Summoner
  * a static helper class
  */
 class Summoner {
@@ -567,4 +568,16 @@ class Summoner {
     static function sysLog(string $msg): void {
         error_log(date("c")." ".$msg."\n", 3, LOGFILE);
     }
+
+    /**
+     * Create unique words from the given data
+     *
+     * @param $data string
+     * @return array
+     *
+     */
+    static function words(string $data): array {
+        preg_match_all('/\w{3,}+/u',$data,$matches);
+        return array_unique($matches[0]);
+    }
 }
index 05295ffc13ee002893f2c058818036f24dda94fb..53bcc1dd678f873568dbadcff3e4f6d8c26b4ef5 100644 (file)
@@ -252,8 +252,10 @@ class Trite {
                        }
                }
 
+        // add systemfields
                $def['created'] = array('identifier' => 'created', 'displayname' => 'Created', 'type' => 'systemfield');
                $def['modified'] = array('identifier' => 'modified', 'displayname' => 'Modified', 'type' => 'systemfield');
+        $def['search'] = array('identifier' => 'search', 'displayname' => 'Combined Search', 'type' => 'systemfield');
                $ret = $def + $ret;
 
                return $ret;
index e6bff5ac236cd8427d6addd026581e3018b2f346..38a1c285ec8c4b983ccac6bbaa225ac4ab668fd1 100644 (file)
                                                ><?php echo $v['displayname']; ?> (<?php echo $v['type']; ?>)</option>
                                                <?php } ?>
                                        </select>
-                                       <small>The field is used in the global search.
+                                       <small>
+                                               The field is used in the global search.<br />
                                                <span class="" uk-icon="icon: warning"></span> Altering the default search field results in
-                                               a DB reindex. This could take some time, depending on the amount of data.</small>
+                                               a DB reindex. This could take some time to complete, depending on the amount of data.
+                                       </small><br />
+                                       <small>
+                                               <span class="" uk-icon="icon: warning"></span> As of version 1.6, the field 'Combined Search'
+                                               provides a much better default search base.<br />
+                                               If you want to use it make sure you update its contents (following option) for all the existing entries in
+                                               your collection. After that and for all new entries the data will be created automatically.
+                                       </small>
+                               </div>
+                       </div>
+                       <div class="uk-margin">
+                               <div class="uk-form-label">Update combined search field data</div>
+                               <div class="uk-form-controls uk-form-controls-text">
+                                       <label>
+                                               <input class="uk-checkbox" type="checkbox" name="fdata[updateSearchData]" value="1">
+                                               <small>
+                                                       <span class="" uk-icon="icon: warning"></span> This could take some time to complete,
+                                                       depending on the amount of data.
+                                               </small><br />
+                                               <small>Plase do this after you remove fields(text) from your collection.</small>
+                                       </label>
                                </div>
                        </div>
                        <div class="uk-margin">
@@ -62,7 +83,7 @@
                                </div>
                        </div>
                        <div class="uk-margin">
-                               <label class="uk-form-label" for="advancedSearchTableFields">Table advanced search view</label>
+                               <label class="uk-form-label" for="advancedSearchTableFields">Advanced search table fields</label>
                                <div class="uk-form-controls">
                                        <select class="uk-select" id="advancedSearchTableFields" name="fdata[advancedSearchTableFields][]" multiple="multiple" size="5">
                                                <?php foreach($TemplateData['existingFields'] as $k=>$v) { ?>
index 8e331e5651f0ee35493c8afd629e68a3c85a871c..d8d83bd3c33cbd9a3ba09f409c67aa6f4523f56f 100644 (file)
  */
 
 require_once 'lib/managecollections.class.php';
-$ManangeCollections = new ManageCollections($DB,$Doomguy);
+$ManageCollections = new ManageCollections($DB,$Doomguy);
 require_once 'lib/managecollectionfields.class.php';
-$ManangeCollectionFields = new ManageCollectionFields($DB,$Doomguy);
+$ManageCollectionFields = new ManageCollectionFields($DB,$Doomguy);
 
-$TemplateData['existingCollections'] = $ManangeCollections->getCollections();
-$TemplateData['ownerSelection'] = $ManangeCollections->getUsersForSelection();
-$TemplateData['groupSelection'] = $ManangeCollections->getGroupsForSelection();
-$TemplateData['toolSelection'] = $ManangeCollections->getToolsForSelection();
+$TemplateData['existingCollections'] = $ManageCollections->getCollections();
+$TemplateData['ownerSelection'] = $ManageCollections->getUsersForSelection();
+$TemplateData['groupSelection'] = $ManageCollections->getGroupsForSelection();
+$TemplateData['toolSelection'] = $ManageCollections->getToolsForSelection();
 // default rights
 $TemplateData['editData']['rights'] = Summoner::prepareRightsArray('rwxr--r--');
 // tool needs to be preset
@@ -51,10 +51,10 @@ if(isset($_GET['id']) && !empty($_GET['id'])) {
 }
 
 if($_editMode === true && !empty($_id)) {
-       $TemplateData['editData'] = $ManangeCollections->getEditData($_id);
-       $ManangeCollectionFields->setCollection($_id);
-       $TemplateData['existingFields'] = $ManangeCollectionFields->getExistingFields();
-       $TemplateData['simpleSearchFields'] = $ManangeCollectionFields->getSimpleSearchFields();
+       $TemplateData['editData'] = $ManageCollections->getEditData($_id);
+       $ManageCollectionFields->setCollection($_id);
+       $TemplateData['existingFields'] = $ManageCollectionFields->getExistingFields();
+       $TemplateData['simpleSearchFields'] = $ManageCollectionFields->getSimpleSearchFields();
        if(!isset($TemplateData['editData']['name'])) {
                $TemplateData['refresh'] = 'index.php?p=managecolletions';
        }
@@ -89,9 +89,14 @@ if(isset($_POST['submitForm'])) {
                        $_saveData['advancedSearchTableFields'] = implode(',',$fdata['advancedSearchTableFields']);
                }
 
+        $_updateSearchData = false;
+        if(isset($fdata['updateSearchData'])) {
+            $_updateSearchData = true;
+        }
+
                if(!empty($TemplateData['editData']['name'])) { // EDIT
                        if(isset($fdata['doDelete'])) {
-                               $do = $ManangeCollections->deleteCollection($_id);
+                               $do = $ManageCollections->deleteCollection($_id);
                                if ($do === true) {
                                        $TemplateData['refresh'] = 'index.php?p=managecolletions';
                                } else {
@@ -104,8 +109,11 @@ if(isset($_POST['submitForm'])) {
                                        && isset($TemplateData['groupSelection'][$_saveData['group']])
                                        && isset($TemplateData['ownerSelection'][$_saveData['owner']])
                                ) {
-                                       $do = $ManangeCollections->updateCollection($_saveData);
+                                       $do = $ManageCollections->updateCollection($_saveData);
                                        if ($do === true) {
+                        if($_updateSearchData) {
+                            $ManageCollections->updateSearchData($_id, $ManageCollectionFields->getSimpleSearchFields());
+                        }
                                                $TemplateData['refresh'] = 'index.php?p=managecolletions';
                                        } else {
                                                $TemplateData['message']['content'] = "Collection could not be updated.";
@@ -123,7 +131,7 @@ if(isset($_POST['submitForm'])) {
                                        && isset($TemplateData['groupSelection'][$_saveData['group']])
                                        && isset($TemplateData['ownerSelection'][$_saveData['owner']])
                                ) {
-                                       $do = $ManangeCollections->createCollection($_saveData);
+                                       $do = $ManageCollections->createCollection($_saveData);
                                        if ($do === true) {
                                                $TemplateData['refresh'] = 'index.php?p=managecolletions';
                                        } else {
index 47ea8338589c924d6cfddaef5d86b05f2f014d20..94c08ad762147c007e583ab6191e9423038a81a6 100644 (file)
@@ -62,7 +62,5 @@
                        <?php } ?>
                        </tbody>
                </table>
-
-
        </div>
 </div>