start improving db member management

Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
This commit is contained in:
Julien Veyssier
2024-01-13 18:42:50 +01:00
parent 9c34da8343
commit 991d023349
6 changed files with 257 additions and 209 deletions

View File

@@ -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 <julien-nc@posteo.net
* @author Julien Veyssier <julien-nc@posteo.net>
* @copyright Julien Veyssier 2019
*/

86
lib/Db/Member.php Normal file
View File

@@ -0,0 +1,86 @@
<?php
/**
* Nextcloud - cospend
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Julien Veyssier <julien-nc@posteo.net>
* @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);
}
}

139
lib/Db/MemberMapper.php Normal file
View File

@@ -0,0 +1,139 @@
<?php
/**
* Nextcloud - cospend
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Julien Veyssier <julien-nc@posteo.net>
* @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<Member>
*/
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 [];
}
}
}

View File

@@ -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 <julien-nc@posteo.net
* @author Julien Veyssier <julien-nc@posteo.net>
* @copyright Julien Veyssier 2019
*/

View File

@@ -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();
}
/**

View File

@@ -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),