mirror of
https://github.com/appwrite/appwrite
synced 2026-05-22 08:28:42 +00:00
Merge remote-tracking branch 'origin/storage-size' into storage-size
This commit is contained in:
commit
93e7dc772d
38 changed files with 1437 additions and 720 deletions
22
.github/workflows/tests.yml
vendored
22
.github/workflows/tests.yml
vendored
|
|
@ -223,7 +223,7 @@ jobs:
|
|||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group abuseEnabled,screenshots
|
||||
|
||||
- name: Failure Logs
|
||||
if: failure()
|
||||
|
|
@ -312,7 +312,7 @@ jobs:
|
|||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group abuseEnabled,screenshots
|
||||
|
||||
- name: Failure Logs
|
||||
if: failure()
|
||||
|
|
@ -322,8 +322,8 @@ jobs:
|
|||
echo "=== OpenRuntimes Executor Logs ==="
|
||||
docker compose logs openruntimes-executor
|
||||
|
||||
e2e_dev_keys:
|
||||
name: E2E Service Test (Dev Keys)
|
||||
e2e_abuse_enabled:
|
||||
name: E2E Service Test (Abuse enabled)
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
steps:
|
||||
|
|
@ -344,7 +344,7 @@ jobs:
|
|||
docker compose up -d
|
||||
sleep 30
|
||||
|
||||
- name: Run Projects tests with dev keys in dedicated table mode
|
||||
- name: Run Projects tests in dedicated table mode
|
||||
run: |
|
||||
echo "Using project tables"
|
||||
export _APP_DATABASE_SHARED_TABLES=
|
||||
|
|
@ -354,7 +354,7 @@ jobs:
|
|||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys
|
||||
appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=abuseEnabled
|
||||
|
||||
- name: Failure Logs
|
||||
if: failure()
|
||||
|
|
@ -364,8 +364,8 @@ jobs:
|
|||
echo "=== OpenRuntimes Executor Logs ==="
|
||||
docker compose logs openruntimes-executor
|
||||
|
||||
e2e_dev_keys_shared_mode:
|
||||
name: E2E Shared Mode Service Test (Dev Keys)
|
||||
e2e_abuse_enabled_shared_mode:
|
||||
name: E2E Shared Mode Service Test (Abuse enabled)
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ setup, check_database_changes ]
|
||||
if: needs.check_database_changes.outputs.database_changed == 'true'
|
||||
|
|
@ -394,7 +394,7 @@ jobs:
|
|||
docker compose up -d
|
||||
sleep 30
|
||||
|
||||
- name: Run Projects tests with dev keys in ${{ matrix.tables-mode }} table mode
|
||||
- name: Run Projects tests in ${{ matrix.tables-mode }} table mode
|
||||
run: |
|
||||
if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then
|
||||
echo "Using shared tables V1"
|
||||
|
|
@ -410,7 +410,7 @@ jobs:
|
|||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys
|
||||
appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=abuseEnabled
|
||||
|
||||
- name: Failure Logs
|
||||
if: failure()
|
||||
|
|
@ -420,7 +420,7 @@ jobs:
|
|||
echo "=== OpenRuntimes Executor Logs ==="
|
||||
docker compose logs openruntimes-executor
|
||||
|
||||
e2e_screenshots_keys:
|
||||
e2e_screenshots:
|
||||
name: E2E Service Test (Site Screenshots)
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
|
|
|
|||
|
|
@ -330,7 +330,18 @@ $platformCollections = [
|
|||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['datetime'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('labels'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
|
|
@ -1402,21 +1413,21 @@ $platformCollections = [
|
|||
'$id' => '_key_type',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['type'],
|
||||
'lengths' => [32],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_trigger',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['trigger'],
|
||||
'lengths' => [32],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_deploymentResourceType',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['deploymentResourceType'],
|
||||
'lengths' => [32],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
|
|
@ -1458,23 +1469,23 @@ $platformCollections = [
|
|||
'$id' => ID::custom('_key_owner'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['owner'],
|
||||
'lengths' => [16],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_region'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['region'],
|
||||
'lengths' => [16],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_piid_riid_rt'),
|
||||
'$id' => ID::custom('_key_piid_diid_drt'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['projectInternalId', 'deploymentInternalId', 'deploymentResourceType'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_region_status_createdAt',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['region', 'status', '$createdAt'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -959,6 +959,7 @@ App::post('/v1/account/sessions/email')
|
|||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->label('abuse-reset', [201])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
|
||||
->inject('request')
|
||||
|
|
@ -1257,6 +1258,7 @@ App::post('/v1/account/sessions/token')
|
|||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'ip:{ip},userId:{param-userId}')
|
||||
->label('abuse-reset', [201])
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. 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('secret', '', new Text(256), 'Secret of a token generated by login methods. For example, the `createMagicURLToken` or `createPhoneToken` methods.')
|
||||
->inject('request')
|
||||
|
|
@ -2645,6 +2647,7 @@ App::put('/v1/account/sessions/magic-url')
|
|||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'ip:{ip},userId:{param-userId}')
|
||||
->label('abuse-reset', [201])
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. 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('secret', '', new Text(256), 'Valid verification token.')
|
||||
->inject('request')
|
||||
|
|
|
|||
|
|
@ -697,7 +697,7 @@ App::get('/v1/avatars/screenshots')
|
|||
}
|
||||
|
||||
$client = new Client();
|
||||
$client->setTimeout(30);
|
||||
$client->setTimeout(30 * 1000); // 30 seconds
|
||||
$client->addHeader('content-type', Client::CONTENT_TYPE_APPLICATION_JSON);
|
||||
|
||||
// Convert indexed array to empty array (should not happen due to Assoc validator)
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ App::post('/v1/projects')
|
|||
'accessedAt' => DateTime::now(),
|
||||
'search' => implode(' ', [$projectId, $name]),
|
||||
'database' => $dsn,
|
||||
'labels' => [],
|
||||
]));
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::PROJECT_ALREADY_EXISTS);
|
||||
|
|
@ -1500,6 +1501,7 @@ App::post('/v1/projects/:projectId/keys')
|
|||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
// TODO: @hmacr Remove `projectInternalId` and `projectId` column writes before deleting the column.
|
||||
'projectInternalId' => $project->getSequence(),
|
||||
'projectId' => $project->getId(),
|
||||
'resourceInternalId' => $project->getSequence(),
|
||||
|
|
@ -1552,13 +1554,8 @@ App::get('/v1/projects/:projectId/keys')
|
|||
}
|
||||
|
||||
$keys = $dbForPlatform->find('keys', [
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
]),
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
Query::limit(5000),
|
||||
]);
|
||||
|
||||
|
|
@ -1599,13 +1596,8 @@ App::get('/v1/projects/:projectId/keys/:keyId')
|
|||
|
||||
$key = $dbForPlatform->findOne('keys', [
|
||||
Query::equal('$id', [$keyId]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
])
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
|
|
@ -1649,13 +1641,8 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
|||
|
||||
$key = $dbForPlatform->findOne('keys', [
|
||||
Query::equal('$id', [$keyId]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
])
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
|
|
@ -1706,13 +1693,8 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
|||
|
||||
$key = $dbForPlatform->findOne('keys', [
|
||||
Query::equal('$id', [$keyId]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
])
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -200,8 +200,12 @@ App::post('/v1/mock/api-key-unprefixed')
|
|||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
// TODO: @hmacr Remove `projectInternalId` and `projectId` column writes before deleting the column.
|
||||
'projectInternalId' => $project->getSequence(),
|
||||
'projectId' => $project->getId(),
|
||||
'resourceInternalId' => $project->getSequence(),
|
||||
'resourceId' => $project->getId(),
|
||||
'resourceType' => 'projects',
|
||||
'name' => 'Outdated key',
|
||||
'scopes' => $scopes,
|
||||
'expire' => null,
|
||||
|
|
|
|||
|
|
@ -814,7 +814,8 @@ App::shutdown()
|
|||
->inject('queueForWebhooks')
|
||||
->inject('queueForRealtime')
|
||||
->inject('dbForProject')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject) use ($parseLabel) {
|
||||
->inject('timelimit')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, callable $timelimit) use ($parseLabel) {
|
||||
|
||||
$responsePayload = $response->getPayload();
|
||||
|
||||
|
|
@ -848,6 +849,41 @@ App::shutdown()
|
|||
$route = $utopia->getRoute();
|
||||
$requestParams = $route->getParamsValues();
|
||||
|
||||
/**
|
||||
* Abuse labels
|
||||
*/
|
||||
$abuseEnabled = System::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled';
|
||||
$abuseResetCode = $route->getLabel('abuse-reset', []);
|
||||
$abuseResetCode = \is_array($abuseResetCode) ? $abuseResetCode : [$abuseResetCode];
|
||||
|
||||
if ($abuseEnabled && \count($abuseResetCode) > 0 && \in_array($response->getStatusCode(), $abuseResetCode)) {
|
||||
$abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}');
|
||||
$abuseKeyLabel = (!is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel;
|
||||
|
||||
foreach ($abuseKeyLabel as $abuseKey) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$timeLimit = $timelimit($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600));
|
||||
$timeLimit
|
||||
->setParam('{projectId}', $project->getId())
|
||||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getHostname() . $route->getPath())
|
||||
->setParam('{method}', $request->getMethod())
|
||||
->setParam('{chunkId}', (int)($start / ($end + 1 - $start)));
|
||||
|
||||
foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys
|
||||
if (!empty($value)) {
|
||||
$timeLimit->setParam('{param-' . $key . '}', (\is_array($value)) ? \json_encode($value) : $value);
|
||||
}
|
||||
}
|
||||
|
||||
$abuse = new Abuse($timeLimit);
|
||||
$abuse->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Audit labels
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ require_once __DIR__ . '/init/database/filters.php';
|
|||
require_once __DIR__ . '/init/database/formats.php';
|
||||
require_once __DIR__ . '/init/locales.php';
|
||||
require_once __DIR__ . '/init/registers.php';
|
||||
require_once __DIR__ . '/init/models.php';
|
||||
require_once __DIR__ . '/init/resources.php';
|
||||
|
||||
\stream_context_set_default([ // Set global user agent and http settings
|
||||
|
|
|
|||
|
|
@ -136,13 +136,8 @@ Database::addFilter(
|
|||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('keys', [
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$document->getSequence()]),
|
||||
])
|
||||
]),
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
344
app/init/models.php
Normal file
344
app/init/models.php
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model\Account;
|
||||
use Appwrite\Utopia\Response\Model\AlgoArgon2;
|
||||
use Appwrite\Utopia\Response\Model\AlgoBcrypt;
|
||||
use Appwrite\Utopia\Response\Model\AlgoMd5;
|
||||
use Appwrite\Utopia\Response\Model\AlgoPhpass;
|
||||
use Appwrite\Utopia\Response\Model\AlgoScrypt;
|
||||
use Appwrite\Utopia\Response\Model\AlgoScryptModified;
|
||||
use Appwrite\Utopia\Response\Model\AlgoSha;
|
||||
use Appwrite\Utopia\Response\Model\Any;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
use Appwrite\Utopia\Response\Model\AttributeBoolean;
|
||||
use Appwrite\Utopia\Response\Model\AttributeDatetime;
|
||||
use Appwrite\Utopia\Response\Model\AttributeEmail;
|
||||
use Appwrite\Utopia\Response\Model\AttributeEnum;
|
||||
use Appwrite\Utopia\Response\Model\AttributeFloat;
|
||||
use Appwrite\Utopia\Response\Model\AttributeInteger;
|
||||
use Appwrite\Utopia\Response\Model\AttributeIP;
|
||||
use Appwrite\Utopia\Response\Model\AttributeLine;
|
||||
use Appwrite\Utopia\Response\Model\AttributeList;
|
||||
use Appwrite\Utopia\Response\Model\AttributePoint;
|
||||
use Appwrite\Utopia\Response\Model\AttributePolygon;
|
||||
use Appwrite\Utopia\Response\Model\AttributeRelationship;
|
||||
use Appwrite\Utopia\Response\Model\AttributeString;
|
||||
use Appwrite\Utopia\Response\Model\AttributeURL;
|
||||
use Appwrite\Utopia\Response\Model\AuthProvider;
|
||||
use Appwrite\Utopia\Response\Model\BaseList;
|
||||
use Appwrite\Utopia\Response\Model\Branch;
|
||||
use Appwrite\Utopia\Response\Model\Bucket;
|
||||
use Appwrite\Utopia\Response\Model\Collection;
|
||||
use Appwrite\Utopia\Response\Model\Column;
|
||||
use Appwrite\Utopia\Response\Model\ColumnBoolean;
|
||||
use Appwrite\Utopia\Response\Model\ColumnDatetime;
|
||||
use Appwrite\Utopia\Response\Model\ColumnEmail;
|
||||
use Appwrite\Utopia\Response\Model\ColumnEnum;
|
||||
use Appwrite\Utopia\Response\Model\ColumnFloat;
|
||||
use Appwrite\Utopia\Response\Model\ColumnIndex;
|
||||
use Appwrite\Utopia\Response\Model\ColumnInteger;
|
||||
use Appwrite\Utopia\Response\Model\ColumnIP;
|
||||
use Appwrite\Utopia\Response\Model\ColumnLine;
|
||||
use Appwrite\Utopia\Response\Model\ColumnList;
|
||||
use Appwrite\Utopia\Response\Model\ColumnPoint;
|
||||
use Appwrite\Utopia\Response\Model\ColumnPolygon;
|
||||
use Appwrite\Utopia\Response\Model\ColumnRelationship;
|
||||
use Appwrite\Utopia\Response\Model\ColumnString;
|
||||
use Appwrite\Utopia\Response\Model\ColumnURL;
|
||||
use Appwrite\Utopia\Response\Model\ConsoleVariables;
|
||||
use Appwrite\Utopia\Response\Model\Continent;
|
||||
use Appwrite\Utopia\Response\Model\Country;
|
||||
use Appwrite\Utopia\Response\Model\Currency;
|
||||
use Appwrite\Utopia\Response\Model\Database;
|
||||
use Appwrite\Utopia\Response\Model\Deployment;
|
||||
use Appwrite\Utopia\Response\Model\DetectionFramework;
|
||||
use Appwrite\Utopia\Response\Model\DetectionRuntime;
|
||||
use Appwrite\Utopia\Response\Model\DetectionVariable;
|
||||
use Appwrite\Utopia\Response\Model\DevKey;
|
||||
use Appwrite\Utopia\Response\Model\Document as ModelDocument;
|
||||
use Appwrite\Utopia\Response\Model\Error;
|
||||
use Appwrite\Utopia\Response\Model\ErrorDev;
|
||||
use Appwrite\Utopia\Response\Model\Execution;
|
||||
use Appwrite\Utopia\Response\Model\File;
|
||||
use Appwrite\Utopia\Response\Model\Framework;
|
||||
use Appwrite\Utopia\Response\Model\FrameworkAdapter;
|
||||
use Appwrite\Utopia\Response\Model\Func;
|
||||
use Appwrite\Utopia\Response\Model\Headers;
|
||||
use Appwrite\Utopia\Response\Model\HealthAntivirus;
|
||||
use Appwrite\Utopia\Response\Model\HealthCertificate;
|
||||
use Appwrite\Utopia\Response\Model\HealthQueue;
|
||||
use Appwrite\Utopia\Response\Model\HealthStatus;
|
||||
use Appwrite\Utopia\Response\Model\HealthTime;
|
||||
use Appwrite\Utopia\Response\Model\HealthVersion;
|
||||
use Appwrite\Utopia\Response\Model\Identity;
|
||||
use Appwrite\Utopia\Response\Model\Index;
|
||||
use Appwrite\Utopia\Response\Model\Installation;
|
||||
use Appwrite\Utopia\Response\Model\JWT;
|
||||
use Appwrite\Utopia\Response\Model\Key;
|
||||
use Appwrite\Utopia\Response\Model\Language;
|
||||
use Appwrite\Utopia\Response\Model\Locale;
|
||||
use Appwrite\Utopia\Response\Model\LocaleCode;
|
||||
use Appwrite\Utopia\Response\Model\Log;
|
||||
use Appwrite\Utopia\Response\Model\Membership;
|
||||
use Appwrite\Utopia\Response\Model\Message;
|
||||
use Appwrite\Utopia\Response\Model\Metric;
|
||||
use Appwrite\Utopia\Response\Model\MetricBreakdown;
|
||||
use Appwrite\Utopia\Response\Model\MFAChallenge;
|
||||
use Appwrite\Utopia\Response\Model\MFAFactors;
|
||||
use Appwrite\Utopia\Response\Model\MFARecoveryCodes;
|
||||
use Appwrite\Utopia\Response\Model\MFAType;
|
||||
use Appwrite\Utopia\Response\Model\Migration;
|
||||
use Appwrite\Utopia\Response\Model\MigrationFirebaseProject;
|
||||
use Appwrite\Utopia\Response\Model\MigrationReport;
|
||||
use Appwrite\Utopia\Response\Model\Mock;
|
||||
use Appwrite\Utopia\Response\Model\MockNumber;
|
||||
use Appwrite\Utopia\Response\Model\None;
|
||||
use Appwrite\Utopia\Response\Model\Phone;
|
||||
use Appwrite\Utopia\Response\Model\Platform;
|
||||
use Appwrite\Utopia\Response\Model\Preferences;
|
||||
use Appwrite\Utopia\Response\Model\Project;
|
||||
use Appwrite\Utopia\Response\Model\Provider;
|
||||
use Appwrite\Utopia\Response\Model\ProviderRepository;
|
||||
use Appwrite\Utopia\Response\Model\ProviderRepositoryFramework;
|
||||
use Appwrite\Utopia\Response\Model\ProviderRepositoryRuntime;
|
||||
use Appwrite\Utopia\Response\Model\ResourceToken;
|
||||
use Appwrite\Utopia\Response\Model\Row;
|
||||
use Appwrite\Utopia\Response\Model\Rule;
|
||||
use Appwrite\Utopia\Response\Model\Runtime;
|
||||
use Appwrite\Utopia\Response\Model\Session;
|
||||
use Appwrite\Utopia\Response\Model\Site;
|
||||
use Appwrite\Utopia\Response\Model\Specification;
|
||||
use Appwrite\Utopia\Response\Model\Subscriber;
|
||||
use Appwrite\Utopia\Response\Model\Table;
|
||||
use Appwrite\Utopia\Response\Model\Target;
|
||||
use Appwrite\Utopia\Response\Model\Team;
|
||||
use Appwrite\Utopia\Response\Model\TemplateEmail;
|
||||
use Appwrite\Utopia\Response\Model\TemplateFramework;
|
||||
use Appwrite\Utopia\Response\Model\TemplateFunction;
|
||||
use Appwrite\Utopia\Response\Model\TemplateRuntime;
|
||||
use Appwrite\Utopia\Response\Model\TemplateSite;
|
||||
use Appwrite\Utopia\Response\Model\TemplateSMS;
|
||||
use Appwrite\Utopia\Response\Model\TemplateVariable;
|
||||
use Appwrite\Utopia\Response\Model\Token;
|
||||
use Appwrite\Utopia\Response\Model\Topic;
|
||||
use Appwrite\Utopia\Response\Model\Transaction;
|
||||
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\UsageFunction;
|
||||
use Appwrite\Utopia\Response\Model\UsageFunctions;
|
||||
use Appwrite\Utopia\Response\Model\UsageProject;
|
||||
use Appwrite\Utopia\Response\Model\UsageSite;
|
||||
use Appwrite\Utopia\Response\Model\UsageSites;
|
||||
use Appwrite\Utopia\Response\Model\UsageStorage;
|
||||
use Appwrite\Utopia\Response\Model\UsageTable;
|
||||
use Appwrite\Utopia\Response\Model\UsageUsers;
|
||||
use Appwrite\Utopia\Response\Model\User;
|
||||
use Appwrite\Utopia\Response\Model\Variable;
|
||||
use Appwrite\Utopia\Response\Model\VcsContent;
|
||||
use Appwrite\Utopia\Response\Model\Webhook;
|
||||
|
||||
// General
|
||||
Response::setModel(new None());
|
||||
Response::setModel(new Any());
|
||||
Response::setModel(new Error());
|
||||
Response::setModel(new ErrorDev());
|
||||
|
||||
// Lists
|
||||
Response::setModel(new BaseList('Rows List', Response::MODEL_ROW_LIST, 'rows', Response::MODEL_ROW));
|
||||
Response::setModel(new BaseList('Documents List', Response::MODEL_DOCUMENT_LIST, 'documents', Response::MODEL_DOCUMENT));
|
||||
Response::setModel(new BaseList('Tables List', Response::MODEL_TABLE_LIST, 'tables', Response::MODEL_TABLE));
|
||||
Response::setModel(new BaseList('Collections List', Response::MODEL_COLLECTION_LIST, 'collections', Response::MODEL_COLLECTION));
|
||||
Response::setModel(new BaseList('Databases List', Response::MODEL_DATABASE_LIST, 'databases', Response::MODEL_DATABASE));
|
||||
Response::setModel(new BaseList('Indexes List', Response::MODEL_INDEX_LIST, 'indexes', Response::MODEL_INDEX));
|
||||
Response::setModel(new BaseList('Column Indexes List', Response::MODEL_COLUMN_INDEX_LIST, 'indexes', Response::MODEL_COLUMN_INDEX));
|
||||
Response::setModel(new BaseList('Users List', Response::MODEL_USER_LIST, 'users', Response::MODEL_USER));
|
||||
Response::setModel(new BaseList('Sessions List', Response::MODEL_SESSION_LIST, 'sessions', Response::MODEL_SESSION));
|
||||
Response::setModel(new BaseList('Identities List', Response::MODEL_IDENTITY_LIST, 'identities', Response::MODEL_IDENTITY));
|
||||
Response::setModel(new BaseList('Logs List', Response::MODEL_LOG_LIST, 'logs', Response::MODEL_LOG));
|
||||
Response::setModel(new BaseList('Files List', Response::MODEL_FILE_LIST, 'files', Response::MODEL_FILE));
|
||||
Response::setModel(new BaseList('Buckets List', Response::MODEL_BUCKET_LIST, 'buckets', Response::MODEL_BUCKET));
|
||||
Response::setModel(new BaseList('Resource Tokens List', Response::MODEL_RESOURCE_TOKEN_LIST, 'tokens', Response::MODEL_RESOURCE_TOKEN));
|
||||
Response::setModel(new BaseList('Teams List', Response::MODEL_TEAM_LIST, 'teams', Response::MODEL_TEAM));
|
||||
Response::setModel(new BaseList('Memberships List', Response::MODEL_MEMBERSHIP_LIST, 'memberships', Response::MODEL_MEMBERSHIP));
|
||||
Response::setModel(new BaseList('Sites List', Response::MODEL_SITE_LIST, 'sites', Response::MODEL_SITE));
|
||||
Response::setModel(new BaseList('Site Templates List', Response::MODEL_TEMPLATE_SITE_LIST, 'templates', Response::MODEL_TEMPLATE_SITE));
|
||||
Response::setModel(new BaseList('Functions List', Response::MODEL_FUNCTION_LIST, 'functions', Response::MODEL_FUNCTION));
|
||||
Response::setModel(new BaseList('Function Templates List', Response::MODEL_TEMPLATE_FUNCTION_LIST, 'templates', Response::MODEL_TEMPLATE_FUNCTION));
|
||||
Response::setModel(new BaseList('Installations List', Response::MODEL_INSTALLATION_LIST, 'installations', Response::MODEL_INSTALLATION));
|
||||
Response::setModel(new BaseList('Framework Provider Repositories List', Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST, 'frameworkProviderRepositories', Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK));
|
||||
Response::setModel(new BaseList('Runtime Provider Repositories List', Response::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST, 'runtimeProviderRepositories', Response::MODEL_PROVIDER_REPOSITORY_RUNTIME));
|
||||
Response::setModel(new BaseList('Branches List', Response::MODEL_BRANCH_LIST, 'branches', Response::MODEL_BRANCH));
|
||||
Response::setModel(new BaseList('Frameworks List', Response::MODEL_FRAMEWORK_LIST, 'frameworks', Response::MODEL_FRAMEWORK));
|
||||
Response::setModel(new BaseList('Runtimes List', Response::MODEL_RUNTIME_LIST, 'runtimes', Response::MODEL_RUNTIME));
|
||||
Response::setModel(new BaseList('Deployments List', Response::MODEL_DEPLOYMENT_LIST, 'deployments', Response::MODEL_DEPLOYMENT));
|
||||
Response::setModel(new BaseList('Executions List', Response::MODEL_EXECUTION_LIST, 'executions', Response::MODEL_EXECUTION));
|
||||
Response::setModel(new BaseList('Projects List', Response::MODEL_PROJECT_LIST, 'projects', Response::MODEL_PROJECT, true, false));
|
||||
Response::setModel(new BaseList('Webhooks List', Response::MODEL_WEBHOOK_LIST, 'webhooks', Response::MODEL_WEBHOOK, true, false));
|
||||
Response::setModel(new BaseList('API Keys List', Response::MODEL_KEY_LIST, 'keys', Response::MODEL_KEY, true, false));
|
||||
Response::setModel(new BaseList('Dev Keys List', Response::MODEL_DEV_KEY_LIST, 'devKeys', Response::MODEL_DEV_KEY, true, false));
|
||||
Response::setModel(new BaseList('Auth Providers List', Response::MODEL_AUTH_PROVIDER_LIST, 'platforms', Response::MODEL_AUTH_PROVIDER, true, false));
|
||||
Response::setModel(new BaseList('Platforms List', Response::MODEL_PLATFORM_LIST, 'platforms', Response::MODEL_PLATFORM, true, false));
|
||||
Response::setModel(new BaseList('Countries List', Response::MODEL_COUNTRY_LIST, 'countries', Response::MODEL_COUNTRY));
|
||||
Response::setModel(new BaseList('Continents List', Response::MODEL_CONTINENT_LIST, 'continents', Response::MODEL_CONTINENT));
|
||||
Response::setModel(new BaseList('Languages List', Response::MODEL_LANGUAGE_LIST, 'languages', Response::MODEL_LANGUAGE));
|
||||
Response::setModel(new BaseList('Currencies List', Response::MODEL_CURRENCY_LIST, 'currencies', Response::MODEL_CURRENCY));
|
||||
Response::setModel(new BaseList('Phones List', Response::MODEL_PHONE_LIST, 'phones', Response::MODEL_PHONE));
|
||||
Response::setModel(new BaseList('Metric List', Response::MODEL_METRIC_LIST, 'metrics', Response::MODEL_METRIC, true, false));
|
||||
Response::setModel(new BaseList('Variables List', Response::MODEL_VARIABLE_LIST, 'variables', Response::MODEL_VARIABLE));
|
||||
Response::setModel(new BaseList('Status List', Response::MODEL_HEALTH_STATUS_LIST, 'statuses', Response::MODEL_HEALTH_STATUS));
|
||||
Response::setModel(new BaseList('Rule List', Response::MODEL_PROXY_RULE_LIST, 'rules', Response::MODEL_PROXY_RULE));
|
||||
Response::setModel(new BaseList('Locale codes list', Response::MODEL_LOCALE_CODE_LIST, 'localeCodes', Response::MODEL_LOCALE_CODE));
|
||||
Response::setModel(new BaseList('Provider list', Response::MODEL_PROVIDER_LIST, 'providers', Response::MODEL_PROVIDER));
|
||||
Response::setModel(new BaseList('Message list', Response::MODEL_MESSAGE_LIST, 'messages', Response::MODEL_MESSAGE));
|
||||
Response::setModel(new BaseList('Topic list', Response::MODEL_TOPIC_LIST, 'topics', Response::MODEL_TOPIC));
|
||||
Response::setModel(new BaseList('Subscriber list', Response::MODEL_SUBSCRIBER_LIST, 'subscribers', Response::MODEL_SUBSCRIBER));
|
||||
Response::setModel(new BaseList('Target list', Response::MODEL_TARGET_LIST, 'targets', Response::MODEL_TARGET));
|
||||
Response::setModel(new BaseList('Transaction List', Response::MODEL_TRANSACTION_LIST, 'transactions', Response::MODEL_TRANSACTION));
|
||||
Response::setModel(new BaseList('Migrations List', Response::MODEL_MIGRATION_LIST, 'migrations', Response::MODEL_MIGRATION));
|
||||
Response::setModel(new BaseList('Migrations Firebase Projects List', Response::MODEL_MIGRATION_FIREBASE_PROJECT_LIST, 'projects', Response::MODEL_MIGRATION_FIREBASE_PROJECT));
|
||||
Response::setModel(new BaseList('Specifications List', Response::MODEL_SPECIFICATION_LIST, 'specifications', Response::MODEL_SPECIFICATION));
|
||||
Response::setModel(new BaseList('VCS Content List', Response::MODEL_VCS_CONTENT_LIST, 'contents', Response::MODEL_VCS_CONTENT));
|
||||
|
||||
// Entities
|
||||
Response::setModel(new Database());
|
||||
|
||||
// Collection API Models
|
||||
Response::setModel(new Collection());
|
||||
Response::setModel(new Attribute());
|
||||
Response::setModel(new AttributeList());
|
||||
Response::setModel(new AttributeString());
|
||||
Response::setModel(new AttributeInteger());
|
||||
Response::setModel(new AttributeFloat());
|
||||
Response::setModel(new AttributeBoolean());
|
||||
Response::setModel(new AttributeEmail());
|
||||
Response::setModel(new AttributeEnum());
|
||||
Response::setModel(new AttributeIP());
|
||||
Response::setModel(new AttributeURL());
|
||||
Response::setModel(new AttributeDatetime());
|
||||
Response::setModel(new AttributeRelationship());
|
||||
Response::setModel(new AttributePoint());
|
||||
Response::setModel(new AttributeLine());
|
||||
Response::setModel(new AttributePolygon());
|
||||
|
||||
// Table API Models
|
||||
Response::setModel(new Table());
|
||||
Response::setModel(new Column());
|
||||
Response::setModel(new ColumnList());
|
||||
Response::setModel(new ColumnString());
|
||||
Response::setModel(new ColumnInteger());
|
||||
Response::setModel(new ColumnFloat());
|
||||
Response::setModel(new ColumnBoolean());
|
||||
Response::setModel(new ColumnEmail());
|
||||
Response::setModel(new ColumnEnum());
|
||||
Response::setModel(new ColumnIP());
|
||||
Response::setModel(new ColumnURL());
|
||||
Response::setModel(new ColumnDatetime());
|
||||
Response::setModel(new ColumnRelationship());
|
||||
Response::setModel(new ColumnPoint());
|
||||
Response::setModel(new ColumnLine());
|
||||
Response::setModel(new ColumnPolygon());
|
||||
Response::setModel(new Index());
|
||||
Response::setModel(new ColumnIndex());
|
||||
Response::setModel(new Row());
|
||||
Response::setModel(new ModelDocument());
|
||||
Response::setModel(new Log());
|
||||
Response::setModel(new User());
|
||||
Response::setModel(new AlgoMd5());
|
||||
Response::setModel(new AlgoSha());
|
||||
Response::setModel(new AlgoPhpass());
|
||||
Response::setModel(new AlgoBcrypt());
|
||||
Response::setModel(new AlgoScrypt());
|
||||
Response::setModel(new AlgoScryptModified());
|
||||
Response::setModel(new AlgoArgon2());
|
||||
Response::setModel(new Account());
|
||||
Response::setModel(new Preferences());
|
||||
Response::setModel(new Session());
|
||||
Response::setModel(new Identity());
|
||||
Response::setModel(new Token());
|
||||
Response::setModel(new JWT());
|
||||
Response::setModel(new Locale());
|
||||
Response::setModel(new LocaleCode());
|
||||
Response::setModel(new File());
|
||||
Response::setModel(new Bucket());
|
||||
Response::setModel(new ResourceToken());
|
||||
Response::setModel(new Team());
|
||||
Response::setModel(new Membership());
|
||||
Response::setModel(new Site());
|
||||
Response::setModel(new TemplateSite());
|
||||
Response::setModel(new TemplateFramework());
|
||||
Response::setModel(new Func());
|
||||
Response::setModel(new TemplateFunction());
|
||||
Response::setModel(new TemplateRuntime());
|
||||
Response::setModel(new TemplateVariable());
|
||||
Response::setModel(new Installation());
|
||||
Response::setModel(new ProviderRepository());
|
||||
Response::setModel(new ProviderRepositoryFramework());
|
||||
Response::setModel(new ProviderRepositoryRuntime());
|
||||
Response::setModel(new DetectionFramework());
|
||||
Response::setModel(new DetectionRuntime());
|
||||
Response::setModel(new DetectionVariable());
|
||||
Response::setModel(new VcsContent());
|
||||
Response::setModel(new Branch());
|
||||
Response::setModel(new Runtime());
|
||||
Response::setModel(new Framework());
|
||||
Response::setModel(new FrameworkAdapter());
|
||||
Response::setModel(new Deployment());
|
||||
Response::setModel(new Execution());
|
||||
Response::setModel(new Project());
|
||||
Response::setModel(new Webhook());
|
||||
Response::setModel(new Key());
|
||||
Response::setModel(new DevKey());
|
||||
Response::setModel(new MockNumber());
|
||||
Response::setModel(new AuthProvider());
|
||||
Response::setModel(new Platform());
|
||||
Response::setModel(new Variable());
|
||||
Response::setModel(new Country());
|
||||
Response::setModel(new Continent());
|
||||
Response::setModel(new Language());
|
||||
Response::setModel(new Currency());
|
||||
Response::setModel(new Phone());
|
||||
Response::setModel(new HealthAntivirus());
|
||||
Response::setModel(new HealthQueue());
|
||||
Response::setModel(new HealthStatus());
|
||||
Response::setModel(new HealthCertificate());
|
||||
Response::setModel(new HealthTime());
|
||||
Response::setModel(new HealthVersion());
|
||||
Response::setModel(new Metric());
|
||||
Response::setModel(new MetricBreakdown());
|
||||
Response::setModel(new UsageDatabases());
|
||||
Response::setModel(new UsageDatabase());
|
||||
Response::setModel(new UsageTable());
|
||||
Response::setModel(new UsageCollection());
|
||||
Response::setModel(new UsageUsers());
|
||||
Response::setModel(new UsageStorage());
|
||||
Response::setModel(new UsageBuckets());
|
||||
Response::setModel(new UsageFunctions());
|
||||
Response::setModel(new UsageFunction());
|
||||
Response::setModel(new UsageSites());
|
||||
Response::setModel(new UsageSite());
|
||||
Response::setModel(new UsageProject());
|
||||
Response::setModel(new Headers());
|
||||
Response::setModel(new Specification());
|
||||
Response::setModel(new Rule());
|
||||
Response::setModel(new TemplateSMS());
|
||||
Response::setModel(new TemplateEmail());
|
||||
Response::setModel(new ConsoleVariables());
|
||||
Response::setModel(new MFAChallenge());
|
||||
Response::setModel(new MFARecoveryCodes());
|
||||
Response::setModel(new MFAType());
|
||||
Response::setModel(new MFAFactors());
|
||||
Response::setModel(new Provider());
|
||||
Response::setModel(new Message());
|
||||
Response::setModel(new Topic());
|
||||
Response::setModel(new Transaction());
|
||||
Response::setModel(new Subscriber());
|
||||
Response::setModel(new Target());
|
||||
Response::setModel(new Migration());
|
||||
Response::setModel(new MigrationReport());
|
||||
Response::setModel(new MigrationFirebaseProject());
|
||||
|
||||
// Tests (keep last)
|
||||
Response::setModel(new Mock());
|
||||
|
|
@ -360,6 +360,8 @@ $register->set('smtp', function () {
|
|||
$mail->SMTPSecure = System::getEnv('_APP_SMTP_SECURE', '');
|
||||
$mail->SMTPAutoTLS = false;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->Timeout = 10; /* Connection timeout */
|
||||
$mail->getSMTPInstance()->Timelimit = 30; /* Timeout for each individual SMTP command (e.g. HELO, EHLO, etc.) */
|
||||
|
||||
$from = \urldecode(System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'));
|
||||
$email = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@
|
|||
"ext-sockets": "*",
|
||||
"appwrite/php-runtimes": "0.19.*",
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "1.*",
|
||||
"utopia-php/abuse": "1.*.*",
|
||||
"utopia-php/analytics": "0.10.*",
|
||||
"utopia-php/audit": "2.0.2-rc1",
|
||||
"utopia-php/audit": "2.0.2-rc3",
|
||||
"utopia-php/auth": "0.5.*",
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
|
|
@ -59,12 +59,12 @@
|
|||
"utopia-php/dns": "1.4.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/fetch": "0.4.*",
|
||||
"utopia-php/fetch": "0.5.*",
|
||||
"utopia-php/image": "0.8.*",
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
"utopia-php/messaging": "0.20.*",
|
||||
"utopia-php/migration": "1.3.*",
|
||||
"utopia-php/migration": "1.*.*",
|
||||
"utopia-php/orchestration": "0.9.*",
|
||||
"utopia-php/platform": "0.7.*",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
|
|
@ -100,6 +100,12 @@
|
|||
"provide": {
|
||||
"ext-phpiredis": "*"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/utopia-php/migration.git"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.3"
|
||||
|
|
|
|||
190
composer.lock
generated
190
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b873febd2b03c32ec61a57b690cc44a2",
|
||||
"content-hash": "f63c88303152af32cae4c800b8642540",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
|
@ -69,16 +69,16 @@
|
|||
},
|
||||
{
|
||||
"name": "appwrite/appwrite",
|
||||
"version": "15.1.0",
|
||||
"version": "19.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-for-php.git",
|
||||
"reference": "c438b3885071ac7c0329199dce5e6f6a24dd215b"
|
||||
"reference": "8738e812062f899c85b2598eef43d6a247f08a56"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/c438b3885071ac7c0329199dce5e6f6a24dd215b",
|
||||
"reference": "c438b3885071ac7c0329199dce5e6f6a24dd215b",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/8738e812062f899c85b2598eef43d6a247f08a56",
|
||||
"reference": "8738e812062f899c85b2598eef43d6a247f08a56",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -87,7 +87,7 @@
|
|||
"php": ">=7.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.6.6",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"phpunit/phpunit": "^10"
|
||||
},
|
||||
"type": "library",
|
||||
|
|
@ -104,10 +104,10 @@
|
|||
"support": {
|
||||
"email": "team@appwrite.io",
|
||||
"issues": "https://github.com/appwrite/sdk-for-php/issues",
|
||||
"source": "https://github.com/appwrite/sdk-for-php/tree/15.1.0",
|
||||
"source": "https://github.com/appwrite/sdk-for-php/tree/19.1.0",
|
||||
"url": "https://appwrite.io/support"
|
||||
},
|
||||
"time": "2025-08-01T04:50:51+00:00"
|
||||
"time": "2025-12-18T08:07:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "appwrite/php-clamav",
|
||||
|
|
@ -3455,24 +3455,25 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "1.0.2",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "611fa66a97e87c0dbbc133a717d970da7a5ca828"
|
||||
"reference": "3339d057c6bb1fa3e5ac5b2598923f6938425ec2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/611fa66a97e87c0dbbc133a717d970da7a5ca828",
|
||||
"reference": "611fa66a97e87c0dbbc133a717d970da7a5ca828",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/3339d057c6bb1fa3e5ac5b2598923f6938425ec2",
|
||||
"reference": "3339d057c6bb1fa3e5ac5b2598923f6938425ec2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"appwrite/appwrite": "19.*.*",
|
||||
"ext-curl": "*",
|
||||
"ext-pdo": "*",
|
||||
"ext-redis": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "*"
|
||||
"utopia-php/database": "3.*.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
|
|
@ -3500,9 +3501,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/1.0.2"
|
||||
"source": "https://github.com/utopia-php/abuse/tree/1.2.0"
|
||||
},
|
||||
"time": "2025-10-20T07:18:33+00:00"
|
||||
"time": "2026-01-05T21:29:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
|
|
@ -3552,23 +3553,23 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "2.0.2-rc1",
|
||||
"version": "2.0.2-rc3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "7b35dab40bce66bda56eeeacd2bbcbf1e823f05f"
|
||||
"reference": "f60a298b516300f56a328403b334b7d62a96e7e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/7b35dab40bce66bda56eeeacd2bbcbf1e823f05f",
|
||||
"reference": "7b35dab40bce66bda56eeeacd2bbcbf1e823f05f",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/f60a298b516300f56a328403b334b7d62a96e7e7",
|
||||
"reference": "f60a298b516300f56a328403b334b7d62a96e7e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "3.*",
|
||||
"utopia-php/fetch": "^0.4.2",
|
||||
"utopia-php/validators": "^0.1.0"
|
||||
"utopia-php/fetch": "0.5.*",
|
||||
"utopia-php/validators": "0.1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
|
|
@ -3595,9 +3596,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/2.0.2-rc1"
|
||||
"source": "https://github.com/utopia-php/audit/tree/2.0.2-rc3"
|
||||
},
|
||||
"time": "2025-12-24T01:20:43+00:00"
|
||||
"time": "2026-01-06T15:32:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/auth",
|
||||
|
|
@ -4167,23 +4168,23 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/emails",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/emails.git",
|
||||
"reference": "9524d7f7bd1651a06fef8a3d964f774b04fe2918"
|
||||
"reference": "fb2bd5c428e88f645b0f7ede0dd29ac0d120ec52"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/emails/zipball/9524d7f7bd1651a06fef8a3d964f774b04fe2918",
|
||||
"reference": "9524d7f7bd1651a06fef8a3d964f774b04fe2918",
|
||||
"url": "https://api.github.com/repos/utopia-php/emails/zipball/fb2bd5c428e88f645b0f7ede0dd29ac0d120ec52",
|
||||
"reference": "fb2bd5c428e88f645b0f7ede0dd29ac0d120ec52",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cli": "^0.15",
|
||||
"utopia-php/domains": "^0.9",
|
||||
"utopia-php/fetch": "^0.4",
|
||||
"utopia-php/fetch": "^0.5",
|
||||
"utopia-php/validators": "0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -4221,26 +4222,26 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/emails/issues",
|
||||
"source": "https://github.com/utopia-php/emails/tree/0.6.3"
|
||||
"source": "https://github.com/utopia-php/emails/tree/0.6.4"
|
||||
},
|
||||
"time": "2025-11-26T12:27:47+00:00"
|
||||
"time": "2025-12-18T16:36:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/fetch",
|
||||
"version": "0.4.2",
|
||||
"version": "0.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/fetch.git",
|
||||
"reference": "83986d1be75a2fae4e684107fe70dd78a8e19b77"
|
||||
"reference": "a96a010e1c273f3888765449687baf58cbc61fcd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/fetch/zipball/83986d1be75a2fae4e684107fe70dd78a8e19b77",
|
||||
"reference": "83986d1be75a2fae4e684107fe70dd78a8e19b77",
|
||||
"url": "https://api.github.com/repos/utopia-php/fetch/zipball/a96a010e1c273f3888765449687baf58cbc61fcd",
|
||||
"reference": "a96a010e1c273f3888765449687baf58cbc61fcd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0"
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.5.0",
|
||||
|
|
@ -4260,9 +4261,9 @@
|
|||
"description": "A simple library that provides an interface for making HTTP Requests.",
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/fetch/issues",
|
||||
"source": "https://github.com/utopia-php/fetch/tree/0.4.2"
|
||||
"source": "https://github.com/utopia-php/fetch/tree/0.5.1"
|
||||
},
|
||||
"time": "2025-04-25T13:48:02+00:00"
|
||||
"time": "2025-12-18T16:25:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
|
|
@ -4515,20 +4516,20 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.3.9",
|
||||
"version": "1.3.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "c55ec67c74663190cda10fd79297422147be7e85"
|
||||
"reference": "798f0976a1c14234c4b283b858b08c9afbcc1662"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/c55ec67c74663190cda10fd79297422147be7e85",
|
||||
"reference": "c55ec67c74663190cda10fd79297422147be7e85",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/798f0976a1c14234c4b283b858b08c9afbcc1662",
|
||||
"reference": "798f0976a1c14234c4b283b858b08c9afbcc1662",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"appwrite/appwrite": "15.*",
|
||||
"appwrite/appwrite": "19.*",
|
||||
"ext-curl": "*",
|
||||
"ext-openssl": "*",
|
||||
"php": ">=8.1",
|
||||
|
|
@ -4550,7 +4551,25 @@
|
|||
"Utopia\\Migration\\": "src/Migration"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Utopia\\Tests\\": "tests/Migration"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
"./vendor/bin/phpunit"
|
||||
],
|
||||
"lint": [
|
||||
"./vendor/bin/pint --test"
|
||||
],
|
||||
"format": [
|
||||
"./vendor/bin/pint"
|
||||
],
|
||||
"check": [
|
||||
"./vendor/bin/phpstan analyse --level 3 src tests --memory-limit 2G"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
|
|
@ -4563,10 +4582,10 @@
|
|||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.3.9"
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.3.11",
|
||||
"issues": "https://github.com/utopia-php/migration/issues"
|
||||
},
|
||||
"time": "2025-12-08T08:45:09+00:00"
|
||||
"time": "2026-01-06T12:07:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
|
|
@ -4837,23 +4856,23 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/queue",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/queue.git",
|
||||
"reference": "a854f7c4abc18e0eca55fc5608cd7088d71eb19f"
|
||||
"reference": "f3b2623efe87595c9ed907b3efd587e77c622d3d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/queue/zipball/a854f7c4abc18e0eca55fc5608cd7088d71eb19f",
|
||||
"reference": "a854f7c4abc18e0eca55fc5608cd7088d71eb19f",
|
||||
"url": "https://api.github.com/repos/utopia-php/queue/zipball/f3b2623efe87595c9ed907b3efd587e77c622d3d",
|
||||
"reference": "f3b2623efe87595c9ed907b3efd587e77c622d3d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"php-amqplib/php-amqplib": "^3.7",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/fetch": "0.4.*",
|
||||
"utopia-php/fetch": "0.5.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
"utopia-php/telemetry": "*"
|
||||
|
|
@ -4897,9 +4916,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/queue/issues",
|
||||
"source": "https://github.com/utopia-php/queue/tree/0.11.2"
|
||||
"source": "https://github.com/utopia-php/queue/tree/0.11.3"
|
||||
},
|
||||
"time": "2025-12-17T09:32:35+00:00"
|
||||
"time": "2025-12-19T10:56:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/registry",
|
||||
|
|
@ -5438,16 +5457,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.8.6",
|
||||
"version": "1.8.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "b6cc29d3bd247e193f3c06b4168dc69d884645f0"
|
||||
"reference": "5fc210f7403f9ecfa068cd2a74210ec6e2a3cec1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/b6cc29d3bd247e193f3c06b4168dc69d884645f0",
|
||||
"reference": "b6cc29d3bd247e193f3c06b4168dc69d884645f0",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/5fc210f7403f9ecfa068cd2a74210ec6e2a3cec1",
|
||||
"reference": "5fc210f7403f9ecfa068cd2a74210ec6e2a3cec1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -5483,9 +5502,9 @@
|
|||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.8.6"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.8.9"
|
||||
},
|
||||
"time": "2025-12-31T10:22:17+00:00"
|
||||
"time": "2026-01-02T12:09:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
|
|
@ -5566,30 +5585,29 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
|
||||
"reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
|
||||
"reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/23da848e1a2308728fe5fdddabf4be17ff9720c7",
|
||||
"reference": "23da848e1a2308728fe5fdddabf4be17ff9720c7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
"php": "^8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^11",
|
||||
"doctrine/coding-standard": "^14",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpbench/phpbench": "^1.2",
|
||||
"phpstan/phpstan": "^1.9.4",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpunit/phpunit": "^9.5.27",
|
||||
"vimeo/psalm": "^5.4"
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^10.5.58"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -5616,7 +5634,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||
"source": "https://github.com/doctrine/instantiator/tree/2.0.0"
|
||||
"source": "https://github.com/doctrine/instantiator/tree/2.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -5632,7 +5650,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-30T00:23:10+00:00"
|
||||
"time": "2026-01-05T06:47:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
|
|
@ -5713,16 +5731,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/pint",
|
||||
"version": "v1.26.0",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/pint.git",
|
||||
"reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f"
|
||||
"reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/69dcca060ecb15e4b564af63d1f642c81a241d6f",
|
||||
"reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/c67b4195b75491e4dfc6b00b1c78b68d86f54c90",
|
||||
"reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -5733,9 +5751,9 @@
|
|||
"php": "^8.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.90.0",
|
||||
"illuminate/view": "^12.40.1",
|
||||
"larastan/larastan": "^3.8.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.92.4",
|
||||
"illuminate/view": "^12.44.0",
|
||||
"larastan/larastan": "^3.8.1",
|
||||
"laravel-zero/framework": "^12.0.4",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/termwind": "^2.3.3",
|
||||
|
|
@ -5776,7 +5794,7 @@
|
|||
"issues": "https://github.com/laravel/pint/issues",
|
||||
"source": "https://github.com/laravel/pint"
|
||||
},
|
||||
"time": "2025-11-25T21:15:52+00:00"
|
||||
"time": "2026-01-05T16:49:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "matthiasmullie/minify",
|
||||
|
|
@ -8562,16 +8580,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v8.0.0",
|
||||
"version": "v8.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149"
|
||||
"reference": "0cbbd88ec836f8757641c651bb995335846abb78"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149",
|
||||
"reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/0cbbd88ec836f8757641c651bb995335846abb78",
|
||||
"reference": "0cbbd88ec836f8757641c651bb995335846abb78",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8603,7 +8621,7 @@
|
|||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v8.0.0"
|
||||
"source": "https://github.com/symfony/process/tree/v8.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8623,7 +8641,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-16T16:25:44+00:00"
|
||||
"time": "2025-12-19T10:01:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
|
|
@ -8971,5 +8989,5 @@
|
|||
"platform-overrides": {
|
||||
"php": "8.3"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Appwrite\Platform;
|
||||
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Coroutine as Co;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
|
|
@ -161,50 +159,4 @@ class Action extends UtopiaAction
|
|||
Console::info("[" . DateTime::now() . "] " . $method . ' ' . $type . ' ' . $project->getSequence() . ' ' . $project->getId() . ' ' . $collectionId . ' ' . $log);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to apply (request) select queries to response model.
|
||||
*
|
||||
* This prevents default values of rules to be presnet for not-selected attributes
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Document $document
|
||||
* @return void
|
||||
*/
|
||||
public function applySelectQueries(Request $request, Response $response, string $model): void
|
||||
{
|
||||
$queries = $request->getParam('queries', []);
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
$selectQueries = Query::groupByType($queries)['selections'] ?? [];
|
||||
|
||||
// No select queries means no filtering out
|
||||
if (empty($selectQueries)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
foreach ($selectQueries as $query) {
|
||||
foreach ($query->getValues() as $attribute) {
|
||||
$attributes[] = $attribute;
|
||||
}
|
||||
}
|
||||
|
||||
// found a wildcard, return!
|
||||
if (\in_array('*', $attributes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$responseModel = $response->getModel($model);
|
||||
foreach ($responseModel->getRules() as $ruleName => $rule) {
|
||||
if (\str_starts_with($ruleName, '$')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!\in_array($ruleName, $attributes)) {
|
||||
$responseModel->removeRule($ruleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ class Decrement extends Action
|
|||
value: $value,
|
||||
min: $min
|
||||
);
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$' . $this->getCollectionsEventsContext() . 'Id', $collectionId);
|
||||
} catch (ConflictException) {
|
||||
throw new Exception($this->getConflictException());
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ class Increment extends Action
|
|||
value: $value,
|
||||
max: $max
|
||||
);
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$' . $this->getCollectionsEventsContext() . 'Id', $collectionId);
|
||||
} catch (ConflictException) {
|
||||
throw new Exception($this->getConflictException());
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Appwrite\SDK\Response as SDKResponse;
|
|||
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filters\ListSelection;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Order as OrderException;
|
||||
|
|
@ -119,7 +120,9 @@ class XList extends Base
|
|||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
$grouped = Query::groupByType($queries);
|
||||
$filterQueries = $grouped['filters'];
|
||||
$selectQueries = $grouped['selections'] ?? [];
|
||||
|
||||
try {
|
||||
$results = $dbForProject->find('deployments', $queries);
|
||||
|
|
@ -128,7 +131,8 @@ class XList extends Base
|
|||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
$this->applySelectQueries($request, $response, Response::MODEL_DEPLOYMENT);
|
||||
$response->addFilter(new ListSelection($selectQueries, 'deployments'));
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'deployments' => $results,
|
||||
'total' => $total,
|
||||
|
|
|
|||
|
|
@ -939,7 +939,7 @@ class Builds extends Action
|
|||
}
|
||||
|
||||
$client = new FetchClient();
|
||||
$client->setTimeout(\intval($resource->getAttribute('timeout', '15')));
|
||||
$client->setTimeout(\intval($resource->getAttribute('timeout', '15')) * 1000);
|
||||
$client->addHeader('content-type', FetchClient::CONTENT_TYPE_APPLICATION_JSON);
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots'));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Projects\Http\Projects\Labels;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'updateProjectLabels';
|
||||
}
|
||||
|
||||
protected function getQueriesValidator(): Validator
|
||||
{
|
||||
return new Projects();
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT)
|
||||
->setHttpPath('/v1/projects/:projectId/labels')
|
||||
->desc('Update project labels')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'projects',
|
||||
name: 'updateLabels',
|
||||
description: <<<EOT
|
||||
Update the project labels by its unique ID. Labels can be used to easily filter projects in an organization.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_PROJECT
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('labels', [], new ArrayList(new Text(36, allowList: [...Text::NUMBERS, ...Text::ALPHABET_UPPER, ...Text::ALPHABET_LOWER]), APP_LIMIT_ARRAY_LABELS_SIZE), 'Array of project labels. Replaces the previous labels. Maximum of ' . APP_LIMIT_ARRAY_LABELS_SIZE . ' labels are allowed, each up to 36 alphanumeric characters long.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $labels
|
||||
*/
|
||||
public function action(
|
||||
string $projectId,
|
||||
array $labels,
|
||||
Response $response,
|
||||
Database $dbForPlatform
|
||||
): void {
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$project->setAttribute('labels', (array) \array_values(\array_unique($labels)));
|
||||
|
||||
$project = $dbForPlatform->updateDocument('projects', $project->getId(), $project);
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ use Appwrite\SDK\Response as SDKResponse;
|
|||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filters\ListSelection;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
|
|
@ -120,7 +121,8 @@ class XList extends Action
|
|||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
$this->applySelectQueries($request, $response, Response::MODEL_PROJECT);
|
||||
$response->addFilter(new ListSelection($selectQueries, 'projects'));
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'projects' => $projects,
|
||||
'total' => $total,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Appwrite\Platform\Modules\Projects\Http\DevKeys\Delete as DeleteDevKey;
|
|||
use Appwrite\Platform\Modules\Projects\Http\DevKeys\Get as GetDevKey;
|
||||
use Appwrite\Platform\Modules\Projects\Http\DevKeys\Update as UpdateDevKey;
|
||||
use Appwrite\Platform\Modules\Projects\Http\DevKeys\XList as ListDevKeys;
|
||||
use Appwrite\Platform\Modules\Projects\Http\Projects\Labels\Update as UpdateProjectLabels;
|
||||
use Appwrite\Platform\Modules\Projects\Http\Projects\XList as ListProjects;
|
||||
use Utopia\Platform\Service;
|
||||
|
||||
|
|
@ -22,5 +23,6 @@ class Http extends Service
|
|||
$this->addAction(DeleteDevKey::getName(), new DeleteDevKey());
|
||||
|
||||
$this->addAction(ListProjects::getName(), new ListProjects());
|
||||
$this->addAction(UpdateProjectLabels::getName(), new UpdateProjectLabels());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Appwrite\SDK\Response as SDKResponse;
|
|||
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filters\ListSelection;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Order as OrderException;
|
||||
|
|
@ -119,7 +120,9 @@ class XList extends Base
|
|||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
$grouped = Query::groupByType($queries);
|
||||
$filterQueries = $grouped['filters'];
|
||||
$selectQueries = $grouped['selections'] ?? [];
|
||||
|
||||
try {
|
||||
$results = $dbForProject->find('deployments', $queries);
|
||||
|
|
@ -128,7 +131,8 @@ class XList extends Base
|
|||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
$this->applySelectQueries($request, $response, Response::MODEL_DEPLOYMENT);
|
||||
$response->addFilter(new ListSelection($selectQueries, 'deployments'));
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'deployments' => $results,
|
||||
'total' => $total,
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class Deletes extends Action
|
|||
break;
|
||||
case DELETE_TYPE_AUDIT:
|
||||
if (!$project->isEmpty()) {
|
||||
$this->deleteAuditLogs($project, $auditRetention, $getAudit);
|
||||
$this->deleteAuditLogs($project, $getAudit, $auditRetention);
|
||||
}
|
||||
break;
|
||||
case DELETE_TYPE_REALTIME:
|
||||
|
|
@ -187,7 +187,7 @@ class Deletes extends Action
|
|||
case DELETE_TYPE_MAINTENANCE:
|
||||
$this->deleteExpiredTargets($project, $getProjectDB);
|
||||
$this->deleteExecutionLogs($project, $getProjectDB, $executionRetention);
|
||||
$this->deleteAuditLogs($project, $getProjectDB, $auditRetention);
|
||||
$this->deleteAuditLogs($project, $getAudit, $auditRetention);
|
||||
$this->deleteUsageStats($project, $getProjectDB, $getLogsDB, $hourlyUsageRetentionDatetime);
|
||||
$this->deleteExpiredSessions($project, $getProjectDB);
|
||||
$this->deleteExpiredTransactions($project, $getProjectDB);
|
||||
|
|
@ -516,130 +516,136 @@ class Deletes extends Action
|
|||
$dsn = new DSN('mysql://' . $document->getAttribute('database', 'console'));
|
||||
}
|
||||
|
||||
$dbForProject = $getProjectDB($document);
|
||||
|
||||
$projectCollectionIds = [
|
||||
...\array_keys(Config::getParam('collections', [])['projects']),
|
||||
SQL::COLLECTION,
|
||||
AbuseDatabase::COLLECTION,
|
||||
];
|
||||
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
$sharedTablesV1 = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES_V1', ''));
|
||||
|
||||
$projectTables = !\in_array($dsn->getHost(), $sharedTables);
|
||||
$sharedTablesV1 = \in_array($dsn->getHost(), $sharedTablesV1);
|
||||
$sharedTablesV2 = !$projectTables && !$sharedTablesV1;
|
||||
|
||||
/**
|
||||
* @var $dbForProject Database
|
||||
*/
|
||||
$dbForProject->foreach(Database::METADATA, function (Document $collection) use ($dbForProject, $projectTables, $projectCollectionIds) {
|
||||
try {
|
||||
if ($projectTables || !\in_array($collection->getId(), $projectCollectionIds)) {
|
||||
$dbForProject->deleteCollection($collection->getId());
|
||||
} else {
|
||||
$this->deleteByGroup(
|
||||
$collection->getId(),
|
||||
[
|
||||
Query::orderAsc()
|
||||
],
|
||||
database: $dbForProject
|
||||
);
|
||||
$dbForProject = $getProjectDB($document);
|
||||
|
||||
try {
|
||||
/**
|
||||
* Disable validation because of Cursor validation on $id underscores
|
||||
*/
|
||||
$dbForProject->disableValidation();
|
||||
|
||||
|
||||
$projectCollectionIds = [
|
||||
...\array_keys(Config::getParam('collections', [])['projects']),
|
||||
SQL::COLLECTION,
|
||||
AbuseDatabase::COLLECTION,
|
||||
];
|
||||
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
$sharedTablesV1 = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES_V1', ''));
|
||||
|
||||
$projectTables = !\in_array($dsn->getHost(), $sharedTables);
|
||||
$sharedTablesV1 = \in_array($dsn->getHost(), $sharedTablesV1);
|
||||
$sharedTablesV2 = !$projectTables && !$sharedTablesV1;
|
||||
|
||||
$dbForProject->foreach(Database::METADATA, function (Document $collection) use ($dbForProject, $projectTables, $projectCollectionIds) {
|
||||
try {
|
||||
if ($projectTables || !\in_array($collection->getId(), $projectCollectionIds)) {
|
||||
$dbForProject->deleteCollection($collection->getId());
|
||||
} else {
|
||||
$this->deleteByGroup(
|
||||
$collection->getId(),
|
||||
[
|
||||
Query::orderAsc()
|
||||
],
|
||||
database: $dbForProject
|
||||
);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Console::error('Error deleting ' . $collection->getId() . ' ' . $e->getMessage());
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
Console::error('Error deleting ' . $collection->getId() . ' ' . $e->getMessage());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Delete Platforms
|
||||
$this->deleteByGroup('platforms', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
// Delete project and function rules
|
||||
$this->deleteByGroup('rules', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform, function (Document $document) use ($dbForPlatform, $certificates) {
|
||||
$this->deleteRule($dbForPlatform, $document, $certificates);
|
||||
});
|
||||
|
||||
// Delete Keys
|
||||
$this->deleteByGroup('keys', [
|
||||
Query::or([
|
||||
// Delete Platforms
|
||||
$this->deleteByGroup('platforms', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$projectInternalId]),
|
||||
])
|
||||
]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
// Delete Webhooks
|
||||
$this->deleteByGroup('webhooks', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
// Delete project and function rules
|
||||
$this->deleteByGroup('rules', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform, function (Document $document) use ($dbForPlatform, $certificates) {
|
||||
$this->deleteRule($dbForPlatform, $document, $certificates);
|
||||
});
|
||||
|
||||
// Delete VCS Installations
|
||||
$this->deleteByGroup('installations', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
// Delete Keys
|
||||
$this->deleteByGroup('keys', [
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
// Delete VCS Repositories
|
||||
$this->deleteByGroup('repositories', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
// Delete Webhooks
|
||||
$this->deleteByGroup('webhooks', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
// Delete VCS comments
|
||||
$this->deleteByGroup('vcsComments', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
// Delete VCS Installations
|
||||
$this->deleteByGroup('installations', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
// Delete Schedules
|
||||
$this->deleteByGroup('schedules', [
|
||||
Query::equal('projectId', [$projectId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
// Delete VCS Repositories
|
||||
$this->deleteByGroup('repositories', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
// Delete metadata table
|
||||
if ($projectTables) {
|
||||
$dbForProject->deleteCollection(Database::METADATA);
|
||||
} elseif ($sharedTablesV1) {
|
||||
$this->deleteByGroup(
|
||||
Database::METADATA,
|
||||
[
|
||||
Query::orderAsc()
|
||||
],
|
||||
$dbForProject
|
||||
);
|
||||
} elseif ($sharedTablesV2) {
|
||||
$queries = \array_map(
|
||||
fn ($id) => Query::notEqual('$id', $id),
|
||||
$projectCollectionIds
|
||||
);
|
||||
// Delete VCS comments
|
||||
$this->deleteByGroup('vcsComments', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
$queries[] = Query::orderAsc();
|
||||
// Delete Schedules
|
||||
$this->deleteByGroup('schedules', [
|
||||
Query::equal('projectId', [$projectId]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
$this->deleteByGroup(
|
||||
Database::METADATA,
|
||||
$queries,
|
||||
$dbForProject
|
||||
);
|
||||
// Delete metadata table
|
||||
if ($projectTables) {
|
||||
$dbForProject->deleteCollection(Database::METADATA);
|
||||
} elseif ($sharedTablesV1) {
|
||||
$this->deleteByGroup(
|
||||
Database::METADATA,
|
||||
[
|
||||
Query::orderAsc()
|
||||
],
|
||||
$dbForProject
|
||||
);
|
||||
} elseif ($sharedTablesV2) {
|
||||
$queries = \array_map(
|
||||
fn ($id) => Query::notEqual('$id', $id),
|
||||
$projectCollectionIds
|
||||
);
|
||||
|
||||
$queries[] = Query::orderAsc();
|
||||
|
||||
$this->deleteByGroup(
|
||||
Database::METADATA,
|
||||
$queries,
|
||||
$dbForProject
|
||||
);
|
||||
}
|
||||
|
||||
// Delete all storage directories
|
||||
$deviceForFiles->delete($deviceForFiles->getRoot(), true);
|
||||
$deviceForSites->delete($deviceForSites->getRoot(), true);
|
||||
$deviceForFunctions->delete($deviceForFunctions->getRoot(), true);
|
||||
$deviceForBuilds->delete($deviceForBuilds->getRoot(), true);
|
||||
$deviceForCache->delete($deviceForCache->getRoot(), true);
|
||||
|
||||
} finally {
|
||||
$dbForProject->enableValidation();
|
||||
}
|
||||
|
||||
// Delete all storage directories
|
||||
$deviceForFiles->delete($deviceForFiles->getRoot(), true);
|
||||
$deviceForSites->delete($deviceForSites->getRoot(), true);
|
||||
$deviceForFunctions->delete($deviceForFunctions->getRoot(), true);
|
||||
$deviceForBuilds->delete($deviceForBuilds->getRoot(), true);
|
||||
$deviceForCache->delete($deviceForCache->getRoot(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -783,14 +789,13 @@ class Deletes extends Action
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Database $dbForPlatform
|
||||
* @param callable $getProjectDB
|
||||
* @param string $auditRetention
|
||||
* @param Document $project
|
||||
* @param callable $getAudit
|
||||
* @param string $auditRetention
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function deleteAuditLogs(Document $project, string $auditRetention, callable $getAudit): void
|
||||
private function deleteAuditLogs(Document $project, callable $getAudit, string $auditRetention): void
|
||||
{
|
||||
$projectId = $project->getId();
|
||||
/** @var Audit $audit */
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ class Mails extends Action
|
|||
throw new Exception('Skipped mail processing. No SMTP configuration has been set.');
|
||||
}
|
||||
|
||||
$log->addTag('type', empty($smtp) ? 'cloud' : 'smtp');
|
||||
$type = empty($smtp) ? 'cloud' : 'smtp';
|
||||
$log->addTag('type', $type);
|
||||
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
|
||||
$hostname = System::getEnv('_APP_CONSOLE_DOMAIN');
|
||||
|
|
@ -182,6 +183,9 @@ class Mails extends Action
|
|||
try {
|
||||
$mail->send();
|
||||
} catch (\Throwable $error) {
|
||||
if ($type === 'smtp') {
|
||||
throw new Exception('Error sending mail: ' . $error->getMessage(), 401);
|
||||
}
|
||||
throw new Exception('Error sending mail: ' . $error->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
|
@ -209,6 +213,8 @@ class Mails extends Action
|
|||
$mail->SMTPSecure = $smtp['secure'];
|
||||
$mail->SMTPAutoTLS = false;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->Timeout = 10; /* Connection timeout */
|
||||
$mail->getSMTPInstance()->Timelimit = 30; /* Timeout for each individual SMTP command (e.g. HELO, EHLO, etc.) */
|
||||
|
||||
$mail->setFrom($smtp['senderEmail'], $smtp['senderName']);
|
||||
|
||||
|
|
|
|||
|
|
@ -111,13 +111,8 @@ class StatsResources extends Action
|
|||
Query::equal('projectInternalId', [$project->getSequence()])
|
||||
]);
|
||||
$keys = $dbForPlatform->count('keys', [
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
]),
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
]);
|
||||
|
||||
$domains = $dbForPlatform->count('rules', [
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ class Projects extends Base
|
|||
{
|
||||
public const ALLOWED_ATTRIBUTES = [
|
||||
'name',
|
||||
'teamId'
|
||||
'teamId',
|
||||
'labels',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,147 +6,8 @@ use Appwrite\Utopia\Database\Documents\User as DBUser;
|
|||
use Appwrite\Utopia\Fetch\BodyMultipart;
|
||||
use Appwrite\Utopia\Response\Filter;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use Appwrite\Utopia\Response\Model\Account;
|
||||
use Appwrite\Utopia\Response\Model\AlgoArgon2;
|
||||
use Appwrite\Utopia\Response\Model\AlgoBcrypt;
|
||||
use Appwrite\Utopia\Response\Model\AlgoMd5;
|
||||
use Appwrite\Utopia\Response\Model\AlgoPhpass;
|
||||
use Appwrite\Utopia\Response\Model\AlgoScrypt;
|
||||
use Appwrite\Utopia\Response\Model\AlgoScryptModified;
|
||||
use Appwrite\Utopia\Response\Model\AlgoSha;
|
||||
use Appwrite\Utopia\Response\Model\Any;
|
||||
use Appwrite\Utopia\Response\Model\Attribute;
|
||||
use Appwrite\Utopia\Response\Model\AttributeBoolean;
|
||||
use Appwrite\Utopia\Response\Model\AttributeDatetime;
|
||||
use Appwrite\Utopia\Response\Model\AttributeEmail;
|
||||
use Appwrite\Utopia\Response\Model\AttributeEnum;
|
||||
use Appwrite\Utopia\Response\Model\AttributeFloat;
|
||||
use Appwrite\Utopia\Response\Model\AttributeInteger;
|
||||
use Appwrite\Utopia\Response\Model\AttributeIP;
|
||||
use Appwrite\Utopia\Response\Model\AttributeLine;
|
||||
use Appwrite\Utopia\Response\Model\AttributeList;
|
||||
use Appwrite\Utopia\Response\Model\AttributePoint;
|
||||
use Appwrite\Utopia\Response\Model\AttributePolygon;
|
||||
use Appwrite\Utopia\Response\Model\AttributeRelationship;
|
||||
use Appwrite\Utopia\Response\Model\AttributeString;
|
||||
use Appwrite\Utopia\Response\Model\AttributeURL;
|
||||
use Appwrite\Utopia\Response\Model\AuthProvider;
|
||||
use Appwrite\Utopia\Response\Model\BaseList;
|
||||
use Appwrite\Utopia\Response\Model\Branch;
|
||||
use Appwrite\Utopia\Response\Model\Bucket;
|
||||
use Appwrite\Utopia\Response\Model\Collection;
|
||||
use Appwrite\Utopia\Response\Model\Column;
|
||||
use Appwrite\Utopia\Response\Model\ColumnBoolean;
|
||||
use Appwrite\Utopia\Response\Model\ColumnDatetime;
|
||||
use Appwrite\Utopia\Response\Model\ColumnEmail;
|
||||
use Appwrite\Utopia\Response\Model\ColumnEnum;
|
||||
use Appwrite\Utopia\Response\Model\ColumnFloat;
|
||||
use Appwrite\Utopia\Response\Model\ColumnIndex;
|
||||
use Appwrite\Utopia\Response\Model\ColumnInteger;
|
||||
use Appwrite\Utopia\Response\Model\ColumnIP;
|
||||
use Appwrite\Utopia\Response\Model\ColumnLine;
|
||||
use Appwrite\Utopia\Response\Model\ColumnList;
|
||||
use Appwrite\Utopia\Response\Model\ColumnPoint;
|
||||
use Appwrite\Utopia\Response\Model\ColumnPolygon;
|
||||
use Appwrite\Utopia\Response\Model\ColumnRelationship;
|
||||
use Appwrite\Utopia\Response\Model\ColumnString;
|
||||
use Appwrite\Utopia\Response\Model\ColumnURL;
|
||||
use Appwrite\Utopia\Response\Model\ConsoleVariables;
|
||||
use Appwrite\Utopia\Response\Model\Continent;
|
||||
use Appwrite\Utopia\Response\Model\Country;
|
||||
use Appwrite\Utopia\Response\Model\Currency;
|
||||
use Appwrite\Utopia\Response\Model\Database;
|
||||
use Appwrite\Utopia\Response\Model\Deployment;
|
||||
use Appwrite\Utopia\Response\Model\DetectionFramework;
|
||||
use Appwrite\Utopia\Response\Model\DetectionRuntime;
|
||||
use Appwrite\Utopia\Response\Model\DetectionVariable;
|
||||
use Appwrite\Utopia\Response\Model\DevKey;
|
||||
use Appwrite\Utopia\Response\Model\Document as ModelDocument;
|
||||
use Appwrite\Utopia\Response\Model\Error;
|
||||
use Appwrite\Utopia\Response\Model\ErrorDev;
|
||||
use Appwrite\Utopia\Response\Model\Execution;
|
||||
use Appwrite\Utopia\Response\Model\File;
|
||||
use Appwrite\Utopia\Response\Model\Framework;
|
||||
use Appwrite\Utopia\Response\Model\FrameworkAdapter;
|
||||
use Appwrite\Utopia\Response\Model\Func;
|
||||
use Appwrite\Utopia\Response\Model\Headers;
|
||||
use Appwrite\Utopia\Response\Model\HealthAntivirus;
|
||||
use Appwrite\Utopia\Response\Model\HealthCertificate;
|
||||
use Appwrite\Utopia\Response\Model\HealthQueue;
|
||||
use Appwrite\Utopia\Response\Model\HealthStatus;
|
||||
use Appwrite\Utopia\Response\Model\HealthTime;
|
||||
use Appwrite\Utopia\Response\Model\HealthVersion;
|
||||
use Appwrite\Utopia\Response\Model\Identity;
|
||||
use Appwrite\Utopia\Response\Model\Index;
|
||||
use Appwrite\Utopia\Response\Model\Installation;
|
||||
use Appwrite\Utopia\Response\Model\JWT;
|
||||
use Appwrite\Utopia\Response\Model\Key;
|
||||
use Appwrite\Utopia\Response\Model\Language;
|
||||
use Appwrite\Utopia\Response\Model\Locale;
|
||||
use Appwrite\Utopia\Response\Model\LocaleCode;
|
||||
use Appwrite\Utopia\Response\Model\Log;
|
||||
use Appwrite\Utopia\Response\Model\Membership;
|
||||
use Appwrite\Utopia\Response\Model\Message;
|
||||
use Appwrite\Utopia\Response\Model\Metric;
|
||||
use Appwrite\Utopia\Response\Model\MetricBreakdown;
|
||||
use Appwrite\Utopia\Response\Model\MFAChallenge;
|
||||
use Appwrite\Utopia\Response\Model\MFAFactors;
|
||||
use Appwrite\Utopia\Response\Model\MFARecoveryCodes;
|
||||
use Appwrite\Utopia\Response\Model\MFAType;
|
||||
use Appwrite\Utopia\Response\Model\Migration;
|
||||
use Appwrite\Utopia\Response\Model\MigrationFirebaseProject;
|
||||
use Appwrite\Utopia\Response\Model\MigrationReport;
|
||||
use Appwrite\Utopia\Response\Model\Mock;
|
||||
use Appwrite\Utopia\Response\Model\MockNumber;
|
||||
use Appwrite\Utopia\Response\Model\None;
|
||||
use Appwrite\Utopia\Response\Model\Phone;
|
||||
use Appwrite\Utopia\Response\Model\Platform;
|
||||
use Appwrite\Utopia\Response\Model\Preferences;
|
||||
use Appwrite\Utopia\Response\Model\Project;
|
||||
use Appwrite\Utopia\Response\Model\Provider;
|
||||
use Appwrite\Utopia\Response\Model\ProviderRepository;
|
||||
use Appwrite\Utopia\Response\Model\ProviderRepositoryFramework;
|
||||
use Appwrite\Utopia\Response\Model\ProviderRepositoryRuntime;
|
||||
use Appwrite\Utopia\Response\Model\ResourceToken;
|
||||
use Appwrite\Utopia\Response\Model\Row;
|
||||
use Appwrite\Utopia\Response\Model\Rule;
|
||||
use Appwrite\Utopia\Response\Model\Runtime;
|
||||
use Appwrite\Utopia\Response\Model\Session;
|
||||
use Appwrite\Utopia\Response\Model\Site;
|
||||
use Appwrite\Utopia\Response\Model\Specification;
|
||||
use Appwrite\Utopia\Response\Model\Subscriber;
|
||||
use Appwrite\Utopia\Response\Model\Table;
|
||||
use Appwrite\Utopia\Response\Model\Target;
|
||||
use Appwrite\Utopia\Response\Model\Team;
|
||||
use Appwrite\Utopia\Response\Model\TemplateEmail;
|
||||
use Appwrite\Utopia\Response\Model\TemplateFramework;
|
||||
use Appwrite\Utopia\Response\Model\TemplateFunction;
|
||||
use Appwrite\Utopia\Response\Model\TemplateRuntime;
|
||||
use Appwrite\Utopia\Response\Model\TemplateSite;
|
||||
use Appwrite\Utopia\Response\Model\TemplateSMS;
|
||||
use Appwrite\Utopia\Response\Model\TemplateVariable;
|
||||
use Appwrite\Utopia\Response\Model\Token;
|
||||
use Appwrite\Utopia\Response\Model\Topic;
|
||||
use Appwrite\Utopia\Response\Model\Transaction;
|
||||
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\UsageFunction;
|
||||
use Appwrite\Utopia\Response\Model\UsageFunctions;
|
||||
use Appwrite\Utopia\Response\Model\UsageProject;
|
||||
use Appwrite\Utopia\Response\Model\UsageSite;
|
||||
use Appwrite\Utopia\Response\Model\UsageSites;
|
||||
use Appwrite\Utopia\Response\Model\UsageStorage;
|
||||
use Appwrite\Utopia\Response\Model\UsageTable;
|
||||
use Appwrite\Utopia\Response\Model\UsageUsers;
|
||||
use Appwrite\Utopia\Response\Model\User;
|
||||
use Appwrite\Utopia\Response\Model\Variable;
|
||||
use Appwrite\Utopia\Response\Model\VcsContent;
|
||||
use Appwrite\Utopia\Response\Model\Webhook;
|
||||
use Exception;
|
||||
use JsonException;
|
||||
// Keep last
|
||||
use Swoole\Http\Response as SwooleHTTPResponse;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
|
@ -418,6 +279,11 @@ class Response extends SwooleResponse
|
|||
*/
|
||||
protected static bool $showSensitive = false;
|
||||
|
||||
/**
|
||||
* @var array<string, Model>
|
||||
*/
|
||||
protected static array $models = [];
|
||||
|
||||
protected SwooleHTTPResponse $swoole;
|
||||
|
||||
/**
|
||||
|
|
@ -428,206 +294,6 @@ class Response extends SwooleResponse
|
|||
public function __construct(SwooleHTTPResponse $response)
|
||||
{
|
||||
$this->swoole = $response;
|
||||
|
||||
$this
|
||||
// General
|
||||
->setModel(new None())
|
||||
->setModel(new Any())
|
||||
->setModel(new Error())
|
||||
->setModel(new ErrorDev())
|
||||
// Lists
|
||||
->setModel(new BaseList('Rows List', self::MODEL_ROW_LIST, 'rows', self::MODEL_ROW))
|
||||
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
|
||||
->setModel(new BaseList('Tables List', self::MODEL_TABLE_LIST, 'tables', self::MODEL_TABLE))
|
||||
->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('Column Indexes List', self::MODEL_COLUMN_INDEX_LIST, 'indexes', self::MODEL_COLUMN_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))
|
||||
->setModel(new BaseList('Identities List', self::MODEL_IDENTITY_LIST, 'identities', self::MODEL_IDENTITY))
|
||||
->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG))
|
||||
->setModel(new BaseList('Files List', self::MODEL_FILE_LIST, 'files', self::MODEL_FILE))
|
||||
->setModel(new BaseList('Buckets List', self::MODEL_BUCKET_LIST, 'buckets', self::MODEL_BUCKET))
|
||||
->setModel(new BaseList('Resource Tokens List', self::MODEL_RESOURCE_TOKEN_LIST, 'tokens', self::MODEL_RESOURCE_TOKEN))
|
||||
->setModel(new BaseList('Teams List', self::MODEL_TEAM_LIST, 'teams', self::MODEL_TEAM))
|
||||
->setModel(new BaseList('Memberships List', self::MODEL_MEMBERSHIP_LIST, 'memberships', self::MODEL_MEMBERSHIP))
|
||||
->setModel(new BaseList('Sites List', self::MODEL_SITE_LIST, 'sites', self::MODEL_SITE))
|
||||
->setModel(new BaseList('Site Templates List', self::MODEL_TEMPLATE_SITE_LIST, 'templates', self::MODEL_TEMPLATE_SITE))
|
||||
->setModel(new BaseList('Functions List', self::MODEL_FUNCTION_LIST, 'functions', self::MODEL_FUNCTION))
|
||||
->setModel(new BaseList('Function Templates List', self::MODEL_TEMPLATE_FUNCTION_LIST, 'templates', self::MODEL_TEMPLATE_FUNCTION))
|
||||
->setModel(new BaseList('Installations List', self::MODEL_INSTALLATION_LIST, 'installations', self::MODEL_INSTALLATION))
|
||||
->setModel(new BaseList('Framework Provider Repositories List', self::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST, 'frameworkProviderRepositories', self::MODEL_PROVIDER_REPOSITORY_FRAMEWORK))
|
||||
->setModel(new BaseList('Runtime Provider Repositories List', self::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST, 'runtimeProviderRepositories', self::MODEL_PROVIDER_REPOSITORY_RUNTIME))
|
||||
->setModel(new BaseList('Branches List', self::MODEL_BRANCH_LIST, 'branches', self::MODEL_BRANCH))
|
||||
->setModel(new BaseList('Frameworks List', self::MODEL_FRAMEWORK_LIST, 'frameworks', self::MODEL_FRAMEWORK))
|
||||
->setModel(new BaseList('Runtimes List', self::MODEL_RUNTIME_LIST, 'runtimes', self::MODEL_RUNTIME))
|
||||
->setModel(new BaseList('Deployments List', self::MODEL_DEPLOYMENT_LIST, 'deployments', self::MODEL_DEPLOYMENT))
|
||||
->setModel(new BaseList('Executions List', self::MODEL_EXECUTION_LIST, 'executions', self::MODEL_EXECUTION))
|
||||
->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false))
|
||||
->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false))
|
||||
->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false))
|
||||
->setModel(new BaseList('Dev Keys List', self::MODEL_DEV_KEY_LIST, 'devKeys', self::MODEL_DEV_KEY, true, false))
|
||||
->setModel(new BaseList('Auth Providers List', self::MODEL_AUTH_PROVIDER_LIST, 'platforms', self::MODEL_AUTH_PROVIDER, true, false))
|
||||
->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false))
|
||||
->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY))
|
||||
->setModel(new BaseList('Continents List', self::MODEL_CONTINENT_LIST, 'continents', self::MODEL_CONTINENT))
|
||||
->setModel(new BaseList('Languages List', self::MODEL_LANGUAGE_LIST, 'languages', self::MODEL_LANGUAGE))
|
||||
->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('Variables List', self::MODEL_VARIABLE_LIST, 'variables', self::MODEL_VARIABLE))
|
||||
->setModel(new BaseList('Status List', self::MODEL_HEALTH_STATUS_LIST, 'statuses', self::MODEL_HEALTH_STATUS))
|
||||
->setModel(new BaseList('Rule List', self::MODEL_PROXY_RULE_LIST, 'rules', self::MODEL_PROXY_RULE))
|
||||
->setModel(new BaseList('Locale codes list', self::MODEL_LOCALE_CODE_LIST, 'localeCodes', self::MODEL_LOCALE_CODE))
|
||||
->setModel(new BaseList('Provider list', self::MODEL_PROVIDER_LIST, 'providers', self::MODEL_PROVIDER))
|
||||
->setModel(new BaseList('Message list', self::MODEL_MESSAGE_LIST, 'messages', self::MODEL_MESSAGE))
|
||||
->setModel(new BaseList('Topic list', self::MODEL_TOPIC_LIST, 'topics', self::MODEL_TOPIC))
|
||||
->setModel(new BaseList('Subscriber list', self::MODEL_SUBSCRIBER_LIST, 'subscribers', self::MODEL_SUBSCRIBER))
|
||||
->setModel(new BaseList('Target list', self::MODEL_TARGET_LIST, 'targets', self::MODEL_TARGET))
|
||||
->setModel(new BaseList('Transaction List', self::MODEL_TRANSACTION_LIST, 'transactions', self::MODEL_TRANSACTION))
|
||||
->setModel(new BaseList('Migrations List', self::MODEL_MIGRATION_LIST, 'migrations', self::MODEL_MIGRATION))
|
||||
->setModel(new BaseList('Migrations Firebase Projects List', self::MODEL_MIGRATION_FIREBASE_PROJECT_LIST, 'projects', self::MODEL_MIGRATION_FIREBASE_PROJECT))
|
||||
->setModel(new BaseList('Specifications List', self::MODEL_SPECIFICATION_LIST, 'specifications', self::MODEL_SPECIFICATION))
|
||||
->setModel(new BaseList('VCS Content List', self::MODEL_VCS_CONTENT_LIST, 'contents', self::MODEL_VCS_CONTENT))
|
||||
// Entities
|
||||
->setModel(new Database())
|
||||
// Collection API Models
|
||||
->setModel(new Collection())
|
||||
->setModel(new Attribute())
|
||||
->setModel(new AttributeList())
|
||||
->setModel(new AttributeString())
|
||||
->setModel(new AttributeInteger())
|
||||
->setModel(new AttributeFloat())
|
||||
->setModel(new AttributeBoolean())
|
||||
->setModel(new AttributeEmail())
|
||||
->setModel(new AttributeEnum())
|
||||
->setModel(new AttributeIP())
|
||||
->setModel(new AttributeURL())
|
||||
->setModel(new AttributeDatetime())
|
||||
->setModel(new AttributeRelationship())
|
||||
->setModel(new AttributePoint())
|
||||
->setModel(new AttributeLine())
|
||||
->setModel(new AttributePolygon())
|
||||
// Table API Models
|
||||
->setModel(new Table())
|
||||
->setModel(new Column())
|
||||
->setModel(new ColumnList())
|
||||
->setModel(new ColumnString())
|
||||
->setModel(new ColumnInteger())
|
||||
->setModel(new ColumnFloat())
|
||||
->setModel(new ColumnBoolean())
|
||||
->setModel(new ColumnEmail())
|
||||
->setModel(new ColumnEnum())
|
||||
->setModel(new ColumnIP())
|
||||
->setModel(new ColumnURL())
|
||||
->setModel(new ColumnDatetime())
|
||||
->setModel(new ColumnRelationship())
|
||||
->setModel(new ColumnPoint())
|
||||
->setModel(new ColumnLine())
|
||||
->setModel(new ColumnPolygon())
|
||||
->setModel(new Index())
|
||||
->setModel(new ColumnIndex())
|
||||
->setModel(new Row())
|
||||
->setModel(new ModelDocument())
|
||||
->setModel(new Log())
|
||||
->setModel(new User())
|
||||
->setModel(new AlgoMd5())
|
||||
->setModel(new AlgoSha())
|
||||
->setModel(new AlgoPhpass())
|
||||
->setModel(new AlgoBcrypt())
|
||||
->setModel(new AlgoScrypt())
|
||||
->setModel(new AlgoScryptModified())
|
||||
->setModel(new AlgoArgon2())
|
||||
->setModel(new Account())
|
||||
->setModel(new Preferences())
|
||||
->setModel(new Session())
|
||||
->setModel(new Identity())
|
||||
->setModel(new Token())
|
||||
->setModel(new JWT())
|
||||
->setModel(new Locale())
|
||||
->setModel(new LocaleCode())
|
||||
->setModel(new File())
|
||||
->setModel(new Bucket())
|
||||
->setModel(new ResourceToken())
|
||||
->setModel(new Team())
|
||||
->setModel(new Membership())
|
||||
->setModel(new Site())
|
||||
->setModel(new TemplateSite())
|
||||
->setModel(new TemplateFramework())
|
||||
->setModel(new Func())
|
||||
->setModel(new TemplateFunction())
|
||||
->setModel(new TemplateRuntime())
|
||||
->setModel(new TemplateVariable())
|
||||
->setModel(new Installation())
|
||||
->setModel(new ProviderRepository())
|
||||
->setModel(new ProviderRepositoryFramework())
|
||||
->setModel(new ProviderRepositoryRuntime())
|
||||
->setModel(new DetectionFramework())
|
||||
->setModel(new DetectionRuntime())
|
||||
->setModel(new DetectionVariable())
|
||||
->setModel(new VcsContent())
|
||||
->setModel(new Branch())
|
||||
->setModel(new Runtime())
|
||||
->setModel(new Framework())
|
||||
->setModel(new FrameworkAdapter())
|
||||
->setModel(new Deployment())
|
||||
->setModel(new Execution())
|
||||
->setModel(new Project())
|
||||
->setModel(new Webhook())
|
||||
->setModel(new Key())
|
||||
->setModel(new DevKey())
|
||||
->setModel(new MockNumber())
|
||||
->setModel(new AuthProvider())
|
||||
->setModel(new Platform())
|
||||
->setModel(new Variable())
|
||||
->setModel(new Country())
|
||||
->setModel(new Continent())
|
||||
->setModel(new Language())
|
||||
->setModel(new Currency())
|
||||
->setModel(new Phone())
|
||||
->setModel(new HealthAntivirus())
|
||||
->setModel(new HealthQueue())
|
||||
->setModel(new HealthStatus())
|
||||
->setModel(new HealthCertificate())
|
||||
->setModel(new HealthTime())
|
||||
->setModel(new HealthVersion())
|
||||
->setModel(new Metric())
|
||||
->setModel(new MetricBreakdown())
|
||||
->setModel(new UsageDatabases())
|
||||
->setModel(new UsageDatabase())
|
||||
->setModel(new UsageTable())
|
||||
->setModel(new UsageCollection())
|
||||
->setModel(new UsageUsers())
|
||||
->setModel(new UsageStorage())
|
||||
->setModel(new UsageBuckets())
|
||||
->setModel(new UsageFunctions())
|
||||
->setModel(new UsageFunction())
|
||||
->setModel(new UsageSites())
|
||||
->setModel(new UsageSite())
|
||||
->setModel(new UsageProject())
|
||||
->setModel(new Headers())
|
||||
->setModel(new Specification())
|
||||
->setModel(new Rule())
|
||||
->setModel(new TemplateSMS())
|
||||
->setModel(new TemplateEmail())
|
||||
->setModel(new ConsoleVariables())
|
||||
->setModel(new MFAChallenge())
|
||||
->setModel(new MFARecoveryCodes())
|
||||
->setModel(new MFAType())
|
||||
->setModel(new MFAFactors())
|
||||
->setModel(new Provider())
|
||||
->setModel(new Message())
|
||||
->setModel(new Topic())
|
||||
->setModel(new Transaction())
|
||||
->setModel(new Subscriber())
|
||||
->setModel(new Target())
|
||||
->setModel(new Migration())
|
||||
->setModel(new MigrationReport())
|
||||
->setModel(new MigrationFirebaseProject())
|
||||
// Tests (keep last)
|
||||
->setModel(new Mock());
|
||||
|
||||
parent::__construct($response);
|
||||
}
|
||||
|
||||
|
|
@ -639,20 +305,14 @@ class Response extends SwooleResponse
|
|||
public const CONTENT_TYPE_MULTIPART = 'multipart/form-data';
|
||||
|
||||
/**
|
||||
* List of defined output objects
|
||||
*/
|
||||
protected $models = [];
|
||||
|
||||
/**
|
||||
* Set Model Object
|
||||
* Register a model
|
||||
*
|
||||
* @return self
|
||||
* @param Model $model
|
||||
* @return void
|
||||
*/
|
||||
public function setModel(Model $instance): Response
|
||||
public static function setModel(Model $model): void
|
||||
{
|
||||
$this->models[$instance->getType()] = $instance;
|
||||
|
||||
return $this;
|
||||
self::$models[$model->getType()] = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -664,11 +324,11 @@ class Response extends SwooleResponse
|
|||
*/
|
||||
public function getModel(string $key): Model
|
||||
{
|
||||
if (!isset($this->models[$key])) {
|
||||
if (!isset(self::$models[$key])) {
|
||||
throw new Exception('Undefined model: ' . $key);
|
||||
}
|
||||
|
||||
return $this->models[$key];
|
||||
return self::$models[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -678,7 +338,18 @@ class Response extends SwooleResponse
|
|||
*/
|
||||
public function getModels(): array
|
||||
{
|
||||
return $this->models;
|
||||
return self::$models;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a model exists
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasModel(string $key): bool
|
||||
{
|
||||
return isset(self::$models[$key]);
|
||||
}
|
||||
|
||||
public function applyFilters(array $data, string $model): array
|
||||
|
|
@ -774,7 +445,7 @@ class Response extends SwooleResponse
|
|||
}
|
||||
|
||||
if ($rule['array']) {
|
||||
if (!is_array($data[$key])) {
|
||||
if (!\is_array($data[$key])) {
|
||||
throw new Exception($key . ' must be an array of type ' . $rule['type']);
|
||||
}
|
||||
|
||||
|
|
@ -798,7 +469,7 @@ class Response extends SwooleResponse
|
|||
$ruleType = $rule['type'];
|
||||
}
|
||||
|
||||
if (!array_key_exists($ruleType, $this->models)) {
|
||||
if (!self::hasModel($ruleType)) {
|
||||
throw new Exception('Missing model for rule: ' . $ruleType);
|
||||
}
|
||||
|
||||
|
|
|
|||
41
src/Appwrite/Utopia/Response/Filters/ListSelection.php
Normal file
41
src/Appwrite/Utopia/Response/Filters/ListSelection.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Filters;
|
||||
|
||||
use Appwrite\Utopia\Response\Filter;
|
||||
|
||||
class ListSelection extends Filter
|
||||
{
|
||||
public function __construct(
|
||||
private array $selectQueries,
|
||||
private string $itemsKey
|
||||
) {
|
||||
}
|
||||
|
||||
public function parse(array $content, string $model): array
|
||||
{
|
||||
if (empty($this->selectQueries)) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$selections = [];
|
||||
foreach ($this->selectQueries as $query) {
|
||||
foreach ($query->getValues() as $value) {
|
||||
if ($value === '*') {
|
||||
return $content;
|
||||
}
|
||||
$selections[$value] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->handleList($content, $this->itemsKey, function (array $item) use ($selections) {
|
||||
$filtered = [];
|
||||
foreach ($item as $key => $value) {
|
||||
if (isset($selections[$key]) || \str_starts_with($key, '$')) {
|
||||
$filtered[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $filtered;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -101,22 +101,6 @@ abstract class Model
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing Rule
|
||||
* If rule exists, it will be removed
|
||||
*
|
||||
* @param string $key
|
||||
* @return Model
|
||||
*/
|
||||
public function removeRule(string $key): self
|
||||
{
|
||||
if (isset($this->rules[$key])) {
|
||||
unset($this->rules[$key]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,18 +3,131 @@
|
|||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Account extends User
|
||||
class Account extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this
|
||||
->removeRule('password')
|
||||
->removeRule('hash')
|
||||
->removeRule('mfaRecoveryCodes')
|
||||
->removeRule('hashOptions');
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('$createdAt', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'description' => 'User creation date in ISO 8601 format.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('$updatedAt', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'description' => 'User update date in ISO 8601 format.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User name.',
|
||||
'default' => '',
|
||||
'example' => 'John Doe',
|
||||
])
|
||||
->addRule('registration', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'description' => 'User registration date in ISO 8601 format.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('status', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'User status. Pass `true` for enabled and `false` for disabled.',
|
||||
'default' => true,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('labels', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Labels for the user.',
|
||||
'default' => [],
|
||||
'example' => ['vip'],
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('passwordUpdate', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'description' => 'Password update time in ISO 8601 format.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('email', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User email address.',
|
||||
'default' => '',
|
||||
'example' => 'john@appwrite.io',
|
||||
])
|
||||
->addRule('phone', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User phone number in E.164 format.',
|
||||
'default' => '',
|
||||
'example' => '+4930901820',
|
||||
])
|
||||
->addRule('emailVerification', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Email verification status.',
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('phoneVerification', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Phone verification status.',
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('mfa', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Multi factor authentication status.',
|
||||
'default' => false,
|
||||
'example' => true,
|
||||
])
|
||||
->addRule('prefs', [
|
||||
'type' => Response::MODEL_PREFERENCES,
|
||||
'description' => 'User preferences as a key-value object',
|
||||
'default' => new \stdClass(),
|
||||
'example' => ['theme' => 'pink', 'timezone' => 'UTC'],
|
||||
])
|
||||
->addRule('targets', [
|
||||
'type' => Response::MODEL_TARGET,
|
||||
'description' => 'A user-owned message receiver. A single user may have multiple e.g. emails, phones, and a browser. Each target is registered with a single provider.',
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'example' => [],
|
||||
])
|
||||
->addRule('accessedAt', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_USER_ACCESS / 60 / 60 . ' hours.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Collection
|
||||
*
|
||||
* @return Document
|
||||
*/
|
||||
public function filter(Document $document): Document
|
||||
{
|
||||
$prefs = $document->getAttribute('prefs');
|
||||
if ($prefs instanceof Document) {
|
||||
$prefs = $prefs->getArrayCopy();
|
||||
}
|
||||
|
||||
if (is_array($prefs) && empty($prefs)) {
|
||||
$document->setAttribute('prefs', new \stdClass());
|
||||
}
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -276,6 +276,13 @@ class Project extends Model
|
|||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('labels', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Labels for the project.',
|
||||
'default' => [],
|
||||
'example' => ['vip'],
|
||||
'array' => true,
|
||||
])
|
||||
;
|
||||
|
||||
$services = Config::getParam('services', []);
|
||||
|
|
|
|||
|
|
@ -3,15 +3,19 @@
|
|||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class UsageSites extends UsageFunctions
|
||||
class UsageSites extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this
|
||||
->removeRule('functionsTotal')
|
||||
->removeRule('functions')
|
||||
->addRule('range', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Time range of the usage stats.',
|
||||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('sitesTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of sites.',
|
||||
|
|
@ -25,6 +29,60 @@ class UsageSites extends UsageFunctions
|
|||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('deploymentsTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of sites deployments.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('deploymentsStorageTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated sum of sites deployment storage.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('buildsTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of sites build.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('buildsStorageTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'total aggregated sum of sites build storage.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('buildsTimeTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated sum of sites build compute time.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('buildsMbSecondsTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated sum of sites build mbSeconds.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('executionsTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of sites execution.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('executionsTimeTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated sum of sites execution compute time.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('executionsMbSecondsTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated sum of sites execution mbSeconds.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('requestsTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of requests.',
|
||||
|
|
@ -64,6 +122,95 @@ class UsageSites extends UsageFunctions
|
|||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('deployments', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of sites deployment per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('deploymentsStorage', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of sites deployment storage per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsSuccessTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of successful site builds.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('buildsFailedTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of failed site builds.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('builds', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of sites build per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsStorage', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated sum of sites build storage per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsTime', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated sum of sites build compute time per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsMbSeconds', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated sum of sites build mbSeconds per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executions', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of sites execution per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsTime', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of sites execution compute time per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsMbSeconds', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of sites mbSeconds per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsSuccess', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of successful site builds per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsFailed', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of failed site builds per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -363,4 +363,77 @@ trait AccountBase
|
|||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
$this->assertEquals('191.0.113.195', $response['body']['clientIp'] ?? $response['body']['ip'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testAccountAbuseReset(): void
|
||||
{
|
||||
$email = \uniqid() . '.abuse.reset.test@example.com';
|
||||
$password = 'password';
|
||||
$account = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'userId' => ID::unique(),
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'name' => 'Abuse Reset Test',
|
||||
]);
|
||||
|
||||
$this->assertEquals($account['headers']['status-code'], 201);
|
||||
|
||||
// 20 successful requests won't get blocked
|
||||
for ($i = 0; $i < 20; $i++) {
|
||||
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($session['headers']['status-code'], 201);
|
||||
}
|
||||
|
||||
// 10 failures are OK
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => 'wrongPassword',
|
||||
]);
|
||||
|
||||
$this->assertEquals($session['headers']['status-code'], 401);
|
||||
}
|
||||
|
||||
// 11th request gets limited
|
||||
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => 'wrongPassword',
|
||||
]);
|
||||
|
||||
$this->assertEquals($session['headers']['status-code'], 429);
|
||||
|
||||
// Even correct password is now blocked, correctness doesn't matter
|
||||
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($session['headers']['status-code'], 429);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6119,6 +6119,7 @@ trait DatabasesBase
|
|||
$this->assertEquals(200, $inc['headers']['status-code']);
|
||||
$this->assertEquals(6, $inc['body']['count']);
|
||||
$this->assertEquals($collectionId, $inc['body']['$collectionId']);
|
||||
$this->assertEquals($databaseId, $inc['body']['$databaseId']);
|
||||
|
||||
// Verify count = 6
|
||||
$get = $this->client->call(Client::METHOD_GET, "/databases/$databaseId/collections/$collectionId/documents/$docId", array_merge([
|
||||
|
|
@ -6231,6 +6232,7 @@ trait DatabasesBase
|
|||
$this->assertEquals(200, $dec['headers']['status-code']);
|
||||
$this->assertEquals(9, $dec['body']['count']);
|
||||
$this->assertEquals($collectionId, $dec['body']['$collectionId']);
|
||||
$this->assertEquals($databaseId, $dec['body']['$databaseId']);
|
||||
|
||||
$get = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
|
|||
|
|
@ -3827,6 +3827,7 @@ trait TransactionsBase
|
|||
$this->assertArrayHasKey('$collectionId', $decrementResponse['body'], 'Response should contain $collectionId for Collections API');
|
||||
$this->assertArrayNotHasKey('$tableId', $decrementResponse['body'], 'Response should not contain $tableId for Collections API');
|
||||
$this->assertEquals($collectionId, $decrementResponse['body']['$collectionId']);
|
||||
$this->assertEquals($databaseId, $decrementResponse['body']['$databaseId']);
|
||||
|
||||
// Test increment endpoint
|
||||
$incrementResponse = $this->client->call(
|
||||
|
|
@ -3846,6 +3847,7 @@ trait TransactionsBase
|
|||
$this->assertArrayHasKey('$collectionId', $incrementResponse['body'], 'Response should contain $collectionId for Collections API');
|
||||
$this->assertArrayNotHasKey('$tableId', $incrementResponse['body'], 'Response should not contain $tableId for Collections API');
|
||||
$this->assertEquals($collectionId, $incrementResponse['body']['$collectionId']);
|
||||
$this->assertEquals($databaseId, $incrementResponse['body']['$databaseId']);
|
||||
|
||||
// Commit transaction - this will fail if transaction log has 'column' instead of 'attribute'
|
||||
$commitResponse = $this->client->call(Client::METHOD_PATCH, "/databases/transactions/{$transactionId}", array_merge([
|
||||
|
|
|
|||
|
|
@ -7761,6 +7761,7 @@ trait DatabasesBase
|
|||
]));
|
||||
$this->assertEquals(200, $inc['headers']['status-code']);
|
||||
$this->assertEquals($tableId, $inc['body']['$tableId']);
|
||||
$this->assertEquals($databaseId, $inc['body']['$databaseId']);
|
||||
$this->assertEquals(6, $inc['body']['count']);
|
||||
|
||||
// Verify count = 6
|
||||
|
|
@ -7874,6 +7875,7 @@ trait DatabasesBase
|
|||
$this->assertEquals(200, $dec['headers']['status-code']);
|
||||
$this->assertEquals(9, $dec['body']['count']);
|
||||
$this->assertEquals($tableId, $dec['body']['$tableId']);
|
||||
$this->assertEquals($databaseId, $dec['body']['$databaseId']);
|
||||
|
||||
$get = $this->client->call(Client::METHOD_GET, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
|
|||
|
|
@ -3963,6 +3963,7 @@ trait TransactionsBase
|
|||
$this->assertArrayHasKey('$tableId', $decrementResponse['body'], 'Response should contain $tableId for TablesDB API');
|
||||
$this->assertArrayNotHasKey('$collectionId', $decrementResponse['body'], 'Response should not contain $collectionId for TablesDB API');
|
||||
$this->assertEquals($tableId, $decrementResponse['body']['$tableId']);
|
||||
$this->assertEquals($databaseId, $decrementResponse['body']['$databaseId']);
|
||||
|
||||
// Test increment endpoint
|
||||
$incrementResponse = $this->client->call(
|
||||
|
|
@ -3982,6 +3983,7 @@ trait TransactionsBase
|
|||
$this->assertArrayHasKey('$tableId', $incrementResponse['body'], 'Response should contain $tableId for TablesDB API');
|
||||
$this->assertArrayNotHasKey('$collectionId', $incrementResponse['body'], 'Response should not contain $collectionId for TablesDB API');
|
||||
$this->assertEquals($tableId, $incrementResponse['body']['$tableId']);
|
||||
$this->assertEquals($databaseId, $incrementResponse['body']['$databaseId']);
|
||||
|
||||
// Commit transaction - this will fail if transaction log has 'attribute' instead of 'column'
|
||||
$commitResponse = $this->client->call(Client::METHOD_PATCH, "/tablesdb/transactions/{$transactionId}", array_merge([
|
||||
|
|
|
|||
|
|
@ -4783,7 +4783,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
*/
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testCreateProjectDevKey(): void
|
||||
{
|
||||
|
|
@ -4844,7 +4844,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testListProjectDevKey(): void
|
||||
{
|
||||
|
|
@ -4935,7 +4935,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testGetProjectDevKey(): void
|
||||
{
|
||||
|
|
@ -4979,7 +4979,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
}
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testGetDevKeyWithSdks(): void
|
||||
{
|
||||
|
|
@ -5036,7 +5036,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
}
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testNoHostValidationWithDevKey(): void
|
||||
{
|
||||
|
|
@ -5117,7 +5117,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
}
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testCorsWithDevKey(): void
|
||||
{
|
||||
|
|
@ -5174,7 +5174,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
}
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testNoRateLimitWithDevKey(): void
|
||||
{
|
||||
|
|
@ -5279,7 +5279,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
}
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testUpdateProjectDevKey(): void
|
||||
{
|
||||
|
|
@ -5324,7 +5324,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
}
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group abuseEnabled
|
||||
*/
|
||||
public function testDeleteProjectDevKey(): void
|
||||
{
|
||||
|
|
@ -5382,4 +5382,216 @@ class ProjectsConsoleClientTest extends Scope
|
|||
/**
|
||||
* Devkeys Tests ends here ------------------------------------------------
|
||||
*/
|
||||
|
||||
public function testProjectLabels(): void
|
||||
{
|
||||
// Setup: Prepare team
|
||||
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'teamId' => ID::unique(),
|
||||
'name' => 'Query Select Test Team',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $team['headers']['status-code']);
|
||||
$teamId = $team['body']['$id'];
|
||||
|
||||
// Setup: Prepare project
|
||||
$project = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'projectId' => ID::unique(),
|
||||
'name' => 'Test project - Labels 1',
|
||||
'teamId' => $teamId,
|
||||
'region' => System::getEnv('_APP_REGION', 'default')
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $project['headers']['status-code']);
|
||||
$this->assertIsArray($project['body']['labels']);
|
||||
$this->assertCount(0, $project['body']['labels']);
|
||||
$projectId = $project['body']['$id'];
|
||||
|
||||
// Apply labels
|
||||
$project = $this->client->call(Client::METHOD_PUT, '/projects/' . $projectId . '/labels', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'labels' => ['vip', 'imagine', 'blocked']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $project['headers']['status-code']);
|
||||
$this->assertIsArray($project['body']['labels']);
|
||||
$this->assertCount(3, $project['body']['labels']);
|
||||
$this->assertEquals('vip', $project['body']['labels'][0]);
|
||||
$this->assertEquals('imagine', $project['body']['labels'][1]);
|
||||
$this->assertEquals('blocked', $project['body']['labels'][2]);
|
||||
|
||||
// Update labels
|
||||
$project = $this->client->call(Client::METHOD_PUT, '/projects/' . $projectId . '/labels', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'labels' => ['nonvip', 'imagine']
|
||||
]);
|
||||
$this->assertEquals(200, $project['headers']['status-code']);
|
||||
$this->assertIsArray($project['body']['labels']);
|
||||
$this->assertCount(2, $project['body']['labels']);
|
||||
$this->assertEquals('nonvip', $project['body']['labels'][0]);
|
||||
$this->assertEquals('imagine', $project['body']['labels'][1]);
|
||||
|
||||
// Filter by labels
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['nonvip'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(1, $projects['body']['total']);
|
||||
$this->assertEquals($projectId, $projects['body']['projects'][0]['$id']);
|
||||
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['vip'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(0, $projects['body']['total']);
|
||||
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['imagine'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(1, $projects['body']['total']);
|
||||
$this->assertEquals($projectId, $projects['body']['projects'][0]['$id']);
|
||||
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['nonvip', 'imagine'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(1, $projects['body']['total']);
|
||||
$this->assertEquals($projectId, $projects['body']['projects'][0]['$id']);
|
||||
|
||||
// Setup: Second project with only imagine label
|
||||
$project = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'projectId' => ID::unique(),
|
||||
'name' => 'Test project - Labels 2',
|
||||
'teamId' => $teamId,
|
||||
'region' => System::getEnv('_APP_REGION', 'default')
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $project['headers']['status-code']);
|
||||
$this->assertIsArray($project['body']['labels']);
|
||||
$this->assertCount(0, $project['body']['labels']);
|
||||
$projectId2 = $project['body']['$id'];
|
||||
|
||||
$project = $this->client->call(Client::METHOD_PUT, '/projects/' . $projectId2 . '/labels', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'labels' => ['vip', 'imagine']
|
||||
]);
|
||||
$this->assertEquals(200, $project['headers']['status-code']);
|
||||
$this->assertIsArray($project['body']['labels']);
|
||||
$this->assertCount(2, $project['body']['labels']);
|
||||
$this->assertEquals('vip', $project['body']['labels'][0]);
|
||||
$this->assertEquals('imagine', $project['body']['labels'][1]);
|
||||
|
||||
// List of imagine has both
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['imagine'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(2, $projects['body']['total']);
|
||||
$this->assertEquals($projectId, $projects['body']['projects'][0]['$id']);
|
||||
$this->assertEquals($projectId2, $projects['body']['projects'][1]['$id']);
|
||||
|
||||
// List of vip only has second
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['vip'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(1, $projects['body']['total']);
|
||||
$this->assertEquals($projectId2, $projects['body']['projects'][0]['$id']);
|
||||
|
||||
// List of vip and imagine has second
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['vip'])->toString(),
|
||||
Query::contains('labels', ['imagine'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(1, $projects['body']['total']);
|
||||
$this->assertEquals($projectId2, $projects['body']['projects'][0]['$id']);
|
||||
|
||||
// List of vip or imagine has second
|
||||
$projects = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::contains('labels', ['vip', 'imagine'])->toString(),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $projects['headers']['status-code']);
|
||||
$this->assertEquals(2, $projects['body']['total']);
|
||||
$this->assertEquals($projectId, $projects['body']['projects'][0]['$id']);
|
||||
$this->assertEquals($projectId2, $projects['body']['projects'][1]['$id']);
|
||||
|
||||
// Cleanup
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $projectId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/projects/' . $projectId2, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue