Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/Activity/PollChanges.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2021 Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Polls\Activity;

use OCA\Polls\AppConstants;
Expand Down
3 changes: 1 addition & 2 deletions lib/Controller/BaseApiV2Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Polls\Controller;

use Closure;
Expand Down Expand Up @@ -42,10 +43,8 @@ public function __construct(
protected function response(Closure $callback, int $successStatus = Http::STATUS_OK): DataResponse {
try {
return new DataResponse($callback(), $successStatus);

} catch (DoesNotExistException $e) {
throw new OCSNotFoundException($e->getMessage());

} catch (Exception $e) {

if ($e->getStatus() === Http::STATUS_NOT_MODIFIED) {
Expand Down
1 change: 0 additions & 1 deletion lib/Controller/OptionApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ public function add(
), Http::STATUS_CREATED);
}


/**
* Add mulitple new options
* @param int $pollId poll id
Expand Down
66 changes: 45 additions & 21 deletions lib/Controller/PollController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
namespace OCA\Polls\Controller;

use OCA\Polls\Db\Poll;
use OCA\Polls\Helper\Container;
use OCA\Polls\Model\Settings\AppSettings;
use OCA\Polls\Service\CommentService;
use OCA\Polls\Service\MailService;
use OCA\Polls\Service\OptionService;
Expand Down Expand Up @@ -46,31 +44,57 @@ public function __construct(
}

/**
* Get list of polls
* Get one page of the current user's polls
* @param string $category Poll list category, see Poll::CATEGORIES; ignored if $pollGroup is set
* @param int|null $pollGroup Only list polls of this poll group
* @param string|null $type Only list polls of this type (datePoll or textPoll)
* @param string $sortBy Sort column, see PollService::SORT_COLUMNS
* @param string $sortDirection 'asc' or 'desc'
* @param int $offset Number of polls to skip
* @param int $limit Page size, max PollService::MAX_PAGE_SIZE
*
* psalm-return JSONResponse<array{polls: array<int, Poll>, total: int}>
*/
#[NoAdminRequired]
#[OpenAPI(OpenAPI::SCOPE_IGNORE)]
#[FrontpageRoute(verb: 'GET', url: '/polls')]
public function listPolls(
string $category = Poll::CATEGORY_RELEVANT,
?int $pollGroup = null,
?string $type = null,
string $sortBy = PollService::SORT_CREATED,
string $sortDirection = 'desc',
int $offset = 0,
int $limit = 20,
): JSONResponse {
return $this->response(fn () => $this->pollService->listPollsPaged(
$category,
$pollGroup,
$type,
$sortBy,
$sortDirection,
$offset,
$limit,
));
}

/**
* Get poll counts per category and poll group and the poll groups for the navigation
*
* psalm-return JSONResponse<array{
* polls: array<int, Poll>,
* permissions: array{
* pollCreationAllowed: bool,
* comboAllowed: bool
* },
* counts: array<string, int>,
* pollGroupCounts: array<int, int>,
* pollGroups: array<int, PollGroup>
* }>
*/
#[NoAdminRequired]
#[OpenAPI(OpenAPI::SCOPE_IGNORE)]
#[FrontpageRoute(verb: 'GET', url: '/polls')]
public function listPolls(): JSONResponse {
return $this->response(function () {
$appSettings = Container::queryClass(AppSettings::class);
return [
'polls' => $this->pollService->listPolls(),
'permissions' => [
'pollCreationAllowed' => $appSettings->getPollCreationAllowed(),
'comboAllowed' => $appSettings->getComboAllowed(),
],
'pollGroups' => $this->pollGroupService->listPollGroups(),
];
});
#[FrontpageRoute(verb: 'GET', url: '/polls/meta')]
public function listPollsMeta(): JSONResponse {
return $this->response(fn () => array_merge(
$this->pollService->getPollListCounts(),
['pollGroups' => $this->pollGroupService->listPollGroups()],
));
}

/**
Expand Down
2 changes: 0 additions & 2 deletions lib/Controller/PublicController.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ public function getSession(): JSONResponse {
]);
}


/**
* Watch poll for updates
* @param string $mode the mode of watching, e.g. 'longPolling'
Expand Down Expand Up @@ -419,7 +418,6 @@ public function setDisplayName(string $token, string $displayName): JSONResponse
]);
}


/**
* Set EmailAddress
* @param string $token Share token
Expand Down
1 change: 0 additions & 1 deletion lib/Controller/ShareApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ public function get(string $token): DataResponse {
return $this->response(fn () => ['share' => $this->shareService->request($token)]);
}


#[CORS]
#[PublicPage]
#[ShareTokenRequired]
Expand Down
1 change: 0 additions & 1 deletion lib/Cron/JanitorCron.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ protected function run($argument) {
$this->logger->info('JanitorCron: ' . $message);
}


// archive polls after defined days after closing date
$autoArchiveOffset = $this->appSettings->getAutoArchiveOffsetDays();

Expand Down
1 change: 0 additions & 1 deletion lib/Cron/UserDeletedJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use OCA\Polls\Db\LogMapper;
use OCA\Polls\Db\OptionMapper;
use OCA\Polls\Db\PollMapper;

use OCA\Polls\Db\PreferencesMapper;
use OCA\Polls\Db\Share;
use OCA\Polls\Db\ShareMapper;
Expand Down
1 change: 0 additions & 1 deletion lib/Db/CommentMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ public function purgeDeletedComments(int $offset): int {
);

return $query->executeStatement();

}

/**
Expand Down
1 change: 0 additions & 1 deletion lib/Db/EntityWithUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ private function getEntityAnonymization(): bool {
return false;
}


/**
* @return UserBase Gets owner of the entity
*/
Expand Down
1 change: 0 additions & 1 deletion lib/Db/Log.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
namespace OCA\Polls\Db;

use JsonSerializable;

use OCP\AppFramework\Db\Entity;

/**
Expand Down
3 changes: 0 additions & 3 deletions lib/Db/OptionMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ public function getMinDate(int $pollId): int|false {
return $qb->executeQuery()->fetchOne();
}


/**
* Get the maximum date of all options in a poll
*
Expand Down Expand Up @@ -207,15 +206,13 @@ protected function buildQuery(bool $hideResults = false): IQueryBuilder {
->groupBy(self::TABLE . '.id')
->orderBy('order', 'ASC');


$this->joinVotesCount($qb, self::TABLE, hideResults: $hideResults);
$this->joinPollForLimits($qb, self::TABLE);
$this->joinCurrentUserVote($qb, self::TABLE, $currentUserId);
$this->joinCurrentUserVoteCount($qb, self::TABLE, $currentUserId);
$this->joinAnon($qb, self::TABLE);
$this->joinShareRole($qb, self::TABLE, $currentUserId);


return $qb;
}

Expand Down
84 changes: 79 additions & 5 deletions lib/Db/Poll.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,29 @@ class Poll extends EntityWithUser implements JsonSerializable {
public const TWO_DAYS = 172800;
public const ONE_AND_HALF_DAY = 129600;

public const CATEGORY_RELEVANT = 'relevant';
public const CATEGORY_MY = 'my';
public const CATEGORY_PRIVATE = 'private';
public const CATEGORY_PARTICIPATED = 'participated';
public const CATEGORY_OPEN = 'open';
public const CATEGORY_ALL = 'all';
public const CATEGORY_CLOSED = 'closed';
public const CATEGORY_ARCHIVED = 'archived';
public const CATEGORY_ADMIN = 'admin';
public const CATEGORIES = [
self::CATEGORY_RELEVANT,
self::CATEGORY_MY,
self::CATEGORY_PRIVATE,
self::CATEGORY_PARTICIPATED,
self::CATEGORY_OPEN,
self::CATEGORY_ALL,
self::CATEGORY_CLOSED,
self::CATEGORY_ARCHIVED,
self::CATEGORY_ADMIN,
];
// polls are relevant, if the relevant threshold is not older than this
public const RELEVANT_PERIOD = 100 * 24 * 60 * 60;

public const ROLE_USER = Share::TYPE_USER;
public const ROLE_ADMIN = Share::TYPE_ADMIN;
public const ROLE_EMAIL = Share::TYPE_EMAIL;
Expand Down Expand Up @@ -348,6 +371,14 @@ public function getPollOwnerId() {
return $this->getOwner();
}

/**
* Uses the injected user session instead of a container lookup per call,
* because this is evaluated multiple times per poll in permission checks
*/
public function getCurrentUserIsEntityUser(): bool {
return $this->userSession->getCurrentUserId() === $this->getOwner();
}

public function getUserRole(): string {
if ($this->getCurrentUserIsEntityUser()) {
return self::ROLE_OWNER;
Expand Down Expand Up @@ -480,7 +511,7 @@ public function getPollGroupUserShares(): array {
return explode(PollGroup::CONCAT_SEPARATOR, $this->pollGroupUserShares);
}

private function getAccess(): string {
public function getAccess(): string {
if ($this->access === self::ACCESS_PUBLIC) {
return self::ACCESS_OPEN;
}
Expand Down Expand Up @@ -517,7 +548,6 @@ private function getMaxDate(): int {
return $this->maxDate;
}


private function setMiscSettingsArray(array $value): void {
$this->setMiscSettings(json_encode($value));
}
Expand All @@ -530,7 +560,7 @@ private function getMiscSettingsArray(): array {
return [];
}

private function getRelevantThreshold(): int {
public function getRelevantThreshold(): int {
return max(
$this->getCreated(),
$this->getLastInteraction(),
Expand Down Expand Up @@ -609,6 +639,52 @@ public function getIsAllowed(string $permission): bool {
};
}

/**
* Get the poll list categories, the poll belongs to for the current user
* Permission checks are evaluated once per poll
*
* @return string[] subset of self::CATEGORIES
*/
public function getCategories(): array {
$isAdmin = $this->userSession->getCurrentUser()->getIsAdmin();
$categories = ($isAdmin && !$this->getCurrentUserIsEntityUser()) ? [self::CATEGORY_ADMIN] : [];
$canView = $this->getAllowAccessPoll();

if ($this->getDeleted()) {
if ($canView) {
$categories[] = self::CATEGORY_ARCHIVED;
}
return $categories;
}

$access = $this->getAccess();

if ($this->getRelevantThreshold() > time() - self::RELEVANT_PERIOD
&& ($this->getIsInvolved() || ($canView && $access !== self::ACCESS_OPEN))
) {
$categories[] = self::CATEGORY_RELEVANT;
}
if ($this->getIsPollOwner()) {
$categories[] = self::CATEGORY_MY;
}
if ($this->getIsParticipant()) {
$categories[] = self::CATEGORY_PARTICIPATED;
}
if ($access === self::ACCESS_OPEN) {
$categories[] = self::CATEGORY_OPEN;
}
if ($canView) {
$categories[] = self::CATEGORY_ALL;
if ($access === self::ACCESS_PRIVATE) {
$categories[] = self::CATEGORY_PRIVATE;
}
if ($this->getExpired()) {
$categories[] = self::CATEGORY_CLOSED;
}
}
return $categories;
}

/**
* getIsInvolved - Is current user involved in current poll?
* @return bool Returns true, if the current user is involved in the poll via share, as a participant or as the poll owner.
Expand Down Expand Up @@ -832,7 +908,6 @@ public function getIsPollOwner(): bool {
return ($this->getUserRole() === Poll::ROLE_OWNER);
}


/**
* Permission checks
*/
Expand Down Expand Up @@ -949,5 +1024,4 @@ private function getAllowShowResults(): bool {
return $this->getShowResults() === Poll::SHOW_RESULTS_ALWAYS;
}


}
1 change: 0 additions & 1 deletion lib/Db/PollGroupMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ public function add(PollGroup $pollGroup): PollGroup {
$pollGroup->setCreated(time());
$pollGroup->setOwner($this->userSession->getCurrentUserId());
return $this->insert($pollGroup);

}

/**
Expand Down
Loading
Loading