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
30 changes: 15 additions & 15 deletions .github/workflows/test-cc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,19 @@ jobs:
- name: codecov upload
uses: codecov/codecov-action@v1

- name: Setup Code Climate test-reporter
run: |
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
chmod +x ./cc-test-reporter

- name: SafeDirFix
run: git config --global safe.directory '*'

- name: Convert
run: ./cc-test-reporter format-coverage coverage.xml -t clover -o codeclimate.0.json

- name: Upload
run: ./cc-test-reporter upload-coverage -i codeclimate.0.json
env:
CC_TEST_REPORTER_ID: 915c317f6988c594001f3f74d7e1b1c919c04fde6ff24421291c6f0f2a345ab0
# - name: Setup Code Climate test-reporter
# run: |
# curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
# chmod +x ./cc-test-reporter
#
# - name: SafeDirFix
# run: git config --global safe.directory '*'
#
# - name: Convert
# run: ./cc-test-reporter format-coverage coverage.xml -t clover -o codeclimate.0.json
#
# - name: Upload
# run: ./cc-test-reporter upload-coverage -i codeclimate.0.json
# env:
# CC_TEST_REPORTER_ID: 915c317f6988c594001f3f74d7e1b1c919c04fde6ff24421291c6f0f2a345ab0

51 changes: 51 additions & 0 deletions src/Dto/GenerateSignedScreenUrlsDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace EscolaLms\Webinar\Dto;

class GenerateSignedScreenUrlsDto extends BaseDto
{
protected int $webinarId;
protected string $executedAt;
protected array $files;
protected int $userId;

public function getWebinarId(): int
{
return $this->webinarId;
}

public function setWebinarId(int $webinarId): void
{
$this->webinarId = $webinarId;
}

public function getExecutedAt(): string
{
return $this->executedAt;
}

public function setExecutedAt(string $executedAt): void
{
$this->executedAt = $executedAt;
}

public function getFiles(): array
{
return $this->files;
}

public function setFiles(array $files): void
{
$this->files = $files;
}

public function getUserId(): int
{
return $this->userId;
}

public function setUserId(int $userId): void
{
$this->userId = $userId;
}
}
73 changes: 73 additions & 0 deletions src/Http/Controllers/Swagger/WebinarAPISwagger.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace EscolaLms\Webinar\Http\Controllers\Swagger;

use EscolaLms\Webinar\Http\Requests\GenerateSignedScreenUrlsRequest;
use EscolaLms\Webinar\Http\Requests\ListWebinarsRequest;
use Illuminate\Http\JsonResponse;

Expand Down Expand Up @@ -335,4 +336,76 @@ public function forCurrentUser(ListWebinarsRequest $listWebinarsRequest): JsonRe
* )
*/
public function startLiveStream(int $id): void;

/**
* @OA\Post(
* path="/api/webinars/signed-screen-urls",
* security={
* {"passport": {}},
* },
* summary="Generate signed url to save screens from jitsi meeting",
* tags={"Webinars"},
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* @OA\Property(
* property="webinar_id",
* type="int"
* ),
* @OA\Property(
* property="user_id",
* type="integer"
* ),
* @OA\Property(
* property="executed_at",
* type="string",
* example="2024-10-04 12:02:12"
* ),
* @OA\Property(
* property="files",
* type="array",
* @OA\Items(
* @OA\Property(
* property="filename",
* type="string",
* ),
* )
* )
* )
* )
* ),
* @OA\Response(
* response=200,
* description="successful operation",
* @OA\MediaType(
* mediaType="application/json"
* ),
* @OA\Schema(
* type="object",
* @OA\Property(
* property="success",
* type="boolean"
* ),
* @OA\Property(
* property="data",
* type="string"
* ),
* @OA\Property(
* property="message",
* type="string"
* )
* )
* ),
* @OA\Response(
* response=404,
* description="Bad request",
* @OA\MediaType(
* mediaType="application/json"
* )
* )
* )
*/
public function generateSignedScreenUrls(GenerateSignedScreenUrlsRequest $request): JsonResponse;
}
9 changes: 9 additions & 0 deletions src/Http/Controllers/WebinarAPIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use EscolaLms\Core\Dtos\OrderDto;
use EscolaLms\Core\Http\Controllers\EscolaLmsBaseController;
use EscolaLms\Webinar\Dto\GenerateSignedScreenUrlsDto;
use EscolaLms\Webinar\Enum\ConstantEnum;
use EscolaLms\Webinar\Http\Controllers\Swagger\WebinarAPISwagger;
use EscolaLms\Webinar\Http\Requests\GenerateSignedScreenUrlsRequest;
use EscolaLms\Webinar\Http\Requests\ListWebinarsRequest;
use EscolaLms\Webinar\Http\Resources\WebinarSimpleResource;
use EscolaLms\Webinar\Services\Contracts\WebinarServiceContract;
Expand Down Expand Up @@ -94,4 +96,11 @@ public function stopLiveStream(int $id): void
*/
$this->webinarServiceContract->setStatusInLiveStreamInYt($id, 'complete');
}

public function generateSignedScreenUrls(GenerateSignedScreenUrlsRequest $request): JsonResponse
{
$data = $this->webinarServiceContract->generateSignedScreenUrls(new GenerateSignedScreenUrlsDto($request->validated()));

return $this->sendResponse($data, __('Urls generated successfully'));
}
}
19 changes: 19 additions & 0 deletions src/Http/Requests/GenerateSignedScreenUrlsRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace EscolaLms\Webinar\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class GenerateSignedScreenUrlsRequest extends FormRequest
{
public function rules(): array
{
return [
'webinar_id' => ['required', 'integer'],
'user_id' => ['required', 'integer'],
'executed_at' => ['required'],
'files' => ['array', 'min:1'],
'files.*.filename' => ['required', 'string'],
];
}
}
2 changes: 2 additions & 0 deletions src/Services/Contracts/WebinarServiceContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Carbon\Carbon;
use EscolaLms\Auth\Models\User;
use EscolaLms\Core\Dtos\OrderDto;
use EscolaLms\Webinar\Dto\GenerateSignedScreenUrlsDto;
use EscolaLms\Webinar\Dto\WebinarDto;
use EscolaLms\Webinar\Models\Webinar;
use Illuminate\Database\Eloquent\Builder;
Expand Down Expand Up @@ -67,4 +68,5 @@ public function reminderAboutWebinar(string $reminderStatus): void;
public function getWebinarEndDate(Webinar $webinar): ?Carbon;
public function setStatusInLiveStreamInYt(int $webinarId, string $broadcastStatus): void;
public function setReminderStatus(Webinar $webinar, string $status): void;
public function generateSignedScreenUrls(GenerateSignedScreenUrlsDto $dto): array;
}
27 changes: 27 additions & 0 deletions src/Services/WebinarService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use EscolaLms\Jitsi\Helpers\StringHelper;
use EscolaLms\Jitsi\Services\Contracts\JitsiServiceContract;
use EscolaLms\Webinar\Dto\FilterListDto;
use EscolaLms\Webinar\Dto\GenerateSignedScreenUrlsDto;
use EscolaLms\Webinar\Dto\WebinarDto;
use EscolaLms\Webinar\Enum\ConstantEnum;
use EscolaLms\Webinar\Events\ReminderAboutTerm;
Expand All @@ -24,6 +25,7 @@
use EscolaLms\Youtube\Services\Contracts\YoutubeServiceContract;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class WebinarService implements WebinarServiceContract
Expand Down Expand Up @@ -361,4 +363,29 @@ public function getWebinarEndDate(Webinar $webinar): ?Carbon

return $webinar->active_to ? Carbon::make($webinar->active_to) : null;
}

public function generateSignedScreenUrls(GenerateSignedScreenUrlsDto $dto): array
{
if (config('filesystems.default') !== 's3') {
abort(400, 'The file driver does not support this method.');
}

$term = Carbon::make($dto->getExecutedAt());
$directory = sprintf(
'%s/%s/%s/%s/',
ConstantEnum::DIRECTORY,
$dto->getWebinarId(),
$term->getTimestamp(),
$dto->getUserId()
);

return array_map(function ($file) use ($directory) {
$filename = $file['filename'];

return array_merge(
['filename' => $filename],
Storage::temporaryUploadUrl($directory . $filename, now()->addMinutes(5))
);
}, $dto->getFiles());
}
}
1 change: 1 addition & 0 deletions src/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
Route::group(['prefix' => 'api/webinars'], function () {
Route::get('/', [WebinarAPIController::class, 'index']);
Route::get('/{id}', [WebinarAPIController::class, 'show']);
Route::post('/signed-screen-urls', [WebinarAPIController::class, 'generateSignedScreenUrls']);
});
53 changes: 53 additions & 0 deletions tests/APIs/WebinarApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use EscolaLms\Youtube\Services\Contracts\YoutubeServiceContract;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Storage;

class WebinarApiTest extends TestCase
{
Expand Down Expand Up @@ -390,4 +391,56 @@ public function testWebinarListOwn(): void
->getJson('/api/admin/webinars')
->assertJsonCount(4, 'data');
}

public function testGenerateSignedUrls(): void
{
config(['filesystems.default' => 's3']);

Storage::shouldReceive('temporaryUploadUrl')
->withArgs(function ($path, $expiration) {
return true;
})
->andReturnUsing(function ($path, $expiration) {
return [
'upload_url' => "https://example.com/{$path}",
];
});

$this->response = $this->json('POST', '/api/webinars/signed-screen-urls', [
'webinar_id' => 1,
'user_id' => 1,
'executed_at' => now()->format('Y-m-d H:i:s'),
'files' => [
[
'filename' => now()->format('Y-m-d H:i:s'),
],
],
])
->assertOk()
->assertJsonStructure([
'data' => [
[
'filename',
'upload_url',
]
]
]);
}

public function testGenerateSignedUrlsNotSupported(): void
{
config(['filesystems.default' => 'local']);

$this->response = $this->json('POST', '/api/webinars/signed-screen-urls', [
'webinar_id' => 1,
'user_id' => 1,
'executed_at' => now()->format('Y-m-d H:i:s'),
'files' => [
[
'filename' => now()->format('Y-m-d H:i:s'),
],
],
])
->assertStatus(400);
}
}
Loading