mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
small fix
This commit is contained in:
+2
-2
@@ -266,14 +266,14 @@ COPY ./src /usr/src/code/src
|
||||
|
||||
# Set Volumes
|
||||
RUN mkdir -p /storage/uploads && \
|
||||
mkdir -p /storage/video && \
|
||||
mkdir -p /storage/videos && \
|
||||
mkdir -p /storage/cache && \
|
||||
mkdir -p /storage/config && \
|
||||
mkdir -p /storage/certificates && \
|
||||
mkdir -p /storage/functions && \
|
||||
mkdir -p /storage/debug && \
|
||||
chown -Rf www-data.www-data /storage/uploads && chmod -Rf 0755 /storage/uploads && \
|
||||
chown -Rf www-data.www-data /storage/video && chmod -Rf 0755 /storage/video && \
|
||||
chown -Rf www-data.www-data /storage/videos && chmod -Rf 0755 /storage/videos && \
|
||||
chown -Rf www-data.www-data /storage/cache && chmod -Rf 0755 /storage/cache && \
|
||||
chown -Rf www-data.www-data /storage/config && chmod -Rf 0755 /storage/config && \
|
||||
chown -Rf www-data.www-data /storage/certificates && chmod -Rf 0755 /storage/certificates && \
|
||||
|
||||
+282
-154
@@ -16,10 +16,10 @@ $auth = Config::getParam('auth', []);
|
||||
*/
|
||||
|
||||
$collections = [
|
||||
'collections' => [
|
||||
'databases' => [
|
||||
'$collection' => Database::METADATA,
|
||||
'$id' => 'collections',
|
||||
'name' => 'Collections',
|
||||
'$id' => 'databases',
|
||||
'name' => 'Databases',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'name',
|
||||
@@ -31,27 +31,63 @@ $collections = [
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'$id' => 'search',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => 'dateUpdated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'$id' => '_fulltext_search',
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
'attributes' => ['search'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
],
|
||||
],
|
||||
'collections' => [
|
||||
'$collection' => 'databases',
|
||||
'$id' => 'collections',
|
||||
'name' => 'Collections',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'databaseInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'databaseId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'signed' => true,
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => 'name',
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'enabled',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
@@ -120,7 +156,7 @@ $collections = [
|
||||
'name' => 'Attributes',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'collectionId',
|
||||
'$id' => 'databaseInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
@@ -130,6 +166,39 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'databaseId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => false,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'collectionInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'collectionId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'key',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -249,11 +318,11 @@ $collections = [
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_collection',
|
||||
'$id' => '_key_db_collection',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['collectionId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
'attributes' => ['databaseInternalId', 'collectionInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -264,7 +333,7 @@ $collections = [
|
||||
'name' => 'Indexes',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'collectionId',
|
||||
'$id' => 'databaseInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
@@ -274,6 +343,39 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'databaseId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => false,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'collectionInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'collectionId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'key',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -343,11 +445,11 @@ $collections = [
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_collection',
|
||||
'$id' => '_key_db_collection',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['collectionId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
'attributes' => ['databaseInternalId', 'collectionInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -357,6 +459,17 @@ $collections = [
|
||||
'$id' => 'projects',
|
||||
'name' => 'Projects',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'teamInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'teamId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -594,6 +707,17 @@ $collections = [
|
||||
'$id' => 'platforms',
|
||||
'name' => 'platforms',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'projectInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'projectId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -659,35 +783,13 @@ $collections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateUpdated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
]
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_project',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['projectId'],
|
||||
'attributes' => ['projectInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
@@ -699,6 +801,17 @@ $collections = [
|
||||
'$id' => 'domains',
|
||||
'name' => 'domains',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'projectInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'projectId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -781,7 +894,7 @@ $collections = [
|
||||
[
|
||||
'$id' => '_key_project',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['projectId'],
|
||||
'attributes' => ['projectInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
@@ -794,7 +907,7 @@ $collections = [
|
||||
'name' => 'keys',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'projectId',
|
||||
'$id' => 'projectInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
@@ -804,6 +917,17 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'projectId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => 0,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'name',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -837,12 +961,23 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => ['encrypt'],
|
||||
],
|
||||
[
|
||||
'$id' => 'expire',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => 0,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_project',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['projectId'],
|
||||
'attributes' => ['projectInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
@@ -854,6 +989,17 @@ $collections = [
|
||||
'$id' => 'webhooks',
|
||||
'name' => 'webhooks',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'projectInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'projectId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -947,10 +1093,10 @@ $collections = [
|
||||
[
|
||||
'$id' => '_key_project',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['projectId'],
|
||||
'attributes' => ['projectInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
@@ -981,6 +1127,17 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'phone',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16, // leading '+' and 15 digitts maximum by E.164 format
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'status',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
@@ -1047,6 +1204,17 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'phoneVerification',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'reset',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
@@ -1111,6 +1279,13 @@ $collections = [
|
||||
'lengths' => [320],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_phone',
|
||||
'type' => Database::INDEX_UNIQUE,
|
||||
'attributes' => ['phone'],
|
||||
'lengths' => [16],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_search',
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
@@ -1126,6 +1301,17 @@ $collections = [
|
||||
'$id' => 'tokens',
|
||||
'name' => 'Tokens',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'userInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'userId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -1197,7 +1383,7 @@ $collections = [
|
||||
[
|
||||
'$id' => '_key_user',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['userId'],
|
||||
'attributes' => ['userInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
@@ -1209,6 +1395,17 @@ $collections = [
|
||||
'$id' => 'sessions',
|
||||
'name' => 'Sessions',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'userInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'userId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -1474,7 +1671,7 @@ $collections = [
|
||||
[
|
||||
'$id' => '_key_user',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['userId'],
|
||||
'attributes' => ['userInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
@@ -1497,17 +1694,6 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'total',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
@@ -1548,7 +1734,7 @@ $collections = [
|
||||
'name' => 'Memberships',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'teamId',
|
||||
'$id' => 'userInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
@@ -1569,6 +1755,28 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'teamInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'teamId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'roles',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -1640,21 +1848,21 @@ $collections = [
|
||||
[
|
||||
'$id' => '_key_unique',
|
||||
'type' => Database::INDEX_UNIQUE,
|
||||
'attributes' => ['teamId', 'userId'],
|
||||
'attributes' => ['teamInternalId', 'userInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_team',
|
||||
'$id' => '_key_user',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['teamId'],
|
||||
'attributes' => ['userInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_user',
|
||||
'$id' => '_key_team',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['userId'],
|
||||
'attributes' => ['teamInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
@@ -1695,28 +1903,6 @@ $collections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateUpdated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'array' => false,
|
||||
'$id' => 'status',
|
||||
@@ -1726,7 +1912,6 @@ $collections = [
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
@@ -1845,17 +2030,6 @@ $collections = [
|
||||
'$id' => 'deployments',
|
||||
'name' => 'Deployments',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'resourceId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -1898,7 +2072,6 @@ $collections = [
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
@@ -2147,17 +2320,6 @@ $collections = [
|
||||
'$id' => 'executions',
|
||||
'name' => 'Executions',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'functionId',
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -2189,7 +2351,6 @@ $collections = [
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
@@ -2368,26 +2529,6 @@ $collections = [
|
||||
'$id' => 'buckets',
|
||||
'name' => 'Buckets',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'signed' => false,
|
||||
'size' => 0,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'dateUpdated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'size' => 0,
|
||||
'format' => '',
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'enabled',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
@@ -2628,17 +2769,6 @@ $collections = [
|
||||
'$id' => 'files',
|
||||
'$name' => 'Files',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'array' => false,
|
||||
'$id' => 'bucketId',
|
||||
@@ -2648,7 +2778,6 @@ $collections = [
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
@@ -3077,10 +3206,10 @@ $collections = [
|
||||
],
|
||||
[
|
||||
'$id' => 'width',
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
@@ -3088,10 +3217,10 @@ $collections = [
|
||||
],
|
||||
[
|
||||
'$id' => 'height',
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
@@ -3300,7 +3429,6 @@ $collections = [
|
||||
],
|
||||
]
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
return $collections;
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
'id' => 1,
|
||||
'name' => '360p',
|
||||
'videoBitrate' => 890, //video bitrate in Kbps
|
||||
'audioBitrate' => 64, //audio bitrate in Kbps
|
||||
'width' => 640, //width resolution in px
|
||||
'height' => 360, //height resolution in px
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => '576p',
|
||||
'videoBitrate' => 2538,
|
||||
'audioBitrate' => 128,
|
||||
'width' => 1024,
|
||||
'height' => 576,
|
||||
],
|
||||
[
|
||||
'id' => 3,
|
||||
'name' => '720p',
|
||||
'videoBitrate' => 3551,
|
||||
'audioBitrate' => 128,
|
||||
'width' => 1280,
|
||||
'height' => 720,
|
||||
],
|
||||
|
||||
];
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
return [
|
||||
[
|
||||
'id' => 1,
|
||||
|
||||
'name' => '360p',
|
||||
'videoBitrate' => 890, //video bitrate in Kbps
|
||||
'audioBitrate' => 64, //audio bitrate in Kbps
|
||||
@@ -10,7 +10,6 @@ return [
|
||||
'height' => 360, //height resolution in px
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => '576p',
|
||||
'videoBitrate' => 2538,
|
||||
'audioBitrate' => 128,
|
||||
@@ -18,7 +17,6 @@ return [
|
||||
'height' => 576,
|
||||
],
|
||||
[
|
||||
'id' => 3,
|
||||
'name' => '720p',
|
||||
'videoBitrate' => 3551,
|
||||
'audioBitrate' => 128,
|
||||
@@ -153,7 +153,7 @@ App::post('/v1/projects')
|
||||
}
|
||||
|
||||
if($dbForProject->exists($dbForProject->getDefaultDatabase(), 'video_profiles')) {
|
||||
foreach (Config::getParam('profiles', []) as $profile) {
|
||||
foreach (Config::getParam('video-profiles', []) as $profile) {
|
||||
Authorization::skip(function () use ($project, $profile, $dbForProject) {
|
||||
return $dbForProject->createDocument('video_profiles', new Document([
|
||||
'name' => $profile['name'],
|
||||
|
||||
+107
-56
@@ -55,7 +55,7 @@ App::get('/v1/video/profiles')
|
||||
|
||||
$profiles = Authorization::skip(fn () => $dbForProject->find('video_profiles', [], 12, 0, [], ['ASC']));
|
||||
|
||||
if(empty($profiles)) {
|
||||
if (empty($profiles)) {
|
||||
throw new Exception('Video profiles where not found', 404, Exception::PROFILES_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ App::get('/v1/video/profiles')
|
||||
'total' => $dbForProject->count('video_profiles', [], APP_LIMIT_COUNT),
|
||||
'profiles' => $profiles,
|
||||
]), Response::MODEL_VIDEO_PROFILE_LIST);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
App::post('/v1/video/buckets/:bucketId/files/:fileId')
|
||||
@@ -135,7 +135,7 @@ App::post('/v1/video/buckets/:bucketId/files/:fileId')
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
try {
|
||||
$video = Authorization::skip(function () use ($dbForProject, $bucket, $file) {
|
||||
$video = Authorization::skip(function () use ($dbForProject, $bucket, $file) {
|
||||
return $dbForProject->createDocument('videos', new Document([
|
||||
'bucketId' => $bucket->getId(),
|
||||
'fileId' => $file->getId(),
|
||||
@@ -156,13 +156,13 @@ App::post('/v1/video/buckets/:bucketId/files/:fileId')
|
||||
|
||||
|
||||
App::post('/v1/video/:videoId/rendition/:profileId')
|
||||
->alias('/v1/video/files', ['bucketId' => 'default'])
|
||||
->alias('/v1/video/:videoId/rendition/:profileId', [])
|
||||
->desc('Start transcoding video rendition')
|
||||
->groups(['api', 'storage'])
|
||||
->label('scope', 'files.write')
|
||||
// ->label('event', 'buckets.[bucketId].files.[fileId].create')
|
||||
->param('videoId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('profileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('videoId', null, new UID(), 'Video unique ID.')
|
||||
->param('profileId', '', new CustomId(), 'Profile unique ID.')
|
||||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->inject('request')
|
||||
@@ -182,7 +182,7 @@ App::post('/v1/video/:videoId/rendition/:profileId')
|
||||
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [new Query('_uid', Query::TYPE_EQUAL, [$videoId])]));
|
||||
|
||||
if($video->isEmpty()){
|
||||
if ($video->isEmpty()) {
|
||||
throw new Exception('Video not found', 400, Exception::VIDEO_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ App::post('/v1/video/:videoId/rendition/:profileId')
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->findOne('video_profiles', [new Query('_uid', Query::TYPE_EQUAL, [$profileId])]));
|
||||
|
||||
if(!$profile){
|
||||
if (!$profile) {
|
||||
throw new Exception('Video profile not found', 400, Exception::PROFILES_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -248,27 +248,31 @@ App::post('/v1/video/:videoId/rendition/:profileId')
|
||||
});
|
||||
|
||||
|
||||
App::get('/v1/video/buckets/:bucketId/files/:fileId/renditions')
|
||||
->alias('/v1/storage/files/:fileId/renditions', ['bucketId' => 'default'])
|
||||
App::get('/v1/video/:videoId/:stream/renditions')
|
||||
->alias('/v1/video/:videoId/renditions', [])
|
||||
->desc('Get File renditions')
|
||||
->groups(['api', 'storage'])
|
||||
->label('scope', 'files.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'storage')
|
||||
->label('sdk.method', 'getFile')
|
||||
->label('sdk.description', '/docs/references/storage/get-file.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE)
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File ID.')
|
||||
->param('videoId', null, new UID(), 'Video unique ID.')
|
||||
->param('stream', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
|
||||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Stats $usage, string $mode) {
|
||||
->action(function (string $videoId, string $stream, ?array $read, ?array $write, Response $response, Database $dbForProject, Stats $usage, string $mode) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [new Query('_uid', Query::TYPE_EQUAL, [$videoId])]));
|
||||
|
||||
if ($video->isEmpty()) {
|
||||
throw new Exception('Video not found', 400, Exception::VIDEO_NOT_FOUND);
|
||||
}
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $video['bucketId']));
|
||||
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
@@ -278,52 +282,81 @@ App::get('/v1/video/buckets/:bucketId/files/:fileId/renditions')
|
||||
}
|
||||
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
$permissionBucket = $bucket->getAttribute('permission') === 'bucket';
|
||||
if ($permissionBucket) {
|
||||
$validator = new Authorization('write');
|
||||
if (!$validator->isValid($bucket->getWrite())) {
|
||||
throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
$read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user
|
||||
$write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? [];
|
||||
|
||||
// Users can only add their roles to files, API keys and Admin users can add any
|
||||
$roles = Authorization::getRoles();
|
||||
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) {
|
||||
foreach ($read as $role) {
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception('Read permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
foreach ($write as $role) {
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception('Write permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND);
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
// skip authorization
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $video['fileId']));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $video['fileId']);
|
||||
}
|
||||
|
||||
$queries = [
|
||||
new Query('bucketId', Query::TYPE_EQUAL, [$bucketId]),
|
||||
new Query('fileId', Query::TYPE_EQUAL, [$fileId]),
|
||||
new Query('stream', Query::TYPE_EQUAL, ['dash']),
|
||||
new Query('videoId', Query::TYPE_EQUAL, [$video->getId()]),
|
||||
new Query('endedAt', Query::TYPE_GREATER, [0]),
|
||||
new Query('status', Query::TYPE_EQUAL, ['ready']),
|
||||
new Query('stream', Query::TYPE_EQUAL, [$stream]),
|
||||
];
|
||||
|
||||
$renditions = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId() . '_video_renditions', $queries, 12, 0, [], ['ASC']));
|
||||
$renditions = Authorization::skip(fn () => $dbForProject->find('video_renditions', $queries, 12, 0, [], ['ASC']));
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $dbForProject->count('bucket_' . $bucket->getInternalId() . '_video_renditions', $queries, APP_LIMIT_COUNT),
|
||||
'total' => $dbForProject->count('video_renditions', $queries, APP_LIMIT_COUNT),
|
||||
'renditions' => $renditions,
|
||||
]), Response::MODEL_FILE_RENDITIONS_LIST);
|
||||
]), Response::MODEL_VIDEO_RENDITIONS_LIST);
|
||||
});
|
||||
|
||||
App::get('/v1/video/buckets/:bucketId/files/:stream/:fileId')
|
||||
App::get('/v1/video/:videoId/:stream/:namespace/:fileName')
|
||||
->alias('/v1/video/buckets/:bucketId/files/:stream/:fileId', [])
|
||||
->desc('Get video playlist manifest')
|
||||
->groups(['api', 'storage'])
|
||||
->label('scope', 'files.read')
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('stream', '', new WhiteList(['hls', 'dash']), 'stream protocol name')
|
||||
->param('fileId', '', new UID(), 'File ID.')
|
||||
->param('videoId', null, new UID(), 'Video unique ID.')
|
||||
->param('stream', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
|
||||
->param('namespace', '', new WhiteList(['master']), 'stream protocol name')
|
||||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function (string $bucketId, string $stream, string $fileId, Response $response, Database $dbForProject, Stats $usage, string $mode) {
|
||||
->action(function (string $videoId, string $stream, string $namespace, ?array $read, ?array $write, Response $response, Database $dbForProject, Stats $usage, string $mode) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [new Query('_uid', Query::TYPE_EQUAL, [$videoId])]));
|
||||
|
||||
if ($video->isEmpty()) {
|
||||
throw new Exception('Video not found', 400, Exception::VIDEO_NOT_FOUND);
|
||||
}
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $video['bucketId']));
|
||||
|
||||
if (
|
||||
$bucket->isEmpty()
|
||||
@@ -333,32 +366,48 @@ App::get('/v1/video/buckets/:bucketId/files/:stream/:fileId')
|
||||
}
|
||||
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
$permissionBucket = $bucket->getAttribute('permission') === 'bucket';
|
||||
if ($permissionBucket) {
|
||||
$validator = new Authorization('write');
|
||||
if (!$validator->isValid($bucket->getWrite())) {
|
||||
throw new Exception('Unauthorized permissions', 401, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
$read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user
|
||||
$write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? [];
|
||||
|
||||
// Users can only add their roles to files, API keys and Admin users can add any
|
||||
$roles = Authorization::getRoles();
|
||||
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) {
|
||||
foreach ($read as $role) {
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception('Read permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
foreach ($write as $role) {
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception('Write permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND);
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
// skip authorization
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $video['fileId']));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $video['fileId']);
|
||||
}
|
||||
|
||||
$queries = [
|
||||
new Query('bucketId', Query::TYPE_EQUAL, [$bucketId]),
|
||||
new Query('fileId', Query::TYPE_EQUAL, [$fileId]),
|
||||
new Query('stream', Query::TYPE_EQUAL, [$stream]),
|
||||
new Query('videoId', Query::TYPE_EQUAL, [$video->getId()]),
|
||||
new Query('endedAt', Query::TYPE_GREATER, [0]),
|
||||
new Query('status', Query::TYPE_EQUAL, ['ready'])
|
||||
new Query('status', Query::TYPE_EQUAL, ['ready']),
|
||||
new Query('stream', Query::TYPE_EQUAL, ['stream']),
|
||||
];
|
||||
|
||||
$renditions = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId() . '_video_renditions', $queries, 12, 0, [], ['ASC']));
|
||||
$renditions = Authorization::skip(fn () => $dbForProject->find('video_renditions', $queries, 12, 0, [], ['ASC']));
|
||||
|
||||
if (empty($renditions)) {
|
||||
throw new Exception('Renditions not found');
|
||||
@@ -379,7 +428,9 @@ App::get('/v1/video/buckets/:bucketId/files/:stream/:fileId')
|
||||
$template->setParam('params', $params);
|
||||
$response->setContentType('application/x-mpegurl');
|
||||
$response->send($template->render());
|
||||
|
||||
} else {
|
||||
|
||||
$adaptations = [];
|
||||
foreach ($renditions as $rendition) {
|
||||
$metadata = $rendition->getAttribute('metadata');
|
||||
|
||||
@@ -19,6 +19,7 @@ use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
||||
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
|
||||
use Appwrite\Utopia\Response\Filters\V13 as ResponseV13;
|
||||
use Appwrite\Utopia\Response\Filters\V14 as ResponseV14;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
@@ -177,6 +178,9 @@ App::init(function (App $utopia, Request $request, Response $response, Document
|
||||
case version_compare($responseFormat, '0.13.4', '<='):
|
||||
Response::setFilter(new ResponseV13());
|
||||
break;
|
||||
case version_compare($responseFormat, '0.14.0', '<='):
|
||||
Response::setFilter(new ResponseV14());
|
||||
break;
|
||||
default:
|
||||
Response::setFilter(null);
|
||||
}
|
||||
@@ -279,6 +283,12 @@ App::init(function (App $utopia, Request $request, Response $response, Document
|
||||
$role = Auth::USER_ROLE_APP;
|
||||
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
|
||||
|
||||
$expire = $key->getAttribute('expire', 0);
|
||||
|
||||
if (!empty($expire) && $expire < \time()) {
|
||||
throw new AppwriteException('Project key expired', 401, AppwriteException:: PROJECT_KEY_EXPIRED);
|
||||
}
|
||||
|
||||
Authorization::setRole('role:' . Auth::USER_ROLE_APP);
|
||||
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
||||
}
|
||||
@@ -292,11 +302,10 @@ App::init(function (App $utopia, Request $request, Response $response, Document
|
||||
|
||||
$service = $route->getLabel('sdk.namespace', '');
|
||||
if (!empty($service)) {
|
||||
$roles = Authorization::getRoles();
|
||||
if (
|
||||
array_key_exists($service, $project->getAttribute('services', []))
|
||||
&& !$project->getAttribute('services', [])[$service]
|
||||
&& !(Auth::isPrivilegedUser($roles) || Auth::isAppUser($roles))
|
||||
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
|
||||
) {
|
||||
throw new AppwriteException('Service is disabled', 503, AppwriteException::GENERAL_SERVICE_DISABLED);
|
||||
}
|
||||
|
||||
+53
-44
@@ -23,11 +23,17 @@ use Ahc\Jwt\JWT;
|
||||
use Ahc\Jwt\JWTException;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Phone\Mock;
|
||||
use Appwrite\Auth\Phone\Telesign;
|
||||
use Appwrite\Auth\Phone\TextMagic;
|
||||
use Appwrite\Auth\Phone\Twilio;
|
||||
use Appwrite\DSN\DSN;
|
||||
use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Phone;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\IP;
|
||||
use Appwrite\Network\Validator\URL;
|
||||
@@ -78,9 +84,10 @@ const APP_LIMIT_ANTIVIRUS = 20000000; //20MB
|
||||
const APP_LIMIT_ENCRYPTION = 20000000; //20MB
|
||||
const APP_LIMIT_COMPRESSION = 20000000; //20MB
|
||||
const APP_LIMIT_ARRAY_PARAMS_SIZE = 100; // Default maximum of how many elements can there be in API parameter that expects array value
|
||||
const APP_LIMIT_ARRAY_ELEMENT_SIZE = 4096; // Default maximum length of element in array parameter represented by maximum URL length.
|
||||
const APP_LIMIT_SUBQUERY = 1000;
|
||||
const APP_CACHE_BUSTER = 305;
|
||||
const APP_VERSION_STABLE = '0.14.2';
|
||||
const APP_CACHE_BUSTER = 401;
|
||||
const APP_VERSION_STABLE = '0.15.1';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||
@@ -89,9 +96,9 @@ const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange';
|
||||
const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange';
|
||||
const APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH = 1073741824; // 2^32 bits / 4 bits per char
|
||||
const APP_STORAGE_UPLOADS = '/storage/uploads';
|
||||
const APP_STORAGE_VIDEO = '/storage/video';
|
||||
const APP_STORAGE_FUNCTIONS = '/storage/functions';
|
||||
const APP_STORAGE_BUILDS = '/storage/builds';
|
||||
const APP_STORAGE_VIDEO = '/storage/videos';
|
||||
const APP_STORAGE_CACHE = '/storage/cache';
|
||||
const APP_STORAGE_CERTIFICATES = '/storage/certificates';
|
||||
const APP_STORAGE_CONFIG = '/storage/config';
|
||||
@@ -119,6 +126,7 @@ const DATABASE_TYPE_DELETE_INDEX = 'deleteIndex';
|
||||
const BUILD_TYPE_DEPLOYMENT = 'deployment';
|
||||
const BUILD_TYPE_RETRY = 'retry';
|
||||
// Deletion Types
|
||||
const DELETE_TYPE_DATABASES = 'databases';
|
||||
const DELETE_TYPE_DOCUMENT = 'document';
|
||||
const DELETE_TYPE_COLLECTIONS = 'collections';
|
||||
const DELETE_TYPE_PROJECTS = 'projects';
|
||||
@@ -133,6 +141,7 @@ const DELETE_TYPE_CERTIFICATES = 'certificates';
|
||||
const DELETE_TYPE_USAGE = 'usage';
|
||||
const DELETE_TYPE_REALTIME = 'realtime';
|
||||
const DELETE_TYPE_BUCKETS = 'buckets';
|
||||
const DELETE_TYPE_SESSIONS = 'sessions';
|
||||
// Mail Types
|
||||
const MAIL_TYPE_VERIFICATION = 'verification';
|
||||
const MAIL_TYPE_MAGIC_SESSION = 'magicSession';
|
||||
@@ -154,32 +163,6 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION));
|
||||
/*
|
||||
* ENV vars
|
||||
*/
|
||||
Config::load('profiles', __DIR__ . '/config/profiles.php');
|
||||
Config::load('events', __DIR__ . '/config/events.php');
|
||||
Config::load('auth', __DIR__ . '/config/auth.php');
|
||||
Config::load('errors', __DIR__ . '/config/errors.php');
|
||||
Config::load('providers', __DIR__ . '/config/providers.php');
|
||||
Config::load('platforms', __DIR__ . '/config/platforms.php');
|
||||
Config::load('collections', __DIR__ . '/config/collections.php');
|
||||
Config::load('runtimes', __DIR__ . '/config/runtimes.php');
|
||||
Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes
|
||||
Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes
|
||||
Config::load('services', __DIR__ . '/config/services.php'); // List of services
|
||||
Config::load('variables', __DIR__ . '/config/variables.php'); // List of env variables
|
||||
Config::load('avatar-browsers', __DIR__ . '/config/avatars/browsers.php');
|
||||
Config::load('avatar-credit-cards', __DIR__ . '/config/avatars/credit-cards.php');
|
||||
Config::load('avatar-flags', __DIR__ . '/config/avatars/flags.php');
|
||||
Config::load('locale-codes', __DIR__ . '/config/locale/codes.php');
|
||||
Config::load('locale-currencies', __DIR__ . '/config/locale/currencies.php');
|
||||
Config::load('locale-eu', __DIR__ . '/config/locale/eu.php');
|
||||
Config::load('locale-languages', __DIR__ . '/config/locale/languages.php');
|
||||
Config::load('locale-phones', __DIR__ . '/config/locale/phones.php');
|
||||
Config::load('locale-countries', __DIR__ . '/config/locale/countries.php');
|
||||
Config::load('locale-continents', __DIR__ . '/config/locale/continents.php');
|
||||
Config::load('storage-logos', __DIR__ . '/config/storage/logos.php');
|
||||
Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php');
|
||||
Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php');
|
||||
Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php');
|
||||
Config::load('events', __DIR__ . '/config/events.php');
|
||||
Config::load('auth', __DIR__ . '/config/auth.php');
|
||||
Config::load('errors', __DIR__ . '/config/errors.php');
|
||||
@@ -191,6 +174,7 @@ Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes
|
||||
Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes
|
||||
Config::load('services', __DIR__ . '/config/services.php'); // List of services
|
||||
Config::load('variables', __DIR__ . '/config/variables.php'); // List of env variables
|
||||
Config::load('video-profiles', __DIR__ . '/config/video-profiles.php');
|
||||
Config::load('avatar-browsers', __DIR__ . '/config/avatars/browsers.php');
|
||||
Config::load('avatar-credit-cards', __DIR__ . '/config/avatars/credit-cards.php');
|
||||
Config::load('avatar-flags', __DIR__ . '/config/avatars/flags.php');
|
||||
@@ -206,6 +190,7 @@ Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php');
|
||||
Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php');
|
||||
Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php');
|
||||
|
||||
|
||||
$user = App::getEnv('_APP_REDIS_USER', '');
|
||||
$pass = App::getEnv('_APP_REDIS_PASS', '');
|
||||
if (!empty($user) || !empty($pass)) {
|
||||
@@ -283,8 +268,9 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('attributes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], $database->getAttributeLimit());
|
||||
new Query('collectionInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]),
|
||||
new Query('databaseInternalId', Query::TYPE_EQUAL, [$document->getAttribute('databaseInternalId')])
|
||||
], $database->getAttributeLimit(), 0, []);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -296,7 +282,8 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('indexes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('collectionInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]),
|
||||
new Query('databaseInternalId', Query::TYPE_EQUAL, [$document->getAttribute('databaseInternalId')])
|
||||
], 64);
|
||||
}
|
||||
);
|
||||
@@ -309,7 +296,7 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('platforms', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
|
||||
], APP_LIMIT_SUBQUERY);
|
||||
}
|
||||
);
|
||||
@@ -322,7 +309,7 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('domains', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
|
||||
], APP_LIMIT_SUBQUERY);
|
||||
}
|
||||
);
|
||||
@@ -335,7 +322,7 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('keys', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
|
||||
], APP_LIMIT_SUBQUERY);
|
||||
}
|
||||
);
|
||||
@@ -348,7 +335,7 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('webhooks', [
|
||||
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
|
||||
], APP_LIMIT_SUBQUERY);
|
||||
}
|
||||
);
|
||||
@@ -360,7 +347,7 @@ Database::addFilter(
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn () => $database->find('sessions', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
|
||||
], APP_LIMIT_SUBQUERY));
|
||||
}
|
||||
);
|
||||
@@ -373,7 +360,7 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
->find('tokens', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
|
||||
], APP_LIMIT_SUBQUERY));
|
||||
}
|
||||
);
|
||||
@@ -386,7 +373,7 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
->find('memberships', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
|
||||
], APP_LIMIT_SUBQUERY));
|
||||
}
|
||||
);
|
||||
@@ -453,7 +440,7 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function ($attribute) {
|
||||
* Registry
|
||||
*/
|
||||
$register->set('logger', function () {
|
||||
// Register error logger
|
||||
// Register error logger
|
||||
$providerName = App::getEnv('_APP_LOGGING_PROVIDER', '');
|
||||
$providerConfig = App::getEnv('_APP_LOGGING_CONFIG', '');
|
||||
|
||||
@@ -487,6 +474,11 @@ $register->set('dbPool', function () {
|
||||
->withPassword($dbPass)
|
||||
->withOptions([
|
||||
PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => true,
|
||||
]),
|
||||
64
|
||||
);
|
||||
@@ -568,7 +560,7 @@ $register->set('smtp', function () {
|
||||
return $mail;
|
||||
});
|
||||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__ . '/db/DBIP/dbip-country-lite-2022-03.mmdb');
|
||||
return new Reader(__DIR__ . '/db/DBIP/dbip-country-lite-2022-06.mmdb');
|
||||
});
|
||||
$register->set('db', function () {
|
||||
// This is usually for our workers or CLI commands scope
|
||||
@@ -579,11 +571,12 @@ $register->set('db', function () {
|
||||
$dbScheme = App::getEnv('_APP_DB_SCHEMA', '');
|
||||
|
||||
$pdo = new PDO("mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, array(
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => true,
|
||||
));
|
||||
|
||||
return $pdo;
|
||||
@@ -712,6 +705,7 @@ App::setResource('audits', fn() => new Audit());
|
||||
App::setResource('mails', fn() => new Mail());
|
||||
App::setResource('deletes', fn() => new Delete());
|
||||
App::setResource('database', fn() => new EventDatabase());
|
||||
App::setResource('messaging', fn() => new Phone());
|
||||
App::setResource('usage', function ($register) {
|
||||
return new Stats($register->get('statsd'));
|
||||
}, ['register']);
|
||||
@@ -862,6 +856,7 @@ App::setResource('project', function ($dbForConsole, $request, $console) {
|
||||
App::setResource('console', function () {
|
||||
return new Document([
|
||||
'$id' => 'console',
|
||||
'$internalId' => 'console',
|
||||
'name' => 'Appwrite',
|
||||
'$collection' => 'projects',
|
||||
'description' => 'Appwrite core engine',
|
||||
@@ -891,12 +886,12 @@ App::setResource('console', function () {
|
||||
]);
|
||||
}, []);
|
||||
|
||||
App::setResource('dbForProject', function ($db, $cache, $project) {
|
||||
App::setResource('dbForProject', function ($db, $cache, Document $project) {
|
||||
$cache = new Cache(new RedisCache($cache));
|
||||
|
||||
$database = new Database(new MariaDB($db), $cache);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace("_{$project->getId()}");
|
||||
$database->setNamespace("_{$project->getInternalId()}");
|
||||
|
||||
return $database;
|
||||
}, ['db', 'cache', 'project']);
|
||||
@@ -987,3 +982,17 @@ App::setResource('geodb', function ($register) {
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
return $register->get('geodb');
|
||||
}, ['register']);
|
||||
|
||||
App::setResource('phone', function () {
|
||||
$dsn = new DSN(App::getEnv('_APP_PHONE_PROVIDER'));
|
||||
$user = $dsn->getUser();
|
||||
$secret = $dsn->getPassword();
|
||||
|
||||
return match ($dsn->getHost()) {
|
||||
'mock' => new Mock('', ''), // used for tests
|
||||
'twilio' => new Twilio($user, $secret),
|
||||
'text-magic' => new TextMagic($user, $secret),
|
||||
'telesign' => new Telesign($user, $secret),
|
||||
default => null
|
||||
};
|
||||
});
|
||||
|
||||
+154
-149
@@ -5,6 +5,7 @@ use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Streaming\Format\StreamFormat;
|
||||
use Streaming\Media;
|
||||
use Streaming\Metadata;
|
||||
use Streaming\Representation;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
@@ -34,7 +35,8 @@ class TranscodingV1 extends Worker
|
||||
|
||||
const HLS_BASE_URL = '';
|
||||
|
||||
protected string $basePath = '/tmp/';
|
||||
//protected string $basePath = '/tmp/';
|
||||
protected string $basePath = '/usr/src/code/tests/tmp/';
|
||||
|
||||
protected string $inDir;
|
||||
|
||||
@@ -68,20 +70,20 @@ class TranscodingV1 extends Worker
|
||||
$this->database = $this->getProjectDB($project->getId());
|
||||
|
||||
$sourceVideo = Authorization::skip(fn() => $this->database->findOne('videos', [new Query('_uid', Query::TYPE_EQUAL, [$this->args['videoId']])]));
|
||||
if(empty($sourceVideo)){
|
||||
if (empty($sourceVideo)) {
|
||||
throw new Exception('Video not found');
|
||||
}
|
||||
|
||||
$profile = Authorization::skip(fn() => $this->database->findOne('video_profiles', [new Query('_uid', Query::TYPE_EQUAL, [$this->args['profileId']])]));
|
||||
if(empty($profile)){
|
||||
if (empty($profile)) {
|
||||
throw new Exception('profile not found');
|
||||
}
|
||||
}
|
||||
|
||||
$user = new Document($this->args['user'] ?? []);
|
||||
$bucket = Authorization::skip(fn() => $this->database->getDocument('buckets', $sourceVideo['bucketId']));
|
||||
$bucket = Authorization::skip(fn() => $this->database->getDocument('buckets', $sourceVideo['bucketId']));
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(fn() => $this->database->getDocument('bucket_' . $bucket->getInternalId(), $video['fileId']));
|
||||
$file = Authorization::skip(fn() => $this->database->getDocument('bucket_' . $bucket->getInternalId(), $video['fileId']));
|
||||
} else {
|
||||
$file = $this->database->getDocument('bucket_' . $bucket->getInternalId(), $sourceVideo['fileId']);
|
||||
}
|
||||
@@ -127,25 +129,24 @@ class TranscodingV1 extends Worker
|
||||
if (!empty($rendition)) {
|
||||
Authorization::skip(fn() => $this->database->deleteDocument($collection, $rendition->getId()));
|
||||
$deviceFiles = $this->getVideoDevice($project->getId());
|
||||
if(!empty($rendition['path'])) {
|
||||
if (!empty($rendition['path'])) {
|
||||
$deviceFiles->deletePath($rendition['path']);
|
||||
}
|
||||
}
|
||||
|
||||
$stream = !empty($rendition['stream']) ? $rendition['stream'] : 'hls';
|
||||
//$general = $this->getMetadataExport($ffprobe->streams($inPath));
|
||||
//var_dump($general);
|
||||
// if(!empty($general)) {
|
||||
// foreach ($general as $key => $value) {
|
||||
// $sourceVideo->setAttribute($key, $value);
|
||||
// }
|
||||
//
|
||||
// Authorization::skip(fn() => $this->database->updateDocument(
|
||||
// 'videos',
|
||||
// $sourceVideo->getId(),
|
||||
// $sourceVideo
|
||||
// ));
|
||||
// }
|
||||
$general = $this->getVideoInfo($ffprobe->streams($inPath));
|
||||
if(!empty($general)) {
|
||||
foreach ($general as $key => $value) {
|
||||
$sourceVideo->setAttribute($key, $value);
|
||||
}
|
||||
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
'videos',
|
||||
$sourceVideo->getId(),
|
||||
$sourceVideo
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
$video = $ffmpeg->open($inPath);
|
||||
@@ -159,142 +160,108 @@ class TranscodingV1 extends Worker
|
||||
'status' => self::STATUS_TRANSCODE_START,
|
||||
'stream' => $stream,
|
||||
]));
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
$representation = (new Representation())->
|
||||
setKiloBitrate($profile->getAttribute('videoBitrate'))->
|
||||
setAudioKiloBitrate($profile->getAttribute('audioBitrate'))->
|
||||
setResize( $profile->getAttribute('width'), $profile->getAttribute('height'));
|
||||
try {
|
||||
$representation = (new Representation())->
|
||||
setKiloBitrate($profile->getAttribute('videoBitrate'))->
|
||||
setAudioKiloBitrate($profile->getAttribute('audioBitrate'))->
|
||||
setResize($profile->getAttribute('width'), $profile->getAttribute('height'));
|
||||
|
||||
$format = new Streaming\Format\X264();
|
||||
$format->on('progress', function ($video, $format, $percentage) use ($query, $collection) {
|
||||
if ($percentage % 3 === 0) {
|
||||
$query->setAttribute('progress', (string)$percentage);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
list($general, $metadata) = $this->transcode($stream, $video, $format, $representation);
|
||||
|
||||
if (!empty($metadata)) {
|
||||
$query->setAttribute('metadata', json_encode($metadata));
|
||||
}
|
||||
|
||||
if(!empty($general)) {
|
||||
foreach ($general as $key => $value) {
|
||||
$query->setAttribute($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$query->setAttribute('status', self::STATUS_TRANSCODE_END);
|
||||
$query->setAttribute('endedAt', time());
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
|
||||
/** Upload & remove files **/
|
||||
$start = 0;
|
||||
$fileNames = scandir($this->outDir);
|
||||
|
||||
foreach ($fileNames as $fileName) {
|
||||
if (
|
||||
$fileName === '.' ||
|
||||
$fileName === '..' ||
|
||||
str_contains($fileName, '.json')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$deviceFiles = $this->getVideoDevice($project->getId());
|
||||
$devicePath = $deviceFiles->getPath($this->args['videoId']);
|
||||
$devicePath = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $devicePath);
|
||||
$data = $this->getFilesDevice($project->getId())->read($this->outDir . $fileName);
|
||||
$renditionDir = $profile->getAttribute('width') . 'X' . $profile->getAttribute('height') . '@' .$profile->getAttribute('videoBitrate');
|
||||
$renditionPath = $devicePath . DIRECTORY_SEPARATOR . $renditionDir;
|
||||
$this->getVideoDevice($project->getId())->write($renditionPath . DIRECTORY_SEPARATOR . $fileName, $data, \mime_content_type($this->outDir . $fileName));
|
||||
|
||||
if ($start === 0) {
|
||||
$query->setAttribute('status', self::STATUS_UPLOADING);
|
||||
$query->setAttribute('path', $renditionPath);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
$start = 1;
|
||||
}
|
||||
|
||||
//$metadata=[];
|
||||
//$chunksUploaded = $deviceFiles->upload($file, $path, -1, 1, $metadata);
|
||||
//var_dump($chunksUploaded);
|
||||
// if (empty($chunksUploaded)) {
|
||||
// throw new Exception('Failed uploading file', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
//}
|
||||
// }
|
||||
|
||||
@unlink($this->outDir . $fileName);
|
||||
}
|
||||
|
||||
$query->setAttribute('status', self::STATUS_PACKAGE_END);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
} catch (\Throwable $th) {
|
||||
$query->setAttribute('metadata', json_encode([
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage(),
|
||||
]));
|
||||
|
||||
$query->setAttribute('status', self::STATUS_ERROR);
|
||||
$format = new Streaming\Format\X264();
|
||||
$format->on('progress', function ($video, $format, $percentage) use ($query, $collection) {
|
||||
if ($percentage % 3 === 0) {
|
||||
$query->setAttribute('progress', (string)$percentage);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @param $metadata array
|
||||
* @return array
|
||||
*/
|
||||
private function getMetadataExport(array $metadata): array
|
||||
{
|
||||
$info = [];
|
||||
|
||||
if (!empty($metadata['stream']['resolutions'][0])) {
|
||||
$general = $metadata['stream']['resolutions'][0];
|
||||
$parts = explode("X", $general['dimension']);
|
||||
$info['width'] = $parts['0'];
|
||||
$info['height'] = $parts['1'];
|
||||
}
|
||||
list($general, $metadata) = $this->transcode($stream, $video, $format, $representation);
|
||||
|
||||
if (!empty($metadata['video']['streams'])) {
|
||||
foreach ($metadata['video']['streams'] as $streams) {
|
||||
if ($streams['codec_type'] === 'video') {
|
||||
$info['duration'] = $streams['duration'];
|
||||
$info['videoCodec'] = $streams['codec_name'] . ',' . $streams['codec_tag_string'];
|
||||
$info['videoBitrate'] = $streams['bit_rate'];
|
||||
$info['videoFramerate'] = $streams['avg_frame_rate'];
|
||||
} elseif ($streams['codec_type'] === 'audio') {
|
||||
$info['audioCodec'] = $streams['codec_name'] . ',' . $streams['codec_tag_string'];
|
||||
$info['audioBitrate'] = $streams['sample_rate'];
|
||||
$info['audioSamplerate'] = $streams['bit_rate'];
|
||||
if (!empty($metadata)) {
|
||||
$query->setAttribute('metadata', json_encode($metadata));
|
||||
}
|
||||
|
||||
if (!empty($general)) {
|
||||
foreach ($general as $key => $value) {
|
||||
$query->setAttribute($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $info;
|
||||
$query->setAttribute('status', self::STATUS_TRANSCODE_END);
|
||||
$query->setAttribute('endedAt', time());
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
|
||||
/** Upload & remove files **/
|
||||
$start = 0;
|
||||
$fileNames = scandir($this->outDir);
|
||||
|
||||
foreach ($fileNames as $fileName) {
|
||||
if (
|
||||
$fileName === '.' ||
|
||||
$fileName === '..' ||
|
||||
str_contains($fileName, '.json')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$deviceFiles = $this->getVideoDevice($project->getId());
|
||||
$devicePath = $deviceFiles->getPath($this->args['videoId']);
|
||||
$data = $this->getFilesDevice($project->getId())->read($this->outDir . $fileName);
|
||||
$renditionDir = $profile->getAttribute('width') . 'X' . $profile->getAttribute('height') . '@' . $profile->getAttribute('videoBitrate');
|
||||
$renditionPath = $devicePath . DIRECTORY_SEPARATOR . $renditionDir;
|
||||
$this->getVideoDevice($project->getId())->write($renditionPath . DIRECTORY_SEPARATOR . $fileName, $data, \mime_content_type($this->outDir . $fileName));
|
||||
|
||||
if ($start === 0) {
|
||||
$query->setAttribute('status', self::STATUS_UPLOADING);
|
||||
$query->setAttribute('path', $renditionPath);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
$start = 1;
|
||||
}
|
||||
|
||||
//$metadata=[];
|
||||
//$chunksUploaded = $deviceFiles->upload($file, $path, -1, 1, $metadata);
|
||||
//var_dump($chunksUploaded);
|
||||
// if (empty($chunksUploaded)) {
|
||||
// throw new Exception('Failed uploading file', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
//}
|
||||
// }
|
||||
|
||||
//@unlink($this->outDir . $fileName);
|
||||
}
|
||||
|
||||
$query->setAttribute('status', self::STATUS_PACKAGE_END);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
} catch (\Throwable $th) {
|
||||
$query->setAttribute('metadata', json_encode([
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage(),
|
||||
]));
|
||||
|
||||
$query->setAttribute('status', self::STATUS_ERROR);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,13 +288,16 @@ class TranscodingV1 extends Worker
|
||||
->addRepresentation($representation)
|
||||
->setAdditionalParams($additionalParams)
|
||||
->save($this->outPath);
|
||||
var_dump($this->outPath);
|
||||
|
||||
$xml = simplexml_load_string(
|
||||
file_get_contents($this->outDir . $this->args['fileId'] . '.mpd')
|
||||
);
|
||||
|
||||
$metadata = $this->getVideoInfo($dash->metadata());
|
||||
$metadata['width'] = $representation->getWidth();
|
||||
$metadata['height'] = $representation->getHeight();
|
||||
return [
|
||||
$this->getMetadataExport($dash->metadata()->export()),
|
||||
$metadata,
|
||||
['mpeg-dash' => !empty($xml) ? json_decode(json_encode((array)$xml), true) : []],
|
||||
];
|
||||
}
|
||||
@@ -340,12 +310,33 @@ class TranscodingV1 extends Worker
|
||||
->setAdditionalParams($additionalParams)
|
||||
->setHlsBaseUrl(self::HLS_BASE_URL)
|
||||
->save($this->outPath);
|
||||
var_dump($this->outPath);
|
||||
|
||||
$metadata = $this->getVideoInfo($hls->metadata()->getVideoStreams());
|
||||
$metadata['width'] = $representation->getWidth();
|
||||
$metadata['height'] = $representation->getHeight();
|
||||
|
||||
$this->rewriteHlsRefs($this->outPath . '_' . $representation->getHeight() . 'P.m3u8');
|
||||
|
||||
return [
|
||||
$this->getMetadataExport($hls->metadata()->export()), []
|
||||
$metadata, []
|
||||
];
|
||||
}
|
||||
|
||||
private function rewriteHlsRefs($path)
|
||||
{
|
||||
$handle = fopen($path, "r");
|
||||
$destination = fopen($path . '_tmp', "w");
|
||||
if ($handle) {
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
if (str_contains($line, ".ts")) {
|
||||
//$return['data'][$i]['url'] = str_replace(array("\r","\n"),"",$line);
|
||||
}
|
||||
fwrite($destination, str_replace(array("\r","\n"), "", $line) . PHP_EOL);
|
||||
}
|
||||
fclose($handle);
|
||||
fclose($destination);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $streams StreamCollection
|
||||
@@ -353,13 +344,27 @@ class TranscodingV1 extends Worker
|
||||
*/
|
||||
private function getVideoInfo(StreamCollection $streams): array
|
||||
{
|
||||
var_dump([
|
||||
'duration' => $streams->videos()->first()->get('duration'),
|
||||
'height' => $streams->videos()->first()->get('height'),
|
||||
'width' => $streams->videos()->first()->get('width'),
|
||||
'videoCodec' => $streams->videos()->first()->get('codec_name') . ',' . $streams->videos()->first()->get('codec_tag_string'),
|
||||
'videoFramerate' => $streams->videos()->first()->get('avg_frame_rate'),
|
||||
'videoBitrate' => (int)$streams->videos()->first()->get('bit_rate'),
|
||||
'audioCodec' => $streams->audios()->first()->get('codec_name') . ',' . $streams->audios()->first()->get('codec_tag_string'),
|
||||
'audioSamplerate' => (int)$streams->audios()->first()->get('sample_rate'),
|
||||
'audioBitrate' => (int)$streams->audios()->first()->get('bit_rate'),
|
||||
]);
|
||||
return [
|
||||
'duration' => $streams->videos()->first()->get('duration'),
|
||||
'height' => $streams->videos()->first()->get('height'),
|
||||
'width' => $streams->videos()->first()->get('width'),
|
||||
'frameRate' => $streams->videos()->first()->get('r_frame_rate'),
|
||||
'bitrateKb' => $streams->videos()->first()->get('bit_rate') / 1000,
|
||||
'bitrateMb' => $streams->videos()->first()->get('bit_rate') / 1000 / 1000,
|
||||
'videoCodec' => $streams->videos()->first()->get('codec_name') . ',' . $streams->videos()->first()->get('codec_tag_string'),
|
||||
'videoFramerate' => $streams->videos()->first()->get('avg_frame_rate'),
|
||||
'videoBitrate' => (int)$streams->videos()->first()->get('bit_rate'),
|
||||
'audioCodec' => $streams->audios()->first()->get('codec_name') . ',' . $streams->audios()->first()->get('codec_tag_string'),
|
||||
'audioSamplerate' => (int)$streams->audios()->first()->get('sample_rate'),
|
||||
'audioBitrate' => (int)$streams->audios()->first()->get('bit_rate'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+84
-37
@@ -7,14 +7,38 @@ x-logging: &x-logging
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
max-file: "5"
|
||||
max-size: 10m
|
||||
max-file: '5'
|
||||
max-size: '10m'
|
||||
|
||||
x-env-storage: &x-env-storage |-
|
||||
_APP_STORAGE_DEVICE
|
||||
_APP_STORAGE_S3_ACCESS_KEY
|
||||
_APP_STORAGE_S3_SECRET
|
||||
_APP_STORAGE_S3_REGION
|
||||
_APP_STORAGE_S3_BUCKET
|
||||
_APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
_APP_STORAGE_DO_SPACES_SECRET
|
||||
_APP_STORAGE_DO_SPACES_REGION
|
||||
_APP_STORAGE_DO_SPACES_BUCKET
|
||||
_APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||
_APP_STORAGE_BACKBLAZE_SECRET
|
||||
_APP_STORAGE_BACKBLAZE_REGION
|
||||
_APP_STORAGE_BACKBLAZE_BUCKET
|
||||
_APP_STORAGE_DO_SPACES_BUCKET
|
||||
_APP_STORAGE_LINODE_ACCESS_KEY
|
||||
_APP_STORAGE_LINODE_SECRET
|
||||
_APP_STORAGE_LINODE_REGION
|
||||
_APP_STORAGE_LINODE_BUCKET
|
||||
_APP_STORAGE_WASABI_ACCESS_KEY
|
||||
_APP_STORAGE_WASABI_SECRET
|
||||
_APP_STORAGE_WASABI_REGION
|
||||
_APP_STORAGE_WASABI_BUCKET
|
||||
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.5
|
||||
image: traefik:2.7
|
||||
<<: *x-logging
|
||||
container_name: appwrite-traefik
|
||||
command:
|
||||
@@ -72,7 +96,7 @@ services:
|
||||
- traefik.http.routers.appwrite_api_https.tls=true
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-video:/storage/video:rw
|
||||
- appwrite-videos:/storage/videos:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
@@ -81,6 +105,7 @@ services:
|
||||
- ./tests:/usr/src/code/tests
|
||||
- ./app:/usr/src/code/app
|
||||
- ./vendor:/usr/src/code/vendor #TODO remove when done!!
|
||||
# - ./vendor/utopia/database:/usr/src/code/vendor/utopia/database
|
||||
- ./docs:/usr/src/code/docs
|
||||
- ./public:/usr/src/code/public
|
||||
- ./src:/usr/src/code/src
|
||||
@@ -129,18 +154,11 @@ services:
|
||||
- _APP_INFLUXDB_HOST
|
||||
- _APP_INFLUXDB_PORT
|
||||
- _APP_STORAGE_LIMIT
|
||||
- _APP_STORAGE_PREVIEW_LIMIT
|
||||
- _APP_STORAGE_ANTIVIRUS
|
||||
- _APP_STORAGE_ANTIVIRUS_HOST
|
||||
- _APP_STORAGE_ANTIVIRUS_PORT
|
||||
- _APP_STORAGE_DEVICE
|
||||
- _APP_STORAGE_S3_ACCESS_KEY
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||
- *x-env-storage
|
||||
- _APP_FUNCTIONS_SIZE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||
@@ -150,6 +168,7 @@ services:
|
||||
- _APP_FUNCTIONS_MEMORY_SWAP
|
||||
- _APP_FUNCTIONS_RUNTIMES
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_STATSD_HOST
|
||||
@@ -158,6 +177,8 @@ services:
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
- _APP_PHONE_PROVIDER
|
||||
- _APP_PHONE_SECRET
|
||||
|
||||
appwrite-realtime:
|
||||
entrypoint: realtime
|
||||
@@ -220,7 +241,7 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-video:/storage/video:rw
|
||||
- appwrite-videos:/storage/videos:rw
|
||||
- ./tests:/usr/src/code/tests #TODO remove when done!!
|
||||
- ./vendor:/usr/src/code/vendor #TODO remove when done!!
|
||||
|
||||
@@ -310,7 +331,7 @@ services:
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-video:/storage/video:rw
|
||||
- appwrite-videos:/storage/videos:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
@@ -329,23 +350,16 @@ services:
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_STORAGE_DEVICE
|
||||
- _APP_STORAGE_S3_ACCESS_KEY
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||
- *x-env-storage
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
|
||||
appwrite-worker-database:
|
||||
entrypoint: worker-database
|
||||
appwrite-worker-databases:
|
||||
entrypoint: worker-databases
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-database
|
||||
container_name: appwrite-worker-databases
|
||||
build:
|
||||
context: .
|
||||
networks:
|
||||
@@ -390,6 +404,7 @@ services:
|
||||
- _APP_ENV
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
@@ -421,6 +436,7 @@ services:
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_REDIS_HOST
|
||||
@@ -464,6 +480,7 @@ services:
|
||||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_USAGE_STATS
|
||||
- DOCKERHUB_PULL_USERNAME
|
||||
- DOCKERHUB_PULL_PASSWORD
|
||||
@@ -510,15 +527,7 @@ services:
|
||||
- OPEN_RUNTIMES_NETWORK
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_STORAGE_DEVICE
|
||||
- _APP_STORAGE_S3_ACCESS_KEY
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||
- *x-env-storage
|
||||
- DOCKERHUB_PULL_USERNAME
|
||||
- DOCKERHUB_PULL_PASSWORD
|
||||
|
||||
@@ -554,6 +563,30 @@ services:
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-messaging:
|
||||
entrypoint: worker-messaging
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-messaging
|
||||
build:
|
||||
context: .
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_PHONE_PROVIDER
|
||||
- _APP_PHONE_FROM
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-maintenance:
|
||||
entrypoint: maintenance
|
||||
<<: *x-logging
|
||||
@@ -569,11 +602,18 @@ services:
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_MAINTENANCE_INTERVAL
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
@@ -611,6 +651,8 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-schedule:
|
||||
entrypoint: schedule
|
||||
@@ -666,6 +708,11 @@ services:
|
||||
image: redis:6.2-alpine
|
||||
<<: *x-logging
|
||||
container_name: appwrite-redis
|
||||
command: >
|
||||
redis-server
|
||||
--maxmemory 512mb
|
||||
--maxmemory-policy allkeys-lru
|
||||
--maxmemory-samples 5
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks:
|
||||
@@ -802,7 +849,7 @@ volumes:
|
||||
appwrite-redis:
|
||||
appwrite-cache:
|
||||
appwrite-uploads:
|
||||
appwrite-video:
|
||||
appwrite-videos:
|
||||
appwrite-certificates:
|
||||
appwrite-functions:
|
||||
appwrite-builds:
|
||||
|
||||
@@ -32,17 +32,17 @@ class Event
|
||||
public const BUILDS_QUEUE_NAME = 'v1-builds';
|
||||
public const BUILDS_CLASS_NAME = 'BuildsV1';
|
||||
|
||||
const TRANSCODING_QUEUE_NAME = 'v1-transcoding';
|
||||
const TRANSCODING_CLASS_NAME = 'TranscodingV1';
|
||||
public const MESSAGING_QUEUE_NAME = 'v1-messaging';
|
||||
public const MESSAGING_CLASS_NAME = 'MessagingV1';
|
||||
|
||||
protected string $queue = '';
|
||||
protected string $class = '';
|
||||
protected string $event = '';
|
||||
protected array $params = [];
|
||||
protected array $payload = [];
|
||||
protected array $context = [];
|
||||
protected ?Document $project = null;
|
||||
protected ?Document $user = null;
|
||||
protected ?Document $context = null;
|
||||
|
||||
/**
|
||||
* @param string $queue
|
||||
@@ -172,12 +172,13 @@ class Event
|
||||
/**
|
||||
* Set context for this event.
|
||||
*
|
||||
* @param string $key
|
||||
* @param Document $context
|
||||
* @return self
|
||||
*/
|
||||
public function setContext(Document $context): self
|
||||
public function setContext(string $key, Document $context): self
|
||||
{
|
||||
$this->context = $context;
|
||||
$this->context[$key] = $context;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -185,11 +186,13 @@ class Event
|
||||
/**
|
||||
* Get context for this event.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return null|Document
|
||||
*/
|
||||
public function getContext(): ?Document
|
||||
public function getContext(string $key): ?Document
|
||||
{
|
||||
return $this->context;
|
||||
return $this->context[$key] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,14 +298,28 @@ class Event
|
||||
$type = $parts[0] ?? false;
|
||||
$resource = $parts[1] ?? false;
|
||||
$hasSubResource = $count > 3 && \str_starts_with($parts[3], '[');
|
||||
$hasSubSubResource = $count > 5 && \str_starts_with($parts[5], '[') && $hasSubResource;
|
||||
|
||||
if ($hasSubResource) {
|
||||
$subType = $parts[2];
|
||||
$subResource = $parts[3];
|
||||
}
|
||||
|
||||
if ($hasSubSubResource) {
|
||||
$subSubType = $parts[4];
|
||||
$subSubResource = $parts[5];
|
||||
if ($count == 8) {
|
||||
$attribute = $parts[7];
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasSubResource && !$hasSubSubResource) {
|
||||
if ($count === 6) {
|
||||
$attribute = $parts[5];
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if (!$hasSubResource) {
|
||||
if ($count === 4) {
|
||||
$attribute = $parts[3];
|
||||
}
|
||||
@@ -310,18 +327,25 @@ class Event
|
||||
|
||||
$subType ??= false;
|
||||
$subResource ??= false;
|
||||
$subSubType ??= false;
|
||||
$subSubResource ??= false;
|
||||
$attribute ??= false;
|
||||
$action = match (true) {
|
||||
!$hasSubResource && $count > 2 => $parts[2],
|
||||
$hasSubSubResource => $parts[6] ?? false,
|
||||
$hasSubResource && $count > 4 => $parts[4],
|
||||
default => false
|
||||
};
|
||||
|
||||
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'resource' => $resource,
|
||||
'subType' => $subType,
|
||||
'subResource' => $subResource,
|
||||
'subSubType' => $subSubType,
|
||||
'subSubResource' => $subSubResource,
|
||||
'action' => $action,
|
||||
'attribute' => $attribute,
|
||||
];
|
||||
@@ -348,6 +372,8 @@ class Event
|
||||
$resource = $parsed['resource'];
|
||||
$subType = $parsed['subType'];
|
||||
$subResource = $parsed['subResource'];
|
||||
$subSubType = $parsed['subSubType'];
|
||||
$subSubResource = $parsed['subSubResource'];
|
||||
$action = $parsed['action'];
|
||||
$attribute = $parsed['attribute'];
|
||||
|
||||
@@ -359,11 +385,21 @@ class Event
|
||||
throw new InvalidArgumentException("{$subResource} is missing from the params.");
|
||||
}
|
||||
|
||||
if ($subSubResource && !\in_array(\trim($subSubResource, "\[\]"), $paramKeys)) {
|
||||
throw new InvalidArgumentException("{$subSubResource} is missing from the params.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create all possible patterns including placeholders.
|
||||
*/
|
||||
if ($action) {
|
||||
if ($subResource) {
|
||||
if ($subSubResource) {
|
||||
if ($attribute) {
|
||||
$patterns[] = \implode('.', [$type, $resource, $subType, $subResource, $subSubType, $subSubResource, $action, $attribute]);
|
||||
}
|
||||
$patterns[] = \implode('.', [$type, $resource, $subType, $subResource, $subSubType, $subSubResource, $action]);
|
||||
$patterns[] = \implode('.', [$type, $resource, $subType, $subResource, $subSubType, $subSubResource]);
|
||||
} elseif ($subResource) {
|
||||
if ($attribute) {
|
||||
$patterns[] = \implode('.', [$type, $resource, $subType, $subResource, $action, $attribute]);
|
||||
}
|
||||
@@ -376,6 +412,9 @@ class Event
|
||||
$patterns[] = \implode('.', [$type, $resource, $action, $attribute]);
|
||||
}
|
||||
}
|
||||
if ($subSubResource) {
|
||||
$patterns[] = \implode('.', [$type, $resource, $subType, $subResource, $subSubType, $subSubResource]);
|
||||
}
|
||||
if ($subResource) {
|
||||
$patterns[] = \implode('.', [$type, $resource, $subType, $subResource]);
|
||||
}
|
||||
@@ -395,12 +434,24 @@ class Event
|
||||
$events[] = \str_replace($paramKeys, '*', $eventPattern);
|
||||
foreach ($paramKeys as $key) {
|
||||
foreach ($paramKeys as $current) {
|
||||
if ($current === $key) {
|
||||
continue;
|
||||
if ($subSubResource) {
|
||||
foreach ($paramKeys as $subCurrent) {
|
||||
if ($subCurrent === $current || $subCurrent === $key) {
|
||||
continue;
|
||||
}
|
||||
$filtered1 = \array_filter($paramKeys, fn(string $k) => $k === $subCurrent);
|
||||
$events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered1, '*', $eventPattern));
|
||||
$filtered2 = \array_filter($paramKeys, fn(string $k) => $k === $current);
|
||||
$events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', \str_replace($filtered1, '*', $eventPattern)));
|
||||
$events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered2, '*', $eventPattern));
|
||||
}
|
||||
} else {
|
||||
if ($current === $key) {
|
||||
continue;
|
||||
}
|
||||
$filtered = \array_filter($paramKeys, fn(string $k) => $k === $current);
|
||||
$events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered, '*', $eventPattern));
|
||||
}
|
||||
|
||||
$filtered = \array_filter($paramKeys, fn(string $k) => $k === $current);
|
||||
$events[] = \str_replace($paramKeys, $paramValues, \str_replace($filtered, '*', $eventPattern));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -411,6 +462,9 @@ class Event
|
||||
$events = \array_map(fn (string $event) => \str_replace(['[', ']'], '', $event), $events);
|
||||
$events = \array_unique($events);
|
||||
|
||||
return $events;
|
||||
/**
|
||||
* Force a non-assoc array.
|
||||
*/
|
||||
return \array_values($events);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,11 @@ use Appwrite\Utopia\Response\Model\AttributeIP;
|
||||
use Appwrite\Utopia\Response\Model\AttributeURL;
|
||||
use Appwrite\Utopia\Response\Model\BaseList;
|
||||
use Appwrite\Utopia\Response\Model\Collection;
|
||||
use Appwrite\Utopia\Response\Model\Database;
|
||||
use Appwrite\Utopia\Response\Model\Continent;
|
||||
use Appwrite\Utopia\Response\Model\Country;
|
||||
use Appwrite\Utopia\Response\Model\Currency;
|
||||
use Appwrite\Utopia\Response\Model\Document as ModelDocument;
|
||||
use Appwrite\Utopia\Response\Model\DocumentList;
|
||||
use Appwrite\Utopia\Response\Model\Domain;
|
||||
use Appwrite\Utopia\Response\Model\Error;
|
||||
use Appwrite\Utopia\Response\Model\ErrorDev;
|
||||
@@ -65,11 +65,12 @@ use Appwrite\Utopia\Response\Model\Runtime;
|
||||
use Appwrite\Utopia\Response\Model\UsageBuckets;
|
||||
use Appwrite\Utopia\Response\Model\UsageCollection;
|
||||
use Appwrite\Utopia\Response\Model\UsageDatabase;
|
||||
use Appwrite\Utopia\Response\Model\UsageDatabases;
|
||||
use Appwrite\Utopia\Response\Model\UsageFunctions;
|
||||
use Appwrite\Utopia\Response\Model\UsageProject;
|
||||
use Appwrite\Utopia\Response\Model\UsageStorage;
|
||||
use Appwrite\Utopia\Response\Model\UsageUsers;
|
||||
use Appwrite\Utopia\Response\Model\FileRendition;
|
||||
use Appwrite\Utopia\Response\Model\VideoRendition;
|
||||
use Appwrite\Utopia\Response\Model\Video;
|
||||
use Appwrite\Utopia\Response\Model\VideoProfile;
|
||||
|
||||
@@ -88,6 +89,7 @@ class Response extends SwooleResponse
|
||||
public const MODEL_METRIC_LIST = 'metricList';
|
||||
public const MODEL_ERROR_DEV = 'errorDev';
|
||||
public const MODEL_BASE_LIST = 'baseList';
|
||||
public const MODEL_USAGE_DATABASES = 'usageDatabases';
|
||||
public const MODEL_USAGE_DATABASE = 'usageDatabase';
|
||||
public const MODEL_USAGE_COLLECTION = 'usageCollection';
|
||||
public const MODEL_USAGE_USERS = 'usageUsers';
|
||||
@@ -97,6 +99,8 @@ class Response extends SwooleResponse
|
||||
public const MODEL_USAGE_PROJECT = 'usageProject';
|
||||
|
||||
// Database
|
||||
public const MODEL_DATABASE = 'database';
|
||||
public const MODEL_DATABASE_LIST = 'databaseList';
|
||||
public const MODEL_COLLECTION = 'collection';
|
||||
public const MODEL_COLLECTION_LIST = 'collectionList';
|
||||
public const MODEL_INDEX = 'index';
|
||||
@@ -135,8 +139,8 @@ class Response extends SwooleResponse
|
||||
public const MODEL_VIDEO = 'video';
|
||||
public const MODEL_VIDEO_PROFILE = 'videoProfile';
|
||||
public const MODEL_VIDEO_PROFILE_LIST = 'videoProfileList';
|
||||
public const MODEL_FILE_RENDITION = 'fileRendition';
|
||||
public const MODEL_FILE_RENDITIONS_LIST = 'fileRenditionsList';
|
||||
public const MODEL_VIDEO_RENDITION = 'videoRendition';
|
||||
public const MODEL_VIDEO_RENDITIONS_LIST = 'videoRenditionsList';
|
||||
|
||||
// Locale
|
||||
public const MODEL_LOCALE = 'locale';
|
||||
@@ -223,6 +227,7 @@ class Response extends SwooleResponse
|
||||
// Lists
|
||||
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
|
||||
->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION))
|
||||
->setModel(new BaseList('Databases List', self::MODEL_DATABASE_LIST, 'databases', self::MODEL_DATABASE))
|
||||
->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX))
|
||||
->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER))
|
||||
->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION))
|
||||
@@ -247,10 +252,11 @@ class Response extends SwooleResponse
|
||||
->setModel(new BaseList('Currencies List', self::MODEL_CURRENCY_LIST, 'currencies', self::MODEL_CURRENCY))
|
||||
->setModel(new BaseList('Phones List', self::MODEL_PHONE_LIST, 'phones', self::MODEL_PHONE))
|
||||
->setModel(new BaseList('Metric List', self::MODEL_METRIC_LIST, 'metrics', self::MODEL_METRIC, true, false))
|
||||
->setModel(new BaseList('File Renditions List', self::MODEL_FILE_RENDITIONS_LIST, 'renditions', self::MODEL_FILE_RENDITION))
|
||||
->setModel(new BaseList('Video Renditions List', self::MODEL_VIDEO_RENDITIONS_LIST, 'renditions', self::MODEL_VIDEO_RENDITION))
|
||||
->setModel(new BaseList('video profile List', self::MODEL_VIDEO_PROFILE_LIST, 'profiles', self::MODEL_VIDEO_PROFILE))
|
||||
|
||||
// Entities
|
||||
->setModel(new Database())
|
||||
->setModel(new Collection())
|
||||
->setModel(new Attribute())
|
||||
->setModel(new AttributeList())
|
||||
@@ -296,6 +302,7 @@ class Response extends SwooleResponse
|
||||
->setModel(new HealthTime())
|
||||
->setModel(new HealthVersion())
|
||||
->setModel(new Metric())
|
||||
->setModel(new UsageDatabases())
|
||||
->setModel(new UsageDatabase())
|
||||
->setModel(new UsageCollection())
|
||||
->setModel(new UsageUsers())
|
||||
@@ -303,7 +310,7 @@ class Response extends SwooleResponse
|
||||
->setModel(new UsageBuckets())
|
||||
->setModel(new UsageFunctions())
|
||||
->setModel(new UsageProject())
|
||||
->setModel(new FileRendition())
|
||||
->setModel(new VideoRendition())
|
||||
->setModel(new Video())
|
||||
->setModel(new VideoProfile())
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class Database extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Database ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Database name.',
|
||||
'default' => '',
|
||||
'example' => 'My Database',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Database';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_DATABASE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class UsageDatabases extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('databasesCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of collections.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for total number of collections.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for documents deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for collections delete.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'UsageDatabases';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_USAGE_DATABASES;
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -5,7 +5,7 @@ namespace Appwrite\Utopia\Response\Model;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class FileRendition extends Model
|
||||
class VideoRendition extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
@@ -16,25 +16,19 @@ class FileRendition extends Model
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('bucketId', [
|
||||
->addRule('videoId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Bucket ID.',
|
||||
'description' => 'Video ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('fileId', [
|
||||
->addRule('profileId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'File ID.',
|
||||
'description' => 'profile ID.',
|
||||
'default' => '',
|
||||
'example' => 'd5fg5ehg1c168g7c',
|
||||
])
|
||||
->addRule('renditionId', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Rendition ID.',
|
||||
'default' => '',
|
||||
'example' => 3,
|
||||
])
|
||||
->addRule('renditionName', [
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Rendition name.',
|
||||
'default' => '',
|
||||
@@ -64,6 +58,12 @@ class FileRendition extends Model
|
||||
'default' => 0,
|
||||
'example' => 88,
|
||||
])
|
||||
->addRule('stream', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Rendition trascoding stream protocol type',
|
||||
'default' => 0,
|
||||
'example' => 88,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class VideoCustomServerTest extends Scope
|
||||
], [
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all']
|
||||
]);
|
||||
]);
|
||||
|
||||
$videoId = $response['body']['$id'];
|
||||
|
||||
@@ -104,29 +104,8 @@ class VideoCustomServerTest extends Scope
|
||||
'write' => ['role:all']
|
||||
]);
|
||||
|
||||
var_dump($response['body']);
|
||||
|
||||
// var_dump($pid);
|
||||
// var_dump($key);
|
||||
// var_dump($fid);
|
||||
// var_dump($bid);
|
||||
//
|
||||
////
|
||||
//// $pid = '62b1956c92e0e39ef577';
|
||||
//// $key = 'f9b8dd3800b93a3dd513cf7cbcbd436cd61850b2c101662210e8ee2f052f796b3d4c7a08149634ce90da6037f6164d7faa36b32b91b568524e6720014e149b83f7a970c28de1a14a97a69010be325d142d51ca51f0f1b29783a7c1f4689d1b90a42cf19a7b55ec9ea6dc51974a1740b67e71de9f80009c2d91c6f3c686aa616c';
|
||||
//// $fid = '62b1956e4f03f57a0f74';
|
||||
//// $bid = '62b1956d0c600d70c8f7';
|
||||
////
|
||||
// $video = $this->client->call(Client::METHOD_POST, '/video/buckets/' . $bid . '/files/' . $fid, [
|
||||
// 'content-type' => 'application/json',
|
||||
// 'x-appwrite-project' => $pid,
|
||||
// 'x-appwrite-key' => $key,
|
||||
// ], [
|
||||
// 'read' => ['role:all'],
|
||||
// 'write' => ['role:all']
|
||||
// ]);
|
||||
// var_dump($video);
|
||||
|
||||
$this->assertNotEmpty($profileId);
|
||||
|
||||
return [
|
||||
'videoId' => $videoId,
|
||||
@@ -135,40 +114,39 @@ class VideoCustomServerTest extends Scope
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateBucketFile
|
||||
* @depends testTranscodingRendition
|
||||
*/
|
||||
public function testRenditions(): void
|
||||
public function testGetRenditions($data): void
|
||||
{
|
||||
|
||||
$pid = '62b1956c92e0e39ef577';
|
||||
$key = 'f9b8dd3800b93a3dd513cf7cbcbd436cd61850b2c101662210e8ee2f052f796b3d4c7a08149634ce90da6037f6164d7faa36b32b91b568524e6720014e149b83f7a970c28de1a14a97a69010be325d142d51ca51f0f1b29783a7c1f4689d1b90a42cf19a7b55ec9ea6dc51974a1740b67e71de9f80009c2d91c6f3c686aa616c';
|
||||
$fid = '62b1956e4f03f57a0f74';
|
||||
$bid = '62b1956d0c600d70c8f7';
|
||||
sleep(30);
|
||||
|
||||
|
||||
$renditions = $this->client->call(Client::METHOD_GET, '/video/buckets/' . $bid . '/files/' . $fid . '/renditions', [
|
||||
$response = $this->client->call(Client::METHOD_GET, '/video/' . $data['videoId'] . '/hls/renditions', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $pid,
|
||||
'x-appwrite-key' => $key,
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],[
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all']
|
||||
]);
|
||||
var_dump($renditions['body']);
|
||||
|
||||
var_dump($response['body']);
|
||||
}
|
||||
|
||||
|
||||
public function testPlaylist(): void
|
||||
/**
|
||||
* @depends testTranscodingRendition
|
||||
*/
|
||||
public function testPlaylist($data): void
|
||||
{
|
||||
sleep(60);
|
||||
|
||||
$pid = '62b1956c92e0e39ef577';
|
||||
$key = 'f9b8dd3800b93a3dd513cf7cbcbd436cd61850b2c101662210e8ee2f052f796b3d4c7a08149634ce90da6037f6164d7faa36b32b91b568524e6720014e149b83f7a970c28de1a14a97a69010be325d142d51ca51f0f1b29783a7c1f4689d1b90a42cf19a7b55ec9ea6dc51974a1740b67e71de9f80009c2d91c6f3c686aa616c';
|
||||
$fid = '62b1956e4f03f57a0f74';
|
||||
$bid = '62b1956d0c600d70c8f7';
|
||||
$stream = 'hls';
|
||||
|
||||
$renditions = $this->client->call(Client::METHOD_GET, '/video/buckets/' . $bid . '/files/' . $stream . '/' . $fid, [
|
||||
$response = $this->client->call(Client::METHOD_GET, '/video/' . $data['videoId'] . '/master/hls/' . $data['videoId'].'.m3u8', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $pid,
|
||||
'x-appwrite-key' => $key,
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],[
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all']
|
||||
]);
|
||||
var_dump($renditions['body']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user