Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(calls): Allow moderators to download a call participants list #13519

Merged
merged 1 commit into from
Oct 15, 2024
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
2 changes: 2 additions & 0 deletions appinfo/routes/routesCallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
'ocs' => [
/** @see \OCA\Talk\Controller\CallController::getPeersForCall() */
['name' => 'Call#getPeersForCall', 'url' => '/api/{apiVersion}/call/{token}', 'verb' => 'GET', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\CallController::downloadParticipantsForCall() */
['name' => 'Call#downloadParticipantsForCall', 'url' => '/api/{apiVersion}/call/{token}/download', 'verb' => 'GET', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\CallController::joinCall() */
['name' => 'Call#joinCall', 'url' => '/api/{apiVersion}/call/{token}', 'verb' => 'POST', 'requirements' => $requirements],
/** @see \OCA\Talk\Controller\CallController::joinFederatedCall() */
Expand Down
1 change: 1 addition & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,5 +159,6 @@
## 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
* `download-call-participants` - Whether the endpoints for moderators to download the call participants is available
* `config => call => start-without-media` (local) - Boolean, whether media should be disabled when starting or joining a conversation
* `config => call => max-duration` - Integer, maximum call duration in seconds. Please note that this should only be used with system cron and with a reasonable high value, due to the expended duration until the background job ran.
1 change: 1 addition & 0 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class Capabilities implements IPublicCapability {
'edit-messages-note-to-self',
'archived-conversations',
'talk-polls-drafts',
'download-call-participants',
];

public const LOCAL_FEATURES = [
Expand Down
50 changes: 50 additions & 0 deletions lib/Controller/CallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use OCA\Talk\Middleware\Attribute\RequireCallEnabled;
use OCA\Talk\Middleware\Attribute\RequireFederatedParticipant;
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;
Expand All @@ -33,7 +34,9 @@
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\DataDownloadResponse;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IRequest;
use OCP\IUserManager;
Expand Down Expand Up @@ -111,6 +114,53 @@ public function getPeersForCall(): DataResponse {
return new DataResponse($result);
}

/**
* Download the list of current call participants
*
* Required capability: `download-call-participants`
*
* @param 'csv'|'pdf' $format Download format
* @return DataDownloadResponse<Http::STATUS_OK, 'text/csv'|'application/pdf', array{}>|Response<Http::STATUS_BAD_REQUEST, array{}>
*
* 200: List of participants in the call downloaded in the requested format
* 400: No call in progress
*/
#[PublicPage]
#[RequireModeratorParticipant]
public function downloadParticipantsForCall(string $format = 'csv'): DataDownloadResponse|Response {
$timeout = $this->timeFactory->getTime() - Session::SESSION_TIMEOUT;
$participants = $this->participantService->getParticipantsInCall($this->room, $timeout);

if (empty($participants)) {
return new Response(Http::STATUS_BAD_REQUEST);
}

if ($format !== 'csv' && $format !== 'pdf') {
// Unsupported format
return new Response(Http::STATUS_BAD_REQUEST);
}

if ($format !== 'csv') {
// FIXME Remove once pdf was implemented.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Currently only CSV is functional

return new Response(Http::STATUS_BAD_REQUEST);
}

$output = fopen('php://memory', 'w');
fputcsv($output, [
'name',
'type',
'identifier',
]);
Comment on lines +149 to +153
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we prettify the output? (headers with capital letters)
image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that for the PDF version later. For the CSV I would keep it "ugly"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as-is should be less confusing for later use (like import)


foreach ($participants as $participant) {
fputcsv($output, [$participant->getAttendee()->getDisplayName(), $participant->getAttendee()->getActorType(), $participant->getAttendee()->getActorId()]);
}

fseek($output, 0);

return new DataDownloadResponse(stream_get_contents($output), 'participants.csv', 'text/csv');
}

/**
* Join a call
*
Expand Down
87 changes: 87 additions & 0 deletions openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -4544,6 +4544,93 @@
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}/download": {
"get": {
"operationId": "call-download-participants-for-call",
"summary": "Download the list of current call participants",
"description": "Required capability: `download-call-participants`",
"tags": [
"call"
],
"security": [
{},
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v4"
],
"default": "v4"
}
},
{
"name": "token",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^[a-z0-9]{4,30}$"
}
},
{
"name": "format",
"in": "query",
"description": "Download format",
"schema": {
"type": "string",
"default": "csv",
"enum": [
"csv",
"pdf"
]
}
},
{
"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": "List of participants in the call downloaded in the requested format",
"content": {
"text/csv": {
"schema": {
"type": "string",
"format": "binary"
}
},
"application/pdf": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"400": {
"description": "No call in progress"
}
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}/federation": {
"post": {
"operationId": "call-join-federated-call",
Expand Down
87 changes: 87 additions & 0 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -4431,6 +4431,93 @@
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}/download": {
"get": {
"operationId": "call-download-participants-for-call",
"summary": "Download the list of current call participants",
"description": "Required capability: `download-call-participants`",
"tags": [
"call"
],
"security": [
{},
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "apiVersion",
"in": "path",
"required": true,
"schema": {
"type": "string",
"enum": [
"v4"
],
"default": "v4"
}
},
{
"name": "token",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^[a-z0-9]{4,30}$"
}
},
{
"name": "format",
"in": "query",
"description": "Download format",
"schema": {
"type": "string",
"default": "csv",
"enum": [
"csv",
"pdf"
]
}
},
{
"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": "List of participants in the call downloaded in the requested format",
"content": {
"text/csv": {
"schema": {
"type": "string",
"format": "binary"
}
},
"application/pdf": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"400": {
"description": "No call in progress"
}
}
}
},
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}/federation": {
"post": {
"operationId": "call-join-federated-call",
Expand Down
57 changes: 57 additions & 0 deletions src/types/openapi/openapi-full.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,26 @@ export type paths = {
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}/download": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Download the list of current call participants
* @description Required capability: `download-call-participants`
*/
get: operations["call-download-participants-for-call"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}/federation": {
parameters: {
query?: never;
Expand Down Expand Up @@ -3443,6 +3463,43 @@ export interface operations {
};
};
};
"call-download-participants-for-call": {
parameters: {
query?: {
/** @description Download format */
format?: "csv" | "pdf";
};
header: {
/** @description Required to be true for the API request to pass */
"OCS-APIRequest": boolean;
};
path: {
apiVersion: "v4";
token: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description List of participants in the call downloaded in the requested format */
200: {
headers: {
[name: string]: unknown;
};
content: {
"text/csv": string;
"application/pdf": string;
};
};
/** @description No call in progress */
400: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
"call-update-federated-call-flags": {
parameters: {
query?: never;
Expand Down
Loading
Loading