mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-18 05:20:50 +01:00
feat(polls): allow editing of draft polls
Signed-off-by: Anna Larch <anna@nextcloud.com> # The commit message #2 will be skipped: # fixup! feat(polls): allow editing of draft polls
This commit is contained in:
parent
1f473a0409
commit
70b43f64d2
16 changed files with 1182 additions and 78 deletions
|
|
@ -21,6 +21,8 @@ return [
|
|||
'ocs' => [
|
||||
/** @see \OCA\Talk\Controller\PollController::createPoll() */
|
||||
['name' => 'Poll#createPoll', 'url' => '/api/{apiVersion}/poll/{token}', 'verb' => 'POST', 'requirements' => $requirements],
|
||||
/** @see \OCA\Talk\Controller\PollController::updateDraftPoll() */
|
||||
['name' => 'Poll#updateDraftPoll', 'url' => '/api/{apiVersion}/poll/{token}/draft/{pollId}', 'verb' => 'POST', 'requirements' => $requirementsWithPollId],
|
||||
/** @see \OCA\Talk\Controller\PollController::getAllDraftPolls() */
|
||||
['name' => 'Poll#getAllDraftPolls', 'url' => '/api/{apiVersion}/poll/{token}/drafts', 'verb' => 'GET', 'requirements' => $requirements],
|
||||
/** @see \OCA\Talk\Controller\PollController::showPoll() */
|
||||
|
|
|
|||
|
|
@ -177,3 +177,4 @@
|
|||
* `config => conversations => description-length` (local) - The maximum length for conversation descriptions, currently 2000. Before this config was added the implicit limit was 500, since the existance of the feature capability `room-description`.
|
||||
* `call-end-to-end-encryption` - Signaling support of the server for the end-to-end encryption of calls
|
||||
* `config => call => end-to-end-encryption` - Whether calls should be end-to-end encrypted (currently off by default, until all Talk mobile clients support it)
|
||||
+ `edit-draft-poll` - Whether moderators can edit draft polls
|
||||
|
|
|
|||
25
docs/poll.md
25
docs/poll.md
|
|
@ -30,6 +30,31 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
|
|||
|
||||
See [Poll data](#poll-data)
|
||||
|
||||
# Edit a draft poll in a conversation
|
||||
|
||||
* Required capability: `edit-draft-poll`
|
||||
* Method: `POST`
|
||||
* Endpoint: `/poll/{token}/draft/{pollId}`
|
||||
* Data:
|
||||
|
||||
| field | type | Description |
|
||||
|--------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `question` | string | The question of the poll |
|
||||
| `options` | string[] | Array of strings with the voting options |
|
||||
| `resultMode` | int | The result and voting mode of the poll, `0` means participants can immediatelly see the result and who voted for which option. `1` means the result is hidden until the poll is closed and then only the summary is published. |
|
||||
| `maxVotes` | int | Maximum amount of options a participant can vote for |
|
||||
|
||||
* Response:
|
||||
- Status code:
|
||||
+ `200 OK`
|
||||
+ `400 Bad Request` Modifying poll is not possible
|
||||
+ `403 Forbidden` No permission to modify this poll
|
||||
+ `404 Not Found` When the draft poll could not be found
|
||||
|
||||
- Data:
|
||||
|
||||
See [Poll data](#poll-data)
|
||||
|
||||
## Get state or result of a poll
|
||||
|
||||
* Federation capability: `federation-v1`
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ class Capabilities implements IPublicCapability {
|
|||
'conversation-creation-password',
|
||||
'call-notification-state-api',
|
||||
'schedule-meeting',
|
||||
'edit-draft-poll',
|
||||
];
|
||||
|
||||
public const CONDITIONAL_FEATURES = [
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class PollController extends AEnvironmentAwareOCSController {
|
|||
* @psalm-param Poll::MODE_* $resultMode Mode how the results will be shown
|
||||
* @param int $maxVotes Number of maximum votes per voter
|
||||
* @param bool $draft Whether the poll should be saved as a draft (only allowed for moderators and with `talk-polls-drafts` capability)
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPollDraft, array{}>|DataResponse<Http::STATUS_CREATED, TalkPoll, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'draft'|'options'|'question'|'room'}, array{}>
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPollDraft, array{}>|DataResponse<Http::STATUS_CREATED, TalkPoll, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'draft'|'options'|'poll'|'question'|'room'}, array{}>
|
||||
*
|
||||
* 200: Draft created successfully
|
||||
* 201: Poll created successfully
|
||||
|
|
@ -133,6 +133,79 @@ class PollController extends AEnvironmentAwareOCSController {
|
|||
return new DataResponse($this->renderPoll($poll), Http::STATUS_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a draft poll
|
||||
*
|
||||
* Required capability: `edit-draft-poll`
|
||||
*
|
||||
* @param int $pollId The poll id
|
||||
* @param string $question Question of the poll
|
||||
* @param string[] $options Options of the poll
|
||||
* @psalm-param list<string> $options
|
||||
* @param 0|1 $resultMode Mode how the results will be shown
|
||||
* @psalm-param Poll::MODE_* $resultMode Mode how the results will be shown
|
||||
* @param int $maxVotes Number of maximum votes per voter
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPollDraft, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array{error: 'draft'|'options'|'poll'|'question'|'room'}, array{}>
|
||||
*
|
||||
* 200: Draft modified successfully
|
||||
* 400: Modifying poll is not possible
|
||||
* 403: No permission to modify this poll
|
||||
* 404: No draft poll exists
|
||||
*/
|
||||
#[FederationSupported]
|
||||
#[PublicPage]
|
||||
#[RequireModeratorOrNoLobby]
|
||||
#[RequireParticipant]
|
||||
#[RequirePermission(permission: RequirePermission::CHAT)]
|
||||
#[RequireReadWriteConversation]
|
||||
public function updateDraftPoll(int $pollId, string $question, array $options, int $resultMode, int $maxVotes): DataResponse {
|
||||
if ($this->room->isFederatedConversation()) {
|
||||
/** @var \OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController $proxy */
|
||||
$proxy = \OCP\Server::get(\OCA\Talk\Federation\Proxy\TalkV1\Controller\PollController::class);
|
||||
return $proxy->updateDraftPoll($pollId, $this->room, $this->participant, $question, $options, $resultMode, $maxVotes);
|
||||
}
|
||||
|
||||
if ($this->room->getType() !== Room::TYPE_GROUP
|
||||
&& $this->room->getType() !== Room::TYPE_PUBLIC) {
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_ROOM], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$poll = $this->pollService->getPoll($this->room->getId(), $pollId);
|
||||
} catch (DoesNotExistException $e) {
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_POLL], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$poll->isDraft()) {
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_POLL], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if (!$this->participant->hasModeratorPermissions()
|
||||
&& ($poll->getActorType() !== $this->participant->getAttendee()->getActorType()
|
||||
|| $poll->getActorId() !== $this->participant->getAttendee()->getActorId())) {
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_DRAFT], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$poll->setQuestion($question);
|
||||
$poll->setOptions($options);
|
||||
$poll->setResultMode($resultMode);
|
||||
$poll->setMaxVotes($maxVotes);
|
||||
} catch (PollPropertyException $e) {
|
||||
$this->logger->error('Error modifying poll', ['exception' => $e]);
|
||||
return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->pollService->updatePoll($this->participant, $poll);
|
||||
} catch (WrongPermissionsException $e) {
|
||||
$this->logger->error('Error modifying poll', ['exception' => $e]);
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_POLL], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
return new DataResponse($poll->renderAsDraft());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all drafted polls
|
||||
*
|
||||
|
|
@ -273,7 +346,7 @@ class PollController extends AEnvironmentAwareOCSController {
|
|||
*
|
||||
* @param int $pollId ID of the poll
|
||||
* @psalm-param non-negative-int $pollId
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPoll, array{}>|DataResponse<Http::STATUS_ACCEPTED, null, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array{error: string}, array{}>
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPoll, array{}>|DataResponse<Http::STATUS_ACCEPTED, null, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array{error: 'draft'|'options'|'poll'|'question'|'room'}, array{}>
|
||||
*
|
||||
* 200: Poll closed successfully
|
||||
* 202: Poll draft was deleted successfully
|
||||
|
|
@ -295,7 +368,7 @@ class PollController extends AEnvironmentAwareOCSController {
|
|||
try {
|
||||
$poll = $this->pollService->getPoll($this->room->getId(), $pollId);
|
||||
} catch (DoesNotExistException) {
|
||||
return new DataResponse(['error' => 'poll'], Http::STATUS_NOT_FOUND);
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_POLL], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($poll->getStatus() === Poll::STATUS_DRAFT) {
|
||||
|
|
@ -304,15 +377,13 @@ class PollController extends AEnvironmentAwareOCSController {
|
|||
}
|
||||
|
||||
if ($poll->getStatus() === Poll::STATUS_CLOSED) {
|
||||
return new DataResponse(['error' => 'poll'], Http::STATUS_BAD_REQUEST);
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_POLL], Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$poll->setStatus(Poll::STATUS_CLOSED);
|
||||
|
||||
try {
|
||||
$this->pollService->updatePoll($this->participant, $poll);
|
||||
} catch (WrongPermissionsException) {
|
||||
return new DataResponse(['error' => 'poll'], Http::STATUS_FORBIDDEN);
|
||||
$this->pollService->closePoll($this->participant, $poll);
|
||||
} catch (WrongPermissionsException $e) {
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_POLL], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
||||
$attendee = $this->participant->getAttendee();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace OCA\Talk\Exceptions;
|
|||
|
||||
class PollPropertyException extends \InvalidArgumentException {
|
||||
public const REASON_DRAFT = 'draft';
|
||||
public const REASON_POLL = 'poll';
|
||||
public const REASON_QUESTION = 'question';
|
||||
public const REASON_OPTIONS = 'options';
|
||||
public const REASON_ROOM = 'room';
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace OCA\Talk\Federation\Proxy\TalkV1\Controller;
|
||||
|
||||
use OCA\Talk\Exceptions\CannotReachRemoteException;
|
||||
use OCA\Talk\Exceptions\PollPropertyException;
|
||||
use OCA\Talk\Federation\Proxy\TalkV1\ProxyRequest;
|
||||
use OCA\Talk\Federation\Proxy\TalkV1\UserConverter;
|
||||
use OCA\Talk\Participant;
|
||||
|
|
@ -17,6 +18,7 @@ use OCA\Talk\ResponseDefinitions;
|
|||
use OCA\Talk\Room;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @psalm-import-type TalkPoll from ResponseDefinitions
|
||||
|
|
@ -26,6 +28,7 @@ class PollController {
|
|||
public function __construct(
|
||||
protected ProxyRequest $proxy,
|
||||
protected UserConverter $userConverter,
|
||||
protected LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +134,7 @@ class PollController {
|
|||
|
||||
|
||||
/**
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPollDraft, array{}>|DataResponse<Http::STATUS_CREATED, TalkPoll, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'draft'|'options'|'question'|'room'}, array{}>
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPollDraft, array{}>|DataResponse<Http::STATUS_CREATED, TalkPoll, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'draft'|'options'|'poll'|'question'|'room'}, array{}>
|
||||
* @throws CannotReachRemoteException
|
||||
*
|
||||
* 200: Draft created successfully
|
||||
|
|
@ -171,7 +174,46 @@ class PollController {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPoll, array{}>|DataResponse<Http::STATUS_ACCEPTED, null, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array{error: string}, array{}>
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPollDraft, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array{error: 'draft'|'options'|'poll'|'question'|'room'}, array{}>
|
||||
* @throws CannotReachRemoteException
|
||||
*
|
||||
* 200: Draft created successfully
|
||||
* 201: Poll created successfully
|
||||
* 400: Creating poll is not possible
|
||||
*
|
||||
* @see \OCA\Talk\Controller\PollController::createPoll()
|
||||
*/
|
||||
public function updateDraftPoll(int $pollId, Room $room, Participant $participant, string $question, array $options, int $resultMode, int $maxVotes): DataResponse {
|
||||
$proxy = $this->proxy->post(
|
||||
$participant->getAttendee()->getInvitedCloudId(),
|
||||
$participant->getAttendee()->getAccessToken(),
|
||||
$room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v1/poll/' . $room->getRemoteToken() . '/draft/' . $pollId,
|
||||
[
|
||||
'question' => $question,
|
||||
'options' => $options,
|
||||
'resultMode' => $resultMode,
|
||||
'maxVotes' => $maxVotes
|
||||
],
|
||||
);
|
||||
|
||||
$status = $proxy->getStatusCode();
|
||||
if ($status === Http::STATUS_BAD_REQUEST) {
|
||||
$data = $this->proxy->getOCSData($proxy, [Http::STATUS_BAD_REQUEST]);
|
||||
return new DataResponse($data, Http::STATUS_BAD_REQUEST);
|
||||
}
|
||||
|
||||
/** @var TalkPollDraft $data */
|
||||
$data = $this->proxy->getOCSData($proxy, [Http::STATUS_OK, Http::STATUS_CREATED]);
|
||||
$data = $this->userConverter->convertPoll($room, $data);
|
||||
|
||||
if ($status === Http::STATUS_OK) {
|
||||
return new DataResponse($data);
|
||||
}
|
||||
return new DataResponse($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DataResponse<Http::STATUS_OK, TalkPoll, array{}>|DataResponse<Http::STATUS_ACCEPTED, null, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array{error: 'poll'}, array{}>
|
||||
* @throws CannotReachRemoteException
|
||||
*
|
||||
* 200: Poll closed successfully
|
||||
|
|
@ -199,7 +241,12 @@ class PollController {
|
|||
}
|
||||
/** @var array{error?: string} $data */
|
||||
$data = $this->proxy->getOCSData($proxy);
|
||||
return new DataResponse(['error' => $data['error'] ?? 'poll'], $statusCode);
|
||||
|
||||
if ($data['error'] !== PollPropertyException::REASON_POLL) {
|
||||
$this->logger->error('Unhandled error in ' . __METHOD__ . ': ' . $data['error']);
|
||||
}
|
||||
|
||||
return new DataResponse(['error' => PollPropertyException::REASON_POLL], $statusCode);
|
||||
}
|
||||
|
||||
/** @var TalkPoll $data */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace OCA\Talk\Model;
|
||||
|
||||
use OCA\Talk\Exceptions\PollPropertyException;
|
||||
use OCA\Talk\ResponseDefinitions;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
|
@ -18,10 +19,8 @@ use OCP\DB\Types;
|
|||
* @method void setRoomId(int $roomId)
|
||||
* @method int getRoomId()
|
||||
* @psalm-method int<1, max> getRoomId()
|
||||
* @method void setQuestion(string $question)
|
||||
* @method string getQuestion()
|
||||
* @psalm-method non-empty-string getQuestion()
|
||||
* @method void setOptions(string $options)
|
||||
* @method string getOptions()
|
||||
* @method void setVotes(string $votes)
|
||||
* @method string getVotes()
|
||||
|
|
@ -121,4 +120,57 @@ class Poll extends Entity {
|
|||
'maxVotes' => $this->getMaxVotes(),
|
||||
];
|
||||
}
|
||||
|
||||
public function isDraft(): bool {
|
||||
return $this->getStatus() === self::STATUS_DRAFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @return void
|
||||
* @throws PollPropertyException
|
||||
*/
|
||||
public function setOptions(array $options): void {
|
||||
try {
|
||||
$jsonOptions = json_encode($options, JSON_THROW_ON_ERROR, 1);
|
||||
} catch (\Exception) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
$validOptions = [];
|
||||
foreach ($options as $option) {
|
||||
if (!is_string($option)) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
$option = trim($option);
|
||||
if ($option !== '') {
|
||||
$validOptions[] = $option;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($validOptions) < 2) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
if (strlen($jsonOptions) > 60_000) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
$this->setter('options', [$jsonOptions]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $question
|
||||
* @return void
|
||||
* @throws PollPropertyException
|
||||
*/
|
||||
public function setQuestion(string $question): void {
|
||||
$question = trim($question);
|
||||
if ($question === '' || strlen($question) > 32_000) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_QUESTION);
|
||||
}
|
||||
|
||||
$this->setter('question', [$question]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,12 +44,13 @@ class PollMapper extends QBMapper {
|
|||
* @throws DoesNotExistException
|
||||
* @throws MultipleObjectsReturnedException
|
||||
*/
|
||||
public function getByPollId(int $pollId): Poll {
|
||||
public function getPollByRoomIdAndPollId(int $roomId, int $pollId): Poll {
|
||||
$query = $this->db->getQueryBuilder();
|
||||
|
||||
$query->select('*')
|
||||
->from($this->getTableName())
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($pollId, IQueryBuilder::PARAM_INT)));
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($pollId, IQueryBuilder::PARAM_INT)))
|
||||
->andWhere($query->expr()->eq('room_id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT)));
|
||||
|
||||
return $this->findEntity($query);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,51 +33,13 @@ class PollService {
|
|||
* @throws PollPropertyException
|
||||
*/
|
||||
public function createPoll(int $roomId, string $actorType, string $actorId, string $displayName, string $question, array $options, int $resultMode, int $maxVotes, bool $draft): Poll {
|
||||
$question = trim($question);
|
||||
|
||||
if ($question === '' || strlen($question) > 32_000) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_QUESTION);
|
||||
}
|
||||
|
||||
try {
|
||||
json_encode($options, JSON_THROW_ON_ERROR, 1);
|
||||
} catch (\Exception) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
$validOptions = [];
|
||||
foreach ($options as $option) {
|
||||
if (!is_string($option)) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
$option = trim($option);
|
||||
if ($option !== '') {
|
||||
$validOptions[] = $option;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($validOptions) < 2) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
try {
|
||||
$jsonOptions = json_encode($validOptions, JSON_THROW_ON_ERROR, 1);
|
||||
} catch (\Exception) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
if (strlen($jsonOptions) > 60_000) {
|
||||
throw new PollPropertyException(PollPropertyException::REASON_OPTIONS);
|
||||
}
|
||||
|
||||
$poll = new Poll();
|
||||
$poll->setRoomId($roomId);
|
||||
$poll->setActorType($actorType);
|
||||
$poll->setActorId($actorId);
|
||||
$poll->setDisplayName($displayName);
|
||||
$poll->setQuestion($question);
|
||||
$poll->setOptions($jsonOptions);
|
||||
$poll->setOptions($options);
|
||||
$poll->setVotes(json_encode([]));
|
||||
$poll->setResultMode($resultMode);
|
||||
$poll->setMaxVotes($maxVotes);
|
||||
|
|
@ -105,13 +67,7 @@ class PollService {
|
|||
* @throws DoesNotExistException
|
||||
*/
|
||||
public function getPoll(int $roomId, int $pollId): Poll {
|
||||
$poll = $this->pollMapper->getByPollId($pollId);
|
||||
|
||||
if ($poll->getRoomId() !== $roomId) {
|
||||
throw new DoesNotExistException('Room id mismatch');
|
||||
}
|
||||
|
||||
return $poll;
|
||||
return $this->pollMapper->getPollByRoomIdAndPollId($roomId, $pollId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -121,12 +77,26 @@ class PollService {
|
|||
*/
|
||||
public function updatePoll(Participant $participant, Poll $poll): void {
|
||||
if (!$participant->hasModeratorPermissions()
|
||||
&& ($poll->getActorType() !== $participant->getAttendee()->getActorType()
|
||||
|| $poll->getActorId() !== $participant->getAttendee()->getActorId())) {
|
||||
&& ($poll->getActorType() !== $participant->getAttendee()->getActorType()
|
||||
|| $poll->getActorId() !== $participant->getAttendee()->getActorId())) {
|
||||
// Only moderators and the author of the poll can update it
|
||||
throw new WrongPermissionsException();
|
||||
}
|
||||
$this->pollMapper->update($poll);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WrongPermissionsException
|
||||
*/
|
||||
public function closePoll(Participant $participant, Poll $poll): void {
|
||||
if (!$participant->hasModeratorPermissions()
|
||||
&& ($poll->getActorType() !== $participant->getAttendee()->getActorType()
|
||||
|| $poll->getActorId() !== $participant->getAttendee()->getActorId())) {
|
||||
// Only moderators and the author of the poll can update it
|
||||
throw new WrongPermissionsException();
|
||||
}
|
||||
|
||||
$poll->setStatus(Poll::STATUS_CLOSED);
|
||||
$this->pollMapper->update($poll);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9517,6 +9517,279 @@
|
|||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/draft/{pollId}": {
|
||||
"post": {
|
||||
"operationId": "poll-update-draft-poll",
|
||||
"summary": "Modify a draft poll",
|
||||
"description": "Required capability: `edit-draft-poll`",
|
||||
"tags": [
|
||||
"poll"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question",
|
||||
"options",
|
||||
"resultMode",
|
||||
"maxVotes"
|
||||
],
|
||||
"properties": {
|
||||
"question": {
|
||||
"type": "string",
|
||||
"description": "Question of the poll"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"description": "Options of the poll",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resultMode": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"enum": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"description": "Mode how the results will be shown"
|
||||
},
|
||||
"maxVotes": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Number of maximum votes per voter"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v1"
|
||||
],
|
||||
"default": "v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]{4,30}$"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pollId",
|
||||
"in": "path",
|
||||
"description": "The poll id",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Draft modified successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/PollDraft"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Modifying poll is not possible",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"error"
|
||||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "No permission to modify this poll",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"error"
|
||||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "No draft poll exists",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"error"
|
||||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
|
|
@ -10143,7 +10416,14 @@
|
|||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10181,7 +10461,14 @@
|
|||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10219,7 +10506,14 @@
|
|||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
300
openapi.json
300
openapi.json
|
|
@ -9422,6 +9422,279 @@
|
|||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/draft/{pollId}": {
|
||||
"post": {
|
||||
"operationId": "poll-update-draft-poll",
|
||||
"summary": "Modify a draft poll",
|
||||
"description": "Required capability: `edit-draft-poll`",
|
||||
"tags": [
|
||||
"poll"
|
||||
],
|
||||
"security": [
|
||||
{},
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"question",
|
||||
"options",
|
||||
"resultMode",
|
||||
"maxVotes"
|
||||
],
|
||||
"properties": {
|
||||
"question": {
|
||||
"type": "string",
|
||||
"description": "Question of the poll"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"description": "Options of the poll",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resultMode": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"enum": [
|
||||
0,
|
||||
1
|
||||
],
|
||||
"description": "Mode how the results will be shown"
|
||||
},
|
||||
"maxVotes": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Number of maximum votes per voter"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v1"
|
||||
],
|
||||
"default": "v1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]{4,30}$"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pollId",
|
||||
"in": "path",
|
||||
"description": "The poll id",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Draft modified successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/PollDraft"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Modifying poll is not possible",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"error"
|
||||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "No permission to modify this poll",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"error"
|
||||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "No draft poll exists",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"error"
|
||||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
|
|
@ -10048,7 +10321,14 @@
|
|||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10086,7 +10366,14 @@
|
|||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10124,7 +10411,14 @@
|
|||
],
|
||||
"properties": {
|
||||
"error": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"options",
|
||||
"poll",
|
||||
"question",
|
||||
"room"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -643,6 +643,26 @@ export type paths = {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/draft/{pollId}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/**
|
||||
* Modify a draft poll
|
||||
* @description Required capability: `edit-draft-poll`
|
||||
*/
|
||||
post: operations["poll-update-draft-poll"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/drafts": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -5521,7 +5541,111 @@ export interface operations {
|
|||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "question" | "room";
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"poll-update-draft-poll": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v1";
|
||||
token: string;
|
||||
/** @description The poll id */
|
||||
pollId: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": {
|
||||
/** @description Question of the poll */
|
||||
question: string;
|
||||
/** @description Options of the poll */
|
||||
options: string[];
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Mode how the results will be shown
|
||||
* @enum {integer}
|
||||
*/
|
||||
resultMode: 0 | 1;
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Number of maximum votes per voter
|
||||
*/
|
||||
maxVotes: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Draft modified successfully */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["PollDraft"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description Modifying poll is not possible */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description No permission to modify this poll */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description No draft poll exists */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -5767,7 +5891,8 @@ export interface operations {
|
|||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
error: string;
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -5783,7 +5908,8 @@ export interface operations {
|
|||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
error: string;
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -5799,7 +5925,8 @@ export interface operations {
|
|||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
error: string;
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -643,6 +643,26 @@ export type paths = {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/draft/{pollId}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/**
|
||||
* Modify a draft poll
|
||||
* @description Required capability: `edit-draft-poll`
|
||||
*/
|
||||
post: operations["poll-update-draft-poll"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/drafts": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -5005,7 +5025,111 @@ export interface operations {
|
|||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "question" | "room";
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"poll-update-draft-poll": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v1";
|
||||
token: string;
|
||||
/** @description The poll id */
|
||||
pollId: number;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": {
|
||||
/** @description Question of the poll */
|
||||
question: string;
|
||||
/** @description Options of the poll */
|
||||
options: string[];
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Mode how the results will be shown
|
||||
* @enum {integer}
|
||||
*/
|
||||
resultMode: 0 | 1;
|
||||
/**
|
||||
* Format: int64
|
||||
* @description Number of maximum votes per voter
|
||||
*/
|
||||
maxVotes: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Draft modified successfully */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["PollDraft"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description Modifying poll is not possible */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description No permission to modify this poll */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description No draft poll exists */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -5251,7 +5375,8 @@ export interface operations {
|
|||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
error: string;
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -5267,7 +5392,8 @@ export interface operations {
|
|||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
error: string;
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -5283,7 +5409,8 @@ export interface operations {
|
|||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: {
|
||||
error: string;
|
||||
/** @enum {string} */
|
||||
error: "draft" | "options" | "poll" | "question" | "room";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2525,6 +2525,49 @@ class FeatureContext implements Context, SnippetAcceptingContext {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^user "([^"]*)" updates a draft poll in room "([^"]*)" with (\d+)(?: \((v1)\))?$/
|
||||
*
|
||||
* @param string $user
|
||||
* @param string $identifier
|
||||
* @param string $statusCode
|
||||
* @param string $apiVersion
|
||||
*/
|
||||
public function updateDraftPoll(string $user, string $identifier, string $statusCode, string $apiVersion = 'v1', ?TableNode $formData = null): void {
|
||||
$data = $formData->getRowsHash();
|
||||
$data['options'] = json_decode($data['options'], true);
|
||||
if ($data['resultMode'] === 'public') {
|
||||
$data['resultMode'] = 0;
|
||||
} elseif ($data['resultMode'] === 'hidden') {
|
||||
$data['resultMode'] = 1;
|
||||
} else {
|
||||
throw new \Exception('Invalid result mode');
|
||||
}
|
||||
if ($data['maxVotes'] === 'unlimited') {
|
||||
$data['maxVotes'] = 0;
|
||||
}
|
||||
|
||||
$this->setCurrentUser($user);
|
||||
$result = preg_match('/POLL_ID\(([^)]+)\)/', $data['id'], $matches);
|
||||
if ($result) {
|
||||
$data['id'] = self::$questionToPollId[$matches[1]];
|
||||
}
|
||||
$this->sendRequest(
|
||||
'POST', '/apps/spreed/api/' . $apiVersion . '/poll/' . self::$identifierToToken[$identifier] . '/draft/' . $data['id'],
|
||||
$data
|
||||
);
|
||||
$this->assertStatusCode($this->response, $statusCode);
|
||||
|
||||
if ($statusCode !== '200') {
|
||||
return;
|
||||
}
|
||||
|
||||
$response = $this->getDataFromResponse($this->response);
|
||||
if (isset($response['id'])) {
|
||||
self::$questionToPollId[$data['question']] = $response['id'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^user "([^"]*)" gets poll drafts for room "([^"]*)" with (\d+)(?: \((v1)\))?$/
|
||||
*
|
||||
|
|
|
|||
|
|
@ -863,3 +863,51 @@ Feature: chat-2/poll
|
|||
| room | actorType | actorId | systemMessage | message | silent | messageParameters |
|
||||
| room | users | participant1 | user_added | {actor} added you | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"},"user":{"type":"user","id":"participant2","name":"participant2-displayname"}} |
|
||||
| room | users | participant1 | conversation_created | {actor} created the conversation | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"}} |
|
||||
|
||||
Scenario: Update a Draft Poll
|
||||
Given user "participant1" creates room "room" (v4)
|
||||
| roomType | 2 |
|
||||
| roomName | room |
|
||||
When user "participant1" adds user "participant2" to room "room" with 200 (v4)
|
||||
When user "participant1" creates a poll in room "room" with 200
|
||||
| question | What is the question? |
|
||||
| options | ["You","me"] |
|
||||
| resultMode | public |
|
||||
| maxVotes | unlimited |
|
||||
| draft | 1 |
|
||||
When user "participant1" gets poll drafts for room "room" with 200
|
||||
| id | question | options | actorType | actorId | actorDisplayName | status | resultMode | maxVotes |
|
||||
| POLL_ID(What is the question?) | What is the question? | ["You","me"] | users | participant1 | participant1-displayname | draft | public | 0 |
|
||||
Then user "participant1" updates a draft poll in room "room" with 200
|
||||
| id | POLL_ID(What is the question?) |
|
||||
| question | What is the question again? |
|
||||
| options | ["You","her"] |
|
||||
| resultMode | public |
|
||||
| maxVotes | unlimited |
|
||||
When user "participant1" gets poll drafts for room "room" with 200
|
||||
| id | question | options | actorType | actorId | actorDisplayName | status | resultMode | maxVotes |
|
||||
| POLL_ID(What is the question?) | What is the question again? | ["You","her"] | users | participant1 | participant1-displayname | draft | public | 0 |
|
||||
|
||||
Scenario: Update a Draft Poll fails
|
||||
Given user "participant1" creates room "room" (v4)
|
||||
| roomType | 2 |
|
||||
| roomName | room |
|
||||
When user "participant1" adds user "participant2" to room "room" with 200 (v4)
|
||||
When user "participant1" creates a poll in room "room" with 200
|
||||
| question | What is the question? |
|
||||
| options | ["You","me"] |
|
||||
| resultMode | public |
|
||||
| maxVotes | unlimited |
|
||||
| draft | 1 |
|
||||
When user "participant1" gets poll drafts for room "room" with 200
|
||||
| id | question | options | actorType | actorId | actorDisplayName | status | resultMode | maxVotes |
|
||||
| POLL_ID(What is the question?) | What is the question? | ["You","me"] | users | participant1 | participant1-displayname | draft | public | 0 |
|
||||
Then user "participant1" updates a draft poll in room "room" with 400
|
||||
| id | POLL_ID(What is the question?) |
|
||||
| question | What is the question again? |
|
||||
| options | [""] |
|
||||
| resultMode | public |
|
||||
| maxVotes | unlimited |
|
||||
When user "participant1" gets poll drafts for room "room" with 200
|
||||
| id | question | options | actorType | actorId | actorDisplayName | status | resultMode | maxVotes |
|
||||
| POLL_ID(What is the question?) | What is the question? | ["You","me"] | users | participant1 | participant1-displayname | draft | public | 0 |
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue