Merge branch 'feat-database-indexing' into feat-quest-filters
This commit is contained in:
commit
e2aebdd2bc
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
@ -28,7 +28,7 @@ jobs:
|
|||
docker pull php:8.0-cli-alpine
|
||||
docker compose build --progress=plain
|
||||
docker compose up -d
|
||||
sleep 10
|
||||
sleep 30
|
||||
- name: Doctor
|
||||
run: docker compose exec -T appwrite doctor
|
||||
|
||||
|
|
17
CHANGES.md
17
CHANGES.md
|
@ -2,11 +2,12 @@
|
|||
|
||||
## Features
|
||||
|
||||
- Completely rewritten Database service:
|
||||
- Completely rewritten Database service: **Breaking Change**
|
||||
- Collection rules are now attributes
|
||||
- Filters for have been replaced with a new, more powerful syntax
|
||||
- Custom indexes for more performant queries
|
||||
- Enum Attributes
|
||||
- Maximum `sum` returned does not exceed 5000 documents anymore **Breaking Change**
|
||||
- **DEPRECATED** Nested documents has been removed
|
||||
- **DEPRECATED** Wildcard rule has been removed
|
||||
- You can now set custom ID’s when creating following resources:
|
||||
|
@ -17,10 +18,14 @@
|
|||
- File
|
||||
- Collection
|
||||
- Document
|
||||
- Wildcard permissions `*` are now `role:all`
|
||||
- All resources with custom ID support required you to set an ID now
|
||||
- Passing `unique()` will generate a unique ID
|
||||
- Auto-generated ID's are now 20 characters long
|
||||
- Wildcard permissions `*` are now `role:all` **Breaking Change**
|
||||
- Collections can be enabled and disabled
|
||||
- Permissions are now found as top-level keys `$read` and `$write` instead of nested under `$permissions`
|
||||
- Accessing collections with insufficient permissions now return a `401` isntead of `404` status code
|
||||
- Offset cannot be higher than 5000 now and cursor pagination is required
|
||||
- Added Cursor pagination to all endpoints that provide pagination by offset
|
||||
- Added new Usage worker to aggregate usage statistics
|
||||
- Added new Database worker to handle heavy database tasks in the background
|
||||
|
@ -38,22 +43,24 @@
|
|||
- Teams
|
||||
- Users
|
||||
- Functions
|
||||
- Added Flutter Desktop Support
|
||||
- Fixed several memory leaks in the Console
|
||||
- Added pagination to account activities in the Console
|
||||
- Added following events from User service to Webhooks and Functions:
|
||||
- `users.update.email`
|
||||
- `users.update.name`
|
||||
- `users.update.password`
|
||||
- Added new environment variables to enable error logging:
|
||||
- The `_APP_LOGGING_PROVIDER` variable allows you to enable the logger set the value to one of `sentry`, `raygun`, `appsignal`.
|
||||
- The `_APP_LOGGING_CONFIG` variable configures authentication to 3rd party error logging providers. If using Sentry, this should be 'SENTRY_API_KEY;SENTRY_APP_ID'. If using Raygun, this should be Raygun API key. If using AppSignal, this should be AppSignal API key.
|
||||
- Added new environment variable `_APP_USAGE_AGGREGATION_INTERVAL` to configure the usage worker interval
|
||||
- Added negative rotation values to file preview endpoint
|
||||
- Multiple HealthAPI response models were changed to new (better) schema
|
||||
- Multiple responses from the Health service were changed to new (better) schema **Breaking Change**
|
||||
- Method `health.getAntiVirus()` has been renamed to `health.getAntivirus()`
|
||||
- Added following langauges to the Locale service:
|
||||
- Latin
|
||||
- Sindhi
|
||||
- Telugu
|
||||
- **DEPRECATED** Tasks service
|
||||
- **DEPRECATED** Tasks service **Breaking Change**
|
||||
|
||||
## Bugs
|
||||
- Fixed `/v1/avatars/initials` when no space in the name, will try to split by `_`
|
||||
|
|
|
@ -15,7 +15,7 @@ return [
|
|||
[
|
||||
'key' => 'web',
|
||||
'name' => 'Web',
|
||||
'version' => '5.0.0',
|
||||
'version' => '6.0.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-web',
|
||||
'package' => 'https://www.npmjs.com/package/appwrite',
|
||||
'enabled' => true,
|
||||
|
@ -63,7 +63,7 @@ return [
|
|||
[
|
||||
'key' => 'flutter',
|
||||
'name' => 'Flutter',
|
||||
'version' => '2.1.0',
|
||||
'version' => '3.0.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-flutter',
|
||||
'package' => 'https://pub.dev/packages/appwrite',
|
||||
'enabled' => true,
|
||||
|
@ -81,7 +81,7 @@ return [
|
|||
[
|
||||
'key' => 'apple',
|
||||
'name' => 'Apple',
|
||||
'version' => '0.1.1',
|
||||
'version' => '0.2.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-apple',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-apple',
|
||||
'enabled' => true,
|
||||
|
@ -116,7 +116,7 @@ return [
|
|||
[
|
||||
'key' => 'android',
|
||||
'name' => 'Android',
|
||||
'version' => '0.2.1',
|
||||
'version' => '0.3.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-android',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
|
||||
'enabled' => true,
|
||||
|
@ -190,7 +190,7 @@ return [
|
|||
[
|
||||
'key' => 'nodejs',
|
||||
'name' => 'Node.js',
|
||||
'version' => '3.0.0',
|
||||
'version' => '4.0.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-node',
|
||||
'package' => 'https://www.npmjs.com/package/node-appwrite',
|
||||
'enabled' => true,
|
||||
|
@ -208,7 +208,7 @@ return [
|
|||
[
|
||||
'key' => 'deno',
|
||||
'name' => 'Deno',
|
||||
'version' => '1.0.0',
|
||||
'version' => '2.0.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-deno',
|
||||
'package' => 'https://deno.land/x/appwrite',
|
||||
'enabled' => true,
|
||||
|
@ -226,7 +226,7 @@ return [
|
|||
[
|
||||
'key' => 'php',
|
||||
'name' => 'PHP',
|
||||
'version' => '2.3.2',
|
||||
'version' => '3.0.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-php',
|
||||
'package' => 'https://packagist.org/packages/appwrite/appwrite',
|
||||
'enabled' => true,
|
||||
|
@ -244,7 +244,7 @@ return [
|
|||
[
|
||||
'key' => 'python',
|
||||
'name' => 'Python',
|
||||
'version' => '0.5.1',
|
||||
'version' => '0.6.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-python',
|
||||
'package' => 'https://pypi.org/project/appwrite/',
|
||||
'enabled' => true,
|
||||
|
@ -262,7 +262,7 @@ return [
|
|||
[
|
||||
'key' => 'ruby',
|
||||
'name' => 'Ruby',
|
||||
'version' => '2.4.1',
|
||||
'version' => '3.0.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-ruby',
|
||||
'package' => 'https://rubygems.org/gems/appwrite',
|
||||
'enabled' => true,
|
||||
|
@ -316,7 +316,7 @@ return [
|
|||
[
|
||||
'key' => 'dotnet',
|
||||
'name' => '.NET',
|
||||
'version' => '0.3.0',
|
||||
'version' => '0.4.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
|
||||
'package' => 'https://www.nuget.org/packages/Appwrite',
|
||||
'enabled' => false,
|
||||
|
@ -334,7 +334,7 @@ return [
|
|||
[
|
||||
'key' => 'dart',
|
||||
'name' => 'Dart',
|
||||
'version' => '2.0.0',
|
||||
'version' => '3.0.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-dart',
|
||||
'package' => 'https://pub.dev/packages/dart_appwrite',
|
||||
'enabled' => true,
|
||||
|
@ -352,7 +352,7 @@ return [
|
|||
[
|
||||
'key' => 'cli',
|
||||
'name' => 'Command Line',
|
||||
'version' => '0.12.1',
|
||||
'version' => '0.13.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-cli',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-cli',
|
||||
'enabled' => true,
|
||||
|
@ -370,7 +370,7 @@ return [
|
|||
[
|
||||
'key' => 'kotlin',
|
||||
'name' => 'Kotlin',
|
||||
'version' => '0.1.1',
|
||||
'version' => '0.2.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
|
||||
'enabled' => true,
|
||||
|
@ -392,7 +392,7 @@ return [
|
|||
[
|
||||
'key' => 'swift',
|
||||
'name' => 'Swift',
|
||||
'version' => '0.1.0',
|
||||
'version' => '0.2.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-swift',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-swift',
|
||||
'enabled' => true,
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1740,7 +1740,7 @@ App::post('/v1/account/recovery')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TOKEN)
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->label('abuse-key', ['url:{url},email:{param-email}', 'ip:{ip}'])
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('url', '', function ($clients) {return new Host($clients);}, 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients'])
|
||||
->inject('request')
|
||||
|
|
|
@ -111,7 +111,7 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
|
|||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('collections', $collectionId);
|
||||
$dbForProject->deleteCachedCollection($collectionId);
|
||||
$dbForProject->deleteCachedCollection('collection_' . $collectionId);
|
||||
|
||||
// Pass clone of $attribute object to workers
|
||||
// so we can later modify Document to fit response model
|
||||
|
@ -1257,7 +1257,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
|
|||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('collections', $collectionId);
|
||||
$dbForProject->deleteCachedCollection($collectionId);
|
||||
$dbForProject->deleteCachedCollection('collection_' . $collectionId);
|
||||
|
||||
$database
|
||||
->setParam('type', DATABASE_TYPE_DELETE_ATTRIBUTE)
|
||||
|
@ -2076,13 +2076,15 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->inject('audits')
|
||||
->inject('deletes')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function ($collectionId, $documentId, $response, $dbForProject, $events, $audits, $usage, $mode) {
|
||||
->action(function ($collectionId, $documentId, $response, $dbForProject, $events, $audits, $deletes, $usage, $mode) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var string $mode */
|
||||
|
||||
|
@ -2129,6 +2131,11 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
*/
|
||||
$document->setAttribute('$collection', $collectionId);
|
||||
|
||||
$deletes
|
||||
->setParam('type', DELETE_TYPE_AUDIT)
|
||||
->setParam('document', $document)
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('database.documents.delete', 1)
|
||||
->setParam('collectionId', $collectionId)
|
||||
|
|
|
@ -341,8 +341,7 @@ App::get('/v1/health/anti-virus')
|
|||
$output['version'] = @$antivirus->version();
|
||||
$output['status'] = (@$antivirus->ping()) ? 'pass' : 'fail';
|
||||
} catch( \Exception $e) {
|
||||
$output['status'] = 'offline';
|
||||
$output['version'] = '';
|
||||
throw new Exception('Antivirus is not available', 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,41 +38,51 @@ App::init(function ($utopia, $request, $response, $project, $user, $events, $aud
|
|||
/*
|
||||
* Abuse Check
|
||||
*/
|
||||
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject);
|
||||
$timeLimit
|
||||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getHostname().$route->getPath())
|
||||
;
|
||||
$abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}');
|
||||
$timeLimitArray = [];
|
||||
|
||||
// TODO make sure we get array here
|
||||
$abuseKeyLabel = (!is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel;
|
||||
|
||||
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);
|
||||
}
|
||||
foreach ($abuseKeyLabel as $abuseKey) {
|
||||
$timeLimit = new TimeLimit($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject);
|
||||
$timeLimit
|
||||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getHostname().$route->getPath());
|
||||
$timeLimitArray[] = $timeLimit;
|
||||
}
|
||||
|
||||
$abuse = new Abuse($timeLimit);
|
||||
|
||||
if ($timeLimit->limit()) {
|
||||
$response
|
||||
->addHeader('X-RateLimit-Limit', $timeLimit->limit())
|
||||
->addHeader('X-RateLimit-Remaining', $timeLimit->remaining())
|
||||
->addHeader('X-RateLimit-Reset', $timeLimit->time() + $route->getLabel('abuse-time', 3600))
|
||||
;
|
||||
}
|
||||
$closestLimit = null;
|
||||
|
||||
$roles = Authorization::getRoles();
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
|
||||
if (($abuse->check() // Route is rate-limited
|
||||
foreach ($timeLimitArray as $timeLimit) {
|
||||
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);
|
||||
|
||||
if ($timeLimit->limit() && ($timeLimit->remaining() < $closestLimit || is_null($closestLimit))) {
|
||||
$closestLimit = $timeLimit->remaining();
|
||||
$response
|
||||
->addHeader('X-RateLimit-Limit', $timeLimit->limit())
|
||||
->addHeader('X-RateLimit-Remaining', $timeLimit->remaining())
|
||||
->addHeader('X-RateLimit-Reset', $timeLimit->time() + $route->getLabel('abuse-time', 3600))
|
||||
;
|
||||
}
|
||||
|
||||
if (($abuse->check() // Route is rate-limited
|
||||
&& App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not disabled
|
||||
&& (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key
|
||||
{
|
||||
throw new Exception('Too many requests', 429);
|
||||
throw new Exception('Too many requests', 429);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,7 +14,6 @@ use Utopia\Abuse\Abuse;
|
|||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
|
@ -110,6 +109,7 @@ function getDatabase(Registry &$register, string $namespace)
|
|||
};
|
||||
|
||||
$server->onStart(function () use ($stats, $register, $containerId, &$statsDocument, $logError) {
|
||||
sleep(5); // wait for the initial database schema to be ready
|
||||
Console::success('Server started succefully');
|
||||
|
||||
/**
|
||||
|
@ -138,7 +138,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
|||
/**
|
||||
* Save current connections to the Database every 5 seconds.
|
||||
*/
|
||||
Timer::tick(5000, function () use ($register, $stats, $containerId, &$statsDocument, $logError) {
|
||||
Timer::tick(5000, function () use ($register, $stats, &$statsDocument, $logError) {
|
||||
/** @var Document $statsDocument */
|
||||
foreach ($stats as $projectId => $value) {
|
||||
$connections = $stats->get($projectId, 'connections') ?? 0;
|
||||
|
@ -398,7 +398,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
|||
|
||||
$abuse = new Abuse($timeLimit);
|
||||
|
||||
if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||
if (App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled' && $abuse->check()) {
|
||||
throw new Exception('Too many requests', 1013);
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|||
git fetch && \
|
||||
git pull ' . $gitUrl . ' && \
|
||||
rm -rf ' . $target . '/* && \
|
||||
cp -r ' . $result . '/ ' . $target . '/ && \
|
||||
cp -r ' . $result . '/* ' . $target . '/ && \
|
||||
git add . && \
|
||||
git commit -m "' . $message . '" && \
|
||||
git push -u origin ' . $gitBranch . '
|
||||
|
@ -231,7 +231,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|||
|
||||
$docDirectories = $language['docDirectories'] ?? [''];
|
||||
|
||||
if($version === 'latest') {
|
||||
if ($version === 'latest') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,12 +24,11 @@ $cli
|
|||
$appRoutes = App::getRoutes();
|
||||
$response = new Response(new HttpResponse());
|
||||
$mocks = ($mode === 'mocks');
|
||||
|
||||
App::setResource('request', fn() => new Request);
|
||||
App::setResource('response', fn() => $response);
|
||||
|
||||
App::setResource('db', fn() => $db);
|
||||
App::setResource('cache', fn() => $redis);
|
||||
App::setResource('request', fn () => new Request);
|
||||
App::setResource('response', fn () => $response);
|
||||
App::setResource('db', fn () => $db);
|
||||
App::setResource('cache', fn () => $redis);
|
||||
|
||||
$platforms = [
|
||||
'client' => APP_PLATFORM_CLIENT,
|
||||
|
@ -132,10 +131,11 @@ $cli
|
|||
$services = [];
|
||||
|
||||
foreach ($appRoutes as $key => $method) {
|
||||
foreach ($method as $route) { /** @var \Utopia\Route $route */
|
||||
foreach ($method as $route) {
|
||||
/** @var \Utopia\Route $route */
|
||||
$routeSecurity = $route->getLabel('sdk.auth', []);
|
||||
$sdkPlatofrms = [];
|
||||
|
||||
|
||||
foreach ($routeSecurity as $value) {
|
||||
switch ($value) {
|
||||
case APP_AUTH_TYPE_SESSION:
|
||||
|
@ -152,115 +152,116 @@ $cli
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($routeSecurity)) {
|
||||
|
||||
if (empty($routeSecurity)) {
|
||||
$sdkPlatofrms[] = APP_PLATFORM_CLIENT;
|
||||
}
|
||||
|
||||
|
||||
if (!$route->getLabel('docs', true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($route->getLabel('sdk.mock', false) && !$mocks) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!$route->getLabel('sdk.mock', false) && $mocks) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (empty($route->getLabel('sdk.namespace', null))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($platform !== APP_PLATFORM_CONSOLE && !\in_array($platforms[$platform], $sdkPlatofrms)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$routes[] = $route;
|
||||
$modelLabel = $route->getLabel('sdk.response.model', 'none');
|
||||
\is_array($modelLabel) ? \array_map(function($m) use($response) {
|
||||
\is_array($modelLabel) ? \array_map(function ($m) use ($response) {
|
||||
return $response->getModel($m);
|
||||
}, $modelLabel) : $response->getModel($modelLabel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (Config::getParam('services', []) as $service) {
|
||||
if(!isset($service['docs']) // Skip service if not part of the public API
|
||||
if (
|
||||
!isset($service['docs']) // Skip service if not part of the public API
|
||||
|| !isset($service['sdk'])
|
||||
|| !$service['docs']
|
||||
|| !$service['sdk']) {
|
||||
|| !$service['sdk']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$services[] = [
|
||||
'name' => $service['key'] ?? '',
|
||||
'description' => $service['subtitle'] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$models = $response->getModels();
|
||||
|
||||
|
||||
foreach ($models as $key => $value) {
|
||||
if($platform !== APP_PLATFORM_CONSOLE && !$value->isPublic()) {
|
||||
if ($platform !== APP_PLATFORM_CONSOLE && !$value->isPublic()) {
|
||||
unset($models[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch ($format) {
|
||||
case 'swagger2':
|
||||
$formatInstance = new Swagger2(new App('UTC'), $services, $routes, $models, $keys[$platform], $authCounts[$platform] ?? 0);
|
||||
break;
|
||||
|
||||
|
||||
case 'open-api3':
|
||||
$formatInstance = new OpenAPI3(new App('UTC'), $services, $routes, $models, $keys[$platform], $authCounts[$platform] ?? 0);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new Exception('Format not found: '.$format);
|
||||
throw new Exception('Format not found: ' . $format);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$specs = new Specification($formatInstance);
|
||||
$endpoint = App::getEnv('_APP_HOME', '[HOSTNAME]');
|
||||
$email = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
|
||||
|
||||
$formatInstance
|
||||
->setParam('name', APP_NAME)
|
||||
->setParam('description', 'Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)')
|
||||
->setParam('endpoint', 'https://HOSTNAME/v1')
|
||||
->setParam('version', APP_VERSION_STABLE)
|
||||
->setParam('terms', $endpoint.'/policy/terms')
|
||||
->setParam('terms', $endpoint . '/policy/terms')
|
||||
->setParam('support.email', $email)
|
||||
->setParam('support.url', $endpoint.'/support')
|
||||
->setParam('contact.name', APP_NAME.' Team')
|
||||
->setParam('support.url', $endpoint . '/support')
|
||||
->setParam('contact.name', APP_NAME . ' Team')
|
||||
->setParam('contact.email', $email)
|
||||
->setParam('contact.url', $endpoint.'/support')
|
||||
->setParam('contact.url', $endpoint . '/support')
|
||||
->setParam('license.name', 'BSD-3-Clause')
|
||||
->setParam('license.url', 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE')
|
||||
->setParam('docs.description', 'Full API docs, specs and tutorials')
|
||||
->setParam('docs.url', $endpoint.'/docs')
|
||||
;
|
||||
->setParam('docs.url', $endpoint . '/docs');
|
||||
|
||||
if($mocks) {
|
||||
$path = __DIR__.'/../config/specs/'.$format.'-mocks-'.$platform.'.json';
|
||||
if ($mocks) {
|
||||
$path = __DIR__ . '/../config/specs/' . $format . '-mocks-' . $platform . '.json';
|
||||
|
||||
if(!file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save mocks spec file: '.$path);
|
||||
if (!file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save mocks spec file: ' . $path);
|
||||
}
|
||||
|
||||
|
||||
Console::success('Saved mocks spec file: ' . realpath($path));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = __DIR__.'/../config/specs/'.$format.'-'.$version.'-'.$platform.'.json';
|
||||
$path = __DIR__ . '/../config/specs/' . $format . '-' . $version . '-' . $platform . '.json';
|
||||
|
||||
if(!file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save spec file: '.$path);
|
||||
if (!file_put_contents($path, json_encode($specs->parse()))) {
|
||||
throw new Exception('Failed to save spec file: ' . $path);
|
||||
}
|
||||
|
||||
Console::success('Saved spec file: ' . realpath($path));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -47,7 +47,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-param-order-types-cast-to="array"
|
||||
data-scope="sdk"
|
||||
data-name="project-documents"
|
||||
x-data="{project: new URLSearchParams(location.search).get('project')}">
|
||||
x-data="{ project: new URLSearchParams(location.search).get('project') }">
|
||||
|
||||
<div data-ls-if="0 == {{project-documents.sum}}" class="box margin-bottom">
|
||||
<h3 class="margin-bottom-small text-bold">No Documents Found</h3>
|
||||
|
@ -101,7 +101,6 @@ $logs = $this->getParam('logs', null);
|
|||
data-service="database.listDocuments"
|
||||
data-event="submit"
|
||||
data-param-collection-id="{{router.params.id}}"
|
||||
data-param-search="{{router.params.search}}"
|
||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||
data-param-order-types="DESC"
|
||||
data-param-order-types-cast-to="array"
|
||||
|
@ -118,7 +117,6 @@ $logs = $this->getParam('logs', null);
|
|||
data-service="database.listDocuments"
|
||||
data-event="submit"
|
||||
data-param-collection-id="{{router.params.id}}"
|
||||
data-param-search="{{router.params.search}}"
|
||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||
data-param-order-types="DESC"
|
||||
data-param-order-types-cast-to="array"
|
||||
|
@ -355,6 +353,7 @@ $logs = $this->getParam('logs', null);
|
|||
<span data-ls-if="{{index.status}} == 'processing'" class="text-size-small text-info">processing </span>
|
||||
<span data-ls-if="{{index.status}} == 'failed'" class="text-size-small text-danger">failed </span>
|
||||
<span data-ls-if="{{index.status}} == 'deleting'" class="text-size-small text-danger">deleting </span>
|
||||
<span data-ls-if="{{index.status}} == 'stuck'" class="text-size-small text-danger">stuck </span>
|
||||
</td>
|
||||
|
||||
<td data-title="Index Key: ">
|
||||
|
|
|
@ -210,6 +210,7 @@ class DatabaseV1 extends Worker
|
|||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('collections', $collectionId);
|
||||
$dbForProject->deleteCachedCollection('collection_' . $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,7 +67,17 @@ class DeletesV1 extends Worker
|
|||
break;
|
||||
|
||||
case DELETE_TYPE_AUDIT:
|
||||
$this->deleteAuditLogs($this->args['timestamp']);
|
||||
$timestamp = $this->args['timestamp'] ?? 0;
|
||||
$document = new Document($this->args['document'] ?? []);
|
||||
|
||||
if (!empty($timestamp)) {
|
||||
$this->deleteAuditLogs($this->args['timestamp']);
|
||||
}
|
||||
|
||||
if (!$document->isEmpty()) {
|
||||
$this->deleteAuditLogsByResource('document/' . $document->getId(), $projectId);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DELETE_TYPE_ABUSE:
|
||||
|
@ -115,6 +125,8 @@ class DeletesV1 extends Worker
|
|||
$this->deleteByGroup('indexes', [
|
||||
new Query('collectionId', Query::TYPE_EQUAL, [$collectionId])
|
||||
], $dbForProject);
|
||||
|
||||
$this->deleteAuditLogsByResource('collection/' . $collectionId, $projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,6 +275,18 @@ class DeletesV1 extends Worker
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $timestamp
|
||||
*/
|
||||
protected function deleteAuditLogsByResource(string $resource, string $projectId): void
|
||||
{
|
||||
$dbForProject = $this->getProjectDB($projectId);
|
||||
|
||||
$this->deleteByGroup(Audit::COLLECTION, [
|
||||
new Query('resource', Query::TYPE_EQUAL, [$resource])
|
||||
], $dbForProject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document function document
|
||||
* @param string $projectId
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"appwrite/sdk-generator": "0.16.3",
|
||||
"appwrite/sdk-generator": "0.17.0",
|
||||
"phpunit/phpunit": "9.5.10",
|
||||
"swoole/ide-helper": "4.8.3",
|
||||
"textalk/websocket": "1.5.5",
|
||||
|
|
|
@ -19,7 +19,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
Account account = new Account(client);
|
||||
|
||||
account.createMagicURLSession(
|
||||
"",
|
||||
"[USER_ID]",
|
||||
"email@example.com",
|
||||
new Continuation<Object>() {
|
||||
@NotNull
|
||||
|
|
|
@ -19,7 +19,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
Account account = new Account(client);
|
||||
|
||||
account.create(
|
||||
"",
|
||||
"[USER_ID]",
|
||||
"email@example.com",
|
||||
"password",
|
||||
new Continuation<Object>() {
|
||||
|
|
|
@ -19,7 +19,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
Account account = new Account(client);
|
||||
|
||||
account.updateMagicURLSession(
|
||||
"",
|
||||
"[USER_ID]",
|
||||
"[SECRET]"
|
||||
new Continuation<Object>() {
|
||||
@NotNull
|
||||
|
|
|
@ -20,7 +20,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
database.createDocument(
|
||||
"[COLLECTION_ID]",
|
||||
"",
|
||||
"[DOCUMENT_ID]",
|
||||
mapOf( "a" to "b" ),
|
||||
new Continuation<Object>() {
|
||||
@NotNull
|
||||
|
|
|
@ -19,7 +19,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
Storage storage = new Storage(client);
|
||||
|
||||
storage.createFile(
|
||||
"",
|
||||
"[FILE_ID]",
|
||||
File("./path-to-files/image.jpg"),
|
||||
new Continuation<Object>() {
|
||||
@NotNull
|
||||
|
|
|
@ -19,7 +19,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
Teams teams = new Teams(client);
|
||||
|
||||
teams.create(
|
||||
"",
|
||||
"[TEAM_ID]",
|
||||
"[NAME]",
|
||||
new Continuation<Object>() {
|
||||
@NotNull
|
||||
|
|
|
@ -18,7 +18,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
GlobalScope.launch {
|
||||
val response = account.createMagicURLSession(
|
||||
userId = "",
|
||||
userId = "[USER_ID]",
|
||||
email = "email@example.com",
|
||||
)
|
||||
val json = response.body?.string()
|
||||
|
|
|
@ -18,7 +18,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
GlobalScope.launch {
|
||||
val response = account.create(
|
||||
userId = "",
|
||||
userId = "[USER_ID]",
|
||||
email = "email@example.com",
|
||||
password = "password",
|
||||
)
|
||||
|
|
|
@ -18,7 +18,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
GlobalScope.launch {
|
||||
val response = account.updateMagicURLSession(
|
||||
userId = "",
|
||||
userId = "[USER_ID]",
|
||||
secret = "[SECRET]"
|
||||
)
|
||||
val json = response.body?.string()
|
||||
|
|
|
@ -19,7 +19,7 @@ class MainActivity : AppCompatActivity() {
|
|||
GlobalScope.launch {
|
||||
val response = database.createDocument(
|
||||
collectionId = "[COLLECTION_ID]",
|
||||
documentId = "",
|
||||
documentId = "[DOCUMENT_ID]",
|
||||
data = mapOf( "a" to "b" ),
|
||||
)
|
||||
val json = response.body?.string()
|
||||
|
|
|
@ -18,7 +18,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
GlobalScope.launch {
|
||||
val response = storage.createFile(
|
||||
fileId = "",
|
||||
fileId = "[FILE_ID]",
|
||||
file = File("./path-to-files/image.jpg"),
|
||||
)
|
||||
val json = response.body?.string()
|
||||
|
|
|
@ -18,7 +18,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
GlobalScope.launch {
|
||||
val response = teams.create(
|
||||
teamId = "",
|
||||
teamId = "[TEAM_ID]",
|
||||
name = "[NAME]",
|
||||
)
|
||||
val json = response.body?.string()
|
||||
|
|
|
@ -7,7 +7,7 @@ func main() {
|
|||
|
||||
let account = Account(client)
|
||||
account.createMagicURLSession(
|
||||
userId: "",
|
||||
userId: "[USER_ID]",
|
||||
email: "email@example.com"
|
||||
) { result in
|
||||
switch result {
|
||||
|
|
|
@ -7,7 +7,7 @@ func main() {
|
|||
|
||||
let account = Account(client)
|
||||
account.create(
|
||||
userId: "",
|
||||
userId: "[USER_ID]",
|
||||
email: "email@example.com",
|
||||
password: "password"
|
||||
) { result in
|
||||
|
|
|
@ -7,7 +7,7 @@ func main() {
|
|||
|
||||
let account = Account(client)
|
||||
account.updateMagicURLSession(
|
||||
userId: "",
|
||||
userId: "[USER_ID]",
|
||||
secret: "[SECRET]"
|
||||
) { result in
|
||||
switch result {
|
||||
|
|
|
@ -8,7 +8,7 @@ func main() {
|
|||
let database = Database(client)
|
||||
database.createDocument(
|
||||
collectionId: "[COLLECTION_ID]",
|
||||
documentId: "",
|
||||
documentId: "[DOCUMENT_ID]",
|
||||
data:
|
||||
) { result in
|
||||
switch result {
|
||||
|
|
|
@ -7,7 +7,7 @@ func main() {
|
|||
|
||||
let storage = Storage(client)
|
||||
storage.createFile(
|
||||
fileId: "",
|
||||
fileId: "[FILE_ID]",
|
||||
file: File(name: "image.jpg", buffer: yourByteBuffer)
|
||||
) { result in
|
||||
switch result {
|
||||
|
|
|
@ -7,7 +7,7 @@ func main() {
|
|||
|
||||
let teams = Teams(client)
|
||||
teams.create(
|
||||
teamId: "",
|
||||
teamId: "[TEAM_ID]",
|
||||
name: "[NAME]"
|
||||
) { result in
|
||||
switch result {
|
||||
|
|
|
@ -9,7 +9,7 @@ void main() { // Init SDK
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
Future result = account.createMagicURLSession(
|
||||
userId: '',
|
||||
userId: '[USER_ID]',
|
||||
email: 'email@example.com',
|
||||
);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ void main() { // Init SDK
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
Future result = account.create(
|
||||
userId: '',
|
||||
userId: '[USER_ID]',
|
||||
email: 'email@example.com',
|
||||
password: 'password',
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@ void main() { // Init SDK
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
Future result = account.updateMagicURLSession(
|
||||
userId: '',
|
||||
userId: '[USER_ID]',
|
||||
secret: '[SECRET]',
|
||||
);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ void main() { // Init SDK
|
|||
;
|
||||
Future result = database.createDocument(
|
||||
collectionId: '[COLLECTION_ID]',
|
||||
documentId: '',
|
||||
documentId: '[DOCUMENT_ID]',
|
||||
data: {},
|
||||
);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ void main() { // Init SDK
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
Future result = storage.createFile(
|
||||
fileId: '',
|
||||
fileId: '[FILE_ID]',
|
||||
file: await MultipartFile.fromPath('file', './path-to-files/image.jpg', 'image.jpg'),
|
||||
);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ void main() { // Init SDK
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
Future result = teams.create(
|
||||
teamId: '',
|
||||
teamId: '[TEAM_ID]',
|
||||
name: '[NAME]',
|
||||
);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.createMagicURLSession('', 'email@example.com');
|
||||
let promise = sdk.account.createMagicURLSession('[USER_ID]', 'email@example.com');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.create('', 'email@example.com', 'password');
|
||||
let promise = sdk.account.create('[USER_ID]', 'email@example.com', 'password');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.updateMagicURLSession('', '[SECRET]');
|
||||
let promise = sdk.account.updateMagicURLSession('[USER_ID]', '[SECRET]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.createDocument('[COLLECTION_ID]', '', {});
|
||||
let promise = sdk.database.createDocument('[COLLECTION_ID]', '[DOCUMENT_ID]', {});
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.storage.createFile('', document.getElementById('uploader').files[0]);
|
||||
let promise = sdk.storage.createFile('[FILE_ID]', document.getElementById('uploader').files[0]);
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.teams.create('', '[NAME]');
|
||||
let promise = sdk.teams.create('[TEAM_ID]', '[NAME]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.createMagicURLSession('', 'email@example.com');
|
||||
let promise = sdk.account.createMagicURLSession('[USER_ID]', 'email@example.com');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.create('', 'email@example.com', 'password');
|
||||
let promise = sdk.account.create('[USER_ID]', 'email@example.com', 'password');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.updateMagicURLSession('', '[SECRET]');
|
||||
let promise = sdk.account.updateMagicURLSession('[USER_ID]', '[SECRET]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.createCollection('', '[NAME]', 'document', ["role:all"], ["role:all"]);
|
||||
let promise = sdk.database.createCollection('[COLLECTION_ID]', '[NAME]', 'document', ["role:all"], ["role:all"]);
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.database.createDocument('[COLLECTION_ID]', '', {});
|
||||
let promise = sdk.database.createDocument('[COLLECTION_ID]', '[DOCUMENT_ID]', {});
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.functions.create('', '[NAME]', [], 'dotnet-5.0');
|
||||
let promise = sdk.functions.create('[FUNCTION_ID]', '[NAME]', [], 'node-14.5');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
const sdk = new Appwrite();
|
||||
|
||||
sdk
|
||||
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
|
||||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.health.getAntivirus();
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.projects.create('', '[NAME]', '[TEAM_ID]');
|
||||
let promise = sdk.projects.create('[PROJECT_ID]', '[NAME]', '[TEAM_ID]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.storage.createFile('', document.getElementById('uploader').files[0]);
|
||||
let promise = sdk.storage.createFile('[FILE_ID]', document.getElementById('uploader').files[0]);
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.teams.create('', '[NAME]');
|
||||
let promise = sdk.teams.create('[TEAM_ID]', '[NAME]');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -5,7 +5,7 @@ sdk
|
|||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.users.create('', 'email@example.com', 'password');
|
||||
let promise = sdk.users.create('[USER_ID]', 'email@example.com', 'password');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createBooleanAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--required="" \
|
||||
--default="" \
|
||||
--array=""
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
appwrite database createCollection \
|
||||
--collectionId="" \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--name="[NAME]" \
|
||||
--permission="document" \
|
||||
--read="["role:all"]" \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createDocument \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--documentId="" \
|
||||
--documentId="[DOCUMENT_ID]" \
|
||||
--data="{}" \
|
||||
--read="["role:all"]" \
|
||||
--write="["role:all"]"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createEmailAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--required="" \
|
||||
--default="email@example.com" \
|
||||
--array=""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createEnumAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--elements="" \
|
||||
--required="" \
|
||||
--default="[DEFAULT]" \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createFloatAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--required="" \
|
||||
--min="" \
|
||||
--max="" \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createIndex \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--indexId="" \
|
||||
--key="" \
|
||||
--type="key" \
|
||||
--attributes="" \
|
||||
--orders=""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createIntegerAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--required="" \
|
||||
--min="" \
|
||||
--max="" \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createIpAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--required="" \
|
||||
--default="" \
|
||||
--array=""
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createStringAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--size="1" \
|
||||
--required="" \
|
||||
--default="[DEFAULT]" \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
appwrite database createUrlAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId="" \
|
||||
--key="" \
|
||||
--required="" \
|
||||
--default="https://example.com" \
|
||||
--array=""
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
appwrite database deleteAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId=""
|
||||
--key=""
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
appwrite database deleteIndex \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--indexId=""
|
||||
--key=""
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
appwrite database getAttribute \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--attributeId=""
|
||||
--key=""
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
appwrite database getIndex \
|
||||
--collectionId="[COLLECTION_ID]" \
|
||||
--indexId=""
|
||||
--key=""
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue