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
* 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.
* 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
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/
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.
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
-## 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(
'coverImageMaxWidth' => 500 // in pixel. Supports image/jpeg, image/png, image/webp
)
);
+```
/**
* 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
$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) {
}
}
+ // 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;
}
/**
`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);
// 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.
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
*
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));
* Some groups are protected and should not be removed.
*
* passwords used here: password_hash("somePassword", PASSWORD_DEFAULT);
- *
*/
class Possessed {
/**
*/
/**
+ * Class Summoner
* a static helper class
*/
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]);
+ }
}
}
}
+ // 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;
><?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">
</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) { ?>
*/
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
}
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';
}
$_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 {
&& 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.";
&& 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 {
<?php } ?>
</tbody>
</table>
-
-
</div>
</div>