diff --git a/lib/Service/ApprovalService.php b/lib/Service/ApprovalService.php index 197918b7..2c128cf8 100644 --- a/lib/Service/ApprovalService.php +++ b/lib/Service/ApprovalService.php @@ -31,6 +31,9 @@ use Sabre\DAV\INode; use Sabre\DAV\PropFind; +/** + * @psalm-import-type Rule from RuleService + */ class ApprovalService { public function __construct( @@ -164,7 +167,7 @@ public function getUserRules(string $userId, string $role = 'requesters', ?int $ * Check if a user is authorized to approve or request by a given rule * * @param string $userId - * @param array $rule + * @param Rule $rule * @param string $role * @return bool */ @@ -180,7 +183,7 @@ private function userIsAuthorizedByRule(string $userId, array $rule, string $rol })); // if user is in rule's user list - if (in_array($userId, $ruleUserIds)) { + if (in_array($userId, $ruleUserIds, true)) { return true; } else { // if user is member of one rule's group list @@ -285,15 +288,15 @@ public function getApprovalState(int $fileId, ?string $userId, bool $userHasAcce $rules = $this->ruleService->getRules(); // Get all tags a file has to prevent needing to check for each tag in every rule - $tags = $this->tagObjectMapper->getTagIdsForObjects([$fileId], 'files'); - if (!array_key_exists($fileId, $tags)) { + $tags = $this->tagObjectMapper->getTagIdsForObjects([(string)$fileId], 'files'); + if (!array_key_exists((string)$fileId, $tags)) { return ['state' => Application::STATE_NOTHING]; } - $tags = $tags[$fileId]; + $tags = array_map(static fn ($tag): string => (string)$tag, $tags[(string)$fileId]); // first check if it's approvable foreach ($rules as $id => $rule) { - if (in_array($rule['tagPending'], $tags) + if (in_array($rule['tagPending'], $tags, true) && $this->userIsAuthorizedByRule($userId, $rule, 'approvers')) { return [ 'state' => Application::STATE_APPROVABLE, @@ -304,7 +307,7 @@ public function getApprovalState(int $fileId, ?string $userId, bool $userHasAcce // then check pending in priority foreach ($rules as $id => $rule) { - if (in_array($rule['tagPending'], $tags)) { + if (in_array($rule['tagPending'], $tags, true)) { return [ 'state' => Application::STATE_PENDING, 'rule' => $rule, @@ -313,7 +316,7 @@ public function getApprovalState(int $fileId, ?string $userId, bool $userHasAcce } // then rejected foreach ($rules as $id => $rule) { - if (in_array($rule['tagRejected'], $tags)) { + if (in_array($rule['tagRejected'], $tags, true)) { return [ 'state' => Application::STATE_REJECTED, 'rule' => $rule, @@ -322,7 +325,7 @@ public function getApprovalState(int $fileId, ?string $userId, bool $userHasAcce } // then approved foreach ($rules as $id => $rule) { - if (in_array($rule['tagApproved'], $tags)) { + if (in_array($rule['tagApproved'], $tags, true)) { return [ 'state' => Application::STATE_APPROVED, 'rule' => $rule, @@ -502,7 +505,7 @@ public function requestViaTagAssignment(int $fileId, int $ruleId, string $reques * Share file with everybody who can approve with given rule and have no access yet * * @param int $fileId - * @param array $rule + * @param Rule $rule * @param string $userId * @return array list of created shares * @throws \OCP\Files\NotPermittedException @@ -626,7 +629,7 @@ public function getRuleAuthorizedUserIds(array $rule, string $role = 'approvers' $ruleUserIds = []; foreach ($rule[$role] as $approver) { if ($approver['type'] === 'user') { - if (!in_array($approver['entityId'], $ruleUserIds)) { + if (!in_array($approver['entityId'], $ruleUserIds, true)) { $ruleUserIds[] = $approver['entityId']; } } elseif ($approver['type'] === 'group') { @@ -634,7 +637,7 @@ public function getRuleAuthorizedUserIds(array $rule, string $role = 'approvers' if ($this->groupManager->groupExists($groupId)) { $users = $this->groupManager->get($groupId)->getUsers(); foreach ($users as $user) { - if ($user instanceof IUser && !in_array($user->getUID(), $ruleUserIds)) { + if ($user instanceof IUser && !in_array($user->getUID(), $ruleUserIds, true)) { $ruleUserIds[] = $user->getUID(); } } @@ -650,7 +653,7 @@ public function getRuleAuthorizedUserIds(array $rule, string $role = 'approvers' continue; } $memberUserId = $member->getUserId(); - if (!in_array($memberUserId, $ruleUserIds)) { + if (!in_array($memberUserId, $ruleUserIds, true)) { $ruleUserIds[] = $memberUserId; } } @@ -678,7 +681,7 @@ public function handleTagAssignmentEvent(int $fileId, array $tags): void { $rules = $this->ruleService->getRules(); foreach ($rules as $id => $rule) { // rule matches tags - if (in_array($rule['tagPending'], $tags)) { + if (in_array($rule['tagPending'], $tags, true)) { $ruleInvolded = $rule; break; } @@ -722,7 +725,7 @@ public function handleTagAssignmentEvent(int $fileId, array $tags): void { * Send it to all users who are authorized to approve it * * @param int $fileId - * @param array $rule + * @param Rule $rule * @param string $requestUserId * @return void */ @@ -731,7 +734,7 @@ public function sendRequestNotification(int $fileId, array $rule, string $reques $rulesUserIds = []; $thisRuleUserIds = $this->getRuleAuthorizedUserIds($rule, 'approvers'); foreach ($thisRuleUserIds as $userId) { - if (!in_array($userId, $rulesUserIds)) { + if (!in_array($userId, $rulesUserIds, true)) { $rulesUserIds[] = $userId; } } diff --git a/lib/Service/RuleService.php b/lib/Service/RuleService.php index b78394ae..ea0028a0 100644 --- a/lib/Service/RuleService.php +++ b/lib/Service/RuleService.php @@ -16,6 +16,18 @@ use OCP\IUserManager; +/** + * @psalm-type Rule = array{ + * id: int, + * tagPending: string, + * tagApproved: string, + * tagRejected: string, + * description: string, + * approvers: array, + * requesters: array, + * unapproveWhenModified: bool, + * } + */ class RuleService { /** @var array */ private $strTypeToInt; @@ -318,7 +330,7 @@ public function deleteRule(int $id): array { /** * Get a rule by id * @param int $id the rule id - * @return array|null the rule or null if not found + * @return Rule|null the rule or null if not found */ public function getRule(int $id): ?array { $rule = null; @@ -331,9 +343,9 @@ public function getRule(int $id): ?array { ); $req = $qb->executeQuery(); while ($row = $req->fetch()) { - $tagPending = (int)$row['tag_pending']; - $tagApproved = (int)$row['tag_approved']; - $tagRejected = (int)$row['tag_rejected']; + $tagPending = (string)$row['tag_pending']; + $tagApproved = (string)$row['tag_approved']; + $tagRejected = (string)$row['tag_rejected']; $description = $row['description']; $rule = [ 'id' => $id, @@ -362,7 +374,7 @@ public function getRule(int $id): ?array { /** * Get all rules * - * @return array + * @return array */ public function getRules(): array { if ($this->cachedRules === null) { @@ -374,9 +386,9 @@ public function getRules(): array { $req = $qb->executeQuery(); while ($row = $req->fetch()) { $id = (int)$row['id']; - $tagPending = (int)$row['tag_pending']; - $tagApproved = (int)$row['tag_approved']; - $tagRejected = (int)$row['tag_rejected']; + $tagPending = (string)$row['tag_pending']; + $tagApproved = (string)$row['tag_approved']; + $tagRejected = (string)$row['tag_rejected']; $description = $row['description']; $rules[$id] = [ 'id' => $id, diff --git a/tests/unit/Service/ApprovalServiceTest.php b/tests/unit/Service/ApprovalServiceTest.php index 001bffc4..8c539c85 100644 --- a/tests/unit/Service/ApprovalServiceTest.php +++ b/tests/unit/Service/ApprovalServiceTest.php @@ -28,49 +28,19 @@ use Psr\Log\LoggerInterface; class ApprovalServiceTest extends TestCase { - - /** - * @var RuleService - */ - private $ruleService; - /** - * @var ApprovalService - */ - private $approvalService; - /** - * @var UtilsService - */ - private $utilsService; - /** - * @var IRootFolder - */ - private $root; - /** - * @var int - */ - private $idTagPending1; - /** - * @var int - */ - private $idTagApproved1; - /** - * @var int - */ - private $idTagRejected1; - /** - * @var int - */ - private $idRule1; - /** - * @var ISystemTagObjectMapper - */ - private $tagObjectMapper; - /** - * @var string[][] - */ - private $approvers1; - private $requesters1; - private $description1; + private RuleService $ruleService; + private ApprovalService $approvalService; + private UtilsService $utilsService; + private IRootFolder $root; + private int $idTagPending1; + private int $idTagApproved1; + private int $idTagRejected1; + private int $idRule1; + private ISystemTagObjectMapper $tagObjectMapper; + /** @var string[][] */ + private array $approvers1; + private array $requesters1; + private string $description1; public static function setUpBeforeClass(): void { $app = new Application(); @@ -271,7 +241,7 @@ public function testGetRuleAuthorizedUserIds() { $this->assertEquals('user1', $uidRequesters[0]); } - public function testGetApprovalState() { + public function testGetApprovalState(): void { $uf = $this->root->getUserFolder('user1'); $file1 = $uf->newFile('file1.txt', 'content'); $state = $this->approvalService->getApprovalState($file1->getId(), 'user1');