Skip to content

Commit

Permalink
Merge pull request #3381 from nextcloud/enh/load-user-role
Browse files Browse the repository at this point in the history
Define user role via joined shares
  • Loading branch information
dartcafe authored Mar 21, 2024
2 parents 6fea153 + f999ebf commit f6104a3
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 184 deletions.
19 changes: 12 additions & 7 deletions lib/Controller/PublicController.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
use OCP\Util;

/**
* Always use parent's classe response* methods to make sure, the token gets set correctly.
* Requesting the token inside the controller is not possible, because the token is submitted
* as a paramter and not known while contruction time
* i.e. ACL requests are not valid before calling the response* method
* @psalm-api
*/
class PublicController extends BasePublicController {
Expand Down Expand Up @@ -89,13 +93,14 @@ public function votePage() {
*/
#[PublicPage]
public function getPoll(string $token): JSONResponse {
$this->acl->request(Acl::PERMISSION_POLL_VIEW);

// load poll through acl
return $this->response(fn () => [
'acl' => $this->acl,
'poll' => $this->acl->getPoll(),
], $token);
return $this->response(function () {
$this->acl->request(Acl::PERMISSION_POLL_VIEW);
// load poll through acl
return [
'acl' => $this->acl,
'poll' => $this->acl->getPoll(),
];
}, $token);
}

/**
Expand Down
47 changes: 39 additions & 8 deletions lib/Db/Poll.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ class Poll extends EntityWithUser implements JsonSerializable {
public const TWO_DAYS = 172800;
public const ONE_AND_HALF_DAY = 129600;

public const ROLE_USER = Share::TYPE_USER;
public const ROLE_ADMIN = Share::TYPE_ADMIN;
public const ROLE_EMAIL = Share::TYPE_EMAIL;
public const ROLE_CONTACT = Share::TYPE_CONTACT;
public const ROLE_EXTERNAL = Share::TYPE_EXTERNAL;
public const ROLE_OWNER = 'owner';
public const ROLE_NONE = 'none';



private IURLGenerator $urlGenerator;
protected UserMapper $userMapper;
private VoteMapper $voteMapper;
Expand Down Expand Up @@ -137,6 +147,8 @@ class Poll extends EntityWithUser implements JsonSerializable {
protected int $maxDate = 0;
protected int $minDate = 0;
protected int $currentUserVotes = 0;
protected string $userRole = self::ROLE_NONE;
protected ?int $isCurrentUserLocked = 0;

public function __construct() {
$this->addType('created', 'int');
Expand Down Expand Up @@ -168,6 +180,7 @@ public function __construct() {
public function jsonSerialize(): array {
return [
'id' => $this->getId(),
'type' => $this->getType(),
'title' => $this->getTitle(),
'description' => $this->getDescription(),
'descriptionSafe' => $this->getDescriptionSafe(),
Expand All @@ -185,14 +198,14 @@ public function jsonSerialize(): array {
'optionLimit' => $this->getOptionLimit(),
'proposalsExpire' => $this->getProposalsExpire(),
'showResults' => $this->getShowResults() === 'expired' ? Poll::SHOW_RESULTS_CLOSED : $this->getShowResults(),
'type' => $this->getType(),
'useNo' => $this->getUseNo(),
'voteLimit' => $this->getVoteLimit(),
'lastInteraction' => $this->getLastInteraction(),
'summary' => [
'orphanedVotes' => count($this->voteMapper->findOrphanedByPollandUser($this->id, $this->userMapper->getCurrentUserCached()->getId())),
'yesByCurrentUser' => count($this->voteMapper->getYesVotesByParticipant($this->getPollId(), $this->userMapper->getCurrentUserCached()->getId())),
'orphanedVotes' => $this->getCurrentUserOrphanedVotes(),
'yesByCurrentUser' => $this->getCurrentUserYesVotes(),
'countVotes' => $this->getCurrentUserCountVotes(),
'userRole' => $this->getUserRole(),
],
];
}
Expand Down Expand Up @@ -231,6 +244,13 @@ public function getExpired(): bool {
);
}

public function getUserRole(): string {
if ($this->userMapper->getCurrentUser()->getId() === $this->getOwner()) {
return self::ROLE_OWNER;
}
return $this->userRole;
}

public function getVoteUrl(): string {
return $this->urlGenerator->linkToRouteAbsolute(
AppConstants::APP_ID . '.page.vote',
Expand Down Expand Up @@ -278,10 +298,6 @@ public function getProposalsExpired(): bool {
);
}

public function getCurrentUserCountVotes(): int {
return $this->currentUserVotes;
}

public function getDescription(): string {
return $this->description ?? '';
}
Expand Down Expand Up @@ -337,13 +353,28 @@ public function getRelevantThresholdNet(): int {
);
}

public function getCurrentUserCountVotes(): int {
return $this->currentUserVotes;
}

public function getIsCurrentUserLocked(): bool {
return (bool) $this->isCurrentUserLocked;
}

/**
* @psalm-return int<0, max>
*/
public function getOrphanedVotes(): int {
public function getCurrentUserOrphanedVotes(): int {
return count($this->voteMapper->findOrphanedByPollandUser($this->id, $this->userMapper->getCurrentUserCached()->getId()));
}

/**
* @psalm-return int<0, max>
*/
public function getCurrentUserYesVotes(): int {
return count($this->voteMapper->getYesVotesByParticipant($this->getPollId(), $this->userMapper->getCurrentUserCached()->getId()));
}

public function getDeadline(): int {
// if expiration is set return expiration date
if ($this->getExpire()) {
Expand Down
24 changes: 22 additions & 2 deletions lib/Db/PollMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,32 @@ protected function buildQuery(): IQueryBuilder {
->from($this->getTableName(), self::TABLE);
$this->joinOptionsForMaxDate($qb, self::TABLE);
$this->joinCurrentUserVotes($qb, self::TABLE, $currentUserId);
$this->joinUserRole($qb, self::TABLE, $currentUserId);
$qb->groupBy(self::TABLE . '.id');
return $qb;
}

/**
* Joins options to evaluate min and max option date for date polls
* if text poll or no options are set,
* the min value is the current time,
* the max value is null
*/
protected function joinUserRole(IQueryBuilder &$qb, string $fromAlias, string $currentUserId): void {
$joinAlias = 'shares';
$qb->addSelect($qb->createFunction('coalesce(' . $joinAlias . '.type, "") AS user_role'));

$qb->leftJoin(
$fromAlias,
Share::TABLE,
$joinAlias,
$qb->expr()->andX(
$qb->expr()->eq($fromAlias . '.id', $joinAlias . '.poll_id'),
$qb->expr()->eq($joinAlias . '.user_id', $qb->createNamedParameter($currentUserId, IQueryBuilder::PARAM_STR)),
)
);
}

/**
* Joins options to evaluate min and max option date for date polls
* if text poll or no options are set,
Expand All @@ -193,8 +215,6 @@ protected function joinOptionsForMaxDate(IQueryBuilder &$qb, string $fromAlias):
$joinAlias = 'options';
$saveMin = (string) time();

// force value into a MIN function to avoid grouping errors
// $qb->selectAlias($qb->func()->max($joinAlias . '.timestamp'), 'max_date');
$qb->addSelect($qb->createFunction('coalesce(MAX(' . $joinAlias . '.timestamp), 0) AS max_date'))
->addSelect($qb->createFunction('coalesce(MIN(' . $joinAlias . '.timestamp), ' . $saveMin . ') AS min_date'));

Expand Down
23 changes: 23 additions & 0 deletions lib/Db/ShareMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,29 @@ public function findByPoll(int $pollId, bool $getDeleted = false): array {
return $this->findEntities($qb);
}

/**
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
* @return Share[]
* @psalm-return array<array-key, Share>
*/
public function findGroupShareByPoll(int $pollId, bool $getDeleted = false): array {
$qb = $this->db->getQueryBuilder();

$qb->select(self::TABLE . '.*')
->from($this->getTableName(), self::TABLE)
->groupBy(self::TABLE . '.id')
->where($qb->expr()->eq(self::TABLE . '.poll_id', $qb->createNamedParameter($pollId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq(self::TABLE . '.type', $qb->createNamedParameter(Share::TYPE_GROUP, IQueryBuilder::PARAM_STR)));

if (!$getDeleted) {
$qb->andWhere($qb->expr()->eq(self::TABLE . '.deleted', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
}

$this->joinUserVoteCount($qb, self::TABLE);

return $this->findEntities($qb);
}

/**
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
* @return Share[]
Expand Down
4 changes: 2 additions & 2 deletions lib/Db/UserMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function getCurrentUser(): UserBase {

} else {
try {
$this->currentUser = $this->getUserFromShareToken($this->getToken());
$this->currentUser = $this->getUserFromShareToken($this->getSessionStoredShareToken());
} catch (DoesNotExistException $e) {
$this->logger->debug('no user found, returned fake user');
$this->currentUser = new GenericUser('', Share::TYPE_PUBLIC);
Expand All @@ -114,7 +114,7 @@ public function getCurrentUserCached(): UserBase {
return $this->currentUser ?? $this->getCurrentUser();
}

private function getToken(): string {
public function getSessionStoredShareToken(): string {
return (string) $this->session->get(AppConstants::SESSION_KEY_SHARE_TOKEN);
}

Expand Down
36 changes: 0 additions & 36 deletions lib/Exceptions/InvalidPollIdException.php

This file was deleted.

Loading

0 comments on commit f6104a3

Please sign in to comment.