From 991d0233499bf539b8ea4a6a28ce67db9c4c2ebc Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Sat, 13 Jan 2024 18:42:50 +0100 Subject: [PATCH] start improving db member management Signed-off-by: Julien Veyssier --- lib/Db/Bill.php | 2 +- lib/Db/Member.php | 86 ++++++++ lib/Db/MemberMapper.php | 139 ++++++++++++ lib/Db/Project.php | 2 +- lib/Service/ProjectService.php | 233 +++------------------ tests/php/controller/ApiControllerTest.php | 4 + 6 files changed, 257 insertions(+), 209 deletions(-) create mode 100644 lib/Db/Member.php create mode 100644 lib/Db/MemberMapper.php diff --git a/lib/Db/Bill.php b/lib/Db/Bill.php index 5f376c9a..474b7abb 100644 --- a/lib/Db/Bill.php +++ b/lib/Db/Bill.php @@ -6,7 +6,7 @@ * This file is licensed under the Affero General Public License version 3 or * later. See the COPYING file. * - * @author Julien Veyssier * @copyright Julien Veyssier 2019 */ diff --git a/lib/Db/Member.php b/lib/Db/Member.php new file mode 100644 index 00000000..f9c5bbc8 --- /dev/null +++ b/lib/Db/Member.php @@ -0,0 +1,86 @@ + + * @copyright Julien Veyssier 2024 + */ + +namespace OCA\Cospend\Db; + +use OCA\Cospend\Utils; +use OCP\AppFramework\Db\Entity; +use OCP\IAvatarManager; + +/** + * @method int getId() + * @method void setId(int $id) + * @method string getProjectid() + * @method void setProjectid(string $projectid) + * @method string getName() + * @method void setName(string $name) + * @method float getWeight() + * @method void setWeight(float $weight) + * @method int getActivated() + * @method void setActivated(int $activated) + * @method int getLastchanged() + * @method void setLastchanged(int $lastchanged) + * @method string getColor() + * @method void setColor(string $color) + * @method string|null getUserid() + * @method void setUserid(string|null $userid) + */ +class Member extends Entity implements \JsonSerializable { + + protected $projectid; + protected $name; + protected $weight; + protected $activated; + protected $lastchanged; + protected $color; + protected $userid; + + private $avatarManager; + + public function __construct() { + $this->addType('id', 'integer'); + $this->addType('projectid', 'string'); + $this->addType('name', 'string'); + $this->addType('weight', 'float'); + $this->addType('activated', 'integer'); + $this->addType('lastchanged', 'integer'); + $this->addType('color', 'string'); + $this->addType('userid', 'string'); + $this->avatarManager = \OC::$server->get(IAvatarManager::class); + } + + #[\ReturnTypeWillChange] + public function jsonSerialize() { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'weight' => $this->weight, + 'activated' => $this->activated === 1, + 'lastchanged' => $this->lastchanged, + 'userid' => $this->userid, + 'color' => $this->getColorArray(), + ]; + } + + private function getColorArray(): array { + if ($this->color === null) { + $av = $this->avatarManager->getGuestAvatar($this->name); + $avBgColor = $av->avatarBackgroundColor($this->name); + return [ + 'r' => $avBgColor->red(), + 'g' => $avBgColor->green(), + 'b' => $avBgColor->blue(), + ]; + } + return Utils::hexToRgb($this->color); + } +} diff --git a/lib/Db/MemberMapper.php b/lib/Db/MemberMapper.php new file mode 100644 index 00000000..b209b6ad --- /dev/null +++ b/lib/Db/MemberMapper.php @@ -0,0 +1,139 @@ + + * @copyright Julien Veyssier 2024 + */ + +namespace OCA\Cospend\Db; + +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\Exception; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +/** + * @extends QBMapper + */ +class MemberMapper extends QBMapper { + public const TABLE_NAME = 'cospend_members'; + + public function __construct( + IDBConnection $db, + ) { + parent::__construct($db, self::TABLE_NAME, Member::class); + } + + /** + * @param string $projectId + * @param string $name + * @return Member|null + */ + public function getMemberByName(string $projectId, string $name): ?Member { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where( + $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) + ) + ->andWhere( + $qb->expr()->eq('name', $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR)) + ); + + try { + return $this->findEntity($qb); + } catch (DoesNotExistException | MultipleObjectsReturnedException | Exception $e) { + return null; + } + } + + /** + * @param string $projectId + * @param string $userId + * @return Member|null + */ + public function getMemberByUserid(string $projectId, string $userId): ?Member { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where( + $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) + ) + ->andWhere( + $qb->expr()->eq('userid', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) + ); + + try { + return $this->findEntity($qb); + } catch (DoesNotExistException | MultipleObjectsReturnedException | Exception $e) { + return null; + } + } + + /** + * @param string $projectId + * @param int $memberId + * @return Member|null + */ + public function getMemberById(string $projectId, int $memberId): ?Member { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where( + $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) + ) + ->andWhere( + $qb->expr()->eq('id', $qb->createNamedParameter($memberId, IQueryBuilder::PARAM_INT)) + ); + + try { + return $this->findEntity($qb); + } catch (DoesNotExistException | MultipleObjectsReturnedException | Exception $e) { + return null; + } + } + + /** + * @param string $projectId + * @param string|null $order + * @param int|null $lastchanged + * @return array + */ + public function getMembers(string $projectId, ?string $order = null, ?int $lastchanged = null): array { + $qb = $this->db->getQueryBuilder(); + + $sqlOrder = 'name'; + if ($order !== null) { + if ($order === 'lowername') { + $sqlOrder = $qb->func()->lower('name'); + } else { + $sqlOrder = $order; + } + } + + $qb->select('*') + ->from(self::TABLE_NAME) + ->where( + $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) + ); + if ($lastchanged !== null) { + $qb->andWhere( + $qb->expr()->gt('lastchanged', $qb->createNamedParameter($lastchanged, IQueryBuilder::PARAM_INT)) + ); + } + $qb->orderBy($sqlOrder, 'ASC'); + + try { + return $this->findEntities($qb); + } catch (Exception $e) { + return []; + } + } +} diff --git a/lib/Db/Project.php b/lib/Db/Project.php index 9bd6c89f..8711e0f2 100644 --- a/lib/Db/Project.php +++ b/lib/Db/Project.php @@ -6,7 +6,7 @@ * This file is licensed under the Affero General Public License version 3 or * later. See the COPYING file. * - * @author Julien Veyssier * @copyright Julien Veyssier 2019 */ diff --git a/lib/Service/ProjectService.php b/lib/Service/ProjectService.php index e3db67e0..349e35da 100644 --- a/lib/Service/ProjectService.php +++ b/lib/Service/ProjectService.php @@ -25,6 +25,8 @@ use OCA\Cospend\Activity\ActivityManager; use OCA\Cospend\AppInfo\Application; use OCA\Cospend\Db\BillMapper; +use OCA\Cospend\Db\Member; +use OCA\Cospend\Db\MemberMapper; use OCA\Cospend\Db\ProjectMapper; use OCA\Cospend\Utils; use OCP\App\IAppManager; @@ -55,19 +57,20 @@ class ProjectService { private array $hardCodedCategoryNames; public function __construct( - private IL10N $l10n, - private IConfig $config, - private ProjectMapper $projectMapper, - private BillMapper $billMapper, + private IL10N $l10n, + private IConfig $config, + private ProjectMapper $projectMapper, + private BillMapper $billMapper, + private MemberMapper $memberMapper, private ActivityManager $activityManager, - private IAvatarManager $avatarManager, - private IUserManager $userManager, - private IAppManager $appManager, - private IGroupManager $groupManager, - private IDateTimeZone $dateTimeZone, - private IRootFolder $root, + private IAvatarManager $avatarManager, + private IUserManager $userManager, + private IAppManager $appManager, + private IGroupManager $groupManager, + private IDateTimeZone $dateTimeZone, + private IRootFolder $root, private INotificationManager $notificationManager, - private IDBConnection $db + private IDBConnection $db, ) { $this->defaultCategories = [ [ @@ -1141,53 +1144,8 @@ class ProjectService { * @return array|null */ public function getMemberById(string $projectId, int $memberId): ?array { - $member = null; - - $qb = $this->db->getQueryBuilder(); - $qb->select('id', 'userid', 'name', 'weight', 'color', 'activated', 'lastchanged') - ->from('cospend_members') - ->where( - $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) - ) - ->andWhere( - $qb->expr()->eq('id', $qb->createNamedParameter($memberId, IQueryBuilder::PARAM_INT)) - ); - $req = $qb->executeQuery(); - - while ($row = $req->fetch()) { - $dbMemberId = (int) $row['id']; - $dbWeight = (float) $row['weight']; - $dbUserid = $row['userid']; - $dbName = $row['name']; - $dbActivated = (int) $row['activated']; - $dbLastchanged = (int) $row['lastchanged']; - $dbColor = $row['color']; - if ($dbColor === null) { - $av = $this->avatarManager->getGuestAvatar($dbName); - $dbColor = $av->avatarBackgroundColor($dbName); - $dbColor = [ - 'r' => $dbColor->red(), - 'g' => $dbColor->green(), - 'b' => $dbColor->blue(), - ]; - } else { - $dbColor = Utils::hexToRgb($dbColor); - } - - $member = [ - 'activated' => $dbActivated === 1, - 'userid' => $dbUserid, - 'name' => $dbName, - 'id' => $dbMemberId, - 'weight' => $dbWeight, - 'color' => $dbColor, - 'lastchanged' => $dbLastchanged, - ]; - break; - } - $req->closeCursor(); - $qb->resetQueryParts(); - return $member; + $member = $this->memberMapper->getMemberById($projectId, $memberId); + return $member?->jsonSerialize(); } /** @@ -1720,64 +1678,10 @@ class ProjectService { * @return array */ public function getMembers(string $projectId, ?string $order = null, ?int $lastchanged = null): array { - $members = []; - $qb = $this->db->getQueryBuilder(); - - $sqlOrder = 'name'; - if ($order !== null) { - if ($order === 'lowername') { - $sqlOrder = $qb->func()->lower('name'); - } else { - $sqlOrder = $order; - } - } - - $qb->select('id', 'userid', 'name', 'weight', 'color', 'activated', 'lastchanged') - ->from('cospend_members') - ->where( - $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) - ); - if ($lastchanged !== null) { - $qb->andWhere( - $qb->expr()->gt('lastchanged', $qb->createNamedParameter($lastchanged, IQueryBuilder::PARAM_INT)) - ); - } - $qb->orderBy($sqlOrder, 'ASC'); - $req = $qb->executeQuery(); - - while ($row = $req->fetch()) { - $dbMemberId = (int) $row['id']; - $dbWeight = (float) $row['weight']; - $dbUserid = $row['userid']; - $dbName = $row['name']; - $dbActivated = (int) $row['activated']; - $dbLastchanged = (int) $row['lastchanged']; - $dbColor = $row['color']; - if ($dbColor === null) { - $av = $this->avatarManager->getGuestAvatar($dbName); - $avatarBgColor = $av->avatarBackgroundColor($dbName); - $dbColor = [ - 'r' => $avatarBgColor->red(), - 'g' => $avatarBgColor->green(), - 'b' => $avatarBgColor->blue(), - ]; - } else { - $dbColor = Utils::hexToRgb($dbColor); - } - - $members[] = [ - 'activated' => $dbActivated === 1, - 'userid' => $dbUserid, - 'name' => $dbName, - 'id' => $dbMemberId, - 'weight' => $dbWeight, - 'color' => $dbColor, - 'lastchanged' => $dbLastchanged, - ]; - } - $req->closeCursor(); - $qb->resetQueryParts(); - return $members; + $members = $this->memberMapper->getMembers($projectId, $order, $lastchanged); + return array_map(static function (Member $dbMember) { + return $dbMember->jsonSerialize(); + }, $members); } /** @@ -2551,51 +2455,8 @@ class ProjectService { * @return array|null */ public function getMemberByName(string $projectId, string $name): ?array { - $member = null; - $qb = $this->db->getQueryBuilder(); - $qb->select('id', 'userid', 'name', 'weight', 'color', 'activated', 'lastchanged') - ->from('cospend_members') - ->where( - $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) - ) - ->andWhere( - $qb->expr()->eq('name', $qb->createNamedParameter($name, IQueryBuilder::PARAM_STR)) - ); - $req = $qb->executeQuery(); - - while ($row = $req->fetch()) { - $dbMemberId = (int) $row['id']; - $dbWeight = (float) $row['weight']; - $dbUserid = $row['userid']; - $dbName = $row['name']; - $dbActivated = (int) $row['activated']; - $dbLastchanged = (int) $row['lastchanged']; - $dbColor = $row['color']; - if ($dbColor === null) { - $av = $this->avatarManager->getGuestAvatar($dbName); - $dbColor = $av->avatarBackgroundColor($dbName); - $dbColor = [ - 'r' => $dbColor->red(), - 'g' => $dbColor->green(), - 'b' => $dbColor->blue(), - ]; - } else { - $dbColor = Utils::hexToRgb($dbColor); - } - $member = [ - 'activated' => $dbActivated === 1, - 'userid' => $dbUserid, - 'name' => $dbName, - 'id' => $dbMemberId, - 'weight' => $dbWeight, - 'color' => $dbColor, - 'lastchanged' => $dbLastchanged, - ]; - break; - } - $req->closeCursor(); - $qb->resetQueryParts(); - return $member; + $member = $this->memberMapper->getMemberByName($projectId, $name); + return $member?->jsonSerialize(); } /** @@ -2606,53 +2467,11 @@ class ProjectService { * @return array|null */ public function getMemberByUserid(string $projectId, ?string $userId): ?array { - $member = null; - if ($userId !== null) { - $qb = $this->db->getQueryBuilder(); - $qb->select('id', 'userid', 'name', 'weight', 'color', 'activated', 'lastchanged') - ->from('cospend_members') - ->where( - $qb->expr()->eq('projectid', $qb->createNamedParameter($projectId, IQueryBuilder::PARAM_STR)) - ) - ->andWhere( - $qb->expr()->eq('userid', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) - ); - $req = $qb->executeQuery(); - - while ($row = $req->fetch()) { - $dbMemberId = (int) $row['id']; - $dbWeight = (float) $row['weight']; - $dbUserid = $row['userid']; - $dbName = $row['name']; - $dbActivated = (int) $row['activated']; - $dbLastchanged = (int) $row['lastchanged']; - $dbColor = $row['color']; - if ($dbColor === null) { - $av = $this->avatarManager->getGuestAvatar($dbName); - $dbColor = $av->avatarBackgroundColor($dbName); - $dbColor = [ - 'r' => $dbColor->red(), - 'g' => $dbColor->green(), - 'b' => $dbColor->blue(), - ]; - } else { - $dbColor = Utils::hexToRgb($dbColor); - } - $member = [ - 'activated' => $dbActivated === 1, - 'userid' => $dbUserid, - 'name' => $dbName, - 'id' => $dbMemberId, - 'weight' => $dbWeight, - 'color' => $dbColor, - 'lastchanged' => $dbLastchanged, - ]; - break; - } - $req->closeCursor(); - $qb->resetQueryParts(); + if ($userId === null) { + return null; } - return $member; + $member = $this->memberMapper->getMemberByUserid($projectId, $userId); + return $member?->jsonSerialize(); } /** diff --git a/tests/php/controller/ApiControllerTest.php b/tests/php/controller/ApiControllerTest.php index 45497d26..05fdeff0 100644 --- a/tests/php/controller/ApiControllerTest.php +++ b/tests/php/controller/ApiControllerTest.php @@ -20,6 +20,7 @@ namespace OCA\Cospend\Controller; use OCA\Cospend\Activity\ActivityManager; use OCA\Cospend\AppInfo\Application; use OCA\Cospend\Db\BillMapper; +use OCA\Cospend\Db\MemberMapper; use OCA\Cospend\Db\ProjectMapper; use OCA\Cospend\Service\ProjectService; use OCA\Cospend\Service\UserService; @@ -44,6 +45,7 @@ class ApiControllerTest extends TestCase { private BillMapper $billMapper; private ProjectMapper $projectMapper; private ProjectService $projectService; + private MemberMapper $memberMapper; public static function setUpBeforeClass(): void { $app = new Application(); @@ -88,6 +90,7 @@ class ApiControllerTest extends TestCase { // $sc = $c->get(ContainerInterface::class); $l10n = $c->get(IL10N::class); $this->billMapper = new BillMapper($sc->getDatabaseConnection()); + $this->memberMapper = new MemberMapper($sc->getDatabaseConnection()); $this->projectMapper = new ProjectMapper($sc->getDatabaseConnection(), $l10n); $activityManager = new ActivityManager( @@ -123,6 +126,7 @@ class ApiControllerTest extends TestCase { $sc->getConfig(), $this->projectMapper, $this->billMapper, + $this->memberMapper, $activityManager, $sc->getAvatarManager(), $c->get(IUserManager::class),