Merge branch '1.4.x' of https://github.com/appwrite/appwrite into disallow-personal-data

This commit is contained in:
Christy Jacob
2023-07-11 19:36:37 +00:00
6019 changed files with 9655 additions and 7884 deletions
+36 -15
View File
@@ -16,9 +16,9 @@ use Appwrite\OpenSSL\OpenSSL;
use Appwrite\Template\Template;
use Appwrite\URL\URL as URLParser;
use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\Utopia\Database\Validator\Queries;
use Appwrite\Utopia\Database\Validator\Query\Limit;
use Appwrite\Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\Queries;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use MaxMind\Db\Reader;
@@ -188,7 +188,7 @@ App::post('/v1/account/sessions/email')
Query::equal('email', [$email]),
]);
if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'), $profile->getAttribute('hash'), $profile->getAttribute('hashOptions'))) {
if (!$profile || empty($profile->getAttribute('passwordUpdate')) || !Auth::passwordVerify($password, $profile->getAttribute('password'), $profile->getAttribute('hash'), $profile->getAttribute('hashOptions'))) {
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
}
@@ -1419,7 +1419,7 @@ App::get('/v1/account/logs')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->inject('response')
->inject('user')
->inject('locale')
@@ -1644,10 +1644,11 @@ App::patch('/v1/account/email')
->inject('dbForProject')
->inject('events')
->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
$isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting
// passwordUpdate will be empty if the user has never set a password
$passwordUpdate = $user->getAttribute('passwordUpdate');
if (
!$isAnonymousUser &&
!empty($passwordUpdate) &&
!Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))
) { // Double check user password
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
@@ -1656,16 +1657,21 @@ App::patch('/v1/account/email')
$email = \strtolower($email);
$user
->setAttribute('password', $isAnonymousUser ? Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS) : $user->getAttribute('password', ''))
->setAttribute('hash', $isAnonymousUser ? Auth::DEFAULT_ALGO : $user->getAttribute('hash', ''))
->setAttribute('hashOptions', $isAnonymousUser ? Auth::DEFAULT_ALGO_OPTIONS : $user->getAttribute('hashOptions', ''))
->setAttribute('email', $email)
->setAttribute('emailVerification', false) // After this user needs to confirm mail again
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name', ''), $email, $user->getAttribute('phone', '')]));
if (empty($passwordUpdate)) {
$user
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now());
}
try {
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
} catch (Duplicate $th) {
} catch (Duplicate) {
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
}
@@ -1700,11 +1706,11 @@ App::patch('/v1/account/phone')
->inject('dbForProject')
->inject('events')
->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
$isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting
// passwordUpdate will be empty if the user has never set a password
$passwordUpdate = $user->getAttribute('passwordUpdate');
if (
!$isAnonymousUser &&
!empty($passwordUpdate) &&
!Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))
) { // Double check user password
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
@@ -1715,6 +1721,14 @@ App::patch('/v1/account/phone')
->setAttribute('phoneVerification', false) // After this user needs to confirm phone number again
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name', ''), $user->getAttribute('email', ''), $phone]));
if (empty($passwordUpdate)) {
$user
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now());
}
try {
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
} catch (Duplicate $th) {
@@ -1778,11 +1792,12 @@ App::patch('/v1/account/status')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->inject('requestTimestamp')
->inject('request')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
$user->setAttribute('status', false);
@@ -1796,6 +1811,12 @@ App::patch('/v1/account/status')
$response->addHeader('X-Fallback-Cookies', \json_encode([]));
}
$protocol = $request->getProtocol();
$response
->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
;
$response->dynamic($user, Response::MODEL_ACCOUNT);
});
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -136,7 +136,7 @@ App::get('/v1/functions')
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -211,7 +211,7 @@ App::get('/v1/functions/:functionId')
App::get('/v1/functions/:functionId/usage')
->desc('Get Function Usage')
->groups(['api', 'functions'])
->groups(['api', 'functions', 'usage'])
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
@@ -321,7 +321,7 @@ App::get('/v1/functions/:functionId/usage')
App::get('/v1/functions/usage')
->desc('Get Functions Usage')
->groups(['api', 'functions'])
->groups(['api', 'functions', 'usage'])
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
@@ -812,7 +812,7 @@ App::get('/v1/functions/:functionId/deployments')
$queries[] = Query::equal('resourceType', ['functions']);
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -1246,7 +1246,7 @@ App::get('/v1/functions/:functionId/executions')
$queries[] = Query::equal('functionId', [$function->getId()]);
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
+128 -48
View File
@@ -29,6 +29,7 @@ use Utopia\Domains\Domain;
use Utopia\Registry\Registry;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Database\Validator\Queries\Projects;
use Utopia\Database\Exception\Duplicate;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Hostname;
@@ -91,38 +92,43 @@ App::post('/v1/projects')
throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project.");
}
$project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId,
'$permissions' => [
Permission::read(Role::team(ID::custom($teamId))),
Permission::update(Role::team(ID::custom($teamId), 'owner')),
Permission::update(Role::team(ID::custom($teamId), 'developer')),
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
],
'name' => $name,
'teamInternalId' => $team->getInternalId(),
'teamId' => $team->getId(),
'region' => $region,
'description' => $description,
'logo' => $logo,
'url' => $url,
'version' => APP_VERSION_STABLE,
'legalName' => $legalName,
'legalCountry' => $legalCountry,
'legalState' => $legalState,
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
'legalTaxId' => ID::custom($legalTaxId),
'services' => new stdClass(),
'platforms' => null,
'authProviders' => [],
'webhooks' => null,
'keys' => null,
'domains' => null,
'auths' => $auths,
'search' => implode(' ', [$projectId, $name]),
]));
try {
$project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId,
'$permissions' => [
Permission::read(Role::team(ID::custom($teamId))),
Permission::update(Role::team(ID::custom($teamId), 'owner')),
Permission::update(Role::team(ID::custom($teamId), 'developer')),
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
],
'name' => $name,
'teamInternalId' => $team->getInternalId(),
'teamId' => $team->getId(),
'region' => $region,
'description' => $description,
'logo' => $logo,
'url' => $url,
'version' => APP_VERSION_STABLE,
'legalName' => $legalName,
'legalCountry' => $legalCountry,
'legalState' => $legalState,
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
'legalTaxId' => ID::custom($legalTaxId),
'services' => new stdClass(),
'platforms' => null,
'authProviders' => [],
'webhooks' => null,
'keys' => null,
'domains' => null,
'auths' => $auths,
'search' => implode(' ', [$projectId, $name]),
]));
} catch (Duplicate $th) {
throw new Exception(Exception::PROJECT_ALREADY_EXISTS);
}
/** @var array $collections */
$collections = Config::getParam('collections', []);
@@ -197,7 +203,7 @@ App::get('/v1/projects')
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -245,7 +251,7 @@ App::get('/v1/projects/:projectId')
App::get('/v1/projects/:projectId/usage')
->desc('Get usage stats for a project')
->groups(['api', 'projects'])
->groups(['api', 'projects', 'usage'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
@@ -404,6 +410,46 @@ App::patch('/v1/projects/:projectId')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/team')
->desc('Update Project Team')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateTeam')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('teamId', '', new UID(), 'Team ID of the team to transfer project to.')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, string $teamId, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
$team = $dbForConsole->getDocument('teams', $teamId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('teamId', $teamId)
->setAttribute('$permissions', [
Permission::read(Role::team(ID::custom($teamId))),
Permission::update(Role::team(ID::custom($teamId), 'owner')),
Permission::update(Role::team(ID::custom($teamId), 'developer')),
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
]));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/service')
->desc('Update service status')
->groups(['api', 'projects'])
@@ -435,6 +481,40 @@ App::patch('/v1/projects/:projectId/service')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/service/all')
->desc('Update all service status')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateServiceStatusAll')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('status', null, new Boolean(), 'Service status.')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, bool $status, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$allServices = array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional']));
$services = [];
foreach ($allServices as $service) {
$services[$service] = $status;
}
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('services', $services));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/oauth2')
->desc('Update Project OAuth2')
->groups(['api', 'projects'])
@@ -851,7 +931,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
}
$webhook = $dbForConsole->findOne('webhooks', [
Query::equal('_uid', [$webhookId]),
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -893,7 +973,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$webhook = $dbForConsole->findOne('webhooks', [
Query::equal('_uid', [$webhookId]),
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -939,7 +1019,7 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
}
$webhook = $dbForConsole->findOne('webhooks', [
Query::equal('_uid', [$webhookId]),
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -977,7 +1057,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
}
$webhook = $dbForConsole->findOne('webhooks', [
Query::equal('_uid', [$webhookId]),
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1099,7 +1179,7 @@ App::get('/v1/projects/:projectId/keys/:keyId')
}
$key = $dbForConsole->findOne('keys', [
Query::equal('_uid', [$keyId]),
Query::equal('$id', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1136,7 +1216,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
}
$key = $dbForConsole->findOne('keys', [
Query::equal('_uid', [$keyId]),
Query::equal('$id', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1179,7 +1259,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
}
$key = $dbForConsole->findOne('keys', [
Query::equal('_uid', [$keyId]),
Query::equal('$id', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1268,7 +1348,7 @@ App::get('/v1/projects/:projectId/platforms')
}
$platforms = $dbForConsole->find('platforms', [
Query::equal('projectId', [$project->getId()]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::limit(5000),
]);
@@ -1301,7 +1381,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
}
$platform = $dbForConsole->findOne('platforms', [
Query::equal('_uid', [$platformId]),
Query::equal('$id', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1338,7 +1418,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
}
$platform = $dbForConsole->findOne('platforms', [
Query::equal('_uid', [$platformId]),
Query::equal('$id', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1382,7 +1462,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
}
$platform = $dbForConsole->findOne('platforms', [
Query::equal('_uid', [$platformId]),
Query::equal('$id', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1519,7 +1599,7 @@ App::get('/v1/projects/:projectId/domains/:domainId')
}
$domain = $dbForConsole->findOne('domains', [
Query::equal('_uid', [$domainId]),
Query::equal('$id', [$domainId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1553,7 +1633,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
}
$domain = $dbForConsole->findOne('domains', [
Query::equal('_uid', [$domainId]),
Query::equal('$id', [$domainId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
@@ -1613,7 +1693,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
}
$domain = $dbForConsole->findOne('domains', [
Query::equal('_uid', [$domainId]),
Query::equal('$id', [$domainId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
]);
+13 -7
View File
@@ -128,7 +128,7 @@ App::post('/v1/storage/buckets')
$bucket = $dbForProject->getDocument('buckets', $bucketId);
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity);
} catch (Duplicate) {
throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS);
}
@@ -167,7 +167,7 @@ App::get('/v1/storage/buckets')
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -274,6 +274,7 @@ App::put('/v1/storage/buckets/:bucketId')
->setAttribute('encryption', $encryption)
->setAttribute('compression', $compression)
->setAttribute('antivirus', $antivirus));
$dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity);
$events
->setParam('bucketId', $bucket->getId())
@@ -514,6 +515,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
$mimeType = $deviceFiles->getFileMimeType($path); // Get mime-type before compression and encryption
$fileHash = $deviceFiles->getFileHash($path); // Get file hash before compression and encryption
$data = '';
// Compression
$algorithm = $bucket->getAttribute('compression', COMPRESSION_TYPE_NONE);
@@ -547,7 +549,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
$sizeActual = $deviceFiles->getFileSize($path);
$fileHash = $deviceFiles->getFileHash($path);
$openSSLVersion = null;
$openSSLCipher = null;
@@ -707,7 +708,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -1268,13 +1269,14 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
->label('sdk.response.model', Response::MODEL_FILE)
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
->param('fileId', '', new UID(), 'File unique ID.')
->param('name', null, new Text(255), 'Name of the file', true)
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
->inject('response')
->inject('dbForProject')
->inject('user')
->inject('mode')
->inject('events')
->action(function (string $bucketId, string $fileId, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) {
->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
@@ -1330,6 +1332,10 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
$file->setAttribute('$permissions', $permissions);
if (!is_null($name)) {
$file->setAttribute('name', $name);
}
if ($fileSecurity && !$valid) {
try {
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
@@ -1447,7 +1453,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
App::get('/v1/storage/usage')
->desc('Get usage stats for storage')
->groups(['api', 'storage'])
->groups(['api', 'storage', 'usage'])
->label('scope', 'files.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')
@@ -1557,7 +1563,7 @@ App::get('/v1/storage/usage')
App::get('/v1/storage/:bucketId/usage')
->desc('Get usage stats for a storage bucket')
->groups(['api', 'storage'])
->groups(['api', 'storage', 'usage'])
->label('scope', 'files.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')
+6 -6
View File
@@ -12,11 +12,11 @@ use Appwrite\Network\Validator\Email;
use Utopia\Validator\Host;
use Appwrite\Template\Template;
use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\Utopia\Database\Validator\Queries;
use Utopia\Database\Validator\Queries;
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
use Appwrite\Utopia\Database\Validator\Queries\Teams;
use Appwrite\Utopia\Database\Validator\Query\Limit;
use Appwrite\Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use MaxMind\Db\Reader;
@@ -148,7 +148,7 @@ App::get('/v1/teams')
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -629,7 +629,7 @@ App::get('/v1/teams/:teamId/memberships')
$queries[] = Query::equal('teamId', [$teamId]);
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -1002,7 +1002,7 @@ App::get('/v1/teams/:teamId/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('teamId', '', new UID(), 'Team ID.')
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->inject('response')
->inject('dbForProject')
->inject('locale')
+6 -6
View File
@@ -8,10 +8,10 @@ use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Network\Validator\Email;
use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\Utopia\Database\Validator\Queries;
use Utopia\Database\Validator\Queries;
use Appwrite\Utopia\Database\Validator\Queries\Users;
use Appwrite\Utopia\Database\Validator\Query\Limit;
use Appwrite\Utopia\Database\Validator\Query\Offset;
use Utopia\Database\Validator\Query\Limit;
use Utopia\Database\Validator\Query\Offset;
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Audit\Audit;
@@ -394,7 +394,7 @@ App::get('/v1/users')
}
// Get cursor document if there was a cursor query
$cursor = Query::getByType($queries, Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE);
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
$cursor = reset($cursor);
if ($cursor) {
/** @var Query $cursor */
@@ -565,7 +565,7 @@ App::get('/v1/users/:userId/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('userId', '', new UID(), 'User ID.')
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->inject('response')
->inject('dbForProject')
->inject('locale')
@@ -1144,7 +1144,7 @@ App::delete('/v1/users/:userId')
App::get('/v1/users/usage')
->desc('Get usage stats for the users API')
->groups(['api', 'users'])
->groups(['api', 'users', 'usage'])
->label('scope', 'users.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'users')
+2 -2
View File
@@ -437,7 +437,7 @@ App::error()
$log->addExtra('line', $error->getLine());
$log->addExtra('trace', $error->getTraceAsString());
$log->addExtra('detailedTrace', $error->getTrace());
$log->addExtra('roles', Authorization::$roles);
$log->addExtra('roles', Authorization::getRoles());
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
$log->setAction($action);
@@ -584,7 +584,7 @@ App::get('/humans.txt')
$response->text($template->render(false));
});
App::get('/.well-known/acme-challenge')
App::get('/.well-known/acme-challenge/*')
->desc('SSL Verification')
->label('scope', 'public')
->label('docs', false)
+8
View File
@@ -552,3 +552,11 @@ App::shutdown()
->submit();
}
});
App::init()
->groups(['usage'])
->action(function () {
if (App::getEnv('_APP_USAGE_STATS', 'enabled') !== 'enabled') {
throw new Exception(Exception::GENERAL_USAGE_DISABLED);
}
});
+3 -2
View File
@@ -3,12 +3,13 @@
use Appwrite\Utopia\Response;
use Utopia\App;
App::get('/console')
App::get('/console/*')
->alias('/')
->alias('auth/*')
->alias('/invite')
->alias('/login')
->alias('/recover')
->alias('/register')
->alias('/register/*')
->groups(['web'])
->label('permission', 'public')
->label('scope', 'home')