mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
profiles crud
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Audit as EventAudit;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
@@ -45,7 +45,6 @@ use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Swoole\Request;
|
||||
|
||||
|
||||
/**
|
||||
* Validate file Permissions
|
||||
*
|
||||
@@ -97,8 +96,112 @@ function validateFilePermissions(Database $dbForProject, string $bucketId, strin
|
||||
return $file;
|
||||
}
|
||||
|
||||
App::post('/v1/videos/profiles')
|
||||
->desc('Create video profile')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'video')
|
||||
->label('sdk.method', 'create')
|
||||
->label('sdk.description', '/docs/references/videos/create-profile.md') // TODO: Create markdown
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VIDEO_PROFILE)
|
||||
->param('name', null, new Text(128), 'Video profile name.')
|
||||
->param('videoBitrate', '', new Range(64, 4000), 'Video profile bitrate in Kbps.')
|
||||
->param('audioBitrate', '', new Range(64, 4000), 'Audio profile bit rate in Kbps.')
|
||||
->param('width', '', new Range(100, 2000), 'Video profile width.')
|
||||
->param('height', '', new Range(100, 2000), 'Video profile height.')
|
||||
->param('stream', false, new WhiteList(['hls', 'mpeg-dash']), 'Video profile stream protocol.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(action: function (string $name, string $videoBitrate, string $audioBitrate, string $width, string $height, string $stream, Response $response, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$profile = Authorization::skip(function () use ($dbForProject, $name, $videoBitrate, $audioBitrate, $width, $height, $stream) {
|
||||
return $dbForProject->createDocument('videos_profiles', new Document([
|
||||
'name' => $name,
|
||||
'videoBitrate' => (int)$videoBitrate,
|
||||
'audioBitrate' => (int)$audioBitrate,
|
||||
'width' => (int)$width,
|
||||
'height' => (int)$height,
|
||||
'stream' => $stream,
|
||||
]));
|
||||
});
|
||||
} catch (StructureException $exception) {
|
||||
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
}
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($profile, Response::MODEL_VIDEO_PROFILE);
|
||||
});
|
||||
|
||||
App::patch('/v1/videos/profiles/:profileId')
|
||||
->desc('Update video profile')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'video')
|
||||
->label('sdk.method', 'update')
|
||||
->label('sdk.description', '/docs/references/videos/update-profile.md') // TODO: Create markdown
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VIDEO_PROFILE)
|
||||
->param('profileId', '', new UID(), 'Video profile unique ID.')
|
||||
->param('name', null, new Text(128), 'Video profile name.')
|
||||
->param('videoBitrate', '', new Range(64, 4000), 'Video profile bitrate in Kbps.')
|
||||
->param('audioBitrate', '', new Range(64, 4000), 'Audio profile bit rate in Kbps.')
|
||||
->param('width', '', new Range(100, 2000), 'Video profile width.')
|
||||
->param('height', '', new Range(100, 2000), 'Video profile height.')
|
||||
->param('stream', false, new WhiteList(['hls', 'mpeg-dash']), 'Video profile stream protocol.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(action: function (string $profileId, string $name, string $videoBitrate, string $audioBitrate, string $width, string $height, string $stream, Response $response, Database $dbForProject) {
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->getDocument('videos_profiles', $profileId));
|
||||
var_dump($profile);
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$profile->setAttribute('name', $name)
|
||||
->setAttribute('videoBitrate', (int)$videoBitrate)
|
||||
->setAttribute('audioBitrate', (int)$audioBitrate)
|
||||
->setAttribute('width', (int)$width)
|
||||
->setAttribute('height', (int)$height)
|
||||
->setAttribute('stream', $stream);
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->updateDocument('videos_profiles', $profile->getId(), $profile));
|
||||
|
||||
$response->dynamic($profile, Response::MODEL_VIDEO_PROFILE);
|
||||
});
|
||||
|
||||
App::get('/v1/videos/profiles/:profileId')
|
||||
->desc('Get video profile')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'video')
|
||||
->label('sdk.method', 'getProfile')
|
||||
->label('sdk.description', '/docs/references/videos/get-profile.md') // TODO: Create markdown
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VIDEO_PROFILE)
|
||||
->param('profileId', '', new UID(), 'Video profile unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $profileId, Response $response, Database $dbForProject) {
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->getDocument('videos_profiles', $profileId));
|
||||
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception('Video profile not found', 404, Exception::PROFILES_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic($profile, Response::MODEL_VIDEO_PROFILE);
|
||||
});
|
||||
|
||||
App::get('/v1/videos/profiles')
|
||||
->alias('/v1/videos/videos/profiles', [])
|
||||
->desc('Get all video profiles')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.read')
|
||||
@@ -125,6 +228,36 @@ App::get('/v1/videos/profiles')
|
||||
]), Response::MODEL_VIDEO_PROFILE_LIST);
|
||||
});
|
||||
|
||||
App::delete('/v1/videos/profiles/:profileId')
|
||||
->desc('Delete a video transcoding profile')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.write')
|
||||
->label('sdk.namespace', 'video')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.method', 'deleteProfile')
|
||||
->label('sdk.description', '/docs/references/videos/delete-profile.md') // TODO: Create markdown
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('profileId', '', new UID(), 'Video profile unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $profileId, Response $response, Database $dbForProject) {
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->getDocument('videos_profiles', $profileId));
|
||||
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception('Video profile not found', 404, Exception::PROFILES_NOT_FOUND);
|
||||
}
|
||||
|
||||
$deleted = $dbForProject->deleteDocument('videos_profiles', $profileId);
|
||||
|
||||
if (!$deleted) {
|
||||
throw new Exception('Failed to remove video profile from DB', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
||||
App::post('/v1/videos/:videoId/subtitles')
|
||||
->alias('/v1/videos/:videoId/subtitles', [])
|
||||
@@ -133,8 +266,8 @@ App::post('/v1/videos/:videoId/subtitles')
|
||||
->label('scope', 'files.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'video')
|
||||
->label('sdk.method', 'addSubtitles')
|
||||
->label('sdk.description', '/docs/references/videos/add-subtitles.md') // TODO: Create markdown
|
||||
->label('sdk.method', 'addSubtitle')
|
||||
->label('sdk.description', '/docs/references/videos/add-subtitle.md') // TODO: Create markdown
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
@@ -288,7 +421,7 @@ App::post('/v1/videos/:videoId/rendition')
|
||||
|
||||
App::get('/v1/videos/:videoId/:stream/renditions')
|
||||
->alias('/v1/videos/:videoId/renditions', [])
|
||||
->desc('Get File renditions')
|
||||
->desc('Get video renditions')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#EXTM3U
|
||||
#EXT-X-VERSION:3
|
||||
<?php foreach ($this->getParam('paramsSubtitles', []) as $subtitle): ?>
|
||||
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="<?php echo $subtitle['name']; ?>",DEFAULT=<?php echo $subtitle['default']; ?>,AUTOSELECT=YES,FORCED=NO,LANGUAGE="<?php echo $subtitle['code']; ?>",URI="<?php echo $subtitle['uri']; ?>"<?php echo PHP_EOL?>
|
||||
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="<?php echo $subtitle['name']; ?>",DEFAULT=<?php echo $subtitle['default']; ?>,AUTOSELECT=NO,FORCED=NO,LANGUAGE="<?php echo $subtitle['code']; ?>",URI="<?php echo $subtitle['uri']; ?>"<?php echo PHP_EOL?>
|
||||
<?php endforeach; ?>
|
||||
<?php foreach ($this->getParam('paramsRenditions', []) as $rendition): ?>
|
||||
#EXT-X-STREAM-INF:BANDWIDTH="<?php echo $rendition['bandwidth']; ?>",RESOLUTION="<?php echo $rendition['resolution']; ?>",NAME="<?php echo $rendition['name']; ?>"<?php if($rendition['subs'] !== null): echo $rendition['subs']; endif?><?php echo PHP_EOL?>
|
||||
|
||||
@@ -14,8 +14,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use FFMpeg\FFProbe\DataMapping\StreamCollection;
|
||||
use FFMpeg\FFProbe\DataMapping\AbstractData;
|
||||
use FFMpeg\FFProbe\DataMapping\Stream;
|
||||
use Utopia\Storage\Compression\Algorithms\GZIP;
|
||||
use Captioning\Format\SubripFile;
|
||||
|
||||
|
||||
@@ -14,6 +14,90 @@ class VideoCustomServerTest extends Scope
|
||||
use VideoCustom;
|
||||
use SideServer;
|
||||
|
||||
|
||||
public function testCreateVideoProfile()
|
||||
{
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/videos/profiles', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'name' => 'My test profile',
|
||||
'videoBitrate' => 570,
|
||||
'audioBitrate' => 120,
|
||||
'width' => 600,
|
||||
'height' => 400,
|
||||
'stream' => 'hls',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/videos/profiles/' . $response['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'name' => 'My updated test profile',
|
||||
'videoBitrate' => 590,
|
||||
'audioBitrate' => 120,
|
||||
'width' => 300,
|
||||
'height' => 400,
|
||||
'stream' => 'hls',
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/videos/profiles/' . $response['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$profileId = $response['body']['$id'];
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals('My updated test profile', $response['body']['name']);
|
||||
$this->assertEquals(300, $response['body']['width']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/videos/profiles/' . $response['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/videos/profiles/' . $profileId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals('Video profile not found', $response['body']['message']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/videos/profiles', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals(3, $response['body']['total']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function testTranscodeWithSubs(): array
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user