diff --git a/CHANGELOG.md b/CHANGELOG.md index d61aa56..f45613d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,4 +28,11 @@ - Adds list of default system tags - Adds linker session manager -- Adds option to share sessions \ No newline at end of file +- Adds option to share sessions + +# v2.0.6 + +- Adds updating watchers for book names, and translation details. +- Adds edit option to owned tags +- Better session management that allows sharing sessions. +- Few bug fixes \ No newline at end of file diff --git a/README.md b/README.md index e18b3b0..622c9f8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Get Bible (2.0.5) +# Get Bible (2.0.6) ![Get Bible image](https://git.vdm.dev/getBible/joomla-component/raw/branch/master/admin/assets/images/vdm-component.jpg "GetBible") @@ -18,38 +18,38 @@ In essence, The Bible for Joomla is designed to transform how the Word of God is + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io) + *Name*: [Get Bible](https://getbible.net) + *First Build*: 3rd December, 2015 -+ *Last Build*: 28th July, 2023 -+ *Version*: 2.0.5 ++ *Last Build*: 1st August, 2023 ++ *Version*: 2.0.6 + *Copyright*: Copyright (C) 2015. All Rights Reserved + *License*: GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html ## Build Time -**536 Hours** or **67 Eight Hour Days** (actual time the author saved - +**543 Hours** or **68 Eight Hour Days** (actual time the author saved - due to [Automated Component Builder](https://www.joomlacomponentbuilder.com)) > (if creating a folder and file took **5 seconds** and writing one line of code took **10 seconds**, > never making one mistake or taking any coffee break.) -+ *Line count*: **191915** -+ *File count*: **1668** -+ *Folder count*: **161** ++ *Line count*: **194656** ++ *File count*: **1697** ++ *Folder count*: **162** -**353 Hours** or **44 Eight Hour Days** (the actual time the author spent) +**359 Hours** or **45 Eight Hour Days** (the actual time the author spent) > (with the following break down: -> **debugging @134hours** = codingtime / 4; -> **planning @77hours** = codingtime / 7; +> **debugging @136hours** = codingtime / 4; +> **planning @78hours** = codingtime / 7; > **mapping @54hours** = codingtime / 10; -> **office @89hours** = codingtime / 6;) +> **office @91hours** = codingtime / 6;) -**889 Hours** or **111 Eight Hour Days** +**902 Hours** or **113 Eight Hour Days** (a total of the realistic time frame for this project) > (if creating a folder and file took **5 seconds** and writing one line of code took **10 seconds**, > with the normal everyday realities at the office, that includes the component planning, mapping & debugging.) -Project duration: **22.2 weeks** or **4.6 months** +Project duration: **22.6 weeks** or **4.7 months** > This **component** was build with a Joomla [Automated Component Builder](https://www.joomlacomponentbuilder.com). > Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io) diff --git a/admin/README.txt b/admin/README.txt index e18b3b0..622c9f8 100644 --- a/admin/README.txt +++ b/admin/README.txt @@ -1,4 +1,4 @@ -# Get Bible (2.0.5) +# Get Bible (2.0.6) ![Get Bible image](https://git.vdm.dev/getBible/joomla-component/raw/branch/master/admin/assets/images/vdm-component.jpg "GetBible") @@ -18,38 +18,38 @@ In essence, The Bible for Joomla is designed to transform how the Word of God is + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io) + *Name*: [Get Bible](https://getbible.net) + *First Build*: 3rd December, 2015 -+ *Last Build*: 28th July, 2023 -+ *Version*: 2.0.5 ++ *Last Build*: 1st August, 2023 ++ *Version*: 2.0.6 + *Copyright*: Copyright (C) 2015. All Rights Reserved + *License*: GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html ## Build Time -**536 Hours** or **67 Eight Hour Days** (actual time the author saved - +**543 Hours** or **68 Eight Hour Days** (actual time the author saved - due to [Automated Component Builder](https://www.joomlacomponentbuilder.com)) > (if creating a folder and file took **5 seconds** and writing one line of code took **10 seconds**, > never making one mistake or taking any coffee break.) -+ *Line count*: **191915** -+ *File count*: **1668** -+ *Folder count*: **161** ++ *Line count*: **194656** ++ *File count*: **1697** ++ *Folder count*: **162** -**353 Hours** or **44 Eight Hour Days** (the actual time the author spent) +**359 Hours** or **45 Eight Hour Days** (the actual time the author spent) > (with the following break down: -> **debugging @134hours** = codingtime / 4; -> **planning @77hours** = codingtime / 7; +> **debugging @136hours** = codingtime / 4; +> **planning @78hours** = codingtime / 7; > **mapping @54hours** = codingtime / 10; -> **office @89hours** = codingtime / 6;) +> **office @91hours** = codingtime / 6;) -**889 Hours** or **111 Eight Hour Days** +**902 Hours** or **113 Eight Hour Days** (a total of the realistic time frame for this project) > (if creating a folder and file took **5 seconds** and writing one line of code took **10 seconds**, > with the normal everyday realities at the office, that includes the component planning, mapping & debugging.) -Project duration: **22.2 weeks** or **4.6 months** +Project duration: **22.6 weeks** or **4.7 months** > This **component** was build with a Joomla [Automated Component Builder](https://www.joomlacomponentbuilder.com). > Developed by [Llewellyn van der Merwe](mailto:joomla@vdm.io) diff --git a/admin/language/en-GB/en-GB.com_getbible.ini b/admin/language/en-GB/en-GB.com_getbible.ini index f181f54..4b5d857 100644 --- a/admin/language/en-GB/en-GB.com_getbible.ini +++ b/admin/language/en-GB/en-GB.com_getbible.ini @@ -1544,6 +1544,7 @@ COM_GETBIBLE_TAG_DESCRIPTION_LABEL="Description" COM_GETBIBLE_TAG_DETAILS="Details" COM_GETBIBLE_TAG_EDIT="Editing the Tag" COM_GETBIBLE_TAG_ERROR_UNIQUE_ALIAS="Another Tag has the same alias." +COM_GETBIBLE_TAG_FOUND_BUT_COULD_NOT_BE_REACTIVATED="Tag found, but could not be reactivated." COM_GETBIBLE_TAG_GUID_DESCRIPTION="Globally Unique Identifier" COM_GETBIBLE_TAG_GUID_HINT="Auto Generated" COM_GETBIBLE_TAG_GUID_LABEL="GUID" @@ -1565,6 +1566,7 @@ COM_GETBIBLE_TAG_PUBLIC="Public" COM_GETBIBLE_TAG_PUBLISHING="Publishing" COM_GETBIBLE_TAG_SAVE_WARNING="Alias already existed so a number was added at the end. You can re-edit the Tag to customise the alias." COM_GETBIBLE_TAG_STATUS="Status" +COM_GETBIBLE_TAG_SUCCESSFULLY_DELETED="Tag successfully deleted." COM_GETBIBLE_TAG_VERSION_DESC="A count of the number of times this Tag has been revised." COM_GETBIBLE_TAG_VERSION_LABEL="Version" COM_GETBIBLE_THE_NAME_COULD_NOT_BE_UPDATED="The name could not be updated." @@ -1574,13 +1576,17 @@ COM_GETBIBLE_THE_NOTE_WAS_SUCCESSFULLY_UPDATED="The note was successfully update COM_GETBIBLE_THE_NOTICE_BOARD_IS_LOADING="The notice board is loading" COM_GETBIBLE_THE_README_IS_LOADING="The readme is loading" COM_GETBIBLE_THE_TAG_SELECTED_IS_NOT_ACTIVE_PLEASE_SELECT_AN_ACTIVE_TAG="The tag selected is not active, please select an active tag." +COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_CREATED="The tag was successfully created." +COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_REACTIVATED="The tag was successfully reactivated." COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_REMOVED_FROM_THE_VERSE="The tag was successfully removed from the verse." -COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_SET="The tag was successfully set." +COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_UPDATED="The tag was successfully updated." COM_GETBIBLE_THE_VERSE_WAS_SUCCESSFULLY_TAGGED="The verse was successfully tagged." COM_GETBIBLE_THE_WIKI_CAN_ONLY_BE_LOADED_WHEN_YOUR_JCB_SYSTEM_HAS_INTERNET_CONNECTION="The wiki can only be loaded when your JCB system has internet connection." COM_GETBIBLE_THE_WIKI_IS_LOADING="The wiki is loading" COM_GETBIBLE_THIS_IS_A_GLOBAL_TAG_SET_BY_US_AT_BSB_FOR_YOUR_CONVENIENCE_WE_HOLD_THE_PRIVILEGE_TO_MODIFY_THESE_TAGS_IF_YOU_BELIEVE_ITS_SET_IN_ERROR_KINDLY_INFORM_US="This is a global tag, set by us at %s for your convenience. We hold the privilege to modify these tags. If you believe it's set in error, kindly inform us." COM_GETBIBLE_THIS_TAG_COULD_NOT_BE_REMOVED="This tag could not be removed." +COM_GETBIBLE_THIS_TAG_DOESNT_BELONG_TO_YOU_THUS_YOU_CANNOT_DELETE_IT="This tag doesn't belong to you, thus you cannot delete it." +COM_GETBIBLE_THIS_TAG_DOESNT_BELONG_TO_YOU_THUS_YOU_CANNOT_EDIT_IT="This tag doesn't belong to you, thus you cannot edit it." COM_GETBIBLE_TRANSLATION="Translation" COM_GETBIBLE_TRANSLATIONS="Translations" COM_GETBIBLE_TRANSLATIONS_ACCESS="Translations Access" diff --git a/admin/sql/install.mysql.utf8.sql b/admin/sql/install.mysql.utf8.sql index c890a51..16da2de 100644 --- a/admin/sql/install.mysql.utf8.sql +++ b/admin/sql/install.mysql.utf8.sql @@ -471,13 +471,13 @@ INSERT INTO `#__getbible_tag` (`id`, `access`, `description`, `guid`, `name`, `p (21, 1, 'Exploring the concept of church gatherings in homes.', 'c3dfb8e7-4ea8-4925-96c1-f3a621a4b9b0', 'Home Church', 1, '2015-07-17 13:18:40'), (22, 1, 'Reflecting on God\'s immutability, His unchanging nature.', '44df4ce6-5e9f-4077-8af1-81b4a5c63f19', 'Immutability', 1, '2015-07-14 13:05:39'), (23, 1, 'Exploring the divine nature of Jesus Christ.', '1a0ad6e8-35fa-4f2c-889f-9ca2b057bbf0', 'Jesus Christ\'s Deity', 1, '2015-01-16 14:23:26'), -(24, 1, 'Exploring the incarnation, Jesus being in the flesh.', 'e84a2c7a-f234-43c6-94de-af432c2f0ab1', 'Jesus Christ’s Humanity', 1, '2015-07-14 16:17:54'), +(24, 1, 'Exploring the incarnation, Jesus being in the flesh.', 'e84a2c7a-f234-43c6-94de-af432c2f0ab1', 'Jesus Christ\'s Humanity', 1, '2015-07-14 16:17:54'), (25, 1, 'Exploring the biblical view of leadership.', '6493a897-7e2a-4bb3-96c1-f3a6b5c5f9f0', 'Leadership', 1, '2015-07-14 13:51:25'), (26, 1, 'Hannah says life has no description.', '04c7f6b3-17df-4920-b96e-65f64932b9c1', 'Life', 1, '2015-12-03 23:26:31'), (27, 1, 'Exploring what gives one a long life.', '17df4ce3-289a-437b-88d1-9c2b057ba1a0', 'Longevity', 1, '2015-07-14 12:32:43'), (28, 1, 'Exploring the roles and responsibilities of men.', 'c3dfb8e7-d234-46a8-96c5-f3a6a6c5f9f0', 'Man\'s Role', 1, '2015-07-14 10:41:41'), (29, 1, 'Beliefs and teachings on the sacrament of marriage.', 'b5fb8c11-dfb7-4fb6-aa4b-e982a12d3e9c', 'Marriage', 1, '2015-07-14 10:24:11'), -(30, 1, 'Understanding the destructive and harmful influence of music.', '44df4ce6-5dfb-473b-973e-af564b2f0ab1', 'Music’s Influence', 1, '2015-01-18 12:16:37'), +(30, 1, 'Understanding the destructive and harmful influence of music.', '44df4ce6-5dfb-473b-973e-af564b2f0ab1', 'Music\'s Influence', 1, '2015-01-18 12:16:37'), (31, 1, 'The correct motive to avoid company or fellowship.', '755ae009-8f6d-4769-9a1b-bec6a6c5f7d5', 'No Fellowship', 1, '2015-07-14 06:21:42'), (32, 1, 'Understanding biblical goodness.', '6493a897-755a-4769-9a1b-bec6a6c5f7d5', 'No One is Good', 1, '2015-07-14 13:34:50'), (33, 1, 'Exploring the concept of loving your enemy', '289ad6e8-39bc-473b-973e-af564b2f0ab1', 'Nonresistance', 1, '2017-10-09 05:27:08'), diff --git a/admin/sql/updates/mysql/2.0.5.sql b/admin/sql/updates/mysql/2.0.5.sql new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/admin/sql/updates/mysql/2.0.5.sql @@ -0,0 +1 @@ + diff --git a/getbible.xml b/getbible.xml index 11f4ce6..7a448b0 100644 --- a/getbible.xml +++ b/getbible.xml @@ -1,15 +1,15 @@ COM_GETBIBLE - 28th July, 2023 + 1st August, 2023 Llewellyn van der Merwe joomla@vdm.io https://getbible.net Copyright (C) 2015. All Rights Reserved GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html - 2.0.5 + 2.0.6 Get Bible (v.2.0.5) +

Get Bible (v.2.0.6)

Welcome to the next level of scripture engagement - The Bible for Joomla! Our purpose is to bring the Word of God to every person, in their native language, entirely free. This isn't just a typical extension; it's a groundbreaking tool developed to span language divides and deliver a rich, customizable Bible study experience to users worldwide. diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Abstraction/Watcher.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Abstraction/Watcher.php new file mode 100644 index 0000000..eb9277c --- /dev/null +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Abstraction/Watcher.php @@ -0,0 +1,177 @@ + + * @git GetBible + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\GetBible\Abstraction; + + +use Joomla\CMS\Date\Date; +use VDM\Joomla\GetBible\Database\Load; +use VDM\Joomla\GetBible\Database\Insert; +use VDM\Joomla\GetBible\Database\Update; + + +/** + * The GetBible Watcher + * + * @since 2.0.1 + */ +abstract class Watcher +{ + /** + * The Load class + * + * @var Load + * @since 2.0.1 + */ + protected Load $load; + + /** + * The Insert class + * + * @var Insert + * @since 2.0.1 + */ + protected Insert $insert; + + /** + * The Update class + * + * @var Update + * @since 2.0.1 + */ + protected Update $update; + + /** + * The fresh load switch + * + * @var bool + * @since 2.0.1 + */ + protected bool $fresh = false; + + /** + * The target + * + * @var object|null + * @since 2.0.1 + */ + protected ?object $target; + + /** + * The target table + * + * @var string + * @since 2.0.1 + */ + protected string $table; + + /** + * Constructor + * + * @param Load $load The load object. + * @param Insert $insert The insert object. + * @param Update $update The update object. + * + * @since 2.0.1 + */ + public function __construct( + Load $load, + Insert $insert, + Update $update) + { + $this->load = $load; + $this->insert = $insert; + $this->update = $update; + + // just in-case we set a date + $this->today = (new Date())->toSql(); + } + + /** + * The see if new target is newly installed + * + * @return bool true if is new + * @since 2.0.1 + */ + public function isNew(): bool + { + return $this->fresh; + } + + /** + * Check if its time to match the API hash + * + * @return bool false if its time to check for an update + * @since 2.0.1 + */ + protected function hold(): bool + { + // Create DateTime objects from the strings + try { + $today = new \DateTime($this->today); + $created = new \DateTime($this->target->created); + } catch (\Exception $e) { + return false; + } + + // Calculate the difference + $interval = $today->diff($created); + + // Check if the interval is more than 1 month + if ($interval->m >= 1 || $interval->y >= 1) + { + return false; // More than a month, it's time to check for an update + } + else + { + return true; // Within the last month, hold off on the update check + } + } + + /** + * Bump the checking time + * + * @return bool true when the update was a success + * @since 2.0.1 + */ + protected function bump(): bool + { + $update = []; + $update['id'] = $this->target->id; + $update['created'] = $this->today; + + // update the local verse + return $this->update->row($update, 'id', $this->table); + } + + /** + * Get local targeted object + * + * @param array $match The [key, value]. + * @param array $local The local values. + * + * @return object|null The found value + * @since 2.0.1 + */ + protected function getTarget(array $match, array &$local): ?object + { + foreach ($local as $_value) + { + if ($_value->{$match['key']} === $match['value']) + { + return $_value; + } + } + + return null; + } +} + diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Factory.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Factory.php index 4bdbfb9..4aeffeb 100644 --- a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Factory.php +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Factory.php @@ -15,6 +15,7 @@ namespace VDM\Joomla\GetBible; use Joomla\DI\Container; use VDM\Joomla\GetBible\Service\Api; use VDM\Joomla\GetBible\Service\Utilities; +use VDM\Joomla\GetBible\Service\Watcher; use VDM\Joomla\GetBible\Service\App; use VDM\Joomla\GetBible\Service\Model; use VDM\Joomla\GetBible\Service\Database; @@ -76,6 +77,7 @@ abstract class Factory implements FactoryInterface return (new Container()) ->registerServiceProvider(new Utilities()) ->registerServiceProvider(new Api()) + ->registerServiceProvider(new Watcher()) ->registerServiceProvider(new App()) ->registerServiceProvider(new Model()) ->registerServiceProvider(new Database()); diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Linker.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Linker.php index 719fdc8..a5fbee9 100644 --- a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Linker.php +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Linker.php @@ -140,7 +140,8 @@ final class Linker if ($setup) { - $guid = (string) GuidHelper::get(); + $guid = $this->getGuid('linker'); + $this->session->set('getbible_active_linker_guid', $guid); return $guid; @@ -537,19 +538,31 @@ final class Linker return false; } - $guid = (string) GuidHelper::get(); - while (!GuidHelper::valid($guid, 'password', 0, 'getbible')) - { - // must always be set - $guid = (string) GuidHelper::get(); - } - return $this->insert->row([ 'name' => 'Favourite-Verse', 'linker' => $linker, 'password' => UserHelper::hashPassword($pass), - 'guid' => $guid + 'guid' => $this->getGuid('password') ], 'password'); + } + + /** + * Get a GUID + * + * @param string $table The table its for + * + * @return string The GUID value + * @since 2.0.1 + **/ + private function getGuid(string $table): string + { + $guid = (string) GuidHelper::get(); + while (!GuidHelper::valid($guid, $table, 0, 'getbible')) + { + // must always be set + $guid = (string) GuidHelper::get(); + } + return $guid; } } diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Service/App.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Service/App.php index 012f390..9a32b1d 100644 --- a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Service/App.php +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Service/App.php @@ -18,7 +18,6 @@ use VDM\Joomla\GetBible\Config; use VDM\Joomla\GetBible\Table; use VDM\Joomla\GetBible\DailyScripture; use VDM\Joomla\GetBible\Search; -use VDM\Joomla\GetBible\Watcher; use VDM\Joomla\GetBible\Loader; use VDM\Joomla\GetBible\Linker; use VDM\Joomla\GetBible\Note; @@ -56,9 +55,6 @@ class App implements ServiceProviderInterface $container->alias(Search::class, 'GetBible.Search') ->share('GetBible.Search', [$this, 'getSearch'], true); - $container->alias(Watcher::class, 'GetBible.Watcher') - ->share('GetBible.Watcher', [$this, 'getWatcher'], true); - $container->alias(Loader::class, 'GetBible.Loader') ->share('GetBible.Loader', [$this, 'getLoader'], true); @@ -134,27 +130,6 @@ class App implements ServiceProviderInterface return new Search(); } - /** - * Get the Watcher class - * - * @param Container $container The DI container. - * - * @return Watcher - * @since 2.0.1 - */ - public function getWatcher(Container $container): Watcher - { - return new Watcher( - $container->get('GetBible.Load'), - $container->get('GetBible.Insert'), - $container->get('GetBible.Update'), - $container->get('GetBible.Api.Translations'), - $container->get('GetBible.Api.Books'), - $container->get('GetBible.Api.Chapters'), - $container->get('GetBible.Api.Verses') - ); - } - /** * Get the Loader class * diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Service/Watcher.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Service/Watcher.php new file mode 100644 index 0000000..28a0e12 --- /dev/null +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Service/Watcher.php @@ -0,0 +1,126 @@ + + * @git GetBible + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\GetBible\Service; + + +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; +use VDM\Joomla\GetBible\Watcher as Watch; +use VDM\Joomla\GetBible\Watcher\Translation; +use VDM\Joomla\GetBible\Watcher\Book; +use VDM\Joomla\GetBible\Watcher\Chapter; + + +/** + * The GetBible Watcher Service + * + * @since 2.0.1 + */ +class Watcher implements ServiceProviderInterface +{ + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * @since 2.0.1 + */ + public function register(Container $container) + { + $container->alias(Watch::class, 'GetBible.Watcher') + ->share('GetBible.Watcher', [$this, 'getWatcher'], true); + + $container->alias(Translation::class, 'GetBible.Watcher.Translation') + ->share('GetBible.Watcher.Translation', [$this, 'getTranslation'], true); + + $container->alias(Book::class, 'GetBible.Watcher.Book') + ->share('GetBible.Watcher.Book', [$this, 'getBook'], true); + + $container->alias(Chapter::class, 'GetBible.Watcher.Chapter') + ->share('GetBible.Watcher.Chapter', [$this, 'getChapter'], true); + } + + /** + * Get the Watcher class + * + * @param Container $container The DI container. + * + * @return Watch + * @since 2.0.1 + */ + public function getWatcher(Container $container): Watch + { + return new Watch( + $container->get('GetBible.Load'), + $container->get('GetBible.Watcher.Translation'), + $container->get('GetBible.Watcher.Book'), + $container->get('GetBible.Watcher.Chapter') + ); + } + + /** + * Get the Translation class + * + * @param Container $container The DI container. + * + * @return Translation + * @since 2.0.1 + */ + public function getTranslation(Container $container): Translation + { + return new Translation( + $container->get('GetBible.Load'), + $container->get('GetBible.Insert'), + $container->get('GetBible.Update'), + $container->get('GetBible.Api.Translations') + ); + } + + /** + * Get the Book class + * + * @param Container $container The DI container. + * + * @return Book + * @since 2.0.1 + */ + public function getBook(Container $container): Book + { + return new Book( + $container->get('GetBible.Load'), + $container->get('GetBible.Insert'), + $container->get('GetBible.Update'), + $container->get('GetBible.Api.Books') + ); + } + + /** + * Get the Chapter class + * + * @param Container $container The DI container. + * + * @return Chapter + * @since 2.0.1 + */ + public function getChapter(Container $container): Chapter + { + return new Chapter( + $container->get('GetBible.Load'), + $container->get('GetBible.Insert'), + $container->get('GetBible.Update'), + $container->get('GetBible.Api.Chapters'), + $container->get('GetBible.Api.Verses') + ); + } +} + diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Tag.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Tag.php index 61e343a..f63c48a 100644 --- a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Tag.php +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Tag.php @@ -82,14 +82,15 @@ final class Tag } /** - * Set a tag + * Create a tag * - * @param string $name The tag name being created + * @param string $name The tag name being created + * @param string|null $description The tag description being created * * @return array|null Array of the tag values on success * @since 2.0.1 **/ - public function set(string $name): ?array + public function create(string $name, ?string $description): ?array { // make sure the linker has access if (($linker = $this->linker->get()) === null) @@ -101,6 +102,7 @@ final class Tag } // get tag if it exist + $name = trim($name); if (($tag = $this->get($linker, $name)) !== null) { // publish if not published @@ -111,15 +113,23 @@ final class Tag ]; } + // update the description if it does not match + $description = $description ?? ''; + $description = trim($description); + if ($tag->description !== $description && $this->update->value($description, 'description', $tag->id, 'id', 'tag')) + { + $tag->description = $description; + } + $tag->published = 1; - $tag->success = Text::_('COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_SET'); + $tag->success = Text::_('COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_REACTIVATED'); return (array) $tag; } // create a new tag - elseif ($this->create($linker, $name) + elseif (strlen($name) >= 2 && $this->createTag($linker, $name, $description) && ($tag = $this->get($linker, $name)) !== null) { - $tag->success = Text::_('COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_SET'); + $tag->success = Text::_('COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_CREATED'); return (array) $tag; } @@ -127,35 +137,105 @@ final class Tag } /** - * Delete a tag + * Update a tag * - * @param string $tag The tagged verse GUID value + * @param string $tag The tag GUID value + * @param string $name The tag name being created + * @param string|null $description The tag description being created * - * @return bool True on success + * @return array|null Array of the tag values on success * @since 2.0.1 **/ - public function delete(string $tag): bool + public function update(string $tag, string $name, ?string $description): ?array { // make sure the linker has access if (($linker = $this->linker->get()) === null) { - return false; + return [ + 'error' => Text::_("COM_GETBIBLE_WITHOUT_SELECTING_THE_CORRECT_FAVOURITE_VERSEBR_YOU_CANT_PERFORM_THE_INITIAL_ACTION"), + 'access_required' => true + ]; + } + + // get tag if it exist + $name = trim($name); + $tag = trim($tag); + if (($_tag = $this->load->item(['linker' => $linker, 'guid' => $tag], 'tag')) !== null) + { + // publish if not published + if ($_tag->published != 1 && !$this->update->value(1, 'published', $_tag->id, 'id', 'tag')) + { + return [ + 'error' => Text::_('COM_GETBIBLE_TAG_FOUND_BUT_COULD_NOT_BE_REACTIVATED') + ]; + } + + // update the description if it does not match + $description = $description ?? ''; + $description = trim($description); + if ($_tag->description !== $description && $this->update->value($description, 'description', $_tag->id, 'id', 'tag')) + { + $_tag->description = $description; + } + + // update the name if it does not match + if (strlen($name) >= 2 && $_tag->name !== $name && $this->update->value($name, 'name', $_tag->id, 'id', 'tag')) + { + $_tag->name = $name; + } + + $_tag->published = 1; + $_tag->success = Text::_('COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_UPDATED'); + return (array) $_tag; + } + //elseif (($_tag = $this->load->item(['guid' => $tag], 'tag')) !== null) + //{ + // we may need to add this + //} + + return [ + 'error' => Text::_("COM_GETBIBLE_THIS_TAG_DOESNT_BELONG_TO_YOU_THUS_YOU_CANNOT_EDIT_IT") + ]; + } + + /** + * Delete a tag + * + * @param string $tag The tagged verse GUID value + * + * @return array|null Array of the message on success + * @since 2.0.1 + **/ + public function delete(string $tag): ?array + { + // make sure the linker has access + if (($linker = $this->linker->get()) === null) + { + return [ + 'error' => Text::_("COM_GETBIBLE_WITHOUT_SELECTING_THE_CORRECT_FAVOURITE_VERSEBR_YOU_CANT_PERFORM_THE_INITIAL_ACTION"), + 'access_required' => true + ]; } // make sure the linker has access to delete this tag - if (($id = $this->load->value(['guid' => $tag, 'linker' => $linker], 'id', 'tag')) !== null && $id > 0) + if (($id = $this->load->value(['guid' => $tag, 'linker' => $linker], 'id', 'tag')) !== null && $id > 0 + && $this->update->value(-2, 'published', $id, 'id', 'tag')) { - return $this->update->value(-2, 'published', $id, 'id', 'tag'); + return [ + 'success' => Text::_('COM_GETBIBLE_TAG_SUCCESSFULLY_DELETED') + ]; } - return false; + return [ + 'error' => Text::_("COM_GETBIBLE_THIS_TAG_DOESNT_BELONG_TO_YOU_THUS_YOU_CANNOT_DELETE_IT") + ]; } /** * Get a tag * - * @param string $linker The linker GUID value - * @param string $name The tag name + * @param string $linker The linker GUID value + * @param string $name The tag name * * @return array|null Array of the tagged verse values on success * @since 2.0.1 @@ -180,15 +260,17 @@ final class Tag /** * Create a Tag * - * @param string $linker The linker GUID value - * @param string $name The tag name + * @param string $linker The linker GUID value + * @param string $name The tag name + * @param string|null $description The tag description being created * * @return bool True on success * @since 2.0.1 **/ - private function create( + private function createTag( string $linker, - string $name + string $name, + ?string $description ): bool { $guid = (string) GuidHelper::get(); @@ -202,6 +284,7 @@ final class Tag 'access' => 0, 'linker' => $linker, 'name' => $name, + 'description' => $description ?? '', 'guid' => $guid ], 'tag'); } diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher.php index 4c65a1b..b1e7f4f 100644 --- a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher.php +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher.php @@ -12,14 +12,10 @@ namespace VDM\Joomla\GetBible; -use Joomla\CMS\Date\Date; use VDM\Joomla\GetBible\Database\Load; -use VDM\Joomla\GetBible\Database\Insert; -use VDM\Joomla\GetBible\Database\Update; -use VDM\Joomla\GetBible\Api\Translations; -use VDM\Joomla\GetBible\Api\Books; -use VDM\Joomla\GetBible\Api\Chapters; -use VDM\Joomla\GetBible\Api\Verses; +use VDM\Joomla\GetBible\Watcher\Translation; +use VDM\Joomla\GetBible\Watcher\Book; +use VDM\Joomla\GetBible\Watcher\Chapter; /** @@ -38,52 +34,28 @@ final class Watcher protected Load $load; /** - * The Insert class + * The Translation class * - * @var Insert + * @var Translation * @since 2.0.1 */ - protected Insert $insert; + protected Translation $translation; /** - * The Update class + * The Book class * - * @var Update + * @var Book * @since 2.0.1 */ - protected Update $update; + protected Book $book; /** - * The Translations class + * The Chapter class * - * @var Translations + * @var Chapter * @since 2.0.1 */ - protected Translations $translations; - - /** - * The Books class - * - * @var Books - * @since 2.0.1 - */ - protected Books $books; - - /** - * The Chapters class - * - * @var Chapters - * @since 2.0.1 - */ - protected Chapters $chapters; - - /** - * The Verses class - * - * @var Verses - * @since 2.0.1 - */ - protected Verses $verses; + protected Chapter $chapter; /** * The fresh load switch @@ -93,54 +65,62 @@ final class Watcher */ protected bool $fresh = false; - /** - * The sql date of today - * - * @var string - * @since 2.0.1 - */ - protected string $today; - - /** - * The target verse - * - * @var object|null - * @since 2.0.1 - */ - protected ?object $verse; - /** * Constructor * - * @param Load $load The load object. - * @param Insert $insert The insert object. - * @param Update $update The update object. - * @param Translations $translations The translations API object. - * @param Books $books The books API object. - * @param Chapters $chapters The chapters API object. - * @param Verses $verses The verses API object. + * @param Load $load The load object. + * @param Translation $translation The translations API object. + * @param Book $book The books API object. + * @param Chapter $chapter The chapters API object. * * @since 2.0.1 */ public function __construct( Load $load, - Insert $insert, - Update $update, - Translations $translations, - Books $books, - Chapters $chapters, - Verses $verses) + Translation $translation, + Book $book, + Chapter $chapter) { $this->load = $load; - $this->insert = $insert; - $this->update = $update; - $this->translations = $translations; - $this->books = $books; - $this->chapters = $chapters; - $this->verses = $verses; + $this->translation = $translation; + $this->book = $book; + $this->chapter = $chapter; + } - // just in-case we set a date - $this->today = (new Date())->toSql(); + /** + * Watching that the local Database and API is in sync + * + * @param string $translation The translation. + * @param int $book The book number. + * @param int $chapter The chapter number. + * + * @return bool True on success + * @since 2.0.1 + */ + public function sync(string $translation, int $book, int $chapter): bool + { + // is the translation details in sync + if (!$this->translation->sync($translation)) + { + return false; + } + + // is the book details in sync + if (!$this->book->sync($translation, $book)) + { + return false; + } + + // is the chapter and its verses in sync + if (!$this->chapter->sync($translation, $book, $chapter)) + { + return false; + } + + // if any is new, then this is class should not load any more stuff + $this->fresh = ($this->translation->isNew() || $this->book->isNew() || $this->chapter->isNew()); + + return true; } /** @@ -189,63 +169,6 @@ final class Watcher ); } - /** - * Watching that the local Database and API is in sync - * - * @param string $translation The translation. - * @param int $book The book number. - * @param int $chapter The chapter number. - * - * @return bool True on success - * @since 2.0.1 - */ - public function api(string $translation, int $book, int $chapter): bool - { - // does the translation exist - if ($this->translation($translation) === null) - { - return false; - } - - // does the book exist - if ($this->book($translation, $book) === null) - { - return false; - } - - // does the chapter exist, and get hash value - if (($hash = $this->chapter($translation, $book, $chapter)) === null) - { - return false; - } - - // load the verses if not found - if ($this->verses($translation, $book, $chapter)) - { - if ($this->isNew() || $this->hold()) - { - return true; - } - - // get API chapter hash value - $api_hash = $this->chapters->sha($translation, $book, $chapter); - - // confirm chapter hash has not changed - if (hash_equals($hash, $api_hash)) - { - return $this->bump(); - } - - if ($this->update($translation, $book, $chapter)) - { - // now update the hash of this chapter - return $this->updateHash($translation, $book, $chapter, $api_hash); - } - } - - return false; - } - /** * Get the next chapter * @@ -392,302 +315,6 @@ final class Watcher } return $this->getPreviousBook($translation, $previous, $try); - } - - /** - * Get Translation Hash Value - * - * @param string $translation The translation. - * - * @return string|null The sha of the translation - * @since 2.0.1 - */ - private function translation(string $translation): ?string - { - // check local value - if (($translation_sha = $this->load->value(['abbreviation' => $translation], 'sha', 'translation')) !== null) - { - return $translation_sha; - } - - // get all the translations - $translations = $this->translations->list(); - - // check return data - if (!isset($translations->{$translation}) || !isset($translations->{$translation}->sha)) - { - return null; - } - - // add them to the database - $this->insert->items((array) $translations, 'translation'); - - return $translations->{$translation}->sha; - } - - /** - * Get Book Hash Value - * - * @param string $translation The translation. - * @param int $book The book number. - * - * @return string|null The sha of the book - * @since 2.0.1 - */ - private function book(string $translation, int $book): ?string - { - // check local value - if (($book_sha = $this->load->value(['abbreviation' => $translation, 'nr' => $book], 'sha', 'book')) !== null) - { - return $book_sha; - } - - // get all the books - $books = $this->books->list($translation); - - // check return data - if (!isset($books->{$book}) || !isset($books->{$book}->sha)) - { - return null; - } - - // add them to the database - $this->insert->items((array) $books, 'book'); - - return $books->{$book}->sha; - } - - /** - * Get Chapter Hash Value - * - * @param string $translation The translation. - * @param int $book The book number. - * @param int $chapter The chapter number. - * - * @return string|null The sha of the chapter - * @since 2.0.1 - */ - private function chapter(string $translation, int $book, int $chapter): ?string - { - // check local value - if (($chapter_sha = $this->load->value( - ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter], - 'sha', 'chapter' - )) !== null) - { - return $chapter_sha; - } - - // get all the books - $chapters = $this->chapters->list($translation, $book); - - // check return data - if (!isset($chapters->{$chapter}) || !isset($chapters->{$chapter}->sha)) - { - return null; - } - - // add them to the database - $this->insert->items((array) $chapters, 'chapter'); - - return $chapters->{$chapter}->sha; - } - - /** - * Load verses if not in local database - * - * @param string $translation The translation. - * @param int $book The book number. - * @param int $chapter The chapter number. - * - * @return bool True if in local database - * @since 2.0.1 - */ - private function verses(string $translation, int $book, int $chapter): bool - { - // check local value - if (($this->verse = $this->load->item( - ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter, 'verse' => 1], - 'verse' - )) !== null) - { - return true; - } - - // get all the verses - if (($verses = $this->verses->get($translation, $book, $chapter)) === null) - { - return false; - } - - // dynamic update all verse objects - $insert = ['book_nr' => $book, 'abbreviation' => $translation]; - array_walk($verses->verses, function ($item, $key) use ($insert) { - foreach ($insert as $k => $v) { $item->$k = $v; } - }); - - $this->fresh = true; - - // add them to the database - return $this->insert->items((array) $verses->verses, 'verse'); - } - - /** - * Trigger the update of the verses of a translation-book-chapter - * - * @param string $translation The translation. - * @param int $book The book number. - * @param int $chapter The chapter number. - * - * @return bool True if update was a success - * @since 2.0.1 - */ - private function update(string $translation, int $book, int $chapter): bool - { - // load all the verses from the local database - if (($verses = $this->load->items( - ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter], - 'verse' - )) !== null) - { - // get verses from the API - if (($api = $this->verses->get($translation, $book, $chapter)) === null) - { - return false; - } - - $update = []; - $insert = []; - - // dynamic update all verse objects - foreach ($api->verses as $verse) - { - // check if the verse exist - if (($object = $this->getVerse((int) $verse->verse, $verses)) !== null) - { - $verse->id = $object->id; - $verse->created = $this->today; - $update[] = $verse; - } - else - { - $insert[] = $verse; - } - } - - // check if we have values to insert - if ($insert !== []) - { - $this->insert->items($insert, 'verse'); - } - - // update the local verses - if ($update !== [] && $this->update->items($update, 'id', 'verse')) - { - return true; - } - } - - return false; - } - - /** - * Get a verse text from the API array of verses - * - * @param int $number The verse number. - * @param array $verses The api verses - * - * @return object|null The verse string - * @since 2.0.1 - */ - private function getVerse(int $number, array &$verses): ?object - { - foreach ($verses as $verse) - { - if ($verse->verse === $number) - { - return $verse; - } - } - - return null; - } - - /** - * Trigger the update of a chapter hash value - * - * @param string $translation The translation. - * @param int $book The book number. - * @param int $chapter The chapter number. - * @param string $hash The API chapter hash value. - * - * @return bool True if update was a success - * @since 2.0.1 - */ - private function updateHash(string $translation, int $book, int $chapter, string $hash): bool - { - // load the chapter - if (($item = $this->load->item( - ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter], - 'chapter' - )) !== null) - { - $update = []; - $update['id'] = $item->id; - $update['sha'] = $hash; - $update['created'] = $this->today; - - // update the local chapter - return $this->update->row($update, 'id', 'chapter'); - } - - return false; - } - - /** - * Check if its time to match the API hash - * - * @return bool false if its time to check for an update - * @since 2.0.1 - */ - private function hold(): bool - { - // Create DateTime objects from the strings - try { - $today = new \DateTime($this->today); - $created = new \DateTime($this->verse->created); - } catch (\Exception $e) { - return false; - } - - // Calculate the difference - $interval = $today->diff($created); - - // Check if the interval is more than 1 month - if ($interval->m >= 1 || $interval->y >= 1) - { - return false; // More than a month, it's time to check for an update - } - else - { - return true; // Within the last month, hold off on the update check - } - } - - /** - * Bump the checking time - * - * @return bool true when the update was a success - * @since 2.0.1 - */ - private function bump(): bool - { - $update = []; - $update['id'] = $this->verse->id; - $update['created'] = $this->today; - - // update the local verse - return $this->update->row($update, 'id', 'verse'); } } diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Book.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Book.php new file mode 100644 index 0000000..1f34b90 --- /dev/null +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Book.php @@ -0,0 +1,191 @@ + + * @git GetBible + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\GetBible\Watcher; + + +use VDM\Joomla\GetBible\Database\Load; +use VDM\Joomla\GetBible\Database\Insert; +use VDM\Joomla\GetBible\Database\Update; +use VDM\Joomla\GetBible\Api\Books; +use VDM\Joomla\GetBible\Abstraction\Watcher; + + +/** + * The GetBible Book Watcher + * + * @since 2.0.1 + */ +final class Book extends Watcher +{ + /** + * The Books class + * + * @var Books + * @since 2.0.1 + */ + protected Books $books; + + /** + * Constructor + * + * @param Load $load The load object. + * @param Insert $insert The insert object. + * @param Update $update The update object. + * @param Books $books The books API object. + * + * @since 2.0.1 + */ + public function __construct( + Load $load, + Insert $insert, + Update $update, + Books $books) + { + // load the parent constructor + parent::__construct($load, $insert, $update); + + $this->books = $books; + + // set the table + $this->table = 'book'; + } + + /** + * Sync the target being watched + * + * @param string $translation The translation. + * @param int $book The book number. + * + * @return bool True on success + * @since 2.0.1 + */ + public function sync(string $translation, int $book): bool + { + // load the target if not found + if ($this->load($translation, $book)) + { + if ($this->isNew() || $this->hold()) + { + return true; + } + + // get API hash value + $hash = $this->books->sha($translation, $book); + + // confirm hash has not changed + if (hash_equals($hash, $this->target->sha)) + { + return $this->bump(); + } + + if ($this->update($translation)) + { + return true; + } + } + + return false; + } + + /** + * Load Book + * + * @param string $translation The translation. + * @param int $book The book number. + * + * @return bool True if translation found + * @since 2.0.1 + */ + private function load(string $translation, int $book): bool + { + // check local value + if (($this->target = $this->load->item(['abbreviation' => $translation, 'nr' => $book], $this->table)) !== null) + { + return true; + } + + // get all this translation books + $books = $this->books->list($translation); + + // check return data + if (!isset($books->{$book}) || !isset($books->{$book}->sha)) + { + return false; + } + + // add them to the database + $this->insert->items((array) $books, 'book'); + + if (($this->target = $this->load->item(['abbreviation' => $translation, 'nr' => $book], $this->table)) !== null) + { + $this->fresh = true; + } + + return $this->fresh; + } + + /** + * Trigger the update of all books of this translation + * + * @param string $translation The translation. + * + * @return bool True if update was a success + * @since 2.0.1 + */ + private function update(string $translation): bool + { + // get translations from the API + if (($books = $this->books->list($translation)) === null) + { + return false; + } + + // get the local books + $local_books = $this->load->items(['abbreviation' => $translation], $this->table); + + $update = []; + $insert = []; + $match = ['key' => 'nr', 'value' => '']; + + // dynamic update all books + foreach ($books as $book) + { + // check if the verse exist + $match['value'] = (string) $book->nr; + if (($object = $this->getTarget($match, $local_books)) !== null) + { + $book->id = $object->id; + $book->created = $this->today; + $update[] = $book; + } + else + { + $insert[] = $book; + } + } + + // check if we have values to insert + if ($insert !== []) + { + $this->insert->items($insert, $this->table); + } + + // update the local values + if ($update !== [] && $this->update->items($update, 'id', $this->table)) + { + return true; + } + + return false; + } +} + diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Chapter.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Chapter.php new file mode 100644 index 0000000..da1d03c --- /dev/null +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Chapter.php @@ -0,0 +1,279 @@ + + * @git GetBible + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\GetBible\Watcher; + + +use VDM\Joomla\GetBible\Database\Load; +use VDM\Joomla\GetBible\Database\Insert; +use VDM\Joomla\GetBible\Database\Update; +use VDM\Joomla\GetBible\Api\Chapters; +use VDM\Joomla\GetBible\Api\Verses; +use VDM\Joomla\GetBible\Abstraction\Watcher; + + +/** + * The GetBible Chapter Watcher + * + * @since 2.0.1 + */ +final class Chapter extends Watcher +{ + /** + * The Chapters class + * + * @var Chapters + * @since 2.0.1 + */ + protected Chapters $chapters; + + /** + * The Verses class + * + * @var Verses + * @since 2.0.1 + */ + protected Verses $verses; + + /** + * Constructor + * + * @param Load $load The load object. + * @param Insert $insert The insert object. + * @param Update $update The update object. + * @param Chapters $chapters The chapters API object. + * @param Verses $verses The verses API object. + * + * @since 2.0.1 + */ + public function __construct( + Load $load, + Insert $insert, + Update $update, + Chapters $chapters, + Verses $verses) + { + // load the parent constructor + parent::__construct($load, $insert, $update); + + $this->chapters = $chapters; + $this->verses = $verses; + + // set the table + $this->table = 'chapter'; + } + + /** + * Sync the target being watched + * + * @param string $translation The translation. + * @param int $book The book number. + * @param int $chapter The chapter number. + * + * @return bool True on success + * @since 2.0.1 + */ + public function sync(string $translation, int $book, int $chapter): bool + { + // load the target if not found + if ($this->chapter($translation, $book, $chapter) + && $this->verses($translation, $book, $chapter)) + { + if ($this->isNew() || $this->hold()) + { + return true; + } + + // get API hash value + $hash = $this->chapters->sha($translation, $book, $chapter); + + // confirm hash has not changed + if (hash_equals($hash, $this->target->sha)) + { + return $this->bump(); + } + + if ($this->update($translation, $book, $chapter) + && $this->hash($hash)) + { + return true; + } + } + + return false; + } + + /** + * Load the chapter numbers + * + * @param string $translation The translation. + * @param int $book The book number. + * @param int $chapter The chapter number. + * + * @return bool True on success + * @since 2.0.1 + */ + private function chapter(string $translation, int $book, int $chapter): bool + { + // check local value + if (($this->target = $this->load->item( + ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter], + 'chapter' + )) !== null) + { + return true; + } + + // get all the books + $chapters = $this->chapters->list($translation, $book); + + // check return data + if (!isset($chapters->{$chapter}) || !isset($chapters->{$chapter}->sha)) + { + return false; + } + + // add them to the database + $this->insert->items((array) $chapters, 'chapter'); + + // check local value + if (($this->target = $this->load->item( + ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter], + 'chapter' + )) !== null) + { + return true; + } + + return false; + } + + /** + * Load verses + * + * @param string $translation The translation. + * @param int $book The book number. + * @param int $chapter The chapter number. + * + * @return bool True if in local database + * @since 2.0.1 + */ + private function verses(string $translation, int $book, int $chapter): bool + { + // check local value + if (($text = $this->load->value( + ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter, 'verse' => 1], + 'text', 'verse' + )) !== null) + { + return true; + } + + // get all the verses + if (($verses = $this->verses->get($translation, $book, $chapter)) === null) + { + return false; + } + + // dynamic update all verse objects + $insert = ['book_nr' => $book, 'abbreviation' => $translation]; + array_walk($verses->verses, function ($item, $key) use ($insert) { + foreach ($insert as $k => $v) { $item->$k = $v; } + }); + + // add them to the database + $this->fresh = $this->insert->items((array) $verses->verses, 'verse'); + + return true; + } + + /** + * Trigger the update of the verses of a translation-book-chapter + * + * @param string $translation The translation. + * @param int $book The book number. + * @param int $chapter The chapter number. + * + * @return bool True if update was a success + * @since 2.0.1 + */ + private function update(string $translation, int $book, int $chapter): bool + { + // load all the verses from the local database + if (($verses = $this->load->items( + ['abbreviation' => $translation, 'book_nr' => $book, 'chapter' => $chapter], + 'verse' + )) !== null) + { + // get verses from the API + if (($api = $this->verses->get($translation, $book, $chapter)) === null) + { + return false; + } + + $update = []; + $insert = []; + $match = ['key' => 'verse', 'value' => '']; + + // dynamic update all verse objects + foreach ($api->verses as $verse) + { + // check if the verse exist + $match['value'] = (string) $verse->verse; + if (($object = $this->getTarget($match, $verses)) !== null) + { + $verse->id = $object->id; + $verse->modified = $this->today; + $update[] = $verse; + } + else + { + $insert[] = $verse; + } + } + + // check if we have values to insert + if ($insert !== []) + { + $this->insert->items($insert, 'verse'); + } + + // update the local verses + if ($update !== [] && $this->update->items($update, 'id', 'verse')) + { + return true; + } + } + + return false; + } + + /** + * Trigger the update of a chapter hash value + * + * @param string $hash The API chapter hash value. + * + * @return bool True if update was a success + * @since 2.0.1 + */ + private function hash(string $hash): bool + { + // load the chapter + $update = []; + $update['id'] = $this->target->id; + $update['sha'] = $hash; + $update['created'] = $this->today; + + // update the local chapter + return $this->update->row($update, 'id', 'chapter'); + } +} + diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Translation.php b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Translation.php new file mode 100644 index 0000000..a336180 --- /dev/null +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/Translation.php @@ -0,0 +1,187 @@ + + * @git GetBible + * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace VDM\Joomla\GetBible\Watcher; + + +use VDM\Joomla\GetBible\Database\Load; +use VDM\Joomla\GetBible\Database\Insert; +use VDM\Joomla\GetBible\Database\Update; +use VDM\Joomla\GetBible\Api\Translations; +use VDM\Joomla\GetBible\Abstraction\Watcher; + + +/** + * The GetBible Translation Watcher + * + * @since 2.0.1 + */ +final class Translation extends Watcher +{ + /** + * The Translations class + * + * @var Translations + * @since 2.0.1 + */ + protected Translations $translations; + + /** + * Constructor + * + * @param Load $load The load object. + * @param Insert $insert The insert object. + * @param Update $update The update object. + * @param Translations $translations The translations API object. + * + * @since 2.0.1 + */ + public function __construct( + Load $load, + Insert $insert, + Update $update, + Translations $translations) + { + // load the parent constructor + parent::__construct($load, $insert, $update); + + $this->translations = $translations; + + // set the table + $this->table = 'translation'; + } + + /** + * Sync the target being watched + * + * @param string $translation The translation. + * + * @return bool True on success + * @since 2.0.1 + */ + public function sync(string $translation): bool + { + // load the target if not found + if ($this->load($translation)) + { + if ($this->isNew() || $this->hold()) + { + return true; + } + + // get API hash value + $hash = $this->translations->sha($translation); + + // confirm hash has not changed + if (hash_equals($hash, $this->target->sha)) + { + return $this->bump(); + } + + if ($this->update()) + { + return true; + } + } + + return false; + } + + /** + * Load Translation + * + * @param string $translation The translation. + * + * @return bool True if translation found + * @since 2.0.1 + */ + private function load(string $translation): bool + { + // check local value + if (($this->target = $this->load->item(['abbreviation' => $translation], $this->table)) !== null) + { + return true; + } + + // get all the translations + $translations = $this->translations->list(); + + // check return data + if (!isset($translations->{$translation}) || !isset($translations->{$translation}->sha)) + { + return false; + } + + // add them to the database + $this->insert->items((array) $translations, 'translation'); + + if (($this->target = $this->load->item(['abbreviation' => $translation], $this->table)) !== null) + { + $this->fresh = true; + } + + return $this->fresh; + } + + /** + * Trigger the update of all translations + * + * @return bool True if update was a success + * @since 2.0.1 + */ + private function update(): bool + { + // get translations from the API + if (($translations = $this->translations->list()) === null) + { + return false; + } + + // get the local published translations + $local_translations = $this->load->items(['published' => 1], $this->table); + + $update = []; + $insert = []; + $match = ['key' => 'abbreviation', 'value' => '']; + + // dynamic update all translations + foreach ($translations as $translation) + { + // check if the verse exist + $match['value'] = $translation->abbreviation ?? null; + if (($object = $this->getTarget($match, $local_translations)) !== null) + { + $translation->id = $object->id; + $translation->created = $this->today; + $update[] = $translation; + } + else + { + $insert[] = $translation; + } + } + + // check if we have values to insert + if ($insert !== []) + { + $this->insert->items($insert, $this->table); + } + + // update the local values + if ($update !== [] && $this->update->items($update, 'id', $this->table)) + { + return true; + } + + return false; + } +} + diff --git a/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/index.html b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/index.html new file mode 100644 index 0000000..fa6d84e --- /dev/null +++ b/libraries/jcb_powers/VDM.Joomla.GetBible/src/Watcher/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/script.php b/script.php index 731e09f..657579f 100644 --- a/script.php +++ b/script.php @@ -1539,7 +1539,7 @@ class com_getbibleInstallerScript echo ' -

Upgrade to Version 2.0.5 Was Successful! Let us know if anything is not working as expected.

'; +

Upgrade to Version 2.0.6 Was Successful! Let us know if anything is not working as expected.

'; // Set db if not set already. if (!isset($db)) diff --git a/site/assets/js/app.js b/site/assets/js/app.js index f9ee252..bd905cf 100644 --- a/site/assets/js/app.js +++ b/site/assets/js/app.js @@ -29,7 +29,7 @@ const setLocalMemory = (key, values, merge = false) => { } else { memoryAppMemory[key] = values; } -} +}; const mergeLocalMemory = (key, values) => { const oldValues = getLocalMemory(key); @@ -38,7 +38,7 @@ const mergeLocalMemory = (key, values) => { } return JSON.stringify(values); -} +}; const getLocalMemory = (key, defaultValue = null, setDefault = false) => { let returnValue = null; @@ -64,14 +64,14 @@ const getLocalMemory = (key, defaultValue = null, setDefault = false) => { } return defaultValue; -} +}; const clearLocalMemory = (key) => { if (typeof Storage !== "undefined") { localStorage.removeItem(key); } else if (typeof memoryAppMemory[key] !== "undefined") { delete memoryAppMemory[key]; } -} +}; const isJsonString = (str) => { try { JSON.parse(str); @@ -79,7 +79,7 @@ const isJsonString = (str) => { return false; } return true; -} +}; class ScrollMemory { constructor(divId) { @@ -508,8 +508,7 @@ const setActiveLinkerOnPage = async (guid) => { for (let i = 0; i < inputs.length; i++) { inputs[i].value = guid; } -} - +}; /** * JS Function to set the search url */ @@ -568,7 +567,7 @@ const updateUrl = (id, url) => { if (button) { button.href = url; } -} +}; /** * JS Function to set a note */ @@ -619,46 +618,6 @@ const setNote = async (book, chapter, verse, note) => { console.error("Error occurred: ", error); } }; -/** - * JS Function to set a tag - */ -const setTag = async (name) => { - try { - // Make a request to your endpoint - const response = await fetch(getSetTagURL(name)); - // Wait for the server to return the response, then parse it as JSON. - const data = await response.json(); - // Call another function after the response has been received - if (data.success) { - // Show success message - UIkit.notification({ - message: data.success, - status: 'success', - timeout: 5000 - }); - } else if (data.access_required && data.error) { - setupGetBibleAccess( - 'getbible-app-tags', - data.error, - setTag, - [name] - ); - } else if (data.error) { - // Show danger message - UIkit.notification({ - message: data.error, - status: 'danger', - timeout: 3000 - }); - } else { - // Handle any errors - console.error("Error occurred: ", data); - } - } catch (error) { - // Handle any errors - console.error("Error occurred: ", error); - } -}; /** * JS Function to set a tag to a verse */ @@ -701,7 +660,134 @@ const tagVerse = async (translation, book, chapter, verse, tag) => { console.error("Error occurred: ", error); } }; - +/** + * JS Function to create a tag + */ +const createTag = async (name, description) => { + try { + // build form + const formData = new FormData(); + // add the form data + formData.set('name', name); + formData.set('description', description); + let options = { + method: 'POST', + body: formData + } + // Make a request to your endpoint + const response = await fetch(getCreateTagURL(), options); + // Wait for the server to return the response, then parse it as JSON. + const data = await response.json(); + // Call another function after the response has been received + if (data.success) { + // Show success message + UIkit.notification({ + message: data.success, + status: 'success', + timeout: 5000 + }); + } else if (data.access_required && data.error) { + setupGetBibleAccess( + 'getbible-app-tags', + data.error, + setTag, + [name] + ); + } else if (data.error) { + // Show danger message + UIkit.notification({ + message: data.error, + status: 'danger', + timeout: 3000 + }); + } else { + // Handle any errors + console.error("Error occurred: ", data); + } + } catch (error) { + // Handle any errors + console.error("Error occurred: ", error); + } +}; +/** + * JS Function to update a tag + */ +const updateTag = async (tag, name, description) => { + // build form + const formData = new FormData(); + // add the form data + formData.set('tag', tag); + formData.set('name', name); + formData.set('description', description); + let options = { + method: 'POST', + body: formData + } + // Make a request to your endpoint + const response = await fetch(getUpdateTagURL(), options); + // Wait for the server to return the response, then parse it as JSON. + const data = await response.json(); + if (data.access_required && data.error) { + setupGetBibleAccess( + 'getbible-tag-editor', + data.error, + updateTag, + [tag, name, description] + ); + } else if (data.success || data.error) { + return data; // return the data object on success + } else { + throw new Error(data); // throw an error if the request was not successful + } +}; +/** + * JS Function to delete a tag + */ +const deleteTag = async (tag, name, description) => { + try { + // build form + const formData = new FormData(); + // add the form data + formData.set('guid', tag); + let options = { + method: 'POST', + body: formData + } + // Make a request to your endpoint + const response = await fetch(getDeleteTagURL(), options); + // Wait for the server to return the response, then parse it as JSON. + const data = await response.json(); + // Call another function after the response has been received + if (data.success) { + // Show success message + UIkit.notification({ + message: data.success, + status: 'success', + timeout: 5000 + }); + } else if (data.access_required && data.error) { + setupGetBibleAccess( + 'getbible-app-tags', + data.error, + setTag, + [name] + ); + } else if (data.error) { + // Show danger message + UIkit.notification({ + message: data.error, + status: 'danger', + timeout: 3000 + }); + } else { + // Handle any errors + console.error("Error occurred: ", data); + } + } catch (error) { + // Handle any errors + console.error("Error occurred: ", error); + } +}; /** * JS Function to remove a tag from a verse */ @@ -801,7 +887,7 @@ const setupGetBibleAccess = async (active_modal, error_message, callback, args) /** * JS Function to create an tag div item */ -const createGetbileTagDivItem = (id, verse, name, url, tagged = null, ) => { +const createGetbileTagDivItem = (id, verse, name, url, canEdit = false, tagged = null) => { let itemElement = document.createElement('div'); itemElement.id = 'getbible-tag-' + id; itemElement.dataset.tag = id; @@ -830,6 +916,17 @@ const createGetbileTagDivItem = (id, verse, name, url, tagged = null, ) => { // Append view icon and name to cardDiv cardDiv.appendChild(handleSpan); cardDiv.appendChild(viewIcon); + // Create edit icon + if (canEdit) { + let editIcon = document.createElement('button'); + editIcon.className = 'uk-icon-button uk-margin-small-left'; + editIcon.setAttribute('uk-icon', 'pencil'); + editIcon.setAttribute('uk-tooltip', 'title: ' + Joomla.JText._('COM_GETBIBLE_EDIT_TAG')); + editIcon.onclick = (event) => { + editGetBibleTag(id, verse); + }; + cardDiv.appendChild(editIcon); + } marginDiv.appendChild(cardDiv); itemElement.appendChild(marginDiv); return itemElement; diff --git a/site/controllers/ajax.json.php b/site/controllers/ajax.json.php index de2c5f3..7aca6ad 100644 --- a/site/controllers/ajax.json.php +++ b/site/controllers/ajax.json.php @@ -45,12 +45,13 @@ class GetbibleControllerAjax extends BaseController $this->registerTask('revokeLinkerSession', 'ajax'); $this->registerTask('revokeLinkerAccess', 'ajax'); $this->registerTask('setLinkerName', 'ajax'); + $this->registerTask('getLinkersDisplay', 'ajax'); $this->registerTask('setNote', 'ajax'); $this->registerTask('tagVerse', 'ajax'); $this->registerTask('removeTagFromVerse', 'ajax'); - $this->registerTask('setTag', 'ajax'); - $this->registerTask('removeTag', 'ajax'); - $this->registerTask('getLinkersDisplay', 'ajax'); + $this->registerTask('createTag', 'ajax'); + $this->registerTask('updateTag', 'ajax'); + $this->registerTask('deleteTag', 'ajax'); $this->registerTask('getSearchUrl', 'ajax'); $this->registerTask('getOpenaiURL', 'ajax'); } @@ -77,10 +78,10 @@ class GetbibleControllerAjax extends BaseController case 'getShareHisWordUrl': try { - $linkerValue = $jinput->get('linker', NULL, 'STRING'); - $translationValue = $jinput->get('translation', NULL, 'ALNUM'); - $bookValue = $jinput->get('book', NULL, 'INT'); - $chapterValue = $jinput->get('chapter', NULL, 'INT'); + $linkerValue = $jinput->get('linker', null, 'STRING'); + $translationValue = $jinput->get('translation', null, 'ALNUM'); + $bookValue = $jinput->get('book', null, 'INT'); + $chapterValue = $jinput->get('chapter', null, 'INT'); if($linkerValue && $translationValue && $bookValue && $chapterValue) { $result = $this->getModel('ajax')->getShareHisWordUrl($linkerValue, $translationValue, $bookValue, $chapterValue); @@ -121,8 +122,8 @@ class GetbibleControllerAjax extends BaseController case 'checkValidLinker': try { - $linkerValue = $jinput->get('linker', NULL, 'STRING'); - $oldValue = $jinput->get('old', NULL, 'STRING'); + $linkerValue = $jinput->get('linker', null, 'STRING'); + $oldValue = $jinput->get('old', null, 'STRING'); if($linkerValue && $oldValue) { $result = $this->getModel('ajax')->checkValidLinker($linkerValue, $oldValue); @@ -163,9 +164,9 @@ class GetbibleControllerAjax extends BaseController case 'installBibleChapter': try { - $translationValue = $jinput->get('translation', NULL, 'ALNUM'); - $bookValue = $jinput->get('book', NULL, 'INT'); - $chapterValue = $jinput->get('chapter', NULL, 'INT'); + $translationValue = $jinput->get('translation', null, 'ALNUM'); + $bookValue = $jinput->get('book', null, 'INT'); + $chapterValue = $jinput->get('chapter', null, 'INT'); if($translationValue && $bookValue && $chapterValue) { $result = $this->getModel('ajax')->installBibleChapter($translationValue, $bookValue, $chapterValue); @@ -206,10 +207,10 @@ class GetbibleControllerAjax extends BaseController case 'getAppUrl': try { - $translationValue = $jinput->get('translation', NULL, 'ALNUM'); - $bookValue = $jinput->get('book', NULL, 'STRING'); + $translationValue = $jinput->get('translation', null, 'ALNUM'); + $bookValue = $jinput->get('book', null, 'STRING'); $chapterValue = $jinput->get('chapter', 1, 'INT'); - $verseValue = $jinput->get('verse', NULL, 'STRING'); + $verseValue = $jinput->get('verse', null, 'STRING'); if($translationValue && $bookValue) { $result = $this->getModel('ajax')->getAppUrl($translationValue, $bookValue, $chapterValue, $verseValue); @@ -250,7 +251,7 @@ class GetbibleControllerAjax extends BaseController case 'setLinker': try { - $linkerValue = $jinput->get('linker', NULL, 'STRING'); + $linkerValue = $jinput->get('linker', null, 'STRING'); if($linkerValue) { $result = $this->getModel('ajax')->setLinker($linkerValue); @@ -291,9 +292,9 @@ class GetbibleControllerAjax extends BaseController case 'setLinkerAccess': try { - $linkerValue = $jinput->get('linker', NULL, 'STRING'); - $passValue = $jinput->get('pass', NULL, 'STRING'); - $oldValue = $jinput->get('old', NULL, 'STRING'); + $linkerValue = $jinput->get('linker', null, 'STRING'); + $passValue = $jinput->get('pass', null, 'STRING'); + $oldValue = $jinput->get('old', null, 'STRING'); if($linkerValue && $passValue) { $result = $this->getModel('ajax')->setLinkerAccess($linkerValue, $passValue, $oldValue); @@ -334,7 +335,7 @@ class GetbibleControllerAjax extends BaseController case 'revokeLinkerSession': try { - $linkerValue = $jinput->get('linker', NULL, 'STRING'); + $linkerValue = $jinput->get('linker', null, 'STRING'); if($linkerValue) { $result = $this->getModel('ajax')->revokeLinkerSession($linkerValue); @@ -375,7 +376,7 @@ class GetbibleControllerAjax extends BaseController case 'revokeLinkerAccess': try { - $linkerValue = $jinput->get('linker', NULL, 'STRING'); + $linkerValue = $jinput->get('linker', null, 'STRING'); if($linkerValue) { $result = $this->getModel('ajax')->revokeLinkerAccess($linkerValue); @@ -416,7 +417,7 @@ class GetbibleControllerAjax extends BaseController case 'setLinkerName': try { - $nameValue = $jinput->get('name', NULL, 'STRING'); + $nameValue = $jinput->get('name', null, 'STRING'); if($nameValue) { $result = $this->getModel('ajax')->setLinkerName($nameValue); @@ -454,13 +455,54 @@ class GetbibleControllerAjax extends BaseController } } break; + case 'getLinkersDisplay': + try + { + $linkersValue = $jinput->get('linkers', null, 'STRING'); + if($linkersValue) + { + $result = $this->getModel('ajax')->getLinkersDisplay($linkersValue); + } + else + { + $result = false; + } + if($callback) + { + echo $callback . "(".json_encode($result).");"; + } + elseif($returnRaw) + { + echo json_encode($result); + } + else + { + echo "(".json_encode($result).");"; + } + } + catch(Exception $e) + { + if($callback) + { + echo $callback."(".json_encode($e).");"; + } + elseif($returnRaw) + { + echo json_encode($e); + } + else + { + echo "(".json_encode($e).");"; + } + } + break; case 'setNote': try { - $bookValue = $jinput->get('book', NULL, 'INT'); - $chapterValue = $jinput->get('chapter', NULL, 'INT'); - $verseValue = $jinput->get('verse', NULL, 'INT'); - $noteValue = $jinput->get('note', NULL, 'STRING'); + $bookValue = $jinput->get('book', null, 'INT'); + $chapterValue = $jinput->get('chapter', null, 'INT'); + $verseValue = $jinput->get('verse', null, 'INT'); + $noteValue = $jinput->get('note', null, 'STRING'); if($bookValue && $chapterValue && $verseValue) { $result = $this->getModel('ajax')->setNote($bookValue, $chapterValue, $verseValue, $noteValue); @@ -501,11 +543,11 @@ class GetbibleControllerAjax extends BaseController case 'tagVerse': try { - $translationValue = $jinput->get('translation', NULL, 'ALNUM'); - $bookValue = $jinput->get('book', NULL, 'INT'); - $chapterValue = $jinput->get('chapter', NULL, 'INT'); - $verseValue = $jinput->get('verse', NULL, 'INT'); - $tagValue = $jinput->get('tag', NULL, 'STRING'); + $translationValue = $jinput->get('translation', null, 'ALNUM'); + $bookValue = $jinput->get('book', null, 'INT'); + $chapterValue = $jinput->get('chapter', null, 'INT'); + $verseValue = $jinput->get('verse', null, 'INT'); + $tagValue = $jinput->get('tag', null, 'STRING'); if($translationValue && $bookValue && $chapterValue && $verseValue && $tagValue) { $result = $this->getModel('ajax')->tagVerse($translationValue, $bookValue, $chapterValue, $verseValue, $tagValue); @@ -546,7 +588,7 @@ class GetbibleControllerAjax extends BaseController case 'removeTagFromVerse': try { - $tagValue = $jinput->get('tag', NULL, 'STRING'); + $tagValue = $jinput->get('tag', null, 'STRING'); if($tagValue) { $result = $this->getModel('ajax')->removeTagFromVerse($tagValue); @@ -584,13 +626,14 @@ class GetbibleControllerAjax extends BaseController } } break; - case 'setTag': + case 'createTag': try { - $nameValue = $jinput->get('name', NULL, 'STRING'); + $nameValue = $jinput->get('name', null, 'STRING'); + $descriptionValue = $jinput->get('description', null, 'STRING'); if($nameValue) { - $result = $this->getModel('ajax')->setTag($nameValue); + $result = $this->getModel('ajax')->createTag($nameValue, $descriptionValue); } else { @@ -625,54 +668,56 @@ class GetbibleControllerAjax extends BaseController } } break; - case 'removeTag': + case 'updateTag': try { - $tagValue = $jinput->get('tag', NULL, 'STRING'); + $tagValue = $jinput->get('tag', null, 'STRING'); + $nameValue = $jinput->get('name', null, 'STRING'); + $descriptionValue = $jinput->get('description', null, 'STRING'); + if($tagValue && $nameValue) + { + $result = $this->getModel('ajax')->updateTag($tagValue, $nameValue, $descriptionValue); + } + else + { + $result = false; + } + if($callback) + { + echo $callback . "(".json_encode($result).");"; + } + elseif($returnRaw) + { + echo json_encode($result); + } + else + { + echo "(".json_encode($result).");"; + } + } + catch(Exception $e) + { + if($callback) + { + echo $callback."(".json_encode($e).");"; + } + elseif($returnRaw) + { + echo json_encode($e); + } + else + { + echo "(".json_encode($e).");"; + } + } + break; + case 'deleteTag': + try + { + $tagValue = $jinput->get('tag', null, 'STRING'); if($tagValue) { - $result = $this->getModel('ajax')->removeTag($tagValue); - } - else - { - $result = false; - } - if($callback) - { - echo $callback . "(".json_encode($result).");"; - } - elseif($returnRaw) - { - echo json_encode($result); - } - else - { - echo "(".json_encode($result).");"; - } - } - catch(Exception $e) - { - if($callback) - { - echo $callback."(".json_encode($e).");"; - } - elseif($returnRaw) - { - echo json_encode($e); - } - else - { - echo "(".json_encode($e).");"; - } - } - break; - case 'getLinkersDisplay': - try - { - $linkersValue = $jinput->get('linkers', NULL, 'STRING'); - if($linkersValue) - { - $result = $this->getModel('ajax')->getLinkersDisplay($linkersValue); + $result = $this->getModel('ajax')->deleteTag($tagValue); } else { diff --git a/site/language/en-GB/en-GB.com_getbible.ini b/site/language/en-GB/en-GB.com_getbible.ini index a073257..3557fdc 100644 --- a/site/language/en-GB/en-GB.com_getbible.ini +++ b/site/language/en-GB/en-GB.com_getbible.ini @@ -42,12 +42,14 @@ COM_GETBIBLE_CREATE_NEW_S="Create New %s" COM_GETBIBLE_DAILY_VERSE="Daily Verse" COM_GETBIBLE_DEACTIVATE_THIS_INSTALLATION_OPTION="Deactivate this Installation Option" COM_GETBIBLE_DEBUG="Debug" +COM_GETBIBLE_DESCRIPTION="Description" COM_GETBIBLE_DETAILS="Details" COM_GETBIBLE_DIRECTION="Direction" COM_GETBIBLE_DISTRIBUTION_ABBREVIATION="Distribution Abbreviation" COM_GETBIBLE_DRAG_AND_DROP_THE_DESIRED_TAG_FROM_THE_AVAILABLE_ONES_TO_THE_ACTIVE_AREA="Drag and drop the desired tag from the available ones to the active area." COM_GETBIBLE_EDIT_NOTE="Edit note" COM_GETBIBLE_EDIT_S="Edit %s" +COM_GETBIBLE_EDIT_TAG="Edit Tag" COM_GETBIBLE_EMPTY="Empty" COM_GETBIBLE_ENABLE_EXCLUSIVE_ACCESS_TO_EDIT_YOUR_NOTES_AND_TAGS="Enable exclusive access to edit your notes and tags." COM_GETBIBLE_ENCODING="Encoding" @@ -169,12 +171,15 @@ COM_GETBIBLE_TAGGING_THIS_VERSE="Tagging this verse." COM_GETBIBLE_TAGS="Tags" COM_GETBIBLE_TAG_ALREADY_EXIST_BUT_COULD_NOT_BE_REACTIVATED="Tag already exist, but could not be reactivated." COM_GETBIBLE_TAG_DESC="getBible Tag" +COM_GETBIBLE_TAG_FOUND_BUT_COULD_NOT_BE_REACTIVATED="Tag found, but could not be reactivated." +COM_GETBIBLE_TAG_SUCCESSFULLY_DELETED="Tag successfully deleted." COM_GETBIBLE_TARGETED_BOOKS="Targeted Books" COM_GETBIBLE_TEMPERATURE="Temperature" COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR="There has been an error" COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR_PLEASE_TRY_AGAIN="There has been an error please try again." COM_GETBIBLE_THERE_IS_NOT_ENOUGH_VERSES_BEEN_INDEXED_FOR_BSB_TRANSLATION_OF_THE_BIBLE_THIS_MEANS_YOUR_SEARCH_RESULTS_WILL_NOT_BE_ACCURATE_PLEASE_CONTACT_THE_SYSTEM_ADMINISTRATOR_OF_THIS_WEBSITE_TO_RESOLVE_THIS="There is not enough verses been indexed for %s translation of the Bible. This means your search results will not be accurate. Please contact the system administrator of this website to resolve this." COM_GETBIBLE_THERE_WAS_AN_ERROR_PLEASE_RELOAD_YOUR_PAGE_AND_TRY_AGAIN="There was an error, please reload your page and try again." +COM_GETBIBLE_THERE_WAS_AN_ERROR_TAG_NOT_FOUND_ON_PAGE="There was an error, tag not found on page!" COM_GETBIBLE_THE_ACTIVE_VERSE_SELECTED_TEXT_SHOULD_LOAD_HERE="The active verse selected text should load here." COM_GETBIBLE_THE_CHAPTERS_OF_BOOKS_WAS_SUCCESSFULLY_INSTALLED_FOR_S_TRANSLATION="The chapter:%s of book:%s was successfully installed for %s translation." COM_GETBIBLE_THE_LINK_WAS_COPIED_TO_YOUR_CLIPBOARD="The link was copied to your clipboard!" @@ -187,9 +192,10 @@ COM_GETBIBLE_THE_SCRIPTURE_WAS_COPIED_TO_YOUR_CLIPBOARD="The scripture was copie COM_GETBIBLE_THE_SEARCH_FEATURE_HAS_NOT_BEEN_ACTIVATED_PLEASE_CONTACT_THE_SYSTEM_ADMINISTRATOR_OF_THIS_WEBSITE_TO_RESOLVE_THIS="The search feature has not been activated. Please contact the system administrator of this website to resolve this." COM_GETBIBLE_THE_SESSION_IS_SET="The session is set." COM_GETBIBLE_THE_TAG_SELECTED_IS_NOT_ACTIVE_PLEASE_SELECT_AN_ACTIVE_TAG="The tag selected is not active, please select an active tag." -COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_REMOVED="The tag was successfully removed." +COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_CREATED="The tag was successfully created." +COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_REACTIVATED="The tag was successfully reactivated." COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_REMOVED_FROM_THE_VERSE="The tag was successfully removed from the verse." -COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_SET="The tag was successfully set." +COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_UPDATED="The tag was successfully updated." COM_GETBIBLE_THE_VERSE_WAS_SUCCESSFULLY_TAGGED="The verse was successfully tagged." COM_GETBIBLE_THE_WORDS_OF_ETERNAL_LIFE="The words of eternal life!" COM_GETBIBLE_THIS_AREA_DISPLAYS_YOUR_RECENTLY_ACCESSED_SESSIONS="This area displays your recently accessed sessions." @@ -201,6 +207,8 @@ COM_GETBIBLE_THIS_PERSISTENT_SESSION_IS_ALREADY_ACTIVE="This persistent session COM_GETBIBLE_THIS_SESSION_KEY_IS_NOT_YET_ELIGIBLE_FOR_SHARING_AS_NO_ACTIONS_HAVE_BEEN_PERFORMED_WITHIN_IT="This session key is not yet eligible for sharing, as no actions have been performed within it." COM_GETBIBLE_THIS_TAG_COULD_NOT_BE_REMOVED="This tag could not be removed." COM_GETBIBLE_THIS_TAG_CURRENTLY_DOESNT_HAVE_ANY_VERSES_LINKED_TO_IT_PLEASE_SELECT_ANOTHER_TAG_OR_ATTACH_SOME_VERSES_TO_THIS_ONE="This tag currently doesn't have any verses linked to it. Please select another tag, or attach some verses to this one." +COM_GETBIBLE_THIS_TAG_DOESNT_BELONG_TO_YOU_THUS_YOU_CANNOT_DELETE_IT="This tag doesn't belong to you, thus you cannot delete it." +COM_GETBIBLE_THIS_TAG_DOESNT_BELONG_TO_YOU_THUS_YOU_CANNOT_EDIT_IT="This tag doesn't belong to you, thus you cannot edit it." COM_GETBIBLE_THIS_VERSE_IN_COMBINATION_WITH_YOUR_ISESSION_KEYI_WILL_BE_USED_TO_AUTHENTICATE_YOU_IN_THE_FUTURE="This verse in combination with your session key will be used to authenticate you in the future." COM_GETBIBLE_TOP="Top" COM_GETBIBLE_TOP_P="Top P" diff --git a/site/layouts/textarea.php b/site/layouts/textarea.php new file mode 100644 index 0000000..2d56afe --- /dev/null +++ b/site/layouts/textarea.php @@ -0,0 +1,42 @@ + + @git Get Bible + @github Get Bible + @support Get Bible + @copyright Copyright (C) 2015. All Rights Reserved + @license GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + +/------------------------------------------------------------------------------------------------------*/ + +// No direct access to this file +defined('JPATH_BASE') or die('Restricted access'); + +$id = (isset($displayData['id'])) ? $displayData['id'] : ''; +$name = (isset($displayData['name'])) ? $displayData['name'] : $id; +$name = str_replace('-', '_', $name); +$class = (isset($displayData['class'])) ? $displayData['class'] : 'uk-textarea'; +$class_other = (isset($displayData['class_other'])) ? ' ' . $displayData['class_other'] : ''; +$rows = (isset($displayData['rows'])) ? $displayData['rows'] : 5; +$columns = (isset($displayData['columns'])) ? $displayData['columns'] : ''; +$placeholder = (isset($displayData['placeholder'])) ? $displayData['placeholder'] : ''; +$readonly = (isset($displayData['readonly']) && $displayData['readonly']) ? ' readonly' : ''; +$onchange = (isset($displayData['onchange'])) ? ' onchange="' . $displayData['onchange'] . '"' : ''; +$onkeydown = (isset($displayData['onkeydown'])) ? ' onkeydown="' . $displayData['onkeydown'] . '"' : ''; + +?> + diff --git a/site/layouts/textareabox.php b/site/layouts/textareabox.php new file mode 100644 index 0000000..2f653ea --- /dev/null +++ b/site/layouts/textareabox.php @@ -0,0 +1,33 @@ + + @git Get Bible + @github Get Bible + @support Get Bible + @copyright Copyright (C) 2015. All Rights Reserved + @license GNU/GPL Version 2 or later - http://www.gnu.org/licenses/gpl-2.0.html + +/------------------------------------------------------------------------------------------------------*/ + +// No direct access to this file +defined('JPATH_BASE') or die('Restricted access'); + +$id = (isset($displayData['id'])) ? $displayData['id'] : ''; +$name = (isset($displayData['name'])) ? $displayData['name'] : $id; +$name = str_replace('-', '_', $name); +$label = (isset($displayData['label'])) ? $displayData['label'] : JText::_('COM_GETBIBLE_LABEL'); +$margin = (isset($displayData['margin'])) ? $displayData['margin'] : 'uk-margin-small'; + +?> +
+ +
+ +
+
diff --git a/site/models/ajax.php b/site/models/ajax.php index cb5fb8f..ab6bf59 100644 --- a/site/models/ajax.php +++ b/site/models/ajax.php @@ -108,7 +108,7 @@ class GetbibleModelAjax extends ListModel { try { - Factory::_('GetBible.Watcher')->api($translation, $book, $chapter); + Factory::_('GetBible.Watcher')->sync($translation, $book, $chapter); } catch(Exception $error) { @@ -234,6 +234,63 @@ class GetbibleModelAjax extends ListModel return ['error' => JText::_('COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR_PLEASE_TRY_AGAIN')]; } + /** + * Create a Tag + * + * @param string $name The tag name being created + * @param string|null $description The tag description being created + * + * @return array + * @since 3.2.0 + **/ + public function createTag(string $name, ?string $description): array + { + if (($tag = Factory::_('GetBible.Tag')->create($name, $description)) !== null) + { + return $tag; + } + + return ['error' => JText::_('COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR')]; + } + + /** + * Update a Tag + * + * @param string $tag The tag GUID value + * @param string $name The tag name being created + * @param string|null $description The tag description being created + * + * @return array + * @since 3.2.0 + **/ + public function updateTag(string $tag, string $name, ?string $description): array + { + if (($tag = Factory::_('GetBible.Tag')->update($tag, $name, $description)) !== null) + { + return $tag; + } + + return ['error' => JText::_('COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR')]; + } + + /** + * Delete a Tag + * + * @param string $tag The tag GUID value + * + * @return array + * @since 3.2.0 + **/ + public function deleteTag(string $tag): array + { + if (($result = Factory::_('GetBible.Tag')->delete($tag)) !== null) + { + return $result; + } + + return ['error' => JText::_('COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR')]; + } + /** * Set a Note * @@ -317,42 +374,6 @@ class GetbibleModelAjax extends ListModel return ['error' => JText::_('COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR')]; } - /** - * Set a Tag - * - * @param string $name The tag name being created - * - * @return array - * @since 3.2.0 - **/ - public function setTag(string $name): array - { - if (($tag = Factory::_('GetBible.Tag')->set($name)) !== null) - { - return $tag; - } - - return ['error' => JText::_('COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR')]; - } - - /** - * Remove a Tag - * - * @param string $tag The tag GUID value - * - * @return array - * @since 3.2.0 - **/ - public function removeTag(string $tag): array - { - if (Factory::_('GetBible.Tag')->delete($tag)) - { - return ['success' => JText::_('COM_GETBIBLE_THE_TAG_WAS_SUCCESSFULLY_REMOVED')]; - } - - return ['error' => JText::_('COM_GETBIBLE_THERE_HAS_BEEN_AN_ERROR')]; - } - /** * Return the build list of linkers * diff --git a/site/models/app.php b/site/models/app.php index 79ec1bc..c7d2418 100644 --- a/site/models/app.php +++ b/site/models/app.php @@ -157,14 +157,14 @@ class GetbibleModelApp extends ItemModel // Get data // we load the queried chapter - if (!Factory::_('GetBible.Watcher')->api($this->translation, $this->book, $this->chapter)) + if (!Factory::_('GetBible.Watcher')->sync($this->translation, $this->book, $this->chapter)) { $book = Factory::_('GetBible.Watcher')->getNextBook($this->translation, $this->book); $this->chapter = 1; $this->verses = null; // so we try to load this one last time - if (empty($book) || !Factory::_('GetBible.Watcher')->api($this->translation, $book, $this->chapter)) + if (empty($book) || !Factory::_('GetBible.Watcher')->sync($this->translation, $book, $this->chapter)) { return false; } @@ -189,13 +189,13 @@ class GetbibleModelApp extends ItemModel // [or] we load the next chapter if (($chapter_next = Factory::_('GetBible.Watcher')->getNextChapter($this->translation, $this->book, $this->chapter)) !== null) { - Factory::_('GetBible.Watcher')->api($this->translation, $this->book, $chapter_next); + Factory::_('GetBible.Watcher')->sync($this->translation, $this->book, $chapter_next); } // [or] we load the previous chapter if (($chapter_previous = Factory::_('GetBible.Watcher')->getPreviousChapter($this->chapter)) !== null) { - Factory::_('GetBible.Watcher')->api($this->translation, $this->book, $chapter_previous); + Factory::_('GetBible.Watcher')->sync($this->translation, $this->book, $chapter_previous); } $data = [ @@ -701,7 +701,7 @@ class GetbibleModelApp extends ItemModel $chapter = 1; // make sure its loaded - if (empty($book) || !Factory::_('GetBible.Watcher')->api($this->translation, $book, $chapter)) + if (empty($book) || !Factory::_('GetBible.Watcher')->sync($this->translation, $book, $chapter)) { return false; } @@ -822,7 +822,7 @@ class GetbibleModelApp extends ItemModel $book = Factory::_('GetBible.Watcher')->getPreviousBook($this->translation, $this->book); // make sure its loaded - if (empty($book) || !Factory::_('GetBible.Watcher')->api($this->translation, $book, 1)) + if (empty($book) || !Factory::_('GetBible.Watcher')->sync($this->translation, $book, 1)) { return false; } diff --git a/site/views/app/tmpl/default_getbibleapp.php b/site/views/app/tmpl/default_getbibleapp.php index 63d1df0..57b3632 100644 --- a/site/views/app/tmpl/default_getbibleapp.php +++ b/site/views/app/tmpl/default_getbibleapp.php @@ -140,13 +140,18 @@ const setActiveTags = async (verse) => { updateActiveGetBibleTaggedItems(verse); updateAllGetBibleTaggedItems(verse); } +const canEditTag = (item) => { + return item.linker && getbible_linker_guid === item.linker; +} const updateActiveGetBibleTaggedItems = async (verse) => { removeChildrenElements('getbible-active-tags'); - getbible_tagged.forEach((itemData) => { - if(itemData.verse == verse) { - let itemElement = createGetbileTagDivItem(itemData.tag, verse, itemData.name, itemData.url, itemData.guid); - let activeList = document.querySelector('#getbible-active-tags'); - activeList.appendChild(itemElement); + getbible_tags.forEach((itemData) => { + // if item is not in getbible_tagged array, move it back to all items list + let foundItem = getbible_tagged.find(item => item.tag == itemData.guid && item.verse == verse); + if (foundItem) { + let itemElement = createGetbileTagDivItem(itemData.guid, verse, itemData.name, itemData.url, canEditTag(itemData), foundItem.guid); + let allList = document.querySelector('#getbible-active-tags'); + allList.appendChild(itemElement); } }); }; @@ -155,12 +160,30 @@ const updateAllGetBibleTaggedItems = async (verse) => { getbible_tags.forEach((itemData) => { // if item is not in getbible_tagged array, move it back to all items list if (!getbible_tagged.find(item => item.tag == itemData.guid && item.verse == verse)) { - let itemElement = createGetbileTagDivItem(itemData.guid, verse, itemData.name, itemData.url); + let itemElement = createGetbileTagDivItem(itemData.guid, verse, itemData.name, itemData.url, canEditTag(itemData)); let allList = document.querySelector('#getbible-tags'); allList.appendChild(itemElement); } }); }; +const getBibleTagItem = (guid) => { + let item = getbible_tags.find(item => item.guid == guid); + if (item) { + return item; + } else { + return null; // or whatever default value you want + } +}; +const setBibleTagItem = (guid, tagItem) => { + let index = getbible_tags.findIndex(item => item.guid == guid); + if (index !== -1) { + // If the item exists, replace it + getbible_tags[index] = tagItem; + } else { + // If the item doesn't exist, add it + getbible_tags.push(tagItem); + } +}; const setActiveTaggedVerse = async (data) => { let found = false; getbible_tagged.forEach((itemData) => { @@ -212,27 +235,22 @@ const setInactiveTaggedVerse = async (tag, verse) => { // Define an object with getter and setter properties const getbibleActiveVerse = { _value: 1, // the actual variable - get value() { return this._value; }, - set value(val) { this._value = val; - // Update all elements with the class name `active-getbible-verse` let activeGetbibleVerse = document.getElementsByClassName('active-getbible-verse'); for (let i = 0; i < activeGetbibleVerse.length; i++) { activeGetbibleVerse[i].textContent = this._value; } - // Update all elements with the class name `getbible-verse-selected-text` let getbibleVerseSelectedText = document.getElementsByClassName('getbible-verse-selected-text'); let verseText = getActiveVerseText(this._value); for (let i = 0; i < getbibleVerseSelectedText.length; i++) { getbibleVerseSelectedText[i].textContent = verseText; } - params->get('activate_notes') == 1): ?> // update the note setActiveNoteTextarea(this._value); params->get('activate_tags') == 1): ?> // update the tags @@ -268,15 +286,12 @@ const setActiveVerse = async (number, update = true) => { const setActiveOpenModel = async (model, update = true) => { // Your new value let newValue = 'target: #getbible-app-' + model; - // Get all elements with the class name 'getbible-verse-link' let elements = document.getElementsByClassName('getbible-verse-link'); - // Update the 'uk-toggle' attribute of each element for (let i = 0; i < elements.length; i++) { elements[i].setAttribute('uk-toggle', newValue); } - // add this to memory if (update) { setLocalMemory('getbible_active_open_model', {target: model}); diff --git a/site/views/app/tmpl/default_getbibleapptags.php b/site/views/app/tmpl/default_getbibleapptags.php index 6ae5879..369e54c 100644 --- a/site/views/app/tmpl/default_getbibleapptags.php +++ b/site/views/app/tmpl/default_getbibleapptags.php @@ -18,6 +18,17 @@ // No direct access to this file defined('_JEXEC') or die('Restricted access'); +$content = ''; +$content .= JLayoutHelper::render('inputbox', ['id' => 'getbible-edit-tag-name', 'label' => JText::_('COM_GETBIBLE_NAME')]); +$content .= JLayoutHelper::render('textareabox', ['id' => 'getbible-edit-tag-description', 'label' => JText::_('COM_GETBIBLE_DESCRIPTION')]); +$content .= ''; +$content .= ''; +// set buttons +$buttons = [ + ['id' => 'getbible-save-edit-tag', 'name' => JText::_('COM_GETBIBLE_SAVE'), 'class' => 'uk-button uk-button-default uk-width-2-3'], + ['id' => 'getbible-cancel-edit-tag', 'name' => JText::_('COM_GETBIBLE_CANCEL'), 'class' => 'uk-button uk-button-danger uk-width-1-3'] +]; + ?>
@@ -65,9 +76,89 @@ defined('_JEXEC') or die('Restricted access'); loadTemplate('getbibleappmodalbottom'); ?>
+ 'getbible-tag-editor', + 'header' => JText::_('COM_GETBIBLE_EDIT_TAG'), + 'header_class_other' => 'uk-text-center', + 'close' => true, + 'content' => $content, + 'buttons_class' => 'uk-button-group uk-width-1-1', + 'buttons_id' => 'getbible-tag-edit-buttons', + 'buttons' => $buttons +]); ?>