feat(polls): Allow moderators to draft polls

Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
Joas Schilling 2024-10-10 11:01:32 +02:00
parent 81c8bfca58
commit 7adfeb2218
No known key found for this signature in database
GPG key ID: F72FA5B49FFA96B0
14 changed files with 736 additions and 26 deletions

View file

@ -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::getAllDraftPolls() */
['name' => 'Poll#getAllDraftPolls', 'url' => '/api/{apiVersion}/poll/{token}/drafts', 'verb' => 'GET', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\PollController::showPoll() */
['name' => 'Poll#showPoll', 'url' => '/api/{apiVersion}/poll/{token}/{pollId}', 'verb' => 'GET', 'requirements' => $requirementsWithPollId],
/** @see \OCA\Talk\Controller\PollController::votePoll() */

View file

@ -158,4 +158,5 @@
## 20.1
* `archived-conversations` (local) - Conversations can be marked as archived which will hide them from the conversation list by default
* `talk-polls-drafts` - Whether moderators can store and retrieve poll drafts
* `config => call => start-without-media` (local) - Boolean, whether media should be disabled when starting or joining a conversation

View file

@ -104,6 +104,7 @@ class Capabilities implements IPublicCapability {
'mention-permissions',
'edit-messages-note-to-self',
'archived-conversations',
'talk-polls-drafts',
];
public const LOCAL_FEATURES = [

View file

@ -14,6 +14,7 @@ use OCA\Talk\Chat\ChatManager;
use OCA\Talk\Exceptions\WrongPermissionsException;
use OCA\Talk\Middleware\Attribute\FederationSupported;
use OCA\Talk\Middleware\Attribute\RequireModeratorOrNoLobby;
use OCA\Talk\Middleware\Attribute\RequireModeratorParticipant;
use OCA\Talk\Middleware\Attribute\RequireParticipant;
use OCA\Talk\Middleware\Attribute\RequirePermission;
use OCA\Talk\Middleware\Attribute\RequireReadWriteConversation;
@ -58,6 +59,7 @@ class PollController extends AEnvironmentAwareController {
* @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
* @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_CREATED, TalkPoll, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array<empty>, array{}>
*
* 201: Poll created successfully
@ -69,11 +71,11 @@ class PollController extends AEnvironmentAwareController {
#[RequireParticipant]
#[RequirePermission(permission: RequirePermission::CHAT)]
#[RequireReadWriteConversation]
public function createPoll(string $question, array $options, int $resultMode, int $maxVotes): DataResponse {
public function createPoll(string $question, array $options, int $resultMode, int $maxVotes, bool $draft = false): 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->createPoll($this->room, $this->participant, $question, $options, $resultMode, $maxVotes);
return $proxy->createPoll($this->room, $this->participant, $question, $options, $resultMode, $maxVotes, $draft);
}
if ($this->room->getType() !== Room::TYPE_GROUP
@ -81,6 +83,10 @@ class PollController extends AEnvironmentAwareController {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
if ($draft === true && !$this->participant->hasModeratorPermissions()) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
$attendee = $this->participant->getAttendee();
try {
$poll = $this->pollService->createPoll(
@ -91,33 +97,66 @@ class PollController extends AEnvironmentAwareController {
$question,
$options,
$resultMode,
$maxVotes
$maxVotes,
$draft,
);
} catch (\Exception $e) {
$this->logger->error('Error creating poll', ['exception' => $e]);
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
$message = json_encode([
'message' => 'object_shared',
'parameters' => [
'objectType' => 'talk-poll',
'objectId' => $poll->getId(),
'metaData' => [
'type' => 'talk-poll',
'id' => $poll->getId(),
'name' => $question,
]
],
], JSON_THROW_ON_ERROR);
if (!$draft) {
$message = json_encode([
'message' => 'object_shared',
'parameters' => [
'objectType' => 'talk-poll',
'objectId' => $poll->getId(),
'metaData' => [
'type' => 'talk-poll',
'id' => $poll->getId(),
'name' => $question,
]
],
], JSON_THROW_ON_ERROR);
try {
$this->chatManager->addSystemMessage($this->room, $attendee->getActorType(), $attendee->getActorId(), $message, $this->timeFactory->getDateTime(), true);
} catch (\Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
try {
$this->chatManager->addSystemMessage($this->room, $attendee->getActorType(), $attendee->getActorId(), $message, $this->timeFactory->getDateTime(), true);
} catch (\Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
}
}
return new DataResponse($this->renderPoll($poll, []), Http::STATUS_CREATED);
return new DataResponse($this->renderPoll($poll), Http::STATUS_CREATED);
}
/**
* Get all drafted polls
*
* Required capability: `talk-polls-drafts`
*
* @return DataResponse<Http::STATUS_OK, list<TalkPoll>, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, list<empty>, array{}>
*
* 200: Poll returned
* 403: User is not a moderator
* 404: Poll not found
*/
#[FederationSupported]
#[PublicPage]
#[RequireModeratorParticipant]
public function getAllDraftPolls(): 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->getDraftsForRoom($this->room, $this->participant);
}
$polls = $this->pollService->getDraftsForRoom($this->room->getId());
$data = [];
foreach ($polls as $poll) {
$data[] = $this->renderPoll($poll);
}
return new DataResponse($data);
}
/**
@ -143,7 +182,11 @@ class PollController extends AEnvironmentAwareController {
try {
$poll = $this->pollService->getPoll($this->room->getId(), $pollId);
} catch (DoesNotExistException $e) {
} catch (DoesNotExistException) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if ($poll->getStatus() === Poll::STATUS_DRAFT && !$this->participant->hasModeratorPermissions()) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
@ -181,7 +224,11 @@ class PollController extends AEnvironmentAwareController {
try {
$poll = $this->pollService->getPoll($this->room->getId(), $pollId);
} catch (\Exception $e) {
} catch (DoesNotExistException) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if ($poll->getStatus() === Poll::STATUS_DRAFT) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
@ -222,9 +269,10 @@ class PollController extends AEnvironmentAwareController {
*
* @param int $pollId ID of the poll
* @psalm-param non-negative-int $pollId
* @return DataResponse<Http::STATUS_OK, TalkPoll, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array<empty>, array{}>
* @return DataResponse<Http::STATUS_OK, TalkPoll, array{}>|DataResponse<Http::STATUS_ACCEPTED|Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array<empty>, array{}>
*
* 200: Poll closed successfully
* 202: Poll draft was deleted successfully
* 400: Poll already closed
* 403: Missing permissions to close poll
* 404: Poll not found
@ -242,10 +290,15 @@ class PollController extends AEnvironmentAwareController {
try {
$poll = $this->pollService->getPoll($this->room->getId(), $pollId);
} catch (\Exception $e) {
} catch (DoesNotExistException) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if ($poll->getStatus() === Poll::STATUS_DRAFT) {
$this->pollService->deleteByPollId($poll->getId());
return new DataResponse([], Http::STATUS_ACCEPTED);
}
if ($poll->getStatus() === Poll::STATUS_CLOSED) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

View file

@ -28,6 +28,38 @@ class PollController {
) {
}
/**
* @return DataResponse<Http::STATUS_OK, list<TalkPoll>, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, list<empty>, array{}>
* @throws CannotReachRemoteException
*
* 200: Polls returned
* 404: Polls not found
*
* @see \OCA\Talk\Controller\PollController::showPoll()
*/
public function getDraftsForRoom(Room $room, Participant $participant): DataResponse {
$proxy = $this->proxy->get(
$participant->getAttendee()->getInvitedCloudId(),
$participant->getAttendee()->getAccessToken(),
$room->getRemoteServer() . '/ocs/v2.php/apps/spreed/api/v1/poll/' . $room->getRemoteToken() . '/drafts',
);
$status = $proxy->getStatusCode();
if ($status === Http::STATUS_NOT_FOUND || $status === Http::STATUS_FORBIDDEN) {
return new DataResponse([], $status);
}
/** @var list<TalkPoll> $list */
$list = $this->proxy->getOCSData($proxy);
$data = [];
foreach ($list as $poll) {
$data[] = $this->userConverter->convertPoll($room, $poll);
}
return new DataResponse($data);
}
/**
* @return DataResponse<Http::STATUS_OK, TalkPoll, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array<empty>, array{}>
* @throws CannotReachRemoteException
@ -101,7 +133,7 @@ class PollController {
*
* @see \OCA\Talk\Controller\PollController::createPoll()
*/
public function createPoll(Room $room, Participant $participant, string $question, array $options, int $resultMode, int $maxVotes): DataResponse {
public function createPoll(Room $room, Participant $participant, string $question, array $options, int $resultMode, int $maxVotes, bool $draft): DataResponse {
$proxy = $this->proxy->post(
$participant->getAttendee()->getInvitedCloudId(),
$participant->getAttendee()->getAccessToken(),
@ -111,6 +143,7 @@ class PollController {
'options' => $options,
'resultMode' => $resultMode,
'maxVotes' => $maxVotes,
'draft' => $draft,
],
);

View file

@ -41,6 +41,7 @@ use OCP\AppFramework\Db\Entity;
class Poll extends Entity {
public const STATUS_OPEN = 0;
public const STATUS_CLOSED = 1;
public const STATUS_DRAFT = 2;
public const MODE_PUBLIC = 0;
public const MODE_HIDDEN = 1;
public const MAX_VOTES_UNLIMITED = 0;

View file

@ -27,6 +27,20 @@ class PollMapper extends QBMapper {
parent::__construct($db, 'talk_polls', Poll::class);
}
/**
* @return Poll[]
*/
public function getDraftsByRoomId(int $roomId): array {
$query = $this->db->getQueryBuilder();
$query->select('*')
->from($this->getTableName())
->where($query->expr()->eq('room_id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('status', $query->createNamedParameter(Poll::STATUS_DRAFT, IQueryBuilder::PARAM_INT)));
return $this->findEntities($query);
}
/**
* @param int $pollId
* @return Poll

View file

@ -29,7 +29,7 @@ class PollService {
) {
}
public function createPoll(int $roomId, string $actorType, string $actorId, string $displayName, string $question, array $options, int $resultMode, int $maxVotes): Poll {
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) {
@ -78,12 +78,23 @@ class PollService {
$poll->setVotes(json_encode([]));
$poll->setResultMode($resultMode);
$poll->setMaxVotes($maxVotes);
if ($draft) {
$poll->setStatus(Poll::STATUS_DRAFT);
}
$this->pollMapper->insert($poll);
return $poll;
}
/**
* @param int $roomId
* @return Poll[]
*/
public function getDraftsForRoom(int $roomId): array {
return $this->pollMapper->getDraftsByRoomId($roomId);
}
/**
* @param int $roomId
* @param int $pollId

View file

@ -8724,6 +8724,11 @@
"type": "integer",
"format": "int64",
"description": "Number of maximum votes per voter"
},
"draft": {
"type": "boolean",
"default": false,
"description": "Whether the poll should be saved as a draft (only allowed for moderators and with `talk-polls-drafts` capability)"
}
}
}
@ -8825,6 +8830,149 @@
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/drafts": {
"get": {
"operationId": "poll-get-all-draft-polls",
"summary": "Get all drafted polls",
"description": "Required capability: `talk-polls-drafts`",
"tags": [
"poll"
],
"security": [
{},
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"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": "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": "Poll returned",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Poll"
}
}
}
}
}
}
}
}
},
"403": {
"description": "User is not a moderator",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
},
"404": {
"description": "Poll not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/{pollId}": {
"get": {
"operationId": "poll-show-poll",
@ -9205,6 +9353,34 @@
}
}
},
"202": {
"description": "Poll draft was deleted successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
},
"400": {
"description": "Poll already closed",
"content": {

View file

@ -8611,6 +8611,11 @@
"type": "integer",
"format": "int64",
"description": "Number of maximum votes per voter"
},
"draft": {
"type": "boolean",
"default": false,
"description": "Whether the poll should be saved as a draft (only allowed for moderators and with `talk-polls-drafts` capability)"
}
}
}
@ -8712,6 +8717,149 @@
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/drafts": {
"get": {
"operationId": "poll-get-all-draft-polls",
"summary": "Get all drafted polls",
"description": "Required capability: `talk-polls-drafts`",
"tags": [
"poll"
],
"security": [
{},
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"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": "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": "Poll returned",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Poll"
}
}
}
}
}
}
}
}
},
"403": {
"description": "User is not a moderator",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
},
"404": {
"description": "Poll not found",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/{pollId}": {
"get": {
"operationId": "poll-show-poll",
@ -9092,6 +9240,34 @@
}
}
},
"202": {
"description": "Poll draft was deleted successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
},
"400": {
"description": "Poll already closed",
"content": {

View file

@ -583,6 +583,26 @@ export type paths = {
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/drafts": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get all drafted polls
* @description Required capability: `talk-polls-drafts`
*/
get: operations["poll-get-all-draft-polls"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/{pollId}": {
parameters: {
query?: never;
@ -5112,6 +5132,11 @@ export interface operations {
* @description Number of maximum votes per voter
*/
maxVotes: number;
/**
* @description Whether the poll should be saved as a draft (only allowed for moderators and with `talk-polls-drafts` capability)
* @default false
*/
draft?: boolean;
};
};
};
@ -5146,6 +5171,65 @@ export interface operations {
};
};
};
"poll-get-all-draft-polls": {
parameters: {
query?: never;
header: {
/** @description Required to be true for the API request to pass */
"OCS-APIRequest": boolean;
};
path: {
apiVersion: "v1";
token: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Poll returned */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: components["schemas"]["Poll"][];
};
};
};
};
/** @description User is not a moderator */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: unknown;
};
};
};
};
/** @description Poll not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: unknown;
};
};
};
};
};
};
"poll-show-poll": {
parameters: {
query?: never;
@ -5295,6 +5379,20 @@ export interface operations {
};
};
};
/** @description Poll draft was deleted successfully */
202: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: unknown;
};
};
};
};
/** @description Poll already closed */
400: {
headers: {

View file

@ -583,6 +583,26 @@ export type paths = {
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/drafts": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get all drafted polls
* @description Required capability: `talk-polls-drafts`
*/
get: operations["poll-get-all-draft-polls"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/poll/{token}/{pollId}": {
parameters: {
query?: never;
@ -4593,6 +4613,11 @@ export interface operations {
* @description Number of maximum votes per voter
*/
maxVotes: number;
/**
* @description Whether the poll should be saved as a draft (only allowed for moderators and with `talk-polls-drafts` capability)
* @default false
*/
draft?: boolean;
};
};
};
@ -4627,6 +4652,65 @@ export interface operations {
};
};
};
"poll-get-all-draft-polls": {
parameters: {
query?: never;
header: {
/** @description Required to be true for the API request to pass */
"OCS-APIRequest": boolean;
};
path: {
apiVersion: "v1";
token: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Poll returned */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: components["schemas"]["Poll"][];
};
};
};
};
/** @description User is not a moderator */
403: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: unknown;
};
};
};
};
/** @description Poll not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: unknown;
};
};
};
};
};
};
"poll-show-poll": {
parameters: {
query?: never;
@ -4776,6 +4860,20 @@ export interface operations {
};
};
};
/** @description Poll draft was deleted successfully */
202: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
ocs: {
meta: components["schemas"]["OCSMeta"];
data: unknown;
};
};
};
};
/** @description Poll already closed */
400: {
headers: {

View file

@ -2407,6 +2407,9 @@ class FeatureContext implements Context, SnippetAcceptingContext {
if ($data['maxVotes'] === 'unlimited') {
$data['maxVotes'] = 0;
}
if (isset($data['draft'])) {
$data['draft'] = (bool)$data['draft'];
}
$this->setCurrentUser($user);
$this->sendRequest(
@ -2528,6 +2531,8 @@ class FeatureContext implements Context, SnippetAcceptingContext {
$expected['status'] = 0;
} elseif ($expected['status'] === 'closed') {
$expected['status'] = 1;
} elseif ($expected['status'] === 'draft') {
$expected['status'] = 2;
}
if (str_ends_with($expected['actorId'], '@{$LOCAL_URL}')) {

View file

@ -805,3 +805,44 @@ Feature: chat-2/poll
Then user "participant1" sees the following system messages in room "room" with 200 (v1)
| room | actorType | actorId | systemMessage | message | silent | messageParameters |
| room | users | participant1 | history_cleared | You cleared the history of the conversation | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"}} |
Scenario: Create a public poll without max votes limit
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 201
| question | What is the question? |
| options | ["Where are you?","How much is the fish?"] |
| resultMode | public |
| maxVotes | unlimited |
| draft | 1 |
Then user "participant1" sees the following messages in room "room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters |
Then user "participant1" sees poll "What is the question?" in room "room" with 200
| id | POLL_ID(What is the question?) |
| question | What is the question? |
| options | ["Where are you?","How much is the fish?"] |
| votes | [] |
| numVoters | 0 |
| resultMode | public |
| maxVotes | unlimited |
| actorType | users |
| actorId | participant1 |
| actorDisplayName | participant1-displayname |
| status | draft |
| votedSelf | not voted |
Then user "participant2" sees poll "What is the question?" in room "room" with 404
Then user "participant1" votes for options "[1]" on poll "What is the question?" in room "room" with 404
Then user "participant2" votes for options "[1]" on poll "What is the question?" in room "room" with 404
Then user "participant1" closes poll "What is the question?" in room "room" with 202
Then user "participant1" sees poll "What is the question?" in room "room" with 404
Then user "participant2" sees poll "What is the question?" in room "room" with 404
Then user "participant1" sees the following system messages in room "room" with 200 (v1)
| room | actorType | actorId | systemMessage | message | silent | messageParameters |
| room | users | participant1 | user_added | You added {user} | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"},"user":{"type":"user","id":"participant2","name":"participant2-displayname"}} |
| room | users | participant1 | conversation_created | You created the conversation | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"}} |
Then user "participant2" sees the following system messages in room "room" with 200 (v1)
| 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"}} |