diff --git a/database/migrations/structure/20230421_2234_currencies.sql b/database/migrations/structure/20230421_2234_currencies.sql new file mode 100644 index 0000000..70a0bb4 --- /dev/null +++ b/database/migrations/structure/20230421_2234_currencies.sql @@ -0,0 +1,10 @@ +CREATE TABLE `currencies` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `community_id` int(10) unsigned NOT NULL, + `code` varchar(3) NOT NULL, + `round_digits` tinyint(1) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `unique_currency_for_community` (`community_id`, `code`), + KEY `community_id` (`community_id`), + CONSTRAINT `currencies_community_id` FOREIGN KEY (`community_id`) REFERENCES `communities` (`id`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; diff --git a/public/static/css/rvr.css b/public/static/css/rvr.css index 9ea08df..bef5c87 100644 --- a/public/static/css/rvr.css +++ b/public/static/css/rvr.css @@ -459,6 +459,14 @@ table th, table td { vertical-align: middle; } +table th:not(:first-child), table td:not(:first-child) { + padding-left: 3px; +} + +table th:not(:last-child), table td:not(:last-child) { + padding-right: 3px; +} + .choices__inner { box-sizing: border-box; } diff --git a/public/static/js/rvr.js b/public/static/js/rvr.js index 45096bb..ccf30b6 100644 --- a/public/static/js/rvr.js +++ b/public/static/js/rvr.js @@ -49,7 +49,7 @@ var RVR = { document.getElementById('loading').style.visibility = 'visible'; var formData = new FormData(form); - var formError = form.getElementsByClassName('formError')[0]; + var formError = document.getElementsByClassName('formError')[0]; var pageLeaveOnSuccess = form.dataset.redirectOnSuccess || form.dataset.reloadOnSuccess; RVR.httpRequest('POST', form.action, function () { diff --git a/scripts/gitHooks/prepare-commit-msg b/scripts/gitHooks/prepare-commit-msg index 6d109a7..716f326 100755 --- a/scripts/gitHooks/prepare-commit-msg +++ b/scripts/gitHooks/prepare-commit-msg @@ -7,7 +7,7 @@ if [[ "${BRANCH_NAME}" =~ $BRANCH_PATTERN ]]; then TICKET_ID=$(echo $BRANCH_NAME | sed -E "s@$BRANCH_PATTERN@\\2@") COMMIT_MESSAGE=$(head -n 1 $1) - COMMIT_MESSAGE_REGEX="^$TICKET_ID .*" + COMMIT_MESSAGE_REGEX="^(fixup! )?$TICKET_ID .*" if [[ ! "${COMMIT_MESSAGE}" =~ $COMMIT_MESSAGE_REGEX ]]; then sed -i.bak -e "1s/^/$TICKET_ID /" $1 diff --git a/src/Controller/CommunityController.php b/src/Controller/CommunityController.php index 101b5c0..fb5eeca 100644 --- a/src/Controller/CommunityController.php +++ b/src/Controller/CommunityController.php @@ -3,9 +3,11 @@ use DateTime; use RVR\PersistentData\Model\Community; use RVR\PersistentData\Model\CommunityMember; +use RVR\PersistentData\Model\Currency; use RVR\PersistentData\Model\User; use RVR\Repository\CommunityRepository; use RVR\Repository\CommunityMemberRepository; +use RVR\Repository\CurrencyRepository; use RVR\Repository\UserRepository; use SokoWeb\Interfaces\Authentication\IAuthenticationRequired; use SokoWeb\Interfaces\Response\IContent; @@ -20,11 +22,14 @@ class CommunityController implements IAuthenticationRequired private CommunityMemberRepository $communityMemberRepository; + private CurrencyRepository $currencyRepository; + public function __construct() { $this->userRepository = new UserRepository(); $this->communityRepository = new CommunityRepository(); $this->communityMemberRepository = new CommunityMemberRepository(); + $this->currencyRepository = new CurrencyRepository(); } public function isAuthenticationRequired(): bool @@ -38,10 +43,15 @@ class CommunityController implements IAuthenticationRequired return null; } + $currencyCodes = []; + foreach ($this->getCurrencies($community) as $currency) { + $currencyCodes[] = $currency->getCode(); + } + return new HtmlContent('communities/community', [ 'community' => $community, 'members' => $this->getMembers($community), - 'currencyNames' => [], + 'currencyCodes' => $currencyCodes, 'upcomingEvents' => [], 'editPermission' => $ownCommunityMember->getOwner() ]); @@ -75,16 +85,6 @@ class CommunityController implements IAuthenticationRequired ]); } - private function getMembers(Community $community): array - { - $members = iterator_to_array($this->communityMemberRepository->getAllByCommunity($community, true)); - usort($members, function($a, $b) { - return strnatcmp($a->getUser()->getDisplayName(), $b->getUser()->getDisplayName()); - }); - return $members; - } - - public function newMember(): ?IContent { if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { @@ -139,6 +139,74 @@ class CommunityController implements IAuthenticationRequired return new JsonContent(['success' => true]); } + public function getCurrenciesEdit(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + return new HtmlContent('communities/community_currencies', [ + 'community' => $community, + 'currencies' => $this->getCurrencies($community) + ]); + } + + public function newCurrency(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + $code = \Container::$request->post('code'); + $roundDigits = (int)\Container::$request->post('round_digits'); + if (strlen($code) === 0 || strlen($code) > 3 || $roundDigits < 0 || $roundDigits > 9) { + return new JsonContent([ + 'error' => ['errorText' => 'Please fill all required fields!'] + ]); + } + + $existingCurrency = $this->currencyRepository->getByCommunityAndCurrencyCode($community, $code); + if ($existingCurrency !== null) { + return new JsonContent([ + 'error' => ['errorText' => 'A currency with the same code exists for this community.'] + ]); + } + + $currency = new Currency(); + $currency->setCommunity($community); + $currency->setCode($code); + $currency->setRoundDigits($roundDigits); + \Container::$persistentDataManager->saveToDb($currency); + + return new JsonContent(['success' => true]); + } + + public function editCurrency(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + $currency = $this->currencyRepository->getById(\Container::$request->query('currency_id')); + $currency->setCode(\Container::$request->post('code')); + $currency->setRoundDigits((int)\Container::$request->post('round_digits')); + \Container::$persistentDataManager->saveToDb($currency); + + return new JsonContent(['success' => true]); + } + + public function deleteCurrency(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + $currency = $this->currencyRepository->getById(\Container::$request->query('currency_id')); + \Container::$persistentDataManager->deleteFromDb($currency); + + return new JsonContent(['success' => true]); + } + public function saveCommunity(): ?IContent { $communityId = \Container::$request->query('communityId'); @@ -183,6 +251,24 @@ class CommunityController implements IAuthenticationRequired ]); } + private function getMembers(Community $community): array + { + $members = iterator_to_array($this->communityMemberRepository->getAllByCommunity($community, true)); + usort($members, function($a, $b) { + return strnatcmp($a->getUser()->getDisplayName(), $b->getUser()->getDisplayName()); + }); + return $members; + } + + private function getCurrencies(Community $community): array + { + $currencies = iterator_to_array($this->currencyRepository->getAllByCommunity($community)); + usort($currencies, function($a, $b) { + return strnatcmp($a->getCode(), $b->getCode()); + }); + return $currencies; + } + private function checkPermission( int $communityId, bool $needToBeOwner, diff --git a/src/PersistentData/Model/Currency.php b/src/PersistentData/Model/Currency.php new file mode 100644 index 0000000..06cbbfd --- /dev/null +++ b/src/PersistentData/Model/Currency.php @@ -0,0 +1,60 @@ + Community::class]; + + private ?Community $community = null; + + private ?int $communityId = null; + + private string $code = ''; + + private int $roundDigits = 0; + + public function setCommunity(Community $community): void + { + $this->community = $community; + } + + public function setCommunityId(int $communityId): void + { + $this->communityId = $communityId; + } + + public function setCode(string $code): void + { + $this->code = $code; + } + + public function setRoundDigits(int $roundDigits): void + { + $this->roundDigits = $roundDigits; + } + + public function getCommunity(): ?Community + { + return $this->community; + } + + public function getCommunityId(): ?int + { + return $this->communityId; + } + + public function getCode(): string + { + return $this->code; + } + + public function getRoundDigits(): int + { + return $this->roundDigits; + } +} diff --git a/src/Repository/CurrencyRepository.php b/src/Repository/CurrencyRepository.php new file mode 100644 index 0000000..b34b089 --- /dev/null +++ b/src/Repository/CurrencyRepository.php @@ -0,0 +1,32 @@ +selectFromDbById($id, Currency::class); + } + + public function getAllByCommunity(Community $community, bool $useRelations = false): Generator + { + $select = new Select(Container::$dbConnection); + $select->where('community_id', '=', $community->getId()); + + yield from Container::$persistentDataManager->selectMultipleFromDb($select, Currency::class, $useRelations); + } + + public function getByCommunityAndCurrencyCode(Community $community, string $code): ?Currency + { + $select = new Select(Container::$dbConnection); + $select->where('community_id', '=', $community->getId()); + $select->where('code', '=', $code); + + return Container::$persistentDataManager->selectFromDb($select, Currency::class); + } +} diff --git a/views/communities/community.php b/views/communities/community.php index 6ce29dc..4630656 100644 --- a/views/communities/community.php +++ b/views/communities/community.php @@ -17,7 +17,13 @@
Main currency: = $community->getCurrency() ?>
-Further currencies: = implode(', ', $currencyNames) ?>
+ 0): ?> +Further currencies: = implode(', ', $currencyCodes) ?>
+ + +Currency | +Round digits | ++ |
---|---|---|
+ + + + | ++ + | ++ + | +
+ + + | ++ + | ++ + | +