Files
nextcloud-workflow-deck-aut…/lib/Controller/WorkflowController.php
T
Patrick Niebeling ada16cb101
Build package / php-lint (8.4) (push) Successful in 1m7s
Build package / php-lint (8.5) (push) Successful in 56s
Build package / xml-lint (push) Successful in 17s
Build package / unit-tests (push) Successful in 42s
Build package / package (push) Successful in 1m4s
Only allow workflows on owned boards, and show the board in the table
The board list now only contains boards the current user owns, which
also makes the controller's board validation enforce the owner rule.

The workflow table gains a Board column (Board, Titel, Von Stapel,
Nach Stapel, Filter, E-Mail, Aktiv) and is sorted alphabetically by
those columns in that order.
2026-09-30 09:16:09 +02:00

208 lines
6.4 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\WorkflowDeckAutomation\Controller;
use OCA\WorkflowDeckAutomation\Db\Workflow;
use OCA\WorkflowDeckAutomation\Db\WorkflowMapper;
use OCA\WorkflowDeckAutomation\Service\DeckIntegrationService;
use OCA\WorkflowDeckAutomation\Service\DeckUnavailableException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCS\OCSPreconditionFailedException;
use OCP\AppFramework\OCSController;
use OCP\IRequest;
use OCP\IUserSession;
class WorkflowController extends OCSController {
public function __construct(
string $appName,
IRequest $request,
private WorkflowMapper $workflowMapper,
private DeckIntegrationService $deckService,
private IUserSession $userSession,
) {
parent::__construct($appName, $request);
}
private function currentUserId(): string {
$user = $this->userSession->getUser();
if ($user === null) {
throw new OCSPreconditionFailedException('Not logged in');
}
return $user->getUID();
}
#[NoAdminRequired]
public function index(): DataResponse {
$workflows = $this->workflowMapper->findAllForUser($this->currentUserId());
return new DataResponse(array_map(static fn (Workflow $w) => $w->jsonSerialize(), $workflows));
}
/**
* @param string[] $filterUserIds
* @param int[] $filterLabelIds
*/
#[NoAdminRequired]
public function create(
string $title,
int $boardId,
int $sourceStackId,
int $targetStackId,
array $filterUserIds = [],
array $filterLabelIds = [],
bool $notifyEmail = false,
bool $enabled = true,
): DataResponse {
$this->validate($title, $boardId, $sourceStackId, $targetStackId);
$workflow = new Workflow();
$workflow->setUserId($this->currentUserId());
$this->applyFields($workflow, $title, $boardId, $sourceStackId, $targetStackId, $filterUserIds, $filterLabelIds, $notifyEmail, $enabled);
$workflow = $this->workflowMapper->insert($workflow);
return new DataResponse($workflow->jsonSerialize(), Http::STATUS_CREATED);
}
/**
* @param string[] $filterUserIds
* @param int[] $filterLabelIds
*/
#[NoAdminRequired]
public function update(
int $id,
string $title,
int $boardId,
int $sourceStackId,
int $targetStackId,
array $filterUserIds = [],
array $filterLabelIds = [],
bool $notifyEmail = false,
bool $enabled = true,
): DataResponse {
try {
$workflow = $this->workflowMapper->findForUser($id, $this->currentUserId());
} catch (DoesNotExistException $e) {
throw new OCSNotFoundException('Workflow not found');
}
$this->validate($title, $boardId, $sourceStackId, $targetStackId);
$this->applyFields($workflow, $title, $boardId, $sourceStackId, $targetStackId, $filterUserIds, $filterLabelIds, $notifyEmail, $enabled);
$workflow = $this->workflowMapper->update($workflow);
return new DataResponse($workflow->jsonSerialize());
}
#[NoAdminRequired]
public function destroy(int $id): DataResponse {
try {
$workflow = $this->workflowMapper->findForUser($id, $this->currentUserId());
} catch (DoesNotExistException $e) {
throw new OCSNotFoundException('Workflow not found');
}
$this->workflowMapper->delete($workflow);
return new DataResponse([]);
}
#[NoAdminRequired]
public function boards(): DataResponse {
$this->assertDeck();
return new DataResponse($this->deckService->listBoardsForCurrentUser($this->currentUserId()));
}
#[NoAdminRequired]
public function stacks(int $boardId): DataResponse {
$this->assertDeck();
return new DataResponse($this->deckService->listStacks($boardId));
}
#[NoAdminRequired]
public function labels(int $boardId): DataResponse {
$this->assertDeck();
return new DataResponse($this->deckService->listLabels($boardId));
}
#[NoAdminRequired]
public function participants(int $boardId): DataResponse {
$this->assertDeck();
return new DataResponse($this->deckService->listParticipants($boardId));
}
private function assertDeck(): void {
$user = $this->userSession->getUser();
if ($user === null) {
throw new OCSPreconditionFailedException('Not logged in');
}
try {
$this->deckService->assertDeckAvailable($user);
} catch (DeckUnavailableException $e) {
throw new OCSPreconditionFailedException('Deck is not available: ' . $e->getMessage());
}
}
private function validate(string $title, int $boardId, int $sourceStackId, int $targetStackId): void {
if (trim($title) === '') {
throw new OCSBadRequestException('Title must not be empty');
}
if ($sourceStackId === $targetStackId) {
throw new OCSBadRequestException('Source and target stack must differ');
}
// Reject references to boards or stacks that are gone (or were never
// the user's) instead of storing a workflow that can only fail later.
// assertDeck() ran first, so an empty list here means "not there",
// not "Deck is unreachable".
$this->assertDeck();
// Only boards the user owns are listed, so this also enforces the
// owner rule.
$boardIds = array_map(
static fn (array $board) => (int)$board['id'],
$this->deckService->listBoardsForCurrentUser($this->currentUserId()),
);
if (!in_array($boardId, $boardIds, true)) {
throw new OCSBadRequestException('The selected board does not exist or is not owned by you');
}
$stackIds = array_map(
static fn (array $stack) => (int)$stack['id'],
$this->deckService->listStacks($boardId),
);
if (!in_array($sourceStackId, $stackIds, true) || !in_array($targetStackId, $stackIds, true)) {
throw new OCSBadRequestException('The selected stack does not exist on this board');
}
}
/**
* @param string[] $filterUserIds
* @param int[] $filterLabelIds
*/
private function applyFields(
Workflow $workflow,
string $title,
int $boardId,
int $sourceStackId,
int $targetStackId,
array $filterUserIds,
array $filterLabelIds,
bool $notifyEmail,
bool $enabled,
): void {
$workflow->setTitle($title);
$workflow->setBoardId($boardId);
$workflow->setSourceStackId($sourceStackId);
$workflow->setTargetStackId($targetStackId);
$workflow->setFilterUserIds($filterUserIds === [] ? null : json_encode(array_values($filterUserIds)));
$workflow->setFilterLabelIds($filterLabelIds === [] ? null : json_encode(array_values($filterLabelIds)));
$workflow->setNotifyEmail($notifyEmail);
$workflow->setEnabled($enabled);
}
}