mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa3c9a5b76 | ||
|
|
c388fea5d0 | ||
|
|
a407d2ea84 | ||
|
|
da56ef39f8 | ||
|
|
275b9a1186 | ||
|
|
2f514ae55e | ||
|
|
38517b8004 | ||
|
|
8758e2e5a0 | ||
|
|
dacc6a97d0 | ||
|
|
13fc2222f8 | ||
|
|
900d8f248e | ||
|
|
de572c3aa9 | ||
|
|
d4fd5e79d9 | ||
|
|
87247826e0 | ||
|
|
05f4d05cf3 | ||
|
|
d12d6acd62 | ||
|
|
133eac66e7 | ||
|
|
53a6fef69e | ||
|
|
0c4f540325 | ||
|
|
f0191202a0 | ||
|
|
19e22e1da7 | ||
|
|
23c1e4fb79 | ||
|
|
904b2da8ce | ||
|
|
ee129e28f1 | ||
|
|
c50ba30f1b | ||
|
|
265ccdb03a | ||
|
|
3b93e925d4 | ||
|
|
10b38c7c6d | ||
|
|
adf6b02462 | ||
|
|
f47c484d8d | ||
|
|
6e1d2008f8 | ||
|
|
38fb9f2814 | ||
|
|
8d37e843e0 | ||
|
|
975510c6a0 | ||
|
|
a971976587 | ||
|
|
9bee2f5a25 | ||
|
|
21e830146b | ||
|
|
44ec8de6bf | ||
|
|
80ad740d36 |
@@ -69,8 +69,8 @@ _APP_STORAGE_ANTIVIRUS_PORT=3310
|
||||
_APP_SMTP_HOST=maildev
|
||||
_APP_SMTP_PORT=1025
|
||||
_APP_SMTP_SECURE=
|
||||
_APP_SMTP_USERNAME=user
|
||||
_APP_SMTP_PASSWORD=password
|
||||
_APP_SMTP_USERNAME=
|
||||
_APP_SMTP_PASSWORD=
|
||||
_APP_SMS_PROVIDER=sms://username:password@mock
|
||||
_APP_SMS_FROM=+123456789
|
||||
_APP_SMS_PROJECTS_DENY_LIST=
|
||||
@@ -101,7 +101,6 @@ _APP_USAGE_AGGREGATION_INTERVAL=30
|
||||
_APP_STATS_RESOURCES_INTERVAL=30
|
||||
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
|
||||
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
|
||||
_APP_INTERVAL_DOMAIN_VERIFICATION=60
|
||||
_APP_USAGE_STATS=enabled
|
||||
_APP_LOGGING_CONFIG=
|
||||
_APP_LOGGING_CONFIG_REALTIME=
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# AGENTS.md
|
||||
|
||||
Appwrite is an end-to-end backend server for web, mobile, native, and backend apps. This guide provides context and instructions for AI coding agents working on the Appwrite codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Appwrite is a self-hosted Backend-as-a-Service (BaaS) platform that provides developers with a set of APIs and tools to build secure, scalable applications. The project uses a hybrid monolithic-microservice architecture built with PHP, running on Swoole for high performance.
|
||||
|
||||
**Key Technologies:**
|
||||
- **Backend:** PHP 8.3+, Swoole
|
||||
- **Libraries:** Utopia PHP
|
||||
- **Database:** MariaDB, Redis
|
||||
- **Cache:** Redis
|
||||
- **Queue:** Redis
|
||||
- **Containers:** Docker
|
||||
|
||||
## Development Commands
|
||||
|
||||
```bash
|
||||
# Run Appwrite
|
||||
docker compose up -d --force-recreate --build
|
||||
|
||||
# Run specific test
|
||||
docker compose exec appwrite test /usr/src/code/tests/e2e/Services/[ServiceName] --filter=[FunctionName]
|
||||
|
||||
# Format code
|
||||
composer format
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
- Follow [PSR-12](https://www.php-fig.org/psr/psr-12/) coding standard
|
||||
- Use PSR-4 autoloading
|
||||
- Strict type declarations where applicable
|
||||
- Comprehensive PHPDoc comments
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
#### `resourceType` Naming Rule
|
||||
|
||||
When a collection has a combination of `resourceType`, `resourceId`, and/or `resourceInternalId`, the value of `resourceType` MUST always be **plural** - for example: `functions`, `sites`, `deployments`.
|
||||
|
||||
Examples:
|
||||
```php
|
||||
'resourceType' => 'functions'
|
||||
'resourceType' => 'sites'
|
||||
'resourceType' => 'deployments'
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Critical Security Practices
|
||||
|
||||
- **Never hardcode credentials** - Use environment variables
|
||||
- **Rate limiting** - Respect abuse prevention mechanisms
|
||||
|
||||
## Dependencies
|
||||
|
||||
Avoid introducing new dependencies other than utopia-php.
|
||||
|
||||
## Adding new endpoints
|
||||
|
||||
When adding new endpoints, make sure to use modules and follow its patterns. Find instruction in [Modules AGENTS.md](src/Appwrite/Platform/AGENTS.md) file.
|
||||
|
||||
## Pull Request Guidelines
|
||||
### Before Submitting
|
||||
|
||||
- Run `composer format`
|
||||
- Update documentation if adding features
|
||||
- Add/update tests for your changes
|
||||
- Check that Docker build succeeds
|
||||
`docs/specs/authentication.drawio.svg`
|
||||
|
||||
## Known Issues and Gotchas
|
||||
|
||||
- **Hot Reload:** Code changes require container restart in some cases
|
||||
- **Logging:** There is no central place for logs, so when debugging, ensure to check all possibly relevant containers
|
||||
+50
-28
@@ -222,51 +222,73 @@ Appwrite's current structure is a combination of both [Monolithic](https://en.wi
|
||||
```bash
|
||||
.
|
||||
├── app # Main application
|
||||
│ ├── assets
|
||||
│ │ ├── dbip
|
||||
│ │ ├── fonts
|
||||
│ │ └── security
|
||||
│ ├── config # Config files
|
||||
│ │ ├── avatars
|
||||
│ │ ├── collections
|
||||
│ │ ├── locale
|
||||
│ │ ├── specs
|
||||
│ │ ├── storage
|
||||
│ │ └── templates
|
||||
│ ├── controllers # API & dashboard controllers
|
||||
│ │ ├── api
|
||||
│ │ ├── shared
|
||||
│ │ └── web
|
||||
│ ├── db # DB schemas
|
||||
│ ├── sdks # SDKs generated copies (used for generating code examples)
|
||||
│ ├── tasks # Server CLI commands
|
||||
│ ├── views # HTML server-side templates
|
||||
│ └── workers # Background workers
|
||||
│ ├── init # DB schemas
|
||||
│ │ └── database
|
||||
│ └── views # HTML server-side templates
|
||||
│ ├── general
|
||||
│ └── install
|
||||
├── bin # Server executables (tasks & workers)
|
||||
├── docker # Docker related resources and configs
|
||||
├── dev # Debugger config
|
||||
├── docs # Docs and tutorials
|
||||
│ ├── examples
|
||||
│ ├── lists
|
||||
│ ├── references
|
||||
│ ├── sdks
|
||||
│ ├── services
|
||||
│ ├── specs
|
||||
│ └── tutorials
|
||||
├── public # Public files
|
||||
│ ├── dist
|
||||
│ ├── fonts
|
||||
│ ├── images
|
||||
│ ├── scripts
|
||||
│ └── styles
|
||||
├── src # Supporting libraries (each lib has one role, common libs are released as individual projects)
|
||||
│ └── Appwrite
|
||||
│ ├── Auth
|
||||
│ ├── Detector
|
||||
│ ├── Docker
|
||||
| ├── DSN
|
||||
│ ├── Event
|
||||
│ ├── Extend
|
||||
│ ├── GraphQL
|
||||
│ ├── Messaging
|
||||
│ ├── Migration
|
||||
│ ├── Network
|
||||
│ ├── OpenSSL
|
||||
│ ├── Promises
|
||||
│ ├── Specification
|
||||
│ ├── Task
|
||||
│ ├── Template
|
||||
│ ├── URL
|
||||
│ └── Utopia
|
||||
│ ├── sdk-console
|
||||
│ ├── sdk-project
|
||||
│ └── sdk-web
|
||||
├── src # Supporting libraries (each lib has one role, common libs are released as
|
||||
│ ├── Appwrite
|
||||
│ │ ├── Auth
|
||||
│ │ ├── Certificates
|
||||
│ │ ├── Deletes
|
||||
│ │ ├── Detector
|
||||
│ │ ├── Docker
|
||||
│ │ ├── Event
|
||||
│ │ ├── Extend
|
||||
│ │ ├── Functions/Validator
|
||||
│ │ ├── GraphQL
|
||||
│ │ ├── Hooks
|
||||
│ │ ├── Messaging
|
||||
│ │ ├── Migration
|
||||
│ │ ├── Network
|
||||
│ │ ├── OpenSSL
|
||||
│ │ ├── Platform
|
||||
│ │ ├── Promises
|
||||
│ │ ├── PubSub
|
||||
│ │ ├── SDK
|
||||
│ │ ├── Task/Validator
|
||||
│ │ ├── Template
|
||||
│ │ ├── Transformation
|
||||
│ │ ├── URL
|
||||
│ │ ├── Utopia
|
||||
│ │ └── Vcs
|
||||
│ └── Executor
|
||||
└── tests # End to end & unit tests
|
||||
├── benchmarks
|
||||
├── e2e
|
||||
├── extensions
|
||||
├── resources
|
||||
└── unit
|
||||
```
|
||||
|
||||
@@ -57,7 +57,6 @@ RUN mkdir -p /storage/uploads && \
|
||||
# Executables
|
||||
RUN chmod +x /usr/local/bin/doctor && \
|
||||
chmod +x /usr/local/bin/install && \
|
||||
chmod +x /usr/local/bin/interval && \
|
||||
chmod +x /usr/local/bin/maintenance && \
|
||||
chmod +x /usr/local/bin/migrate && \
|
||||
chmod +x /usr/local/bin/realtime && \
|
||||
|
||||
+18
-18
@@ -41,8 +41,6 @@ Config::setParam('runtimes', (new Runtimes('v5'))->getAll(supported: false));
|
||||
// require controllers after overwriting runtimes
|
||||
require_once __DIR__ . '/controllers/general.php';
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
CLI::setResource('register', fn () => $register);
|
||||
|
||||
CLI::setResource('cache', function ($pools) {
|
||||
@@ -60,7 +58,13 @@ CLI::setResource('pools', function (Registry $register) {
|
||||
return $register->get('pools');
|
||||
}, ['register']);
|
||||
|
||||
CLI::setResource('dbForPlatform', function ($pools, $cache) {
|
||||
CLI::setResource('authorization', function () {
|
||||
$authorization = new Authorization();
|
||||
$authorization->disable();
|
||||
return $authorization;
|
||||
}, []);
|
||||
|
||||
CLI::setResource('dbForPlatform', function ($pools, $cache, $authorization) {
|
||||
$sleep = 3;
|
||||
$maxAttempts = 5;
|
||||
$attempts = 0;
|
||||
@@ -74,6 +78,7 @@ CLI::setResource('dbForPlatform', function ($pools, $cache) {
|
||||
$dbForPlatform = new Database($adapter, $cache);
|
||||
|
||||
$dbForPlatform
|
||||
->setAuthorization($authorization)
|
||||
->setNamespace('_console')
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', 'console');
|
||||
@@ -99,7 +104,7 @@ CLI::setResource('dbForPlatform', function ($pools, $cache) {
|
||||
}
|
||||
|
||||
return $dbForPlatform;
|
||||
}, ['pools', 'cache']);
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
|
||||
CLI::setResource('console', function () {
|
||||
return new Document(Config::getParam('console'));
|
||||
@@ -110,10 +115,10 @@ CLI::setResource(
|
||||
fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false
|
||||
);
|
||||
|
||||
CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) {
|
||||
CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, $authorization) {
|
||||
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
|
||||
|
||||
return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases) {
|
||||
return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases) {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return $dbForPlatform;
|
||||
}
|
||||
@@ -146,6 +151,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
|
||||
|
||||
$adapter = new DatabasePool($pools->get($dsn->getHost()));
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$databases[$dsn->getHost()] = $database;
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
|
||||
@@ -162,17 +168,18 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
|
||||
}
|
||||
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId());
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'dbForPlatform', 'cache']);
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'authorization']);
|
||||
|
||||
CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
CLI::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) {
|
||||
$database = null;
|
||||
|
||||
return function (?Document $project = null) use ($pools, $cache, $database) {
|
||||
return function (?Document $project = null) use ($pools, $cache, $database, $authorization) {
|
||||
if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
|
||||
$database->setTenant((int)$project->getSequence());
|
||||
return $database;
|
||||
@@ -182,6 +189,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setSharedTables(true)
|
||||
->setNamespace('logsV1')
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_TASK)
|
||||
@@ -194,7 +202,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'cache']);
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
CLI::setResource('publisher', function (Group $pools) {
|
||||
return new BrokerPool(publisher: $pools->get('publisher'));
|
||||
}, ['pools']);
|
||||
@@ -257,14 +265,6 @@ CLI::setResource('logError', function (Registry $register) {
|
||||
$log->addExtra('trace', $error->getTraceAsString());
|
||||
$log->addExtra('detailedTrace', $error->getTrace());
|
||||
|
||||
if ($error->getPrevious() !== null) {
|
||||
if ($error->getPrevious()->getMessage() != $error->getMessage()) {
|
||||
$log->addExtra('previousMessage', $error->getPrevious()->getMessage());
|
||||
}
|
||||
$log->addExtra('previousFile', $error->getPrevious()->getFile());
|
||||
$log->addExtra('previousLine', $error->getPrevious()->getLine());
|
||||
}
|
||||
|
||||
$log->setAction($action);
|
||||
|
||||
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
|
||||
|
||||
@@ -6,7 +6,7 @@ use Utopia\Database\Helpers\ID;
|
||||
|
||||
$providers = Config::getParam('oAuthProviders', []);
|
||||
|
||||
$platformCollections = [
|
||||
return [
|
||||
'projects' => [
|
||||
'$collection' => ID::custom(Database::METADATA),
|
||||
'$id' => ID::custom('projects'),
|
||||
@@ -643,39 +643,6 @@ $platformCollections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'resourceType',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'resourceId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'resourceInternalId',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('name'),
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -751,13 +718,6 @@ $platformCollections = [
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_resource',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['resourceType', 'resourceInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_accessedAt',
|
||||
'type' => Database::INDEX_KEY,
|
||||
@@ -1943,31 +1903,3 @@ $platformCollections = [
|
||||
'indexes' => []
|
||||
],
|
||||
];
|
||||
|
||||
// Organization API keys subquery
|
||||
$platformCollections['teams']['attributes'][] = [
|
||||
'$id' => ID::custom('keys'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryOrganizationKeys'],
|
||||
];
|
||||
|
||||
// Account API keys subquery
|
||||
$platformCollections['users']['attributes'][] = [
|
||||
'$id' => ID::custom('keys'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryAccountKeys'],
|
||||
];
|
||||
|
||||
return $platformCollections;
|
||||
|
||||
@@ -116,7 +116,6 @@ return [
|
||||
[
|
||||
'key' => 'android',
|
||||
'name' => 'Android',
|
||||
'namespace' => 'io.appwrite',
|
||||
'version' => '11.4.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-android',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
|
||||
@@ -396,7 +395,6 @@ return [
|
||||
[
|
||||
'key' => 'kotlin',
|
||||
'name' => 'Kotlin',
|
||||
'namespace' => 'io.appwrite',
|
||||
'version' => '13.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
|
||||
|
||||
@@ -20,7 +20,7 @@ return [
|
||||
'name' => 'Console',
|
||||
'subtitle' => '',
|
||||
'description' => '',
|
||||
'controller' => '', // Uses modules
|
||||
'controller' => 'web/console.php',
|
||||
'sdk' => false,
|
||||
'docs' => false,
|
||||
'docsUrl' => '',
|
||||
@@ -146,7 +146,7 @@ return [
|
||||
'name' => 'Storage',
|
||||
'subtitle' => 'The Storage service allows you to manage your project files.',
|
||||
'description' => '/docs/services/storage.md',
|
||||
'controller' => '',
|
||||
'controller' => 'api/storage.php',
|
||||
'sdk' => true,
|
||||
'docs' => true,
|
||||
'docsUrl' => 'https://appwrite.io/docs/client/storage',
|
||||
@@ -270,9 +270,9 @@ return [
|
||||
'console' => [
|
||||
'key' => 'console',
|
||||
'name' => 'Console',
|
||||
'subtitle' => 'The Console service allows you to interact with console relevant information.',
|
||||
'subtitle' => 'The Console service allows you to interact with console relevant informations.',
|
||||
'description' => '',
|
||||
'controller' => '', // Uses modules
|
||||
'controller' => 'api/console.php',
|
||||
'sdk' => true,
|
||||
'docs' => true,
|
||||
'docsUrl' => '',
|
||||
|
||||
@@ -407,8 +407,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -429,23 +429,7 @@
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration": {
|
||||
"type": "integer",
|
||||
"description": "Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.",
|
||||
"x-example": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"\/account\/logs": {
|
||||
@@ -551,7 +535,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMFA",
|
||||
"group": "mfa",
|
||||
"weight": 307,
|
||||
"weight": 306,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa.md",
|
||||
@@ -623,7 +607,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 309,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-authenticator.md",
|
||||
@@ -747,7 +731,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 310,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-authenticator.md",
|
||||
@@ -887,7 +871,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 311,
|
||||
"weight": 310,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/delete-mfa-authenticator.md",
|
||||
@@ -1011,7 +995,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 315,
|
||||
"weight": 314,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-challenge.md",
|
||||
@@ -1145,7 +1129,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 316,
|
||||
"weight": 315,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-challenge.md",
|
||||
@@ -1283,7 +1267,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listMfaFactors",
|
||||
"group": "mfa",
|
||||
"weight": 308,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/list-mfa-factors.md",
|
||||
@@ -1384,7 +1368,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 314,
|
||||
"weight": 313,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/get-mfa-recovery-codes.md",
|
||||
@@ -1483,7 +1467,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 312,
|
||||
"weight": 311,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-recovery-codes.md",
|
||||
@@ -1582,7 +1566,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 313,
|
||||
"weight": 312,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-recovery-codes.md",
|
||||
@@ -2574,8 +2558,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": []
|
||||
@@ -3505,8 +3488,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": []
|
||||
@@ -5843,7 +5825,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-name": null,
|
||||
"x-enum-keys": [],
|
||||
"default": ""
|
||||
},
|
||||
@@ -5876,7 +5858,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 381,
|
||||
"weight": 380,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-transactions.md",
|
||||
@@ -5943,7 +5925,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 377,
|
||||
"weight": 376,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-transaction.md",
|
||||
@@ -6013,7 +5995,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 378,
|
||||
"weight": 377,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-transaction.md",
|
||||
@@ -6077,7 +6059,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 379,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-transaction.md",
|
||||
@@ -6155,7 +6137,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 380,
|
||||
"weight": 379,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-transaction.md",
|
||||
@@ -6221,7 +6203,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 382,
|
||||
"weight": 381,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-operations.md",
|
||||
@@ -6306,7 +6288,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listDocuments",
|
||||
"group": "documents",
|
||||
"weight": 340,
|
||||
"weight": 339,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-documents.md",
|
||||
@@ -6418,7 +6400,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createDocument",
|
||||
"group": "documents",
|
||||
"weight": 332,
|
||||
"weight": 331,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-document.md",
|
||||
@@ -6579,7 +6561,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getDocument",
|
||||
"group": "documents",
|
||||
"weight": 333,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-document.md",
|
||||
@@ -6690,7 +6672,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertDocument",
|
||||
"group": "documents",
|
||||
"weight": 336,
|
||||
"weight": 335,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/upsert-document.md",
|
||||
@@ -6845,7 +6827,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateDocument",
|
||||
"group": "documents",
|
||||
"weight": 334,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-document.md",
|
||||
@@ -6957,7 +6939,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"group": "documents",
|
||||
"weight": 338,
|
||||
"weight": 337,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-document.md",
|
||||
@@ -7064,7 +7046,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 343,
|
||||
"weight": 342,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/decrement-document-attribute.md",
|
||||
@@ -7191,7 +7173,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 342,
|
||||
"weight": 341,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/increment-document-attribute.md",
|
||||
@@ -7318,7 +7300,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 473,
|
||||
"weight": 472,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -7405,7 +7387,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 471,
|
||||
"weight": 470,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -7523,7 +7505,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 472,
|
||||
"weight": 471,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7598,7 +7580,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"group": "graphql",
|
||||
"weight": 242,
|
||||
"weight": 241,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/query.md",
|
||||
@@ -7652,7 +7634,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"group": "graphql",
|
||||
"weight": 241,
|
||||
"weight": 240,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/mutation.md",
|
||||
@@ -8138,7 +8120,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 291,
|
||||
"weight": 290,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/create-subscriber.md",
|
||||
@@ -8222,7 +8204,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 295,
|
||||
"weight": 294,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/delete-subscriber.md",
|
||||
@@ -9131,7 +9113,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 446,
|
||||
"weight": 445,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-transactions.md",
|
||||
@@ -9201,7 +9183,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 442,
|
||||
"weight": 441,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-transaction.md",
|
||||
@@ -9274,7 +9256,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 443,
|
||||
"weight": 442,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-transaction.md",
|
||||
@@ -9341,7 +9323,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 444,
|
||||
"weight": 443,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-transaction.md",
|
||||
@@ -9422,7 +9404,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 445,
|
||||
"weight": 444,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-transaction.md",
|
||||
@@ -9491,7 +9473,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 447,
|
||||
"weight": 446,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-operations.md",
|
||||
@@ -9579,7 +9561,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 438,
|
||||
"weight": 437,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -9690,7 +9672,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 430,
|
||||
"weight": 429,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -9846,7 +9828,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 431,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -9956,7 +9938,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 434,
|
||||
"weight": 433,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -10106,7 +10088,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 432,
|
||||
"weight": 431,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -10217,7 +10199,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 436,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -10323,7 +10305,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 441,
|
||||
"weight": 440,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -10449,7 +10431,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 440,
|
||||
"weight": 439,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -407,8 +407,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -429,23 +429,7 @@
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application\/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration": {
|
||||
"type": "integer",
|
||||
"description": "Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.",
|
||||
"x-example": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"\/account\/logs": {
|
||||
@@ -551,7 +535,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMFA",
|
||||
"group": "mfa",
|
||||
"weight": 307,
|
||||
"weight": 306,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa.md",
|
||||
@@ -623,7 +607,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 309,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-authenticator.md",
|
||||
@@ -747,7 +731,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 310,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-authenticator.md",
|
||||
@@ -887,7 +871,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 311,
|
||||
"weight": 310,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/delete-mfa-authenticator.md",
|
||||
@@ -1011,7 +995,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 315,
|
||||
"weight": 314,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-challenge.md",
|
||||
@@ -1145,7 +1129,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 316,
|
||||
"weight": 315,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-challenge.md",
|
||||
@@ -1283,7 +1267,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listMfaFactors",
|
||||
"group": "mfa",
|
||||
"weight": 308,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/list-mfa-factors.md",
|
||||
@@ -1384,7 +1368,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 314,
|
||||
"weight": 313,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/get-mfa-recovery-codes.md",
|
||||
@@ -1483,7 +1467,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 312,
|
||||
"weight": 311,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-recovery-codes.md",
|
||||
@@ -1582,7 +1566,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 313,
|
||||
"weight": 312,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-recovery-codes.md",
|
||||
@@ -2574,8 +2558,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": []
|
||||
@@ -3505,8 +3488,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": []
|
||||
@@ -5843,7 +5825,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-name": null,
|
||||
"x-enum-keys": [],
|
||||
"default": ""
|
||||
},
|
||||
@@ -5876,7 +5858,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 381,
|
||||
"weight": 380,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-transactions.md",
|
||||
@@ -5943,7 +5925,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 377,
|
||||
"weight": 376,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-transaction.md",
|
||||
@@ -6013,7 +5995,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 378,
|
||||
"weight": 377,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-transaction.md",
|
||||
@@ -6077,7 +6059,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 379,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-transaction.md",
|
||||
@@ -6155,7 +6137,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 380,
|
||||
"weight": 379,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-transaction.md",
|
||||
@@ -6221,7 +6203,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 382,
|
||||
"weight": 381,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-operations.md",
|
||||
@@ -6306,7 +6288,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listDocuments",
|
||||
"group": "documents",
|
||||
"weight": 340,
|
||||
"weight": 339,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-documents.md",
|
||||
@@ -6418,7 +6400,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createDocument",
|
||||
"group": "documents",
|
||||
"weight": 332,
|
||||
"weight": 331,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-document.md",
|
||||
@@ -6579,7 +6561,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getDocument",
|
||||
"group": "documents",
|
||||
"weight": 333,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-document.md",
|
||||
@@ -6690,7 +6672,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertDocument",
|
||||
"group": "documents",
|
||||
"weight": 336,
|
||||
"weight": 335,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/upsert-document.md",
|
||||
@@ -6845,7 +6827,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateDocument",
|
||||
"group": "documents",
|
||||
"weight": 334,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-document.md",
|
||||
@@ -6957,7 +6939,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"group": "documents",
|
||||
"weight": 338,
|
||||
"weight": 337,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-document.md",
|
||||
@@ -7064,7 +7046,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 343,
|
||||
"weight": 342,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/decrement-document-attribute.md",
|
||||
@@ -7191,7 +7173,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 342,
|
||||
"weight": 341,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/increment-document-attribute.md",
|
||||
@@ -7318,7 +7300,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 473,
|
||||
"weight": 472,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -7405,7 +7387,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 471,
|
||||
"weight": 470,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -7523,7 +7505,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 472,
|
||||
"weight": 471,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7598,7 +7580,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"group": "graphql",
|
||||
"weight": 242,
|
||||
"weight": 241,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/query.md",
|
||||
@@ -7652,7 +7634,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"group": "graphql",
|
||||
"weight": 241,
|
||||
"weight": 240,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/mutation.md",
|
||||
@@ -8138,7 +8120,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 291,
|
||||
"weight": 290,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/create-subscriber.md",
|
||||
@@ -8222,7 +8204,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 295,
|
||||
"weight": 294,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/delete-subscriber.md",
|
||||
@@ -9131,7 +9113,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 446,
|
||||
"weight": 445,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-transactions.md",
|
||||
@@ -9201,7 +9183,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 442,
|
||||
"weight": 441,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-transaction.md",
|
||||
@@ -9274,7 +9256,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 443,
|
||||
"weight": 442,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-transaction.md",
|
||||
@@ -9341,7 +9323,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 444,
|
||||
"weight": 443,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-transaction.md",
|
||||
@@ -9422,7 +9404,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 445,
|
||||
"weight": 444,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-transaction.md",
|
||||
@@ -9491,7 +9473,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 447,
|
||||
"weight": 446,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-operations.md",
|
||||
@@ -9579,7 +9561,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 438,
|
||||
"weight": 437,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -9690,7 +9672,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 430,
|
||||
"weight": 429,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -9846,7 +9828,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 431,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -9956,7 +9938,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 434,
|
||||
"weight": 433,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -10106,7 +10088,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 432,
|
||||
"weight": 431,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -10217,7 +10199,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 436,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -10323,7 +10305,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 441,
|
||||
"weight": 440,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -10449,7 +10431,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 440,
|
||||
"weight": 439,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -464,8 +464,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -486,23 +486,6 @@
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration": {
|
||||
"type": "integer",
|
||||
"description": "Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.",
|
||||
"default": 900,
|
||||
"x-example": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -608,7 +591,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMFA",
|
||||
"group": "mfa",
|
||||
"weight": 307,
|
||||
"weight": 306,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa.md",
|
||||
@@ -683,7 +666,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 309,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-authenticator.md",
|
||||
@@ -807,7 +790,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 310,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-authenticator.md",
|
||||
@@ -948,7 +931,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 311,
|
||||
"weight": 310,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/delete-mfa-authenticator.md",
|
||||
@@ -1072,7 +1055,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 315,
|
||||
"weight": 314,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-challenge.md",
|
||||
@@ -1209,7 +1192,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 316,
|
||||
"weight": 315,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-challenge.md",
|
||||
@@ -1349,7 +1332,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listMfaFactors",
|
||||
"group": "mfa",
|
||||
"weight": 308,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/list-mfa-factors.md",
|
||||
@@ -1450,7 +1433,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 314,
|
||||
"weight": 313,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/get-mfa-recovery-codes.md",
|
||||
@@ -1551,7 +1534,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 312,
|
||||
"weight": 311,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-recovery-codes.md",
|
||||
@@ -1652,7 +1635,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 313,
|
||||
"weight": 312,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-recovery-codes.md",
|
||||
@@ -2684,8 +2667,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": [],
|
||||
@@ -3639,8 +3621,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": [],
|
||||
@@ -5950,7 +5931,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-name": null,
|
||||
"x-enum-keys": [],
|
||||
"default": "",
|
||||
"in": "query"
|
||||
@@ -5982,7 +5963,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 381,
|
||||
"weight": 380,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-transactions.md",
|
||||
@@ -6049,7 +6030,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 377,
|
||||
"weight": 376,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-transaction.md",
|
||||
@@ -6119,7 +6100,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 378,
|
||||
"weight": 377,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-transaction.md",
|
||||
@@ -6182,7 +6163,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 379,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-transaction.md",
|
||||
@@ -6261,7 +6242,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 380,
|
||||
"weight": 379,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-transaction.md",
|
||||
@@ -6326,7 +6307,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 382,
|
||||
"weight": 381,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-operations.md",
|
||||
@@ -6407,7 +6388,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listDocuments",
|
||||
"group": "documents",
|
||||
"weight": 340,
|
||||
"weight": 339,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-documents.md",
|
||||
@@ -6511,7 +6492,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createDocument",
|
||||
"group": "documents",
|
||||
"weight": 332,
|
||||
"weight": 331,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-document.md",
|
||||
@@ -6670,7 +6651,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getDocument",
|
||||
"group": "documents",
|
||||
"weight": 333,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-document.md",
|
||||
@@ -6773,7 +6754,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertDocument",
|
||||
"group": "documents",
|
||||
"weight": 336,
|
||||
"weight": 335,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/upsert-document.md",
|
||||
@@ -6924,7 +6905,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateDocument",
|
||||
"group": "documents",
|
||||
"weight": 334,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-document.md",
|
||||
@@ -7034,7 +7015,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"group": "documents",
|
||||
"weight": 338,
|
||||
"weight": 337,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-document.md",
|
||||
@@ -7135,7 +7116,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 343,
|
||||
"weight": 342,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/decrement-document-attribute.md",
|
||||
@@ -7256,7 +7237,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 342,
|
||||
"weight": 341,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/increment-document-attribute.md",
|
||||
@@ -7375,7 +7356,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 473,
|
||||
"weight": 472,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -7458,7 +7439,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 471,
|
||||
"weight": 470,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -7577,7 +7558,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 472,
|
||||
"weight": 471,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7649,7 +7630,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"group": "graphql",
|
||||
"weight": 242,
|
||||
"weight": 241,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/query.md",
|
||||
@@ -7724,7 +7705,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"group": "graphql",
|
||||
"weight": 241,
|
||||
"weight": 240,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/mutation.md",
|
||||
@@ -8223,7 +8204,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 291,
|
||||
"weight": 290,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/create-subscriber.md",
|
||||
@@ -8308,7 +8289,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 295,
|
||||
"weight": 294,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/delete-subscriber.md",
|
||||
@@ -9165,7 +9146,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 446,
|
||||
"weight": 445,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-transactions.md",
|
||||
@@ -9235,7 +9216,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 442,
|
||||
"weight": 441,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-transaction.md",
|
||||
@@ -9308,7 +9289,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 443,
|
||||
"weight": 442,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-transaction.md",
|
||||
@@ -9374,7 +9355,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 444,
|
||||
"weight": 443,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-transaction.md",
|
||||
@@ -9456,7 +9437,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 445,
|
||||
"weight": 444,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-transaction.md",
|
||||
@@ -9524,7 +9505,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 447,
|
||||
"weight": 446,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-operations.md",
|
||||
@@ -9608,7 +9589,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 438,
|
||||
"weight": 437,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -9711,7 +9692,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 430,
|
||||
"weight": 429,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -9865,7 +9846,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 431,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -9967,7 +9948,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 434,
|
||||
"weight": 433,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -10113,7 +10094,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 432,
|
||||
"weight": 431,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -10222,7 +10203,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 436,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -10322,7 +10303,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 441,
|
||||
"weight": 440,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -10442,7 +10423,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 440,
|
||||
"weight": 439,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -464,8 +464,8 @@
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-jwt.md",
|
||||
"rate-limit": 120,
|
||||
"rate-time": 60,
|
||||
"rate-limit": 100,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},userId:{userId}",
|
||||
"scope": "account",
|
||||
"platforms": [
|
||||
@@ -486,23 +486,6 @@
|
||||
"Session": [],
|
||||
"JWT": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"duration": {
|
||||
"type": "integer",
|
||||
"description": "Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.",
|
||||
"default": 900,
|
||||
"x-example": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -608,7 +591,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMFA",
|
||||
"group": "mfa",
|
||||
"weight": 307,
|
||||
"weight": 306,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa.md",
|
||||
@@ -683,7 +666,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 309,
|
||||
"weight": 308,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-authenticator.md",
|
||||
@@ -807,7 +790,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 310,
|
||||
"weight": 309,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-authenticator.md",
|
||||
@@ -948,7 +931,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteMfaAuthenticator",
|
||||
"group": "mfa",
|
||||
"weight": 311,
|
||||
"weight": 310,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/delete-mfa-authenticator.md",
|
||||
@@ -1072,7 +1055,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 315,
|
||||
"weight": 314,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-challenge.md",
|
||||
@@ -1209,7 +1192,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaChallenge",
|
||||
"group": "mfa",
|
||||
"weight": 316,
|
||||
"weight": 315,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-challenge.md",
|
||||
@@ -1349,7 +1332,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listMfaFactors",
|
||||
"group": "mfa",
|
||||
"weight": 308,
|
||||
"weight": 307,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/list-mfa-factors.md",
|
||||
@@ -1450,7 +1433,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 314,
|
||||
"weight": 313,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/get-mfa-recovery-codes.md",
|
||||
@@ -1551,7 +1534,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 312,
|
||||
"weight": 311,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/create-mfa-recovery-codes.md",
|
||||
@@ -1652,7 +1635,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateMfaRecoveryCodes",
|
||||
"group": "mfa",
|
||||
"weight": 313,
|
||||
"weight": 312,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "account\/update-mfa-recovery-codes.md",
|
||||
@@ -2684,8 +2667,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": [],
|
||||
@@ -3639,8 +3621,7 @@
|
||||
"yandex",
|
||||
"zoho",
|
||||
"zoom",
|
||||
"mock",
|
||||
"mock-unverified"
|
||||
"mock"
|
||||
],
|
||||
"x-enum-name": "OAuthProvider",
|
||||
"x-enum-keys": [],
|
||||
@@ -5950,7 +5931,7 @@
|
||||
"avif",
|
||||
"gif"
|
||||
],
|
||||
"x-enum-name": "ImageFormat",
|
||||
"x-enum-name": null,
|
||||
"x-enum-keys": [],
|
||||
"default": "",
|
||||
"in": "query"
|
||||
@@ -5982,7 +5963,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 381,
|
||||
"weight": 380,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-transactions.md",
|
||||
@@ -6049,7 +6030,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 377,
|
||||
"weight": 376,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-transaction.md",
|
||||
@@ -6119,7 +6100,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 378,
|
||||
"weight": 377,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-transaction.md",
|
||||
@@ -6182,7 +6163,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 379,
|
||||
"weight": 378,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-transaction.md",
|
||||
@@ -6261,7 +6242,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 380,
|
||||
"weight": 379,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-transaction.md",
|
||||
@@ -6326,7 +6307,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 382,
|
||||
"weight": 381,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-operations.md",
|
||||
@@ -6407,7 +6388,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listDocuments",
|
||||
"group": "documents",
|
||||
"weight": 340,
|
||||
"weight": 339,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/list-documents.md",
|
||||
@@ -6511,7 +6492,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createDocument",
|
||||
"group": "documents",
|
||||
"weight": 332,
|
||||
"weight": 331,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/create-document.md",
|
||||
@@ -6670,7 +6651,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getDocument",
|
||||
"group": "documents",
|
||||
"weight": 333,
|
||||
"weight": 332,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/get-document.md",
|
||||
@@ -6773,7 +6754,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertDocument",
|
||||
"group": "documents",
|
||||
"weight": 336,
|
||||
"weight": 335,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/upsert-document.md",
|
||||
@@ -6924,7 +6905,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateDocument",
|
||||
"group": "documents",
|
||||
"weight": 334,
|
||||
"weight": 333,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/update-document.md",
|
||||
@@ -7034,7 +7015,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteDocument",
|
||||
"group": "documents",
|
||||
"weight": 338,
|
||||
"weight": 337,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/delete-document.md",
|
||||
@@ -7135,7 +7116,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 343,
|
||||
"weight": 342,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/decrement-document-attribute.md",
|
||||
@@ -7256,7 +7237,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementDocumentAttribute",
|
||||
"group": "documents",
|
||||
"weight": 342,
|
||||
"weight": 341,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "databases\/increment-document-attribute.md",
|
||||
@@ -7375,7 +7356,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 473,
|
||||
"weight": 472,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -7458,7 +7439,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 471,
|
||||
"weight": 470,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -7577,7 +7558,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 472,
|
||||
"weight": 471,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7649,7 +7630,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "query",
|
||||
"group": "graphql",
|
||||
"weight": 242,
|
||||
"weight": 241,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/query.md",
|
||||
@@ -7724,7 +7705,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "mutation",
|
||||
"group": "graphql",
|
||||
"weight": 241,
|
||||
"weight": 240,
|
||||
"cookies": false,
|
||||
"type": "graphql",
|
||||
"demo": "graphql\/mutation.md",
|
||||
@@ -8223,7 +8204,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 291,
|
||||
"weight": 290,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/create-subscriber.md",
|
||||
@@ -8308,7 +8289,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteSubscriber",
|
||||
"group": "subscribers",
|
||||
"weight": 295,
|
||||
"weight": 294,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "messaging\/delete-subscriber.md",
|
||||
@@ -9165,7 +9146,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listTransactions",
|
||||
"group": "transactions",
|
||||
"weight": 446,
|
||||
"weight": 445,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-transactions.md",
|
||||
@@ -9235,7 +9216,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 442,
|
||||
"weight": 441,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-transaction.md",
|
||||
@@ -9308,7 +9289,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 443,
|
||||
"weight": 442,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-transaction.md",
|
||||
@@ -9374,7 +9355,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 444,
|
||||
"weight": 443,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-transaction.md",
|
||||
@@ -9456,7 +9437,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteTransaction",
|
||||
"group": "transactions",
|
||||
"weight": 445,
|
||||
"weight": 444,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-transaction.md",
|
||||
@@ -9524,7 +9505,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createOperations",
|
||||
"group": "transactions",
|
||||
"weight": 447,
|
||||
"weight": 446,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-operations.md",
|
||||
@@ -9608,7 +9589,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 438,
|
||||
"weight": 437,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -9711,7 +9692,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 430,
|
||||
"weight": 429,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -9865,7 +9846,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 431,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -9967,7 +9948,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 434,
|
||||
"weight": 433,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -10113,7 +10094,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 432,
|
||||
"weight": 431,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -10222,7 +10203,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 436,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -10322,7 +10303,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 441,
|
||||
"weight": 440,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -10442,7 +10423,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 440,
|
||||
"weight": 439,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,4 +3,6 @@
|
||||
use Utopia\Image\Image;
|
||||
use Utopia\System\System;
|
||||
|
||||
Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64)));
|
||||
if (\class_exists('Imagick')) {
|
||||
Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64)));
|
||||
}
|
||||
|
||||
@@ -31,13 +31,14 @@ use Appwrite\URL\URL as URLParser;
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Identities;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use libphonenumber\PhoneNumberUtil;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Audit\Audit as EventAudit;
|
||||
use Utopia\Auth\Hashes\Sha;
|
||||
use Utopia\Auth\Proofs\Code as ProofsCode;
|
||||
use Utopia\Auth\Proofs\Password as ProofsPassword;
|
||||
@@ -55,10 +56,7 @@ use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Email;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -68,7 +66,6 @@ use Utopia\Validator;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -207,10 +204,10 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, arr
|
||||
}
|
||||
|
||||
|
||||
$createSession = function (string $userId, string $secret, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Store $store, ProofsToken $proofForToken, ProofsCode $proofForCode) {
|
||||
$createSession = function (string $userId, string $secret, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Store $store, ProofsToken $proofForToken, ProofsCode $proofForCode, Authorization $authorization) {
|
||||
|
||||
/** @var Appwrite\Utopia\Database\Documents\User $userFromRequest */
|
||||
$userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId));
|
||||
$userFromRequest = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId));
|
||||
|
||||
if ($userFromRequest->isEmpty()) {
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
@@ -266,7 +263,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res
|
||||
$detector->getDevice()
|
||||
));
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$session = $dbForProject->createDocument('sessions', $session
|
||||
->setAttribute('$permissions', [
|
||||
@@ -275,7 +272,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
]));
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId()));
|
||||
$authorization->skip(fn () => $dbForProject->deleteDocument('tokens', $verifiedToken->getId()));
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
// Magic URL + Email OTP
|
||||
@@ -376,8 +373,9 @@ App::post('/v1/account')
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('hooks')
|
||||
->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Hooks $hooks) {
|
||||
->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Authorization $authorization, Hooks $hooks) {
|
||||
|
||||
$email = \strtolower($email);
|
||||
if ('console' === $project->getId()) {
|
||||
@@ -469,9 +467,9 @@ App::post('/v1/account')
|
||||
]);
|
||||
|
||||
$user->removeAttribute('$sequence');
|
||||
$user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
$user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
try {
|
||||
$target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([
|
||||
$target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
@@ -497,9 +495,9 @@ App::post('/v1/account')
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
Authorization::unsetRole(Role::guests()->toString());
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
Authorization::setRole(Role::users()->toString());
|
||||
$authorization->removeRole(Role::guests()->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::users()->toString());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -975,7 +973,8 @@ App::post('/v1/account/sessions/email')
|
||||
->inject('store')
|
||||
->inject('proofForPassword')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $email, string $password, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken) {
|
||||
->inject('authorization')
|
||||
->action(function (string $email, string $password, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken, Authorization $authorization) {
|
||||
$email = \strtolower($email);
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
@@ -1020,7 +1019,7 @@ App::post('/v1/account/sessions/email')
|
||||
$detector->getDevice()
|
||||
));
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
// Re-hash if not using recommended algo
|
||||
if ($user->getAttribute('hash') !== $proofForPassword->getHash()->getName()) {
|
||||
@@ -1119,7 +1118,8 @@ App::post('/v1/account/sessions/anonymous')
|
||||
->inject('store')
|
||||
->inject('proofForPassword')
|
||||
->inject('proofForToken')
|
||||
->action(function (Request $request, Response $response, Locale $locale, User $user, Document $project, Database $dbForProject, Reader $geodb, Event $queueForEvents, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken) {
|
||||
->inject('authorization')
|
||||
->action(function (Request $request, Response $response, Locale $locale, User $user, Document $project, Database $dbForProject, Reader $geodb, Event $queueForEvents, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken, Authorization $authorization) {
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
if ('console' === $project->getId()) {
|
||||
@@ -1164,7 +1164,7 @@ App::post('/v1/account/sessions/anonymous')
|
||||
'accessedAt' => DateTime::now(),
|
||||
]);
|
||||
$user->removeAttribute('$sequence');
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
$user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
|
||||
// Create session token
|
||||
$duration = $project->getAttribute('auths', [])['duration'] ?? TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
@@ -1190,7 +1190,7 @@ App::post('/v1/account/sessions/anonymous')
|
||||
$detector->getDevice()
|
||||
));
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$session = $dbForProject->createDocument('sessions', $session->setAttribute('$permissions', [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
@@ -1272,6 +1272,7 @@ App::post('/v1/account/sessions/token')
|
||||
->inject('store')
|
||||
->inject('proofForToken')
|
||||
->inject('proofForCode')
|
||||
->inject('authorization')
|
||||
->action($createSession);
|
||||
|
||||
App::get('/v1/account/sessions/oauth2/:provider')
|
||||
@@ -1468,7 +1469,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
->inject('store')
|
||||
->inject('proofForPassword')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Validator $redirectValidator, Document $devKey, User $user, Database $dbForProject, Reader $geodb, Event $queueForEvents, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken) use ($oauthDefaultSuccess) {
|
||||
->inject('authorization')
|
||||
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Validator $redirectValidator, Document $devKey, User $user, Database $dbForProject, Reader $geodb, Event $queueForEvents, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken, Authorization $authorization) use ($oauthDefaultSuccess) {
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$port = $request->getPort();
|
||||
$callbackBase = $protocol . '://' . $request->getHostname();
|
||||
@@ -1724,7 +1726,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
]);
|
||||
|
||||
$user->removeAttribute('$sequence');
|
||||
$userDoc = Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
$userDoc = $authorization->skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
$dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
@@ -1742,8 +1744,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
}
|
||||
}
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
Authorization::setRole(Role::users()->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::users()->toString());
|
||||
|
||||
if (false === $user->getAttribute('status')) { // Account is blocked
|
||||
$failureRedirect(Exception::USER_BLOCKED); // User is in status blocked
|
||||
@@ -1814,7 +1816,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$state['success'] = URLParser::parse($state['success']);
|
||||
$query = URLParser::parseQuery($state['success']['query']);
|
||||
@@ -1838,7 +1840,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$token = $dbForProject->createDocument('tokens', $token
|
||||
->setAttribute('$permissions', [
|
||||
@@ -2075,7 +2077,8 @@ App::post('/v1/account/tokens/magic-url')
|
||||
->inject('queueForMails')
|
||||
->inject('proofForPassword')
|
||||
->inject('platform')
|
||||
->action(function (string $userId, string $email, string $url, bool $phrase, Request $request, Response $response, User $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsPassword $proofForPassword, array $platform) {
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $email, string $url, bool $phrase, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsPassword $proofForPassword, array $platform, Authorization $authorization) {
|
||||
if (empty(System::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled');
|
||||
}
|
||||
@@ -2148,7 +2151,7 @@ App::post('/v1/account/tokens/magic-url')
|
||||
]);
|
||||
|
||||
$user->removeAttribute('$sequence');
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
$user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
}
|
||||
|
||||
$proofForToken = new ProofsToken(TOKEN_LENGTH_MAGIC_URL);
|
||||
@@ -2168,7 +2171,7 @@ App::post('/v1/account/tokens/magic-url')
|
||||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$token = $dbForProject->createDocument('tokens', $token
|
||||
->setAttribute('$permissions', [
|
||||
@@ -2354,7 +2357,8 @@ App::post('/v1/account/tokens/email')
|
||||
->inject('queueForMails')
|
||||
->inject('proofForPassword')
|
||||
->inject('proofForCode')
|
||||
->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, User $user, Document $project, array $platform, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsPassword $proofForPassword, ProofsCode $proofForCode) {
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, User $user, Document $project, array $platform, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsPassword $proofForPassword, ProofsCode $proofForCode, Authorization $authorization) {
|
||||
if (empty(System::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled');
|
||||
}
|
||||
@@ -2423,9 +2427,9 @@ App::post('/v1/account/tokens/email')
|
||||
]);
|
||||
|
||||
$user->removeAttribute('$sequence');
|
||||
$user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
$user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
try {
|
||||
$target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([
|
||||
$target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
@@ -2463,7 +2467,7 @@ App::post('/v1/account/tokens/email')
|
||||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$token = $dbForProject->createDocument('tokens', $token
|
||||
->setAttribute('$permissions', [
|
||||
@@ -2659,10 +2663,11 @@ App::put('/v1/account/sessions/magic-url')
|
||||
->inject('queueForMails')
|
||||
->inject('store')
|
||||
->inject('proofForCode')
|
||||
->action(function ($userId, $secret, $request, $response, $user, $dbForProject, $project, $platform, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForCode) use ($createSession) {
|
||||
->inject('authorization')
|
||||
->action(function ($userId, $secret, $request, $response, $user, $dbForProject, $project, $platform, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForCode, $authorization) use ($createSession) {
|
||||
$proofForToken = new ProofsToken(TOKEN_LENGTH_MAGIC_URL);
|
||||
$proofForToken->setHash(new Sha());
|
||||
$createSession($userId, $secret, $request, $response, $user, $dbForProject, $project, $platform, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForToken, $proofForCode);
|
||||
$createSession($userId, $secret, $request, $response, $user, $dbForProject, $project, $platform, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForToken, $proofForCode, $authorization);
|
||||
});
|
||||
|
||||
App::put('/v1/account/sessions/phone')
|
||||
@@ -2708,6 +2713,7 @@ App::put('/v1/account/sessions/phone')
|
||||
->inject('store')
|
||||
->inject('proofForToken')
|
||||
->inject('proofForCode')
|
||||
->inject('authorization')
|
||||
->action($createSession);
|
||||
|
||||
App::post('/v1/account/tokens/phone')
|
||||
@@ -2751,7 +2757,8 @@ App::post('/v1/account/tokens/phone')
|
||||
->inject('plan')
|
||||
->inject('store')
|
||||
->inject('proofForCode')
|
||||
->action(function (string $userId, string $phone, Request $request, Response $response, User $user, Document $project, array $platform, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Store $store, ProofsCode $proofForCode) {
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $phone, Request $request, Response $response, User $user, Document $project, array $platform, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Store $store, ProofsCode $proofForCode, Authorization $authorization) {
|
||||
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
|
||||
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
|
||||
}
|
||||
@@ -2801,9 +2808,9 @@ App::post('/v1/account/tokens/phone')
|
||||
]);
|
||||
|
||||
$user->removeAttribute('$sequence');
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
$user = $authorization->skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
try {
|
||||
$target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([
|
||||
$target = $authorization->skip(fn () => $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
@@ -2849,7 +2856,7 @@ App::post('/v1/account/tokens/phone')
|
||||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$token = $dbForProject->createDocument('tokens', $token
|
||||
->setAttribute('$permissions', [
|
||||
@@ -2954,22 +2961,20 @@ App::post('/v1/account/jwts')
|
||||
],
|
||||
contentType: ContentType::JSON,
|
||||
))
|
||||
->param('duration', 900, new Range(0, 3600), 'Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.', true)
|
||||
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT * 2)
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('abuse-limit', 100)
|
||||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('store')
|
||||
->inject('proofForToken')
|
||||
->action(function (int $duration, Response $response, User $user, Store $store, ProofsToken $proofForToken) {
|
||||
->action(function (Response $response, User $user, Store $store, ProofsToken $proofForToken) {
|
||||
$sessionId = $user->sessionVerify($store->getProperty('secret', ''), $proofForToken);
|
||||
|
||||
if (!$sessionId) {
|
||||
throw new Exception(Exception::USER_SESSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $duration, 0);
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 0);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -3026,15 +3031,14 @@ App::get('/v1/account/logs')
|
||||
],
|
||||
contentType: ContentType::JSON,
|
||||
))
|
||||
->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 Types([Query::TYPE_LIMIT, Query::TYPE_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('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('dbForProject')
|
||||
->inject('audit')
|
||||
->action(function (array $queries, bool $includeTotal, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject, Audit $audit) {
|
||||
->action(function (array $queries, bool $includeTotal, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -3042,10 +3046,9 @@ App::get('/v1/account/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), offset: $offset, limit: $limit);
|
||||
$audit = new EventAudit($dbForProject);
|
||||
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), $queries);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -3074,7 +3077,7 @@ App::get('/v1/account/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence()) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence(), $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -3240,7 +3243,8 @@ App::patch('/v1/account/email')
|
||||
->inject('project')
|
||||
->inject('hooks')
|
||||
->inject('proofForPassword')
|
||||
->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, User $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, ProofsPassword $proofForPassword) {
|
||||
->inject('authorization')
|
||||
->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, User $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, ProofsPassword $proofForPassword, Authorization $authorization) {
|
||||
// passwordUpdate will be empty if the user has never set a password
|
||||
$passwordUpdate = $user->getAttribute('passwordUpdate');
|
||||
|
||||
@@ -3292,7 +3296,7 @@ App::patch('/v1/account/email')
|
||||
->setAttribute('passwordUpdate', DateTime::now());
|
||||
}
|
||||
|
||||
$target = Authorization::skip(fn () => $dbForProject->findOne('targets', [
|
||||
$target = $authorization->skip(fn () => $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$email]),
|
||||
]));
|
||||
|
||||
@@ -3308,7 +3312,7 @@ App::patch('/v1/account/email')
|
||||
$oldTarget = $user->find('identifier', $oldEmail, 'targets');
|
||||
|
||||
if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) {
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)));
|
||||
}
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
} catch (Duplicate) {
|
||||
@@ -3349,8 +3353,9 @@ App::patch('/v1/account/phone')
|
||||
->inject('queueForEvents')
|
||||
->inject('project')
|
||||
->inject('hooks')
|
||||
->inject('proofForPassword')
|
||||
->action(function (string $phone, string $password, Response $response, User $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, ProofsPassword $proofForPassword) {
|
||||
->inject('proofForPassword')
|
||||
->inject('authorization')
|
||||
->action(function (string $phone, string $password, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Document $project, Hooks $hooks, ProofsPassword $proofForPassword, Authorization $authorization) {
|
||||
// passwordUpdate will be empty if the user has never set a password
|
||||
$passwordUpdate = $user->getAttribute('passwordUpdate');
|
||||
|
||||
@@ -3365,7 +3370,7 @@ App::patch('/v1/account/phone')
|
||||
|
||||
$hooks->trigger('passwordValidator', [$dbForProject, $project, $password, &$user, false]);
|
||||
|
||||
$target = Authorization::skip(fn () => $dbForProject->findOne('targets', [
|
||||
$target = $authorization->skip(fn () => $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$phone]),
|
||||
]));
|
||||
|
||||
@@ -3396,7 +3401,7 @@ App::patch('/v1/account/phone')
|
||||
$oldTarget = $user->find('identifier', $oldPhone, 'targets');
|
||||
|
||||
if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) {
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)));
|
||||
}
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
} catch (Duplicate $th) {
|
||||
@@ -3532,7 +3537,9 @@ App::post('/v1/account/recovery')
|
||||
->inject('queueForMails')
|
||||
->inject('queueForEvents')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $email, string $url, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Mail $queueForMails, Event $queueForEvents, ProofsToken $proofForToken) {
|
||||
->inject('authorization')
|
||||
->action(function (string $email, string $url, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Mail $queueForMails, Event $queueForEvents, ProofsToken $proofForToken, Authorization $authorization) {
|
||||
|
||||
if (empty(System::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled');
|
||||
}
|
||||
@@ -3568,7 +3575,7 @@ App::post('/v1/account/recovery')
|
||||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole(Role::user($profile->getId())->toString());
|
||||
$authorization->addRole(Role::user($profile->getId())->toString());
|
||||
|
||||
$recovery = $dbForProject->createDocument('tokens', $recovery
|
||||
->setAttribute('$permissions', [
|
||||
@@ -3724,7 +3731,8 @@ App::put('/v1/account/recovery')
|
||||
->inject('hooks')
|
||||
->inject('proofForPassword')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $userId, string $secret, string $password, Response $response, User $user, Database $dbForProject, Document $project, Event $queueForEvents, Hooks $hooks, ProofsPassword $proofForPassword, ProofsToken $proofForToken) {
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $secret, string $password, Response $response, User $user, Database $dbForProject, Document $project, Event $queueForEvents, Hooks $hooks, ProofsPassword $proofForPassword, ProofsToken $proofForToken, Authorization $authorization) {
|
||||
/** @var Appwrite\Utopia\Database\Documents\User $profile */
|
||||
$profile = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
@@ -3738,7 +3746,7 @@ App::put('/v1/account/recovery')
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
Authorization::setRole(Role::user($profile->getId())->toString());
|
||||
$authorization->addRole(Role::user($profile->getId())->toString());
|
||||
|
||||
$newPassword = $proofForPassword->hash($password);
|
||||
|
||||
@@ -3841,7 +3849,8 @@ App::post('/v1/account/verifications/email')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForMails')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $url, Request $request, Response $response, Document $project, array $platform, User $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsToken $proofForToken) {
|
||||
->inject('authorization')
|
||||
->action(function (string $url, Request $request, Response $response, Document $project, array $platform, User $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsToken $proofForToken, Authorization $authorization) {
|
||||
|
||||
if (empty(System::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled');
|
||||
@@ -3870,7 +3879,7 @@ App::post('/v1/account/verifications/email')
|
||||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$verification = $dbForProject->createDocument('tokens', $verification
|
||||
->setAttribute('$permissions', [
|
||||
@@ -4069,9 +4078,10 @@ App::put('/v1/account/verifications/email')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $userId, string $secret, Response $response, User $user, Database $dbForProject, Event $queueForEvents, ProofsToken $proofForToken) {
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $secret, Response $response, User $user, Database $dbForProject, Event $queueForEvents, ProofsToken $proofForToken, Authorization $authorization) {
|
||||
/** @var Appwrite\Utopia\Database\Documents\User $profile */
|
||||
$profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId));
|
||||
$profile = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId));
|
||||
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
@@ -4083,7 +4093,7 @@ App::put('/v1/account/verifications/email')
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
Authorization::setRole(Role::user($profile->getId())->toString());
|
||||
$authorization->addRole(Role::user($profile->getId())->toString());
|
||||
|
||||
$profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('emailVerification', true));
|
||||
|
||||
@@ -4143,7 +4153,8 @@ App::post('/v1/account/verifications/phone')
|
||||
->inject('queueForStatsUsage')
|
||||
->inject('plan')
|
||||
->inject('proofForCode')
|
||||
->action(function (Request $request, Response $response, User $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, ProofsCode $proofForCode) {
|
||||
->inject('authorization')
|
||||
->action(function (Request $request, Response $response, User $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, ProofsCode $proofForCode, Authorization $authorization) {
|
||||
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
|
||||
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
|
||||
}
|
||||
@@ -4182,7 +4193,7 @@ App::post('/v1/account/verifications/phone')
|
||||
'ip' => $request->getIP(),
|
||||
]);
|
||||
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$verification = $dbForProject->createDocument('tokens', $verification
|
||||
->setAttribute('$permissions', [
|
||||
@@ -4288,9 +4299,10 @@ App::put('/v1/account/verifications/phone')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('proofForCode')
|
||||
->action(function (string $userId, string $secret, Response $response, User $user, Database $dbForProject, Event $queueForEvents, ProofsCode $proofForCode) {
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $secret, Response $response, User $user, Database $dbForProject, Event $queueForEvents, ProofsCode $proofForCode, Authorization $authorization) {
|
||||
/** @var Appwrite\Utopia\Database\Documents\User $profile */
|
||||
$profile = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId));
|
||||
$profile = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId));
|
||||
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
@@ -4302,7 +4314,7 @@ App::put('/v1/account/verifications/phone')
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
Authorization::setRole(Role::user($profile->getId())->toString());
|
||||
$authorization->addRole(Role::user($profile->getId())->toString());
|
||||
|
||||
$profile = $dbForProject->updateDocument('users', $profile->getId(), $profile->setAttribute('phoneVerification', true));
|
||||
|
||||
@@ -4355,12 +4367,13 @@ App::post('/v1/account/targets/push')
|
||||
->inject('dbForProject')
|
||||
->inject('store')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, User $user, Request $request, Response $response, Database $dbForProject, Store $store, ProofsToken $proofForToken) {
|
||||
->inject('authorization')
|
||||
->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, User $user, Request $request, Response $response, Database $dbForProject, Store $store, ProofsToken $proofForToken, Authorization $authorization) {
|
||||
$targetId = $targetId == 'unique()' ? ID::unique() : $targetId;
|
||||
|
||||
$provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId));
|
||||
$provider = $authorization->skip(fn () => $dbForProject->getDocument('providers', $providerId));
|
||||
|
||||
$target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
$target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
|
||||
if (!$target->isEmpty()) {
|
||||
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||
@@ -4435,9 +4448,10 @@ App::put('/v1/account/targets/:targetId/push')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject) {
|
||||
->inject('authorization')
|
||||
->action(function (string $targetId, string $identifier, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) {
|
||||
|
||||
$target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
$target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
|
||||
if ($target->isEmpty()) {
|
||||
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
|
||||
@@ -4500,8 +4514,9 @@ App::delete('/v1/account/targets/:targetId/push')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject) {
|
||||
$target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
->inject('authorization')
|
||||
->action(function (string $targetId, Event $queueForEvents, Delete $queueForDeletes, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) {
|
||||
$target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
|
||||
if ($target->isEmpty()) {
|
||||
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
|
||||
|
||||
@@ -70,9 +70,9 @@ $avatarCallback = function (string $type, string $code, int $width, int $height,
|
||||
unset($image);
|
||||
};
|
||||
|
||||
$getUserGitHub = function (string $userId, Document $project, Database $dbForProject, Database $dbForPlatform, ?Logger $logger) {
|
||||
$getUserGitHub = function (string $userId, Document $project, Database $dbForProject, Database $dbForPlatform, Authorization $authorization, ?Logger $logger) {
|
||||
try {
|
||||
$user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
$user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
|
||||
@@ -123,7 +123,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
||||
->setAttribute('providerRefreshToken', $refreshToken)
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry('')));
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession));
|
||||
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
} catch (Throwable $err) {
|
||||
@@ -131,7 +131,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
||||
do {
|
||||
$previousAccessToken = $gitHubSession->getAttribute('providerAccessToken');
|
||||
|
||||
$user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
$user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
|
||||
$gitHubSession = new Document();
|
||||
@@ -841,8 +841,9 @@ App::get('/v1/cards/cloud')
|
||||
->inject('contributors')
|
||||
->inject('employees')
|
||||
->inject('logger')
|
||||
->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) {
|
||||
$user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) {
|
||||
$user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
|
||||
if ($user->isEmpty() && empty($mock)) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
@@ -853,7 +854,7 @@ App::get('/v1/cards/cloud')
|
||||
$email = $user->getAttribute('email', '');
|
||||
$createdAt = new \DateTime($user->getCreatedAt());
|
||||
|
||||
$gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger);
|
||||
$gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $authorization, $logger);
|
||||
$githubName = $gitHub['name'] ?? '';
|
||||
$githubId = $gitHub['id'] ?? '';
|
||||
|
||||
@@ -1048,8 +1049,9 @@ App::get('/v1/cards/cloud-back')
|
||||
->inject('contributors')
|
||||
->inject('employees')
|
||||
->inject('logger')
|
||||
->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) {
|
||||
$user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) {
|
||||
$user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
|
||||
if ($user->isEmpty() && empty($mock)) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
@@ -1059,7 +1061,7 @@ App::get('/v1/cards/cloud-back')
|
||||
$userId = $user->getId();
|
||||
$email = $user->getAttribute('email', '');
|
||||
|
||||
$gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger);
|
||||
$gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $authorization, $logger);
|
||||
$githubId = $gitHub['id'] ?? '';
|
||||
|
||||
$isHero = \array_key_exists($email, $heroes);
|
||||
@@ -1126,8 +1128,9 @@ App::get('/v1/cards/cloud-og')
|
||||
->inject('contributors')
|
||||
->inject('employees')
|
||||
->inject('logger')
|
||||
->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger) use ($getUserGitHub) {
|
||||
$user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
->inject('authorization')
|
||||
->action(function (string $userId, string $mock, int $width, int $height, Document $user, Document $project, Database $dbForProject, Database $dbForPlatform, Response $response, array $heroes, array $contributors, array $employees, ?Logger $logger, Authorization $authorization) use ($getUserGitHub) {
|
||||
$user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
|
||||
if ($user->isEmpty() && empty($mock)) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
@@ -1142,7 +1145,7 @@ App::get('/v1/cards/cloud-og')
|
||||
$email = $user->getAttribute('email', '');
|
||||
$createdAt = new \DateTime($user->getCreatedAt());
|
||||
|
||||
$gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $logger);
|
||||
$gitHub = $getUserGitHub($user->getId(), $project, $dbForProject, $dbForPlatform, $authorization, $logger);
|
||||
$githubName = $gitHub['name'] ?? '';
|
||||
$githubId = $gitHub['id'] ?? '';
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\IP;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
App::init()
|
||||
->groups(['console'])
|
||||
->inject('project')
|
||||
->action(function (Document $project) {
|
||||
if ($project->getId() !== 'console') {
|
||||
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
App::get('/v1/console/variables')
|
||||
->desc('Get variables')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'console',
|
||||
group: 'console',
|
||||
name: 'variables',
|
||||
description: '/docs/references/console/variables.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_CONSOLE_VARIABLES,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$validator = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME'));
|
||||
$isCNAMEValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_CNAME', '')) && $validator->isKnown() && !$validator->isTest();
|
||||
|
||||
$validator = new IP(IP::V4);
|
||||
$isAValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_A', '')) && ($validator->isValid(System::getEnv('_APP_DOMAIN_TARGET_A')));
|
||||
|
||||
$validator = new IP(IP::V6);
|
||||
$isAAAAValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_AAAA', '')) && $validator->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA'));
|
||||
|
||||
$isDomainEnabled = $isAAAAValid || $isAValid || $isCNAMEValid;
|
||||
|
||||
$isVcsEnabled = !empty(System::getEnv('_APP_VCS_GITHUB_APP_NAME', ''))
|
||||
&& !empty(System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY', ''))
|
||||
&& !empty(System::getEnv('_APP_VCS_GITHUB_APP_ID', ''))
|
||||
&& !empty(System::getEnv('_APP_VCS_GITHUB_CLIENT_ID', ''))
|
||||
&& !empty(System::getEnv('_APP_VCS_GITHUB_CLIENT_SECRET', ''));
|
||||
|
||||
$isAssistantEnabled = !empty(System::getEnv('_APP_ASSISTANT_OPENAI_API_KEY', ''));
|
||||
|
||||
$variables = new Document([
|
||||
'_APP_DOMAIN_TARGET_CNAME' => System::getEnv('_APP_DOMAIN_TARGET_CNAME'),
|
||||
'_APP_DOMAIN_TARGET_AAAA' => System::getEnv('_APP_DOMAIN_TARGET_AAAA'),
|
||||
'_APP_DOMAIN_TARGET_A' => System::getEnv('_APP_DOMAIN_TARGET_A'),
|
||||
// Combine CAA domain with most common flags and tag (no parameters)
|
||||
'_APP_DOMAIN_TARGET_CAA' => '0 issue "' . System::getEnv('_APP_DOMAIN_TARGET_CAA') . '"',
|
||||
'_APP_STORAGE_LIMIT' => +System::getEnv('_APP_STORAGE_LIMIT'),
|
||||
'_APP_COMPUTE_BUILD_TIMEOUT' => +System::getEnv('_APP_COMPUTE_BUILD_TIMEOUT'),
|
||||
'_APP_COMPUTE_SIZE_LIMIT' => +System::getEnv('_APP_COMPUTE_SIZE_LIMIT'),
|
||||
'_APP_USAGE_STATS' => System::getEnv('_APP_USAGE_STATS'),
|
||||
'_APP_VCS_ENABLED' => $isVcsEnabled,
|
||||
'_APP_DOMAIN_ENABLED' => $isDomainEnabled,
|
||||
'_APP_ASSISTANT_ENABLED' => $isAssistantEnabled,
|
||||
'_APP_DOMAIN_SITES' => System::getEnv('_APP_DOMAIN_SITES'),
|
||||
'_APP_DOMAIN_FUNCTIONS' => System::getEnv('_APP_DOMAIN_FUNCTIONS'),
|
||||
'_APP_OPTIONS_FORCE_HTTPS' => System::getEnv('_APP_OPTIONS_FORCE_HTTPS'),
|
||||
'_APP_DOMAINS_NAMESERVERS' => System::getEnv('_APP_DOMAINS_NAMESERVERS'),
|
||||
]);
|
||||
|
||||
$response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES);
|
||||
});
|
||||
|
||||
App::post('/v1/console/assistant')
|
||||
->desc('Create assistant query')
|
||||
->groups(['api', 'assistant'])
|
||||
->label('scope', 'assistant.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'assistant',
|
||||
group: 'console',
|
||||
name: 'chat',
|
||||
description: '/docs/references/assistant/chat.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_NONE,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::TEXT
|
||||
))
|
||||
->label('abuse-limit', 15)
|
||||
->label('abuse-key', 'userId:{userId}')
|
||||
->param('prompt', '', new Text(2000), 'Prompt. A string containing questions asked to the AI assistant.')
|
||||
->inject('response')
|
||||
->action(function (string $prompt, Response $response) {
|
||||
$ch = curl_init('http://appwrite-assistant:3003/v1/models/assistant/prompt');
|
||||
$responseHeaders = [];
|
||||
$query = json_encode(['prompt' => $prompt]);
|
||||
$headers = ['accept: text/event-stream'];
|
||||
$handleEvent = function ($ch, $data) use ($response) {
|
||||
$response->chunk($data);
|
||||
|
||||
return \strlen($data);
|
||||
};
|
||||
|
||||
curl_setopt($ch, CURLOPT_WRITEFUNCTION, $handleEvent);
|
||||
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 9000);
|
||||
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) {
|
||||
$len = strlen($header);
|
||||
$header = explode(':', $header, 2);
|
||||
|
||||
if (count($header) < 2) { // ignore invalid headers
|
||||
return $len;
|
||||
}
|
||||
|
||||
$responseHeaders[strtolower(trim($header[0]))] = trim($header[1]);
|
||||
|
||||
return $len;
|
||||
});
|
||||
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
|
||||
|
||||
curl_exec($ch);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$response->chunk('', true);
|
||||
});
|
||||
@@ -28,11 +28,12 @@ use Utopia\Validator\Text;
|
||||
App::init()
|
||||
->groups(['graphql'])
|
||||
->inject('project')
|
||||
->action(function (Document $project) {
|
||||
->inject('authorization')
|
||||
->action(function (Document $project, Authorization $authorization) {
|
||||
if (
|
||||
array_key_exists('graphql', $project->getAttribute('apis', []))
|
||||
&& !$project->getAttribute('apis', [])['graphql']
|
||||
&& !(User::isPrivileged(Authorization::getRoles()) || User::isApp(Authorization::getRoles()))
|
||||
&& !(User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
|
||||
) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ App::get('/v1/health/db')
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) * 1000)
|
||||
]);
|
||||
} else {
|
||||
$failures[] = $database;
|
||||
@@ -131,6 +131,8 @@ App::get('/v1/health/db')
|
||||
}
|
||||
}
|
||||
|
||||
// Only throw error if ALL databases failed (no successful pings)
|
||||
// This allows partial failures in environments where not all DBs are ready
|
||||
if (!empty($failures)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'DB failure on: ' . implode(", ", $failures));
|
||||
}
|
||||
@@ -180,7 +182,7 @@ App::get('/v1/health/cache')
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($cache)",
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) * 1000)
|
||||
]);
|
||||
} else {
|
||||
$failures[] = $cache;
|
||||
@@ -240,7 +242,7 @@ App::get('/v1/health/pubsub')
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($pubsub)",
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) * 1000)
|
||||
]);
|
||||
} else {
|
||||
$failures[] = $pubsub;
|
||||
@@ -822,7 +824,7 @@ App::get('/v1/health/storage/local')
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) * 1000)
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -874,7 +876,7 @@ App::get('/v1/health/storage')
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) * 1000)
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -945,18 +947,18 @@ App::get('/v1/health/queue/failed/:name')
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('name', '', new WhiteList([
|
||||
System::getEnv('_APP_DATABASE_QUEUE_NAME', Event::DATABASE_QUEUE_NAME),
|
||||
System::getEnv('_APP_DELETE_QUEUE_NAME', Event::DELETE_QUEUE_NAME),
|
||||
System::getEnv('_APP_AUDITS_QUEUE_NAME', Event::AUDITS_QUEUE_NAME),
|
||||
System::getEnv('_APP_MAILS_QUEUE_NAME', Event::MAILS_QUEUE_NAME),
|
||||
System::getEnv('_APP_FUNCTIONS_QUEUE_NAME', Event::FUNCTIONS_QUEUE_NAME),
|
||||
System::getEnv('_APP_STATS_RESOURCES_QUEUE_NAME', Event::STATS_RESOURCES_QUEUE_NAME),
|
||||
System::getEnv('_APP_STATS_USAGE_QUEUE_NAME', Event::STATS_USAGE_QUEUE_NAME),
|
||||
System::getEnv('_APP_WEBHOOK_QUEUE_NAME', Event::WEBHOOK_QUEUE_NAME),
|
||||
System::getEnv('_APP_CERTIFICATES_QUEUE_NAME', Event::CERTIFICATES_QUEUE_NAME),
|
||||
System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME),
|
||||
System::getEnv('_APP_MESSAGING_QUEUE_NAME', Event::MESSAGING_QUEUE_NAME),
|
||||
System::getEnv('_APP_MIGRATIONS_QUEUE_NAME', Event::MIGRATIONS_QUEUE_NAME)
|
||||
Event::DATABASE_QUEUE_NAME,
|
||||
Event::DELETE_QUEUE_NAME,
|
||||
Event::AUDITS_QUEUE_NAME,
|
||||
Event::MAILS_QUEUE_NAME,
|
||||
Event::FUNCTIONS_QUEUE_NAME,
|
||||
Event::STATS_RESOURCES_QUEUE_NAME,
|
||||
Event::STATS_USAGE_QUEUE_NAME,
|
||||
Event::WEBHOOK_QUEUE_NAME,
|
||||
Event::CERTIFICATES_QUEUE_NAME,
|
||||
Event::BUILDS_QUEUE_NAME,
|
||||
Event::MESSAGING_QUEUE_NAME,
|
||||
Event::MIGRATIONS_QUEUE_NAME
|
||||
]), 'The name of the queue')
|
||||
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
|
||||
->inject('response')
|
||||
@@ -993,18 +995,18 @@ App::get('/v1/health/queue/failed/:name')
|
||||
|
||||
/** @var Event $queue */
|
||||
$queue = match ($name) {
|
||||
System::getEnv('_APP_DATABASE_QUEUE_NAME', Event::DATABASE_QUEUE_NAME) => $queueForDatabase,
|
||||
System::getEnv('_APP_DELETE_QUEUE_NAME', Event::DELETE_QUEUE_NAME) => $queueForDeletes,
|
||||
System::getEnv('_APP_AUDITS_QUEUE_NAME', Event::AUDITS_QUEUE_NAME) => $queueForAudits,
|
||||
System::getEnv('_APP_MAILS_QUEUE_NAME', Event::MAILS_QUEUE_NAME) => $queueForMails,
|
||||
System::getEnv('_APP_FUNCTIONS_QUEUE_NAME', Event::FUNCTIONS_QUEUE_NAME) => $queueForFunctions,
|
||||
System::getEnv('_APP_STATS_RESOURCES_QUEUE_NAME', Event::STATS_RESOURCES_QUEUE_NAME) => $queueForStatsResources,
|
||||
System::getEnv('_APP_STATS_USAGE_QUEUE_NAME', Event::STATS_USAGE_QUEUE_NAME) => $queueForStatsUsage,
|
||||
System::getEnv('_APP_WEBHOOK_QUEUE_NAME', Event::WEBHOOK_QUEUE_NAME) => $queueForWebhooks,
|
||||
System::getEnv('_APP_CERTIFICATES_QUEUE_NAME', Event::CERTIFICATES_QUEUE_NAME) => $queueForCertificates,
|
||||
System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME) => $queueForBuilds,
|
||||
System::getEnv('_APP_MESSAGING_QUEUE_NAME', Event::MESSAGING_QUEUE_NAME) => $queueForMessaging,
|
||||
System::getEnv('_APP_MIGRATIONS_QUEUE_NAME', Event::MIGRATIONS_QUEUE_NAME) => $queueForMigrations,
|
||||
Event::DATABASE_QUEUE_NAME => $queueForDatabase,
|
||||
Event::DELETE_QUEUE_NAME => $queueForDeletes,
|
||||
Event::AUDITS_QUEUE_NAME => $queueForAudits,
|
||||
Event::MAILS_QUEUE_NAME => $queueForMails,
|
||||
Event::FUNCTIONS_QUEUE_NAME => $queueForFunctions,
|
||||
Event::STATS_RESOURCES_QUEUE_NAME => $queueForStatsResources,
|
||||
Event::STATS_USAGE_QUEUE_NAME => $queueForStatsUsage,
|
||||
Event::WEBHOOK_QUEUE_NAME => $queueForWebhooks,
|
||||
Event::CERTIFICATES_QUEUE_NAME => $queueForCertificates,
|
||||
Event::BUILDS_QUEUE_NAME => $queueForBuilds,
|
||||
Event::MESSAGING_QUEUE_NAME => $queueForMessaging,
|
||||
Event::MIGRATIONS_QUEUE_NAME => $queueForMigrations,
|
||||
};
|
||||
$failed = $queue->getSize(failed: true);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Providers;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Subscribers;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Targets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Topics;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Response;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\App;
|
||||
@@ -36,11 +37,9 @@ use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Authorization\Input;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -1073,8 +1072,9 @@ App::get('/v1/messaging/providers')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('response')
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -1100,7 +1100,7 @@ App::get('/v1/messaging/providers')
|
||||
}
|
||||
|
||||
$providerId = $cursor->getValue();
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId));
|
||||
$cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('providers', $providerId));
|
||||
|
||||
if ($cursorDocument->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found.");
|
||||
@@ -1139,14 +1139,13 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider 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 Types([Query::TYPE_LIMIT, Query::TYPE_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('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->action(function (string $providerId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
->action(function (string $providerId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
@@ -1159,12 +1158,9 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'provider/' . $providerId;
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$output = [];
|
||||
|
||||
foreach ($logs as $i => &$log) {
|
||||
@@ -1211,7 +1207,7 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -2481,8 +2477,9 @@ App::get('/v1/messaging/topics')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('response')
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -2508,7 +2505,7 @@ App::get('/v1/messaging/topics')
|
||||
}
|
||||
|
||||
$topicId = $cursor->getValue();
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
$cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
|
||||
if ($cursorDocument->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Topic '{$topicId}' for the 'cursor' value not found.");
|
||||
@@ -2547,14 +2544,13 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic 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 Types([Query::TYPE_LIMIT, Query::TYPE_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('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->action(function (string $topicId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
->action(function (string $topicId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$topic = $dbForProject->getDocument('topics', $topicId);
|
||||
|
||||
if ($topic->isEmpty()) {
|
||||
@@ -2567,12 +2563,9 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'topic/' . $topicId;
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -2620,7 +2613,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -2782,29 +2775,27 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
|
||||
->param('targetId', '', new UID(), 'Target ID. The target ID to link to the specified Topic ID.')
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('response')
|
||||
->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Response $response) {
|
||||
->action(function (string $subscriberId, string $topicId, string $targetId, Event $queueForEvents, Database $dbForProject, Authorization $authorization, Response $response) {
|
||||
$subscriberId = $subscriberId == 'unique()' ? ID::unique() : $subscriberId;
|
||||
|
||||
$topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
$topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
|
||||
if ($topic->isEmpty()) {
|
||||
throw new Exception(Exception::TOPIC_NOT_FOUND);
|
||||
}
|
||||
|
||||
$validator = new Authorization('subscribe');
|
||||
|
||||
if (!$validator->isValid($topic->getAttribute('subscribe'))) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription());
|
||||
if (!$authorization->isValid(new Input('subscribe', $topic->getAttribute('subscribe')))) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription());
|
||||
}
|
||||
|
||||
$target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
$target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
||||
|
||||
if ($target->isEmpty()) {
|
||||
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId')));
|
||||
$user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId')));
|
||||
|
||||
$subscriber = new Document([
|
||||
'$id' => $subscriberId,
|
||||
@@ -2837,7 +2828,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
|
||||
default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE),
|
||||
};
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute(
|
||||
$authorization->skip(fn () => $dbForProject->increaseDocumentAttribute(
|
||||
'topics',
|
||||
$topicId,
|
||||
$totalAttribute,
|
||||
@@ -2882,8 +2873,9 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('response')
|
||||
->action(function (string $topicId, array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
->action(function (string $topicId, array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -2894,7 +2886,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
$topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
$topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
|
||||
if ($topic->isEmpty()) {
|
||||
throw new Exception(Exception::TOPIC_NOT_FOUND);
|
||||
@@ -2917,7 +2909,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
}
|
||||
|
||||
$subscriberId = $cursor->getValue();
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId));
|
||||
$cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('subscribers', $subscriberId));
|
||||
|
||||
if ($cursorDocument->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Subscriber '{$subscriberId}' for the 'cursor' value not found.");
|
||||
@@ -2931,10 +2923,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
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.");
|
||||
}
|
||||
|
||||
$subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) {
|
||||
return function () use ($subscriber, $dbForProject) {
|
||||
$target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId')));
|
||||
$user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId')));
|
||||
$subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject, $authorization) {
|
||||
return function () use ($subscriber, $dbForProject, $authorization) {
|
||||
$target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId')));
|
||||
$user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId')));
|
||||
|
||||
return $subscriber
|
||||
->setAttribute('target', $target)
|
||||
@@ -2968,14 +2960,13 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
]
|
||||
))
|
||||
->param('subscriberId', '', new UID(), 'Subscriber 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 Types([Query::TYPE_LIMIT, Query::TYPE_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('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->action(function (string $subscriberId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
->action(function (string $subscriberId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$subscriber = $dbForProject->getDocument('subscribers', $subscriberId);
|
||||
|
||||
if ($subscriber->isEmpty()) {
|
||||
@@ -2988,12 +2979,9 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'subscriber/' . $subscriberId;
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -3041,7 +3029,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -3067,9 +3055,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.')
|
||||
->param('subscriberId', '', new UID(), 'Subscriber ID.')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('response')
|
||||
->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) {
|
||||
$topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
->action(function (string $topicId, string $subscriberId, Database $dbForProject, Authorization $authorization, Response $response) {
|
||||
$topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
|
||||
if ($topic->isEmpty()) {
|
||||
throw new Exception(Exception::TOPIC_NOT_FOUND);
|
||||
@@ -3081,8 +3070,8 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
throw new Exception(Exception::SUBSCRIBER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$target = Authorization::skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId')));
|
||||
$user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId')));
|
||||
$target = $authorization->skip(fn () => $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId')));
|
||||
$user = $authorization->skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId')));
|
||||
|
||||
$subscriber
|
||||
->setAttribute('target', $target)
|
||||
@@ -3118,9 +3107,10 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
->param('subscriberId', '', new UID(), 'Subscriber ID.')
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('response')
|
||||
->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Response $response) {
|
||||
$topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
->action(function (string $topicId, string $subscriberId, Event $queueForEvents, Database $dbForProject, Authorization $authorization, Response $response) {
|
||||
$topic = $authorization->skip(fn () => $dbForProject->getDocument('topics', $topicId));
|
||||
|
||||
if ($topic->isEmpty()) {
|
||||
throw new Exception(Exception::TOPIC_NOT_FOUND);
|
||||
@@ -3143,7 +3133,7 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE),
|
||||
};
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute(
|
||||
$authorization->skip(fn () => $dbForProject->decreaseDocumentAttribute(
|
||||
'topics',
|
||||
$topicId,
|
||||
$totalAttribute,
|
||||
@@ -3702,8 +3692,9 @@ App::get('/v1/messaging/messages')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('response')
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Response $response) {
|
||||
->action(function (array $queries, string $search, bool $includeTotal, Database $dbForProject, Authorization $authorization, Response $response) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
@@ -3729,7 +3720,7 @@ App::get('/v1/messaging/messages')
|
||||
}
|
||||
|
||||
$messageId = $cursor->getValue();
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('messages', $messageId));
|
||||
$cursorDocument = $authorization->skip(fn () => $dbForProject->getDocument('messages', $messageId));
|
||||
|
||||
if ($cursorDocument->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Message '{$messageId}' for the 'cursor' value not found.");
|
||||
@@ -3768,14 +3759,13 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
],
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message 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 Types([Query::TYPE_LIMIT, Query::TYPE_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('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->action(function (string $messageId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
->action(function (string $messageId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
$message = $dbForProject->getDocument('messages', $messageId);
|
||||
|
||||
if ($message->isEmpty()) {
|
||||
@@ -3788,12 +3778,9 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'message/' . $messageId;
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -3841,7 +3828,7 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
@@ -18,8 +18,9 @@ use Utopia\Database\Exception\Order as OrderException;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\QueryContext;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries\Documents;
|
||||
use Utopia\Database\Validator\Queries\V2 as DocumentsValidator;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Migration\Resource;
|
||||
@@ -342,6 +343,7 @@ App::post('/v1/migrations/csv/imports')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->inject('authorization')
|
||||
->inject('project')
|
||||
->inject('platform')
|
||||
->inject('deviceForFiles')
|
||||
@@ -356,6 +358,7 @@ App::post('/v1/migrations/csv/imports')
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
Document $project,
|
||||
array $platform,
|
||||
Device $deviceForFiles,
|
||||
@@ -363,7 +366,7 @@ App::post('/v1/migrations/csv/imports')
|
||||
Event $queueForEvents,
|
||||
Migration $queueForMigrations
|
||||
) {
|
||||
$bucket = Authorization::skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) {
|
||||
$bucket = $authorization->skip(function () use ($internalFile, $dbForPlatform, $dbForProject, $bucketId) {
|
||||
if ($internalFile) {
|
||||
return $dbForPlatform->getDocument('buckets', 'default');
|
||||
}
|
||||
@@ -374,7 +377,7 @@ App::post('/v1/migrations/csv/imports')
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = Authorization::skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
|
||||
$file = $authorization->skip(fn () => $internalFile ? $dbForPlatform->getDocument('bucket_' . $bucket->getSequence(), $fileId) : $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
@@ -491,6 +494,7 @@ App::post('/v1/migrations/csv/exports')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->inject('authorization')
|
||||
->inject('project')
|
||||
->inject('platform')
|
||||
->inject('queueForEvents')
|
||||
@@ -509,6 +513,7 @@ App::post('/v1/migrations/csv/exports')
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
Document $project,
|
||||
array $platform,
|
||||
Event $queueForEvents,
|
||||
@@ -520,7 +525,7 @@ App::post('/v1/migrations/csv/exports')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'default'));
|
||||
$bucket = $authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'default'));
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
@@ -533,19 +538,21 @@ App::post('/v1/migrations/csv/exports')
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = $authorization->skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId));
|
||||
$collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId));
|
||||
if ($collection->isEmpty()) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$validator = new Documents(
|
||||
attributes: $collection->getAttribute('attributes', []),
|
||||
indexes: $collection->getAttribute('indexes', []),
|
||||
$context = new QueryContext();
|
||||
$context->add($collection);
|
||||
|
||||
$validator = new DocumentsValidator(
|
||||
$context,
|
||||
idAttributeType: $dbForProject->getAdapter()->getIdAttributeType(),
|
||||
);
|
||||
|
||||
|
||||
@@ -45,9 +45,10 @@ App::get('/v1/project/usage')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('getLogsDB')
|
||||
->inject('smsRates')
|
||||
->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, callable $getLogsDB, array $smsRates) {
|
||||
->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, Authorization $authorization, callable $getLogsDB, array $smsRates) {
|
||||
$stats = $total = $usage = [];
|
||||
$format = 'Y-m-d 00:00:00';
|
||||
$firstDay = (new DateTime($startDate))->format($format);
|
||||
@@ -102,7 +103,7 @@ App::get('/v1/project/usage')
|
||||
'1d' => 'Y-m-d\T00:00:00.000P',
|
||||
};
|
||||
|
||||
Authorization::skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) {
|
||||
$authorization->skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) {
|
||||
foreach ($metrics['total'] as $metric) {
|
||||
$db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject;
|
||||
|
||||
@@ -286,7 +287,7 @@ App::get('/v1/project/usage')
|
||||
}, $dbForProject->find('functions'));
|
||||
|
||||
// This total is includes free and paid SMS usage
|
||||
$authPhoneTotal = Authorization::skip(fn () => $dbForProject->sum('stats', 'value', [
|
||||
$authPhoneTotal = $authorization->skip(fn () => $dbForProject->sum('stats', 'value', [
|
||||
Query::equal('metric', [METRIC_AUTH_METHOD_PHONE]),
|
||||
Query::equal('period', ['1d']),
|
||||
Query::greaterThanEqual('time', $firstDay),
|
||||
@@ -294,7 +295,7 @@ App::get('/v1/project/usage')
|
||||
]));
|
||||
|
||||
// This estimate is only for paid SMS usage
|
||||
$authPhoneMetrics = Authorization::skip(fn () => $dbForProject->find('stats', [
|
||||
$authPhoneMetrics = $authorization->skip(fn () => $dbForProject->find('stats', [
|
||||
Query::startsWith('metric', METRIC_AUTH_METHOD_PHONE . '.'),
|
||||
Query::equal('period', ['1d']),
|
||||
Query::greaterThanEqual('time', $firstDay),
|
||||
|
||||
@@ -21,7 +21,6 @@ use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Adapter\Database as AdapterDatabase;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Config\Config;
|
||||
@@ -248,15 +247,13 @@ App::post('/v1/projects')
|
||||
}
|
||||
|
||||
if ($create || $projectTables) {
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
$audit = new Audit($adapter);
|
||||
$audit = new Audit($dbForProject);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
if (!$create && $sharedTablesV1) {
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
$attributes = $adapter->getAttributeDocuments();
|
||||
$indexes = $adapter->getIndexDocuments();
|
||||
$attributes = \array_map(fn ($attribute) => new Document($attribute), Audit::ATTRIBUTES);
|
||||
$indexes = \array_map(fn (array $index) => new Document($index), Audit::INDEXES);
|
||||
$dbForProject->createDocument(Database::METADATA, new Document([
|
||||
'$id' => ID::custom('audit'),
|
||||
'$permissions' => [Permission::create(Role::any())],
|
||||
@@ -297,7 +294,7 @@ App::post('/v1/projects')
|
||||
|
||||
// Hook allowing instant project mirroring during migration
|
||||
// Outside of migration, hook is not registered and has no effect
|
||||
$hooks->trigger('afterProjectCreation', [$project, $pools, $cache]);
|
||||
$hooks->trigger('afterProjectCreation', [ $project, $pools, $cache ]);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -1502,9 +1499,6 @@ App::post('/v1/projects/:projectId/keys')
|
||||
],
|
||||
'projectInternalId' => $project->getSequence(),
|
||||
'projectId' => $project->getId(),
|
||||
'resourceInternalId' => $project->getSequence(),
|
||||
'resourceId' => $project->getId(),
|
||||
'resourceType' => 'projects',
|
||||
'name' => $name,
|
||||
'scopes' => $scopes,
|
||||
'expire' => $expire,
|
||||
@@ -1552,13 +1546,7 @@ 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('projectInternalId', [$project->getSequence()]),
|
||||
Query::limit(5000),
|
||||
]);
|
||||
|
||||
@@ -1599,13 +1587,7 @@ 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('projectInternalId', [$project->getSequence()]),
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
@@ -1649,13 +1631,7 @@ 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('projectInternalId', [$project->getSequence()]),
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
@@ -1706,13 +1682,7 @@ 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('projectInternalId', [$project->getSequence()]),
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
@@ -2109,7 +2079,6 @@ App::patch('/v1/projects/:projectId/smtp')
|
||||
if ($enabled) {
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->isSMTP();
|
||||
$mail->SMTPAuth = (!empty($username) && !empty($password));
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->Host = $host;
|
||||
@@ -2125,7 +2094,7 @@ App::patch('/v1/projects/:projectId/smtp')
|
||||
throw new Exception('Connection is not valid.');
|
||||
}
|
||||
} catch (Throwable $error) {
|
||||
throw new Exception(Exception::PROJECT_SMTP_CONFIG_INVALID, $error->getMessage());
|
||||
throw new Exception(Exception::PROJECT_SMTP_CONFIG_INVALID, 'Could not connect to SMTP server: ' . $error->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2696,7 +2665,7 @@ App::patch('/v1/projects/:projectId/auth/session-invalidation')
|
||||
$auths = $project->getAttribute('auths', []);
|
||||
$auths['invalidateSessions'] = $enabled;
|
||||
$dbForPlatform->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('auths', $auths));
|
||||
->setAttribute('auths', $auths));
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ use Appwrite\Utopia\Database\Documents\User;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Teams;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use libphonenumber\PhoneNumberUtil;
|
||||
@@ -49,7 +50,6 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Email;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -86,16 +86,17 @@ App::post('/v1/teams')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Event $queueForEvents) {
|
||||
|
||||
$isPrivilegedUser = User::isPrivileged(Authorization::getRoles());
|
||||
$isAppUser = User::isApp(Authorization::getRoles());
|
||||
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
|
||||
$isAppUser = User::isApp($authorization->getRoles());
|
||||
|
||||
$teamId = $teamId == 'unique()' ? ID::unique() : $teamId;
|
||||
|
||||
try {
|
||||
$team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([
|
||||
$team = $authorization->skip(fn () => $dbForProject->createDocument('teams', new Document([
|
||||
'$id' => $teamId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::team($teamId)),
|
||||
@@ -491,6 +492,7 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->inject('project')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('locale')
|
||||
->inject('queueForMails')
|
||||
->inject('queueForMessaging')
|
||||
@@ -500,9 +502,9 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->inject('plan')
|
||||
->inject('proofForPassword')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Password $proofForPassword, Token $proofForToken) {
|
||||
$isAppUser = User::isApp(Authorization::getRoles());
|
||||
$isPrivilegedUser = User::isPrivileged(Authorization::getRoles());
|
||||
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Authorization $authorization, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Password $proofForPassword, Token $proofForToken) {
|
||||
$isAppUser = User::isApp($authorization->getRoles());
|
||||
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
|
||||
|
||||
$url = htmlentities($url);
|
||||
if (empty($url)) {
|
||||
@@ -619,13 +621,13 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
]);
|
||||
|
||||
try {
|
||||
$invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', $userDocument));
|
||||
$invitee = $authorization->skip(fn () => $dbForProject->createDocument('users', $userDocument));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');
|
||||
$isOwner = $authorization->hasRole('team:' . $team->getId() . '/owner');
|
||||
|
||||
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team');
|
||||
@@ -661,11 +663,11 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
]);
|
||||
|
||||
$membership = ($isPrivilegedUser || $isAppUser) ?
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership)) :
|
||||
$authorization->skip(fn () => $dbForProject->createDocument('memberships', $membership)) :
|
||||
$dbForProject->createDocument('memberships', $membership);
|
||||
|
||||
if ($isPrivilegedUser || $isAppUser) {
|
||||
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||
$authorization->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||
}
|
||||
} elseif ($membership->getAttribute('confirm') === false) {
|
||||
$membership->setAttribute('secret', $proofForToken->hash($secret));
|
||||
@@ -677,7 +679,7 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
}
|
||||
|
||||
$membership = ($isPrivilegedUser || $isAppUser) ?
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) :
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) :
|
||||
$dbForProject->updateDocument('memberships', $membership->getId(), $membership);
|
||||
} else {
|
||||
throw new Exception(Exception::MEMBERSHIP_ALREADY_CONFIRMED);
|
||||
@@ -863,7 +865,8 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject) {
|
||||
->inject('authorization')
|
||||
->action(function (string $teamId, array $queries, string $search, bool $includeTotal, Response $response, Document $project, Database $dbForProject, Authorization $authorization) {
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -933,7 +936,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true,
|
||||
];
|
||||
|
||||
$roles = Authorization::getRoles();
|
||||
$roles = $authorization->getRoles();
|
||||
$isPrivilegedUser = User::isPrivileged($roles);
|
||||
$isAppUser = User::isApp($roles);
|
||||
|
||||
@@ -1004,7 +1007,8 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject) {
|
||||
->inject('authorization')
|
||||
->action(function (string $teamId, string $membershipId, Response $response, Document $project, Database $dbForProject, Authorization $authorization) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
@@ -1024,7 +1028,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
||||
'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true,
|
||||
];
|
||||
|
||||
$roles = Authorization::getRoles();
|
||||
$roles = $authorization->getRoles();
|
||||
$isPrivilegedUser = User::isPrivileged($roles);
|
||||
$isAppUser = User::isApp($roles);
|
||||
|
||||
@@ -1103,8 +1107,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Authorization $authorization, Event $queueForEvents) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
if ($team->isEmpty()) {
|
||||
@@ -1121,9 +1126,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$isPrivilegedUser = User::isPrivileged(Authorization::getRoles());
|
||||
$isAppUser = User::isApp(Authorization::getRoles());
|
||||
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');
|
||||
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
|
||||
$isAppUser = User::isApp($authorization->getRoles());
|
||||
$isOwner = $authorization->hasRole('team:' . $team->getId() . '/owner');
|
||||
|
||||
if ($project->getId() === 'console') {
|
||||
// Quick check: fetch up to 2 owners to determine if only one exists
|
||||
@@ -1204,12 +1209,13 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('project')
|
||||
->inject('geodb')
|
||||
->inject('queueForEvents')
|
||||
->inject('store')
|
||||
->inject('proofForToken')
|
||||
->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Reader $geodb, Event $queueForEvents, Store $store, Token $proofForToken) {
|
||||
->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Authorization $authorization, $project, Reader $geodb, Event $queueForEvents, Store $store, Token $proofForToken) {
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
$membership = $dbForProject->getDocument('memberships', $membershipId);
|
||||
@@ -1218,7 +1224,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
throw new Exception(Exception::MEMBERSHIP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId));
|
||||
$team = $authorization->skip(fn () => $dbForProject->getDocument('teams', $teamId));
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
@@ -1254,11 +1260,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
->setAttribute('confirm', true)
|
||||
;
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true)));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true)));
|
||||
|
||||
// Create session for the user if not logged in
|
||||
if (!$hasSession) {
|
||||
Authorization::setRole(Role::user($user->getId())->toString());
|
||||
$authorization->addRole(Role::user($user->getId())->toString());
|
||||
|
||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||
$record = $geodb->get($request->getIP());
|
||||
@@ -1286,7 +1292,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
|
||||
$session = $dbForProject->createDocument('sessions', $session);
|
||||
|
||||
Authorization::setRole(Role::user($userId)->toString());
|
||||
$authorization->addRole(Role::user($userId)->toString());
|
||||
|
||||
$encoded = $store
|
||||
->setProperty('id', $user->getId())
|
||||
@@ -1324,7 +1330,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||
$authorization->skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
@@ -1368,8 +1374,9 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('authorization')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Authorization $authorization, Event $queueForEvents) {
|
||||
|
||||
$membership = $dbForProject->getDocument('memberships', $membershipId);
|
||||
|
||||
@@ -1427,7 +1434,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
||||
|
||||
if ($membership->getAttribute('confirm')) { // Count only confirmed members
|
||||
Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0));
|
||||
$authorization->skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0));
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
@@ -1458,14 +1465,13 @@ App::get('/v1/teams/:teamId/logs')
|
||||
]
|
||||
))
|
||||
->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 Types([Query::TYPE_LIMIT, Query::TYPE_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('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->action(function (string $teamId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
->action(function (string $teamId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
@@ -1479,12 +1485,9 @@ App::get('/v1/teams/:teamId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'team/' . $team->getId();
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -1531,7 +1534,7 @@ App::get('/v1/teams/:teamId/logs')
|
||||
}
|
||||
}
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
@@ -25,6 +25,7 @@ use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Identities;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Targets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Users;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
@@ -57,8 +58,6 @@ use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Email;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -939,14 +938,13 @@ App::get('/v1/users/:userId/logs')
|
||||
]
|
||||
))
|
||||
->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 Types([Query::TYPE_LIMIT, Query::TYPE_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('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->action(function (string $userId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
->action(function (string $userId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
@@ -959,11 +957,8 @@ App::get('/v1/users/:userId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), limit: $limit, offset: $offset);
|
||||
$audit = new Audit($dbForProject);
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), $queries);
|
||||
$output = [];
|
||||
foreach ($logs as $i => &$log) {
|
||||
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
@@ -1003,7 +998,7 @@ App::get('/v1/users/:userId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence()) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence(), $queries) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -2678,8 +2673,8 @@ App::get('/v1/users/usage')
|
||||
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('register')
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
->inject('authorization')
|
||||
->action(function (string $range, Response $response, Database $dbForProject, Authorization $authorization) {
|
||||
|
||||
$periods = Config::getParam('usage', []);
|
||||
$stats = $usage = [];
|
||||
@@ -2689,7 +2684,7 @@ App::get('/v1/users/usage')
|
||||
METRIC_SESSIONS,
|
||||
];
|
||||
|
||||
Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) {
|
||||
$authorization->skip(function () use ($dbForProject, $days, $metrics, &$stats) {
|
||||
foreach ($metrics as $count => $metric) {
|
||||
$result = $dbForProject->findOne('stats', [
|
||||
Query::equal('metric', [$metric]),
|
||||
|
||||
+33
-33
@@ -10,6 +10,7 @@ use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\MethodType;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Installations;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Types;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Vcs\Comment;
|
||||
@@ -30,10 +31,7 @@ use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Detector\Detection\Framework\Analog;
|
||||
use Utopia\Detector\Detection\Framework\Angular;
|
||||
use Utopia\Detector\Detection\Framework\Astro;
|
||||
@@ -76,7 +74,7 @@ use Utopia\VCS\Exception\RepositoryNotFound;
|
||||
|
||||
use function Swoole\Coroutine\batch;
|
||||
|
||||
$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForPlatform, Build $queueForBuilds, callable $getProjectDB, array $platform) {
|
||||
$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForPlatform, Authorization $authorization, Build $queueForBuilds, callable $getProjectDB, Request $request, array $platform) {
|
||||
$errors = [];
|
||||
foreach ($repositories as $repository) {
|
||||
try {
|
||||
@@ -87,12 +85,12 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
}
|
||||
|
||||
$projectId = $repository->getAttribute('projectId');
|
||||
$project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
|
||||
$project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
|
||||
$dbForProject = $getProjectDB($project);
|
||||
|
||||
$resourceCollection = $resourceType === "function" ? 'functions' : 'sites';
|
||||
$resourceId = $repository->getAttribute('resourceId');
|
||||
$resource = Authorization::skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId));
|
||||
$resource = $authorization->skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId));
|
||||
$resourceInternalId = $resource->getSequence();
|
||||
|
||||
$deploymentId = ID::unique();
|
||||
@@ -141,7 +139,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$latestCommentId = '';
|
||||
|
||||
if (!empty($providerPullRequestId) && $resource->getAttribute('providerSilentMode', false) === false) {
|
||||
$latestComment = Authorization::skip(fn () => $dbForPlatform->findOne('vcsComments', [
|
||||
$latestComment = $authorization->skip(fn () => $dbForPlatform->findOne('vcsComments', [
|
||||
Query::equal('providerRepositoryId', [$providerRepositoryId]),
|
||||
Query::equal('providerPullRequestId', [$providerPullRequestId]),
|
||||
Query::orderDesc('$createdAt'),
|
||||
@@ -180,7 +178,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
} finally {
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
$authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -191,7 +189,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
if (!empty($latestCommentId)) {
|
||||
$teamId = $project->getAttribute('teamId', '');
|
||||
|
||||
$latestComment = Authorization::skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([
|
||||
$latestComment = $authorization->skip(fn () => $dbForPlatform->createDocument('vcsComments', new Document([
|
||||
'$id' => ID::unique(),
|
||||
'$permissions' => [
|
||||
Permission::read(Role::team(ID::custom($teamId))),
|
||||
@@ -212,7 +210,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
}
|
||||
}
|
||||
} elseif (!empty($providerBranch)) {
|
||||
$latestComments = Authorization::skip(fn () => $dbForPlatform->find('vcsComments', [
|
||||
$latestComments = $authorization->skip(fn () => $dbForPlatform->find('vcsComments', [
|
||||
Query::equal('providerRepositoryId', [$providerRepositoryId]),
|
||||
Query::equal('providerBranch', [$providerBranch]),
|
||||
Query::orderDesc('$createdAt'),
|
||||
@@ -251,7 +249,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
} finally {
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
$authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,7 +292,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$commands[] = $resource->getAttribute('commands', '');
|
||||
}
|
||||
|
||||
$deployment = Authorization::skip(fn () => $dbForProject->createDocument('deployments', new Document([
|
||||
$deployment = $authorization->skip(fn () => $dbForProject->createDocument('deployments', new Document([
|
||||
'$id' => $deploymentId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
@@ -334,7 +332,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
->setAttribute('latestDeploymentInternalId', $deployment->getSequence())
|
||||
->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt())
|
||||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource));
|
||||
|
||||
if ($resource->getCollection() === 'sites') {
|
||||
$projectId = $project->getId();
|
||||
@@ -344,7 +342,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
$ruleId = md5($domain);
|
||||
$previewRuleId = $ruleId;
|
||||
Authorization::skip(
|
||||
$authorization->skip(
|
||||
fn () => $dbForPlatform->createDocument('rules', new Document([
|
||||
'$id' => $ruleId,
|
||||
'projectId' => $project->getId(),
|
||||
@@ -377,7 +375,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}";
|
||||
$ruleId = md5($domain);
|
||||
try {
|
||||
Authorization::skip(
|
||||
$authorization->skip(
|
||||
fn () => $dbForPlatform->createDocument('rules', new Document([
|
||||
'$id' => $ruleId,
|
||||
'projectId' => $project->getId(),
|
||||
@@ -408,7 +406,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$domain = "commit-" . substr($providerCommitHash, 0, 16) . ".{$sitesDomain}";
|
||||
$ruleId = md5($domain);
|
||||
try {
|
||||
Authorization::skip(
|
||||
$authorization->skip(
|
||||
fn () => $dbForPlatform->createDocument('rules', new Document([
|
||||
'$id' => $ruleId,
|
||||
'projectId' => $project->getId(),
|
||||
@@ -460,7 +458,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
if ($lockAcquired) {
|
||||
// Wrap in try/finally to ensure lock file gets deleted
|
||||
try {
|
||||
$rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId));
|
||||
$rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId));
|
||||
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$previewUrl = !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '';
|
||||
@@ -472,7 +470,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment());
|
||||
}
|
||||
} finally {
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
$authorization->skip(fn () => $dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1035,7 +1033,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
|
||||
->param('installationId', '', new Text(256), 'Installation Id')
|
||||
->param('type', '', new WhiteList(['runtime', 'framework']), 'Detector type. Must be one of the following: runtime, framework')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', 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)
|
||||
->param('queries', [], new Types([Query::TYPE_LIMIT, Query::TYPE_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('gitHub')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1476,11 +1474,12 @@ App::post('/v1/vcs/github/events')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->inject('authorization')
|
||||
->inject('getProjectDB')
|
||||
->inject('queueForBuilds')
|
||||
->inject('platform')
|
||||
->action(
|
||||
function (GitHub $github, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Build $queueForBuilds, array $platform) use ($createGitDeployments) {
|
||||
function (GitHub $github, Request $request, Response $response, Database $dbForPlatform, Authorization $authorization, callable $getProjectDB, Build $queueForBuilds, array $platform) use ($createGitDeployments) {
|
||||
$payload = $request->getRawPayload();
|
||||
$signatureRemote = $request->getHeader('x-hub-signature-256', '');
|
||||
$signatureLocal = System::getEnv('_APP_VCS_GITHUB_WEBHOOK_SECRET', '');
|
||||
@@ -1516,14 +1515,14 @@ App::post('/v1/vcs/github/events')
|
||||
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
|
||||
|
||||
//find resourceId from relevant resources table
|
||||
$repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [
|
||||
$repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [
|
||||
Query::equal('providerRepositoryId', [$providerRepositoryId]),
|
||||
Query::limit(100),
|
||||
]));
|
||||
|
||||
// create new deployment only on push (not committed by us) and not when branch is created or deleted
|
||||
if ($providerCommitAuthorEmail !== APP_VCS_GITHUB_EMAIL && !$providerBranchCreated && !$providerBranchDeleted) {
|
||||
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $queueForBuilds, $getProjectDB, $platform);
|
||||
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request, $platform);
|
||||
}
|
||||
} elseif ($event == $github::EVENT_INSTALLATION) {
|
||||
if ($parsedPayload["action"] == "deleted") {
|
||||
@@ -1536,16 +1535,16 @@ App::post('/v1/vcs/github/events')
|
||||
]);
|
||||
|
||||
foreach ($installations as $installation) {
|
||||
$repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [
|
||||
$repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [
|
||||
Query::equal('installationInternalId', [$installation->getSequence()]),
|
||||
Query::limit(1000)
|
||||
]));
|
||||
|
||||
foreach ($repositories as $repository) {
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId()));
|
||||
$authorization->skip(fn () => $dbForPlatform->deleteDocument('repositories', $repository->getId()));
|
||||
}
|
||||
|
||||
Authorization::skip(fn () => $dbForPlatform->deleteDocument('installations', $installation->getId()));
|
||||
$authorization->skip(fn () => $dbForPlatform->deleteDocument('installations', $installation->getId()));
|
||||
}
|
||||
}
|
||||
} elseif ($event == $github::EVENT_PULL_REQUEST) {
|
||||
@@ -1574,12 +1573,12 @@ App::post('/v1/vcs/github/events')
|
||||
$providerCommitAuthor = $commitDetails["commitAuthor"] ?? '';
|
||||
$providerCommitMessage = $commitDetails["commitMessage"] ?? '';
|
||||
|
||||
$repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [
|
||||
$repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [
|
||||
Query::equal('providerRepositoryId', [$providerRepositoryId]),
|
||||
Query::orderDesc('$createdAt')
|
||||
]));
|
||||
|
||||
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $queueForBuilds, $getProjectDB, $platform);
|
||||
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request, $platform);
|
||||
} elseif ($parsedPayload["action"] == "closed") {
|
||||
// Allowed external contributions cleanup
|
||||
|
||||
@@ -1588,7 +1587,7 @@ App::post('/v1/vcs/github/events')
|
||||
$external = $parsedPayload["external"] ?? true;
|
||||
|
||||
if ($external) {
|
||||
$repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [
|
||||
$repositories = $authorization->skip(fn () => $dbForPlatform->find('repositories', [
|
||||
Query::equal('providerRepositoryId', [$providerRepositoryId]),
|
||||
Query::orderDesc('$createdAt')
|
||||
]));
|
||||
@@ -1599,7 +1598,7 @@ App::post('/v1/vcs/github/events')
|
||||
if (\in_array($providerPullRequestId, $providerPullRequestIds)) {
|
||||
$providerPullRequestIds = \array_diff($providerPullRequestIds, [$providerPullRequestId]);
|
||||
$repository = $repository->setAttribute('providerPullRequestIds', $providerPullRequestIds);
|
||||
$repository = Authorization::skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository));
|
||||
$repository = $authorization->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1786,17 +1785,18 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForPlatform')
|
||||
->inject('authorization')
|
||||
->inject('getProjectDB')
|
||||
->inject('queueForBuilds')
|
||||
->inject('platform')
|
||||
->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Response $response, Document $project, Database $dbForPlatform, callable $getProjectDB, Build $queueForBuilds, array $platform) use ($createGitDeployments) {
|
||||
->action(function (string $installationId, string $repositoryId, string $providerPullRequestId, GitHub $github, Request $request, Response $response, Document $project, Database $dbForPlatform, Authorization $authorization, callable $getProjectDB, Build $queueForBuilds, array $platform) use ($createGitDeployments) {
|
||||
$installation = $dbForPlatform->getDocument('installations', $installationId);
|
||||
|
||||
if ($installation->isEmpty()) {
|
||||
throw new Exception(Exception::INSTALLATION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$repository = Authorization::skip(fn () => $dbForPlatform->findOne('repositories', [
|
||||
$repository = $authorization->skip(fn () => $dbForPlatform->findOne('repositories', [
|
||||
Query::equal('$id', [$repositoryId]),
|
||||
Query::equal('projectInternalId', [$project->getSequence()])
|
||||
]));
|
||||
@@ -1814,7 +1814,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor
|
||||
|
||||
// TODO: Delete from array when PR is closed
|
||||
|
||||
$repository = Authorization::skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository));
|
||||
$repository = $authorization->skip(fn () => $dbForPlatform->updateDocument('repositories', $repository->getId(), $repository));
|
||||
|
||||
$privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
|
||||
$githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID');
|
||||
@@ -1846,7 +1846,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor
|
||||
$providerCommitMessage = $pullRequestResponse['title'] ?? '';
|
||||
$providerCommitUrl = $pullRequestResponse['html_url'] ?? '';
|
||||
|
||||
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, true, $dbForPlatform, $queueForBuilds, $getProjectDB, $platform);
|
||||
$createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, '', '', '', '', $providerCommitHash, '', '', '', '', $providerPullRequestId, true, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $request, $platform);
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
+47
-37
@@ -59,7 +59,7 @@ Config::setParam('domainVerification', false);
|
||||
Config::setParam('cookieDomain', 'localhost');
|
||||
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
|
||||
|
||||
function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey)
|
||||
function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, Authorization $authorization, ?Key $apiKey)
|
||||
{
|
||||
$host = $request->getHostname() ?? '';
|
||||
if (!empty($previewHostname)) {
|
||||
@@ -67,16 +67,16 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
}
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$isMd5 = System::getEnv('_APP_RULES_FORMAT') === 'md5';
|
||||
$rule = Authorization::skip(function () use ($dbForPlatform, $host, $isMd5) {
|
||||
if ($isMd5) {
|
||||
return $dbForPlatform->getDocument('rules', md5($host));
|
||||
}
|
||||
|
||||
return $dbForPlatform->findOne('rules', [
|
||||
Query::equal('domain', [$host]),
|
||||
]) ?? new Document();
|
||||
});
|
||||
if (System::getEnv('_APP_RULES_FORMAT') === 'md5') {
|
||||
$rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', md5($host)));
|
||||
} else {
|
||||
$rule = $authorization->skip(
|
||||
fn () => $dbForPlatform->find('rules', [
|
||||
Query::equal('domain', [$host]),
|
||||
Query::limit(1)
|
||||
])
|
||||
)[0] ?? new Document();
|
||||
}
|
||||
|
||||
$errorView = __DIR__ . '/../views/general/error.phtml';
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
|
||||
@@ -111,7 +111,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
}
|
||||
|
||||
$projectId = $rule->getAttribute('projectId');
|
||||
$project = Authorization::skip(
|
||||
$project = $authorization->skip(
|
||||
fn () => $dbForPlatform->getDocument('projects', $projectId)
|
||||
);
|
||||
|
||||
@@ -119,7 +119,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
$accessedAt = $project->getAttribute('accessedAt', 0);
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) {
|
||||
$project->setAttribute('accessedAt', DateTime::now());
|
||||
Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project));
|
||||
$authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,7 +158,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
|
||||
/** @var Document $deployment */
|
||||
if (!empty($rule->getAttribute('deploymentId', ''))) {
|
||||
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId')));
|
||||
$deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId')));
|
||||
} else {
|
||||
// 1.6.x DB schema compatibility
|
||||
// TODO: Make sure deploymentId is never empty, and remove this code
|
||||
@@ -172,15 +172,15 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
|
||||
// Document of site or function
|
||||
$resource = $resourceType === 'function' ?
|
||||
Authorization::skip(fn () => $dbForProject->getDocument('functions', $resourceId)) :
|
||||
Authorization::skip(fn () => $dbForProject->getDocument('sites', $resourceId));
|
||||
$authorization->skip(fn () => $dbForProject->getDocument('functions', $resourceId)) :
|
||||
$authorization->skip(fn () => $dbForProject->getDocument('sites', $resourceId));
|
||||
|
||||
// ID of active deployments
|
||||
// Attempts to use attribute from both schemas (1.6 and 1.7)
|
||||
$activeDeploymentId = $resource->getAttribute('deploymentId', $resource->getAttribute('deployment', ''));
|
||||
|
||||
// Get deployment document, as intended originally
|
||||
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId));
|
||||
$deployment = $authorization->skip(fn () => $dbForProject->getDocument('deployments', $activeDeploymentId));
|
||||
}
|
||||
|
||||
if ($deployment->getAttribute('resourceType', '') === 'functions') {
|
||||
@@ -199,8 +199,8 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
}
|
||||
|
||||
$resource = $type === 'function' ?
|
||||
Authorization::skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) :
|
||||
Authorization::skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', '')));
|
||||
$authorization->skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) :
|
||||
$authorization->skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', '')));
|
||||
|
||||
$isPreview = $type === 'function' ? false : ($rule->getAttribute('trigger', '') !== 'manual');
|
||||
|
||||
@@ -242,7 +242,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
$userExists = false;
|
||||
$userId = $payload['userId'] ?? '';
|
||||
if (!empty($userId)) {
|
||||
$user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
$user = $authorization->skip(fn () => $dbForPlatform->getDocument('users', $userId));
|
||||
if (!$user->isEmpty() && $user->getAttribute('status', false)) {
|
||||
$userExists = true;
|
||||
}
|
||||
@@ -255,7 +255,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
}
|
||||
|
||||
$membershipExists = false;
|
||||
$project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
|
||||
$project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
|
||||
if (!$project->isEmpty() && isset($user)) {
|
||||
$teamId = $project->getAttribute('teamId', '');
|
||||
$membership = $user->find('teamId', $teamId, 'memberships');
|
||||
@@ -862,15 +862,16 @@ App::init()
|
||||
->inject('devKey')
|
||||
->inject('apiKey')
|
||||
->inject('cors')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Func $queueForFunctions, Executor $executor, array $platform, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, Cors $cors) {
|
||||
->inject('authorization')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Func $queueForFunctions, Executor $executor, array $platform, callable $isResourceBlocked, string $previewHostname, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization) {
|
||||
/*
|
||||
* Appwrite Router
|
||||
*/
|
||||
$hostname = $request->getHostname() ?? '';
|
||||
$platformHostnames = $platform['hostnames'] ?? [];
|
||||
// Only run Router when external domain
|
||||
if (!in_array($hostname, $platformHostnames) || !empty($previewHostname)) {
|
||||
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $apiKey)) {
|
||||
if (!\in_array($hostname, $platformHostnames) || !empty($previewHostname)) {
|
||||
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey)) {
|
||||
$utopia->getRoute()?->label('router', true);
|
||||
}
|
||||
}
|
||||
@@ -1033,7 +1034,8 @@ App::init()
|
||||
->inject('dbForPlatform')
|
||||
->inject('queueForCertificates')
|
||||
->inject('platform')
|
||||
->action(function (Request $request, Document $console, Database $dbForPlatform, Certificate $queueForCertificates, array $platform) {
|
||||
->inject('authorization')
|
||||
->action(function (Request $request, Document $console, Database $dbForPlatform, Certificate $queueForCertificates, array $platform, Authorization $authorization) {
|
||||
$hostname = $request->getHostname();
|
||||
$cache = Config::getParam('hostnames', []);
|
||||
$platformHostnames = $platform['hostnames'] ?? [];
|
||||
@@ -1048,20 +1050,23 @@ App::init()
|
||||
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
|
||||
$cache[$domain->get()] = false;
|
||||
Config::setParam('hostnames', $cache);
|
||||
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
||||
Console::warning('Skipping SSL certificates generation on ACME challenge.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Check if domain is a main domain
|
||||
if (!in_array($domain->get(), $platformHostnames)) {
|
||||
Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Check/create rule (requires DB access)
|
||||
Authorization::disable();
|
||||
$authorization->disable();
|
||||
try {
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$isMd5 = System::getEnv('_APP_RULES_FORMAT') === 'md5';
|
||||
@@ -1117,7 +1122,7 @@ App::init()
|
||||
} finally {
|
||||
$cache[$domain->get()] = true;
|
||||
Config::setParam('hostnames', $cache);
|
||||
Authorization::reset();
|
||||
$authorization->reset();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1141,7 +1146,8 @@ App::options()
|
||||
->inject('devKey')
|
||||
->inject('apiKey')
|
||||
->inject('cors')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey, Cors $cors) {
|
||||
->inject('authorization')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, Document $project, Document $devKey, ?Key $apiKey, Cors $cors, Authorization $authorization) {
|
||||
/*
|
||||
* Appwrite Router
|
||||
*/
|
||||
@@ -1182,7 +1188,8 @@ App::error()
|
||||
->inject('log')
|
||||
->inject('queueForStatsUsage')
|
||||
->inject('devKey')
|
||||
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage) {
|
||||
->inject('authorization')
|
||||
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage, Document $devKey, Authorization $authorization) {
|
||||
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
$route = $utopia->getRoute();
|
||||
$class = \get_class($error);
|
||||
@@ -1264,7 +1271,7 @@ App::error()
|
||||
* If not a publishable error, track usage stats. Publishable errors are >= 500 or those explicitly marked as publish=true in errors.php
|
||||
*/
|
||||
if (!$publish && $project->getId() !== 'console') {
|
||||
if (!DBUser::isPrivileged(Authorization::getRoles())) {
|
||||
if (!DBUser::isPrivileged($authorization->getRoles())) {
|
||||
$fileSize = 0;
|
||||
$file = $request->getFiles('file');
|
||||
if (!empty($file)) {
|
||||
@@ -1326,7 +1333,7 @@ App::error()
|
||||
$log->addExtra('file', $error->getFile());
|
||||
$log->addExtra('line', $error->getLine());
|
||||
$log->addExtra('trace', $error->getTraceAsString());
|
||||
$log->addExtra('roles', Authorization::getRoles());
|
||||
$log->addExtra('roles', $authorization->getRoles());
|
||||
|
||||
$action = 'UNKNOWN_NAMESPACE.UNKNOWN.METHOD';
|
||||
if (!empty($sdk)) {
|
||||
@@ -1450,13 +1457,14 @@ App::get('/robots.txt')
|
||||
->inject('platform')
|
||||
->inject('previewHostname')
|
||||
->inject('apiKey')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey) {
|
||||
->inject('authorization')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey, Authorization $authorization) {
|
||||
$platformHostnames = $platform['hostnames'] ?? [];
|
||||
if (in_array($request->getHostname(), $platformHostnames) || !empty($previewHostname)) {
|
||||
$template = new View(__DIR__ . '/../views/general/robots.phtml');
|
||||
$response->text($template->render(false));
|
||||
} else {
|
||||
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $apiKey)) {
|
||||
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey)) {
|
||||
$utopia->getRoute()?->label('router', true);
|
||||
}
|
||||
}
|
||||
@@ -1482,13 +1490,14 @@ App::get('/humans.txt')
|
||||
->inject('platform')
|
||||
->inject('previewHostname')
|
||||
->inject('apiKey')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey) {
|
||||
->inject('authorization')
|
||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, array $platform, string $previewHostname, ?Key $apiKey, Authorization $authorization) {
|
||||
$platformHostnames = $platform['hostnames'] ?? [];
|
||||
if (in_array($request->getHostname(), $platformHostnames) || !empty($previewHostname)) {
|
||||
$template = new View(__DIR__ . '/../views/general/humans.phtml');
|
||||
$response->text($template->render(false));
|
||||
} else {
|
||||
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $apiKey)) {
|
||||
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $log, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $platform, $previewHostname, $authorization, $apiKey)) {
|
||||
$utopia->getRoute()?->label('router', true);
|
||||
}
|
||||
}
|
||||
@@ -1572,7 +1581,8 @@ App::get('/v1/ping')
|
||||
->inject('project')
|
||||
->inject('dbForPlatform')
|
||||
->inject('queueForEvents')
|
||||
->action(function (Response $response, Document $project, Database $dbForPlatform, Event $queueForEvents) {
|
||||
->inject('authorization')
|
||||
->action(function (Response $response, Document $project, Database $dbForPlatform, Event $queueForEvents, Authorization $authorization) {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
|
||||
}
|
||||
@@ -1584,7 +1594,7 @@ App::get('/v1/ping')
|
||||
->setAttribute('pingCount', $pingCount)
|
||||
->setAttribute('pingedAt', $pingedAt);
|
||||
|
||||
Authorization::skip(function () use ($dbForPlatform, $project) {
|
||||
$authorization->skip(function () use ($dbForPlatform, $project) {
|
||||
$dbForPlatform->updateDocument('projects', $project->getId(), $project);
|
||||
});
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Authorization\Input;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Telemetry\Adapter as Telemetry;
|
||||
@@ -233,7 +234,8 @@ App::init()
|
||||
->inject('mode')
|
||||
->inject('team')
|
||||
->inject('apiKey')
|
||||
->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, User $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey) {
|
||||
->inject('authorization')
|
||||
->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey, Authorization $authorization) {
|
||||
$route = $utopia->getRoute();
|
||||
|
||||
/**
|
||||
@@ -318,7 +320,7 @@ App::init()
|
||||
// Handle special app role case
|
||||
if ($apiKey->getRole() === User::ROLE_APPS) {
|
||||
// Disable authorization checks for API keys
|
||||
Authorization::setDefaultStatus(false);
|
||||
$authorization->setDefaultStatus(false);
|
||||
|
||||
$user = new User([
|
||||
'$id' => '',
|
||||
@@ -392,14 +394,14 @@ App::init()
|
||||
$scopes = \array_merge($scopes, $roles[$role]['scopes']);
|
||||
}
|
||||
|
||||
Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
|
||||
$authorization->setDefaultStatus(false); // Cancel security segmentation for admin users.
|
||||
}
|
||||
|
||||
$scopes = \array_unique($scopes);
|
||||
|
||||
Authorization::setRole($role);
|
||||
foreach ($user->getRoles() as $authRole) {
|
||||
Authorization::setRole($authRole);
|
||||
$authorization->addRole($role);
|
||||
foreach ($user->getRoles($authorization) as $authRole) {
|
||||
$authorization->addRole($authRole);
|
||||
}
|
||||
|
||||
// Step 6: Update project and user last activity
|
||||
@@ -407,7 +409,7 @@ App::init()
|
||||
$accessedAt = $project->getAttribute('accessedAt', 0);
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) {
|
||||
$project->setAttribute('accessedAt', DateTime::now());
|
||||
Authorization::skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project));
|
||||
$authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $project));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +444,7 @@ App::init()
|
||||
if (
|
||||
array_key_exists($namespace, $project->getAttribute('services', []))
|
||||
&& !$project->getAttribute('services', [])[$namespace]
|
||||
&& !(User::isPrivileged(Authorization::getRoles()) || User::isApp(Authorization::getRoles()))
|
||||
&& !(User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
|
||||
) {
|
||||
throw new Exception(Exception::GENERAL_SERVICE_DISABLED);
|
||||
}
|
||||
@@ -509,14 +511,15 @@ App::init()
|
||||
->inject('devKey')
|
||||
->inject('telemetry')
|
||||
->inject('platform')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Publisher $publisherFunctions, Publisher $publisherWebhooks, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Mail $queueForMails, Migration $queueForMigrations, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform) use ($usageDatabaseListener, $eventDatabaseListener) {
|
||||
->inject('authorization')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Publisher $publisherFunctions, Publisher $publisherWebhooks, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Mail $queueForMails, Migration $queueForMigrations, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform, Authorization $authorization) use ($usageDatabaseListener, $eventDatabaseListener) {
|
||||
|
||||
$route = $utopia->getRoute();
|
||||
|
||||
if (
|
||||
array_key_exists('rest', $project->getAttribute('apis', []))
|
||||
&& !$project->getAttribute('apis', [])['rest']
|
||||
&& !(User::isPrivileged(Authorization::getRoles()) || User::isApp(Authorization::getRoles()))
|
||||
&& !(User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
|
||||
) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
|
||||
}
|
||||
@@ -546,7 +549,7 @@ App::init()
|
||||
|
||||
$closestLimit = null;
|
||||
|
||||
$roles = Authorization::getRoles();
|
||||
$roles = $authorization->getRoles();
|
||||
$isPrivilegedUser = User::isPrivileged($roles);
|
||||
$isAppUser = User::isApp($roles);
|
||||
|
||||
@@ -657,10 +660,10 @@ App::init()
|
||||
if ($useCache) {
|
||||
$route = $utopia->match($request);
|
||||
$isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview';
|
||||
$isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !User::isPrivileged(Authorization::getRoles());
|
||||
$isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !User::isPrivileged($authorization->getRoles());
|
||||
|
||||
$key = $request->cacheIdentifier();
|
||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$cacheLog = $authorization->skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
|
||||
);
|
||||
@@ -677,10 +680,10 @@ App::init()
|
||||
|
||||
if ($type === 'bucket' && (!$isImageTransformation || !$isDisabled)) {
|
||||
$bucketId = $parts[1] ?? null;
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
$bucket = $authorization->skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence();
|
||||
$isPrivilegedUser = User::isPrivileged(Authorization::getRoles());
|
||||
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
@@ -691,8 +694,7 @@ App::init()
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
$valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()));
|
||||
if (!$fileSecurity && !$valid && !$isToken) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
@@ -703,7 +705,7 @@ App::init()
|
||||
if ($fileSecurity && !$valid && !$isToken) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
|
||||
$file = $authorization->skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
|
||||
}
|
||||
|
||||
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) {
|
||||
@@ -714,11 +716,11 @@ App::init()
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
//Do not update transformedAt if it's a console user
|
||||
if (!User::isPrivileged(Authorization::getRoles())) {
|
||||
if (!User::isPrivileged($authorization->getRoles())) {
|
||||
$transformedAt = $file->getAttribute('transformedAt', '');
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
|
||||
$file->setAttribute('transformedAt', DateTime::now());
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,7 +816,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('authorization')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization) use ($parseLabel) {
|
||||
|
||||
$responsePayload = $response->getPayload();
|
||||
|
||||
@@ -940,11 +943,11 @@ App::shutdown()
|
||||
|
||||
$key = $request->cacheIdentifier();
|
||||
$signature = md5($data['payload']);
|
||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$cacheLog = $authorization->skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$accessedAt = $cacheLog->getAttribute('accessedAt', 0);
|
||||
$now = DateTime::now();
|
||||
if ($cacheLog->isEmpty()) {
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
|
||||
$authorization->skip(fn () => $dbForProject->createDocument('cache', new Document([
|
||||
'$id' => $key,
|
||||
'resource' => $resource,
|
||||
'resourceType' => $resourceType,
|
||||
@@ -954,7 +957,7 @@ App::shutdown()
|
||||
])));
|
||||
} elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
|
||||
$cacheLog->setAttribute('accessedAt', $now);
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('cache', $cacheLog->getId(), $cacheLog));
|
||||
// Overwrite the file every APP_CACHE_UPDATE seconds to update the file modified time that is used in the TTL checks in cache->load()
|
||||
$cache->save($key, $data['payload']);
|
||||
}
|
||||
@@ -966,7 +969,7 @@ App::shutdown()
|
||||
}
|
||||
|
||||
if ($project->getId() !== 'console') {
|
||||
if (!User::isPrivileged(Authorization::getRoles())) {
|
||||
if (!User::isPrivileged($authorization->getRoles())) {
|
||||
$fileSize = 0;
|
||||
$file = $request->getFiles('file');
|
||||
if (!empty($file)) {
|
||||
|
||||
@@ -36,7 +36,8 @@ App::init()
|
||||
->inject('request')
|
||||
->inject('project')
|
||||
->inject('geodb')
|
||||
->action(function (App $utopia, Request $request, Document $project, Reader $geodb) {
|
||||
->inject('authorization')
|
||||
->action(function (App $utopia, Request $request, Document $project, Reader $geodb, Authorization $authorization) {
|
||||
$denylist = System::getEnv('_APP_CONSOLE_COUNTRIES_DENYLIST', '');
|
||||
if (!empty($denylist && $project->getId() === 'console')) {
|
||||
$countries = explode(',', $denylist);
|
||||
@@ -49,8 +50,8 @@ App::init()
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
$isPrivilegedUser = User::isPrivileged(Authorization::getRoles());
|
||||
$isAppUser = User::isApp(Authorization::getRoles());
|
||||
$isPrivilegedUser = User::isPrivileged($authorization->getRoles());
|
||||
$isAppUser = User::isApp($authorization->getRoles());
|
||||
|
||||
if ($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
|
||||
App::init()
|
||||
->groups(['web'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (Request $request, Response $response) {
|
||||
$response
|
||||
->addHeader('X-Frame-Options', 'SAMEORIGIN') // Avoid console and homepage from showing in iframes
|
||||
->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url=' . \urlencode($request->getURI()))
|
||||
->addHeader('X-UA-Compatible', 'IE=Edge') // Deny IE browsers from going into quirks mode
|
||||
;
|
||||
});
|
||||
|
||||
App::get('/')
|
||||
->alias('auth/*')
|
||||
->alias('/invite')
|
||||
->alias('/login')
|
||||
->alias('/mfa')
|
||||
->alias('/card/*')
|
||||
->alias('/recover')
|
||||
->alias('/register/*')
|
||||
->groups(['web'])
|
||||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (Request $request, Response $response) {
|
||||
$url = parse_url($request->getURI());
|
||||
$target = "/console{$url['path']}";
|
||||
$params = $request->getParams();
|
||||
if (!empty($params)) {
|
||||
$target .= "?" . \http_build_query($params);
|
||||
}
|
||||
if ($url['fragment'] ?? false) {
|
||||
$target .= "#{$url['fragment']}";
|
||||
}
|
||||
$response->redirect($target);
|
||||
});
|
||||
+21
-19
@@ -12,8 +12,6 @@ use Swoole\Process;
|
||||
use Swoole\Table;
|
||||
use Swoole\Timer;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Adapter\Database as AdapterDatabase;
|
||||
use Utopia\Audit\Adapter\SQL as AuditAdapterSQL;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Compression\Compression;
|
||||
@@ -27,7 +25,6 @@ use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Utopia\Pools\Group;
|
||||
@@ -261,10 +258,11 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
createDatabase($app, 'getLogsDB', 'logs', $collections['logs'], $pools);
|
||||
|
||||
// create appwrite database, `dbForPlatform` is a direct access call.
|
||||
createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections) {
|
||||
if ($dbForPlatform->getCollection(AuditAdapterSQL::COLLECTION)->isEmpty()) {
|
||||
$adapter = new AdapterDatabase($dbForPlatform);
|
||||
$audit = new Audit($adapter);
|
||||
createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections, $app) {
|
||||
$authorization = $app->getResource('authorization');
|
||||
|
||||
if ($dbForPlatform->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
$audit = new Audit($dbForPlatform);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
@@ -321,9 +319,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
$dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes);
|
||||
}
|
||||
|
||||
if (Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) {
|
||||
if ($authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) {
|
||||
Console::info(" └── Creating screenshots bucket...");
|
||||
Authorization::skip(fn () => $dbForPlatform->createDocument('buckets', new Document([
|
||||
$authorization->skip(fn () => $dbForPlatform->createDocument('buckets', new Document([
|
||||
'$id' => ID::custom('screenshots'),
|
||||
'$collection' => ID::custom('buckets'),
|
||||
'name' => 'Screenshots',
|
||||
@@ -338,7 +336,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
'search' => 'buckets Screenshots',
|
||||
])));
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots'));
|
||||
$bucket = $authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots'));
|
||||
|
||||
Console::info(" └── Creating files collection for screenshots bucket...");
|
||||
$files = $collections['buckets']['files'] ?? [];
|
||||
@@ -366,7 +364,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
'orders' => $index['orders'],
|
||||
]), $files['indexes']);
|
||||
|
||||
Authorization::skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes));
|
||||
$authorization->skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -392,9 +390,8 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
Console::success('[Setup] - Skip: metadata table already exists');
|
||||
}
|
||||
|
||||
if ($dbForProject->getCollection(AuditAdapterSQL::COLLECTION)->isEmpty()) {
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
$audit = new Audit($adapter);
|
||||
if ($dbForProject->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
$audit = new Audit($dbForProject);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
@@ -458,8 +455,12 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool
|
||||
App::setResource('pools', fn () => $pools);
|
||||
|
||||
try {
|
||||
Authorization::cleanRoles();
|
||||
Authorization::setRole(Role::any()->toString());
|
||||
$authorization = $app->getResource('authorization');
|
||||
|
||||
$request->setAuthorization($authorization);
|
||||
$response->setAuthorization($authorization);
|
||||
$authorization->cleanRoles();
|
||||
$authorization->addRole(Role::any()->toString());
|
||||
|
||||
$app->run($request, $response);
|
||||
} catch (\Throwable $th) {
|
||||
@@ -501,7 +502,7 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool
|
||||
$log->addExtra('file', $th->getFile());
|
||||
$log->addExtra('line', $th->getLine());
|
||||
$log->addExtra('trace', $th->getTraceAsString());
|
||||
$log->addExtra('roles', Authorization::getRoles());
|
||||
$log->addExtra('roles', isset($authorization) ? $authorization->getRoles() : []);
|
||||
|
||||
$sdk = $route->getLabel("sdk", false);
|
||||
|
||||
@@ -560,7 +561,7 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) {
|
||||
/** @var Utopia\Database\Database $dbForPlatform */
|
||||
$dbForPlatform = $app->getResource('dbForPlatform');
|
||||
|
||||
Timer::tick(DOMAIN_SYNC_TIMER * 1000, function () use ($dbForPlatform, $domains, &$lastSyncUpdate) {
|
||||
Timer::tick(DOMAIN_SYNC_TIMER * 1000, function () use ($dbForPlatform, $domains, &$lastSyncUpdate, $app) {
|
||||
try {
|
||||
$time = DateTime::now();
|
||||
$limit = 1000;
|
||||
@@ -577,7 +578,8 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) {
|
||||
}
|
||||
$results = [];
|
||||
try {
|
||||
$results = Authorization::skip(fn () => $dbForPlatform->find('rules', $queries));
|
||||
$authorization = $app->getResource('authorization');
|
||||
$results = $authorization->skip(fn () => $dbForPlatform->find('rules', $queries));
|
||||
} catch (Throwable $th) {
|
||||
Console::error($th->getMessage());
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ use Appwrite\OpenSSL\OpenSSL;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\System\System;
|
||||
|
||||
Database::addFilter(
|
||||
@@ -70,11 +69,11 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
$attributes = $database->find('attributes', [
|
||||
$attributes = $database->getAuthorization()->skip(fn () => $database->find('attributes', [
|
||||
Query::equal('collectionInternalId', [$document->getSequence()]),
|
||||
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
|
||||
Query::limit($database->getLimitForAttributes()),
|
||||
]);
|
||||
]));
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$attributeType = $attribute->getAttribute('type');
|
||||
@@ -105,12 +104,12 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('indexes', [
|
||||
Query::equal('collectionInternalId', [$document->getSequence()]),
|
||||
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
|
||||
Query::limit($database->getLimitForIndexes()),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -120,11 +119,11 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('platforms', [
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -134,17 +133,11 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('keys', [
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$document->getSequence()]),
|
||||
])
|
||||
]),
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -154,11 +147,11 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('devKeys', [
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -168,11 +161,11 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('webhooks', [
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -182,7 +175,7 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn () => $database->find('sessions', [
|
||||
return $database->getAuthorization()->skip(fn () => $database->find('sessions', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]));
|
||||
@@ -195,7 +188,7 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn () => $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('tokens', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -209,7 +202,7 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn () => $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('challenges', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -223,7 +216,7 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn () => $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('authenticators', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -237,7 +230,7 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn () => $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('memberships', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -257,14 +250,14 @@ Database::addFilter(
|
||||
default => ['function', 'site']
|
||||
};
|
||||
|
||||
return $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('variables', [
|
||||
Query::equal('resourceInternalId', [$document->getSequence()]),
|
||||
Query::equal('resourceType', $resourceType),
|
||||
Query::orderAsc('resourceType'),
|
||||
Query::orderAsc(),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -300,11 +293,11 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('variables', [
|
||||
Query::equal('resourceType', ['project']),
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
]);
|
||||
]));
|
||||
}
|
||||
);
|
||||
|
||||
@@ -337,7 +330,7 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn () => $database
|
||||
return $database->getAuthorization()->skip(fn () => $database
|
||||
->find('targets', [
|
||||
Query::equal('userInternalId', [$document->getSequence()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
@@ -351,7 +344,7 @@ Database::addFilter(
|
||||
return;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
$targetIds = Authorization::skip(fn () => \array_map(
|
||||
$targetIds = $database->getAuthorization()->skip(fn () => \array_map(
|
||||
fn ($document) => $document->getAttribute('targetInternalId'),
|
||||
$database->find('subscribers', [
|
||||
Query::equal('topicInternalId', [$document->getSequence()]),
|
||||
|
||||
+60
-58
@@ -4,7 +4,7 @@ use Ahc\Jwt\JWT;
|
||||
use Ahc\Jwt\JWTException;
|
||||
use Appwrite\Auth\Key;
|
||||
use Appwrite\Databases\TransactionState;
|
||||
use Appwrite\Event\Audit as AuditEvent;
|
||||
use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
@@ -30,8 +30,6 @@ use Appwrite\Utopia\Response;
|
||||
use Executor\Executor;
|
||||
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Adapter\Database as AdapterDatabase;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Auth\Hashes\Argon2;
|
||||
use Utopia\Auth\Hashes\Sha;
|
||||
use Utopia\Auth\Proofs\Code;
|
||||
@@ -148,7 +146,7 @@ App::setResource('queueForStatsUsage', function (Publisher $publisher) {
|
||||
return new StatsUsage($publisher);
|
||||
}, ['publisher']);
|
||||
App::setResource('queueForAudits', function (Publisher $publisher) {
|
||||
return new AuditEvent($publisher);
|
||||
return new Audit($publisher);
|
||||
}, ['publisher']);
|
||||
App::setResource('queueForFunctions', function (Publisher $publisher) {
|
||||
return new Func($publisher);
|
||||
@@ -226,7 +224,7 @@ App::setResource('allowedSchemes', function (Document $project) {
|
||||
/**
|
||||
* Rule associated with a request origin.
|
||||
*/
|
||||
App::setResource('rule', function (Request $request, Database $dbForPlatform, Document $project) {
|
||||
App::setResource('rule', function (Request $request, Database $dbForPlatform, Document $project, Authorization $authorization) {
|
||||
$domain = \parse_url($request->getOrigin(), PHP_URL_HOST);
|
||||
if (empty($domain)) {
|
||||
return new Document();
|
||||
@@ -234,7 +232,7 @@ App::setResource('rule', function (Request $request, Database $dbForPlatform, Do
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$isMd5 = System::getEnv('_APP_RULES_FORMAT') === 'md5';
|
||||
$rule = Authorization::skip(function () use ($dbForPlatform, $domain, $isMd5) {
|
||||
$rule = $authorization->skip(function () use ($dbForPlatform, $domain, $isMd5) {
|
||||
if ($isMd5) {
|
||||
return $dbForPlatform->getDocument('rules', md5($domain));
|
||||
}
|
||||
@@ -249,7 +247,7 @@ App::setResource('rule', function (Request $request, Database $dbForPlatform, Do
|
||||
}
|
||||
|
||||
return $rule;
|
||||
}, ['request', 'dbForPlatform', 'project']);
|
||||
}, ['request', 'dbForPlatform', 'project', 'authorization']);
|
||||
|
||||
/**
|
||||
* CORS service
|
||||
@@ -277,7 +275,6 @@ App::setResource('cors', fn (array $allowedHostnames) => new Cors(
|
||||
'X-Appwrite-ID',
|
||||
'X-Appwrite-Timestamp',
|
||||
'X-Appwrite-Session',
|
||||
'X-Appwrite-Platform', // for `$platform` injection and SDK generator
|
||||
// SDK generator
|
||||
'X-SDK-Version',
|
||||
'X-SDK-Name',
|
||||
@@ -317,7 +314,7 @@ App::setResource('redirectValidator', function (Document $devKey, array $allowed
|
||||
return new Redirect($allowedHostnames, $allowedSchemes);
|
||||
}, ['devKey', 'allowedHostnames', 'allowedSchemes']);
|
||||
|
||||
App::setResource('user', function (string $mode, Document $project, Document $console, Request $request, Response $response, Database $dbForProject, Database $dbForPlatform, Store $store, Token $proofForToken) {
|
||||
App::setResource('user', function (string $mode, Document $project, Document $console, Request $request, Response $response, Database $dbForProject, Database $dbForPlatform, Store $store, Token $proofForToken, $authorization) {
|
||||
/**
|
||||
* Handles user authentication and session validation.
|
||||
*
|
||||
@@ -337,7 +334,7 @@ App::setResource('user', function (string $mode, Document $project, Document $co
|
||||
* overwriting the previous value.
|
||||
*/
|
||||
|
||||
Authorization::setDefaultStatus(true);
|
||||
$authorization->setDefaultStatus(true);
|
||||
|
||||
$store->setKey('a_session_' . $project->getId());
|
||||
|
||||
@@ -404,7 +401,7 @@ App::setResource('user', function (string $mode, Document $project, Document $co
|
||||
}
|
||||
// if (APP_MODE_ADMIN === $mode) {
|
||||
// if ($user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships')) {
|
||||
// Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
|
||||
// $authorization->setDefaultStatus(false); // Cancel security segmentation for admin users.
|
||||
// } else {
|
||||
// $user = new Document([]);
|
||||
// }
|
||||
@@ -436,9 +433,9 @@ App::setResource('user', function (string $mode, Document $project, Document $co
|
||||
$dbForPlatform->setMetadata('user', $user->getId());
|
||||
|
||||
return $user;
|
||||
}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForPlatform', 'store', 'proofForToken']);
|
||||
}, ['mode', 'project', 'console', 'request', 'response', 'dbForProject', 'dbForPlatform', 'store', 'proofForToken', 'authorization']);
|
||||
|
||||
App::setResource('project', function ($dbForPlatform, $request, $console) {
|
||||
App::setResource('project', function ($dbForPlatform, $request, $console, $authorization) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Utopia\Database\Database $dbForPlatform */
|
||||
/** @var Utopia\Database\Document $console */
|
||||
@@ -449,10 +446,10 @@ App::setResource('project', function ($dbForPlatform, $request, $console) {
|
||||
return $console;
|
||||
}
|
||||
|
||||
$project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
|
||||
$project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
|
||||
|
||||
return $project;
|
||||
}, ['dbForPlatform', 'request', 'console']);
|
||||
}, ['dbForPlatform', 'request', 'console', 'authorization']);
|
||||
|
||||
App::setResource('session', function (User $user, Store $store, Token $proofForToken) {
|
||||
if ($user->isEmpty()) {
|
||||
@@ -475,10 +472,6 @@ App::setResource('session', function (User $user, Store $store, Token $proofForT
|
||||
return;
|
||||
}, ['user', 'store', 'proofForToken']);
|
||||
|
||||
App::setResource('console', function () {
|
||||
return new Document(Config::getParam('console'));
|
||||
}, []);
|
||||
|
||||
App::setResource('store', function (): Store {
|
||||
return new Store();
|
||||
});
|
||||
@@ -509,7 +502,15 @@ App::setResource('proofForCode', function (): Code {
|
||||
return $code;
|
||||
});
|
||||
|
||||
App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform, Cache $cache, Document $project) {
|
||||
App::setResource('console', function () {
|
||||
return new Document(Config::getParam('console'));
|
||||
}, []);
|
||||
|
||||
App::setResource('authorization', function () {
|
||||
return new Authorization();
|
||||
}, []);
|
||||
|
||||
App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform, Cache $cache, Document $project, Authorization $authorization) {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return $dbForPlatform;
|
||||
}
|
||||
@@ -525,6 +526,7 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId())
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API)
|
||||
@@ -546,13 +548,15 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform
|
||||
}
|
||||
|
||||
return $database;
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'project']);
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'project', 'authorization']);
|
||||
|
||||
App::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authorization $authorization) {
|
||||
|
||||
App::setResource('dbForPlatform', function (Group $pools, Cache $cache) {
|
||||
$adapter = new DatabasePool($pools->get('console'));
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setNamespace('_console')
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', 'console')
|
||||
@@ -562,12 +566,12 @@ App::setResource('dbForPlatform', function (Group $pools, Cache $cache) {
|
||||
$database->setDocumentType('users', User::class);
|
||||
|
||||
return $database;
|
||||
}, ['pools', 'cache']);
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
|
||||
App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) {
|
||||
App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, Authorization $authorization) {
|
||||
$databases = [];
|
||||
|
||||
return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases) {
|
||||
return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases) {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return $dbForPlatform;
|
||||
}
|
||||
@@ -579,13 +583,15 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
|
||||
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
|
||||
}
|
||||
|
||||
$configure = (function (Database $database) use ($project, $dsn) {
|
||||
$configure = (function (Database $database) use ($project, $dsn, $authorization) {
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId())
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API)
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
|
||||
$database->setDocumentType('users', User::class);
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES)
|
||||
->setDocumentType('users', User::class)
|
||||
;
|
||||
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
|
||||
@@ -615,12 +621,12 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'dbForPlatform', 'cache']);
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'authorization']);
|
||||
|
||||
App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
App::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) {
|
||||
$database = null;
|
||||
|
||||
return function (?Document $project = null) use ($pools, $cache, &$database) {
|
||||
return function (?Document $project = null) use ($pools, $cache, $authorization, &$database) {
|
||||
if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
|
||||
$database->setTenant((int) $project->getSequence());
|
||||
return $database;
|
||||
@@ -630,6 +636,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setSharedTables(true)
|
||||
->setNamespace('logsV1')
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API)
|
||||
@@ -642,12 +649,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'cache']);
|
||||
|
||||
App::setResource('audit', function ($dbForProject) {
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
return new Audit($adapter);
|
||||
}, ['dbForProject']);
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
|
||||
App::setResource('telemetry', fn () => new NoTelemetry());
|
||||
|
||||
@@ -841,7 +843,7 @@ App::setResource('promiseAdapter', function ($register) {
|
||||
return $register->get('promiseAdapter');
|
||||
}, ['register']);
|
||||
|
||||
App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
App::setResource('schema', function ($utopia, $dbForProject, $authorization) {
|
||||
|
||||
$complexity = function (int $complexity, array $args) {
|
||||
$queries = Query::parseQueries($args['queries'] ?? []);
|
||||
@@ -851,8 +853,8 @@ App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
return $complexity * $limit;
|
||||
};
|
||||
|
||||
$attributes = function (int $limit, int $offset) use ($dbForProject) {
|
||||
$attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [
|
||||
$attributes = function (int $limit, int $offset) use ($dbForProject, $authorization) {
|
||||
$attrs = $authorization->skip(fn () => $dbForProject->find('attributes', [
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
]));
|
||||
@@ -926,7 +928,7 @@ App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
$urls,
|
||||
$params,
|
||||
);
|
||||
}, ['utopia', 'dbForProject']);
|
||||
}, ['utopia', 'dbForProject', 'authorization']);
|
||||
|
||||
App::setResource('gitHub', function (Cache $cache) {
|
||||
return new VcsGitHub($cache);
|
||||
@@ -954,7 +956,7 @@ App::setResource('smsRates', function () {
|
||||
return [];
|
||||
});
|
||||
|
||||
App::setResource('devKey', function (Request $request, Document $project, array $servers, Database $dbForPlatform) {
|
||||
App::setResource('devKey', function (Request $request, Document $project, array $servers, Database $dbForPlatform, Authorization $authorization) {
|
||||
$devKey = $request->getHeader('x-appwrite-dev-key', $request->getParam('devKey', ''));
|
||||
|
||||
// Check if given key match project's development keys
|
||||
@@ -973,7 +975,7 @@ App::setResource('devKey', function (Request $request, Document $project, array
|
||||
$accessedAt = $key->getAttribute('accessedAt', 0);
|
||||
if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) {
|
||||
$key->setAttribute('accessedAt', DatabaseDateTime::now());
|
||||
Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key));
|
||||
$authorization->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key));
|
||||
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
|
||||
}
|
||||
|
||||
@@ -990,15 +992,15 @@ App::setResource('devKey', function (Request $request, Document $project, array
|
||||
|
||||
/** Update access time as well */
|
||||
$key->setAttribute('accessedAt', DatabaseDateTime::now());
|
||||
$key = Authorization::skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key));
|
||||
$key = $authorization->skip(fn () => $dbForPlatform->updateDocument('devKeys', $key->getId(), $key));
|
||||
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
|
||||
}
|
||||
}
|
||||
|
||||
return $key;
|
||||
}, ['request', 'project', 'servers', 'dbForPlatform']);
|
||||
}, ['request', 'project', 'servers', 'dbForPlatform', 'authorization']);
|
||||
|
||||
App::setResource('team', function (Document $project, Database $dbForPlatform, App $utopia, Request $request) {
|
||||
App::setResource('team', function (Document $project, Database $dbForPlatform, App $utopia, Request $request, Authorization $authorization) {
|
||||
$teamInternalId = '';
|
||||
if ($project->getId() !== 'console') {
|
||||
$teamInternalId = $project->getAttribute('teamInternalId', '');
|
||||
@@ -1008,7 +1010,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A
|
||||
if (str_starts_with($path, '/v1/projects/:projectId')) {
|
||||
$uri = $request->getURI();
|
||||
$pid = explode('/', $uri)[3];
|
||||
$p = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $pid));
|
||||
$p = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $pid));
|
||||
$teamInternalId = $p->getAttribute('teamInternalId', '');
|
||||
} elseif ($path === '/v1/projects') {
|
||||
$teamId = $request->getParam('teamId', '');
|
||||
@@ -1017,7 +1019,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A
|
||||
return new Document([]);
|
||||
}
|
||||
|
||||
$team = Authorization::skip(fn () => $dbForPlatform->getDocument('teams', $teamId));
|
||||
$team = $authorization->skip(fn () => $dbForPlatform->getDocument('teams', $teamId));
|
||||
return $team;
|
||||
}
|
||||
}
|
||||
@@ -1026,14 +1028,14 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A
|
||||
return new Document([]);
|
||||
}
|
||||
|
||||
$team = Authorization::skip(function () use ($dbForPlatform, $teamInternalId) {
|
||||
$team = $authorization->skip(function () use ($dbForPlatform, $teamInternalId) {
|
||||
return $dbForPlatform->findOne('teams', [
|
||||
Query::equal('$sequence', [$teamInternalId]),
|
||||
]);
|
||||
});
|
||||
|
||||
return $team;
|
||||
}, ['project', 'dbForPlatform', 'utopia', 'request']);
|
||||
}, ['project', 'dbForPlatform', 'utopia', 'request', 'authorization']);
|
||||
|
||||
App::setResource(
|
||||
'isResourceBlocked',
|
||||
@@ -1071,7 +1073,7 @@ App::setResource('apiKey', function (Request $request, Document $project): ?Key
|
||||
|
||||
App::setResource('executor', fn () => new Executor());
|
||||
|
||||
App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
||||
App::setResource('resourceToken', function ($project, $dbForProject, $request, Authorization $authorization) {
|
||||
$tokenJWT = $request->getParam('token');
|
||||
|
||||
if (!empty($tokenJWT) && !$project->isEmpty()) { // JWT authentication
|
||||
@@ -1089,7 +1091,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
||||
return new Document([]);
|
||||
}
|
||||
|
||||
$token = Authorization::skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId));
|
||||
$token = $authorization->skip(fn () => $dbForProject->getDocument('resourceTokens', $tokenId));
|
||||
|
||||
if ($token->isEmpty()) {
|
||||
return new Document([]);
|
||||
@@ -1107,7 +1109,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
||||
}
|
||||
|
||||
return match ($token->getAttribute('resourceType')) {
|
||||
TOKENS_RESOURCE_TYPE_FILES => (function () use ($token, $dbForProject) {
|
||||
TOKENS_RESOURCE_TYPE_FILES => (function () use ($token, $dbForProject, $authorization) {
|
||||
$sequences = explode(':', $token->getAttribute('resourceInternalId'));
|
||||
$ids = explode(':', $token->getAttribute('resourceId'));
|
||||
|
||||
@@ -1118,7 +1120,7 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
||||
$accessedAt = $token->getAttribute('accessedAt', 0);
|
||||
if (empty($accessedAt) || DatabaseDateTime::formatTz(DatabaseDateTime::addSeconds(new \DateTime(), -APP_RESOURCE_TOKEN_ACCESS)) > $accessedAt) {
|
||||
$token->setAttribute('accessedAt', DatabaseDateTime::now());
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token));
|
||||
$authorization->skip(fn () => $dbForProject->updateDocument('resourceTokens', $token->getId(), $token));
|
||||
}
|
||||
|
||||
return new Document([
|
||||
@@ -1133,8 +1135,8 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
||||
};
|
||||
}
|
||||
return new Document([]);
|
||||
}, ['project', 'dbForProject', 'request']);
|
||||
}, ['project', 'dbForProject', 'request', 'authorization']);
|
||||
|
||||
App::setResource('transactionState', function (Database $dbForProject) {
|
||||
return new TransactionState($dbForProject);
|
||||
}, ['dbForProject']);
|
||||
App::setResource('transactionState', function (Database $dbForProject, Authorization $authorization) {
|
||||
return new TransactionState($dbForProject, $authorization);
|
||||
}, ['dbForProject', 'authorization']);
|
||||
|
||||
+30
-11
@@ -32,7 +32,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Pools\Group;
|
||||
@@ -309,7 +308,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
'value' => '{}'
|
||||
]);
|
||||
|
||||
$statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document));
|
||||
$statsDocument = $database->getAuthorization()->skip(fn () => $database->createDocument('realtime', $document));
|
||||
break;
|
||||
} catch (Throwable) {
|
||||
Console::warning("Collection not ready. Retrying connection ({$attempts})...");
|
||||
@@ -339,7 +338,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
->setAttribute('timestamp', DateTime::now())
|
||||
->setAttribute('value', json_encode($payload));
|
||||
|
||||
Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
|
||||
$database->getAuthorization()->skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
|
||||
} catch (Throwable $th) {
|
||||
$logError($th, "updateWorkerDocument");
|
||||
}
|
||||
@@ -370,7 +369,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
|
||||
$payload = [];
|
||||
|
||||
$list = Authorization::skip(fn () => $database->find('realtime', [
|
||||
$list = $database->getAuthorization()->skip(fn () => $database->find('realtime', [
|
||||
Query::greaterThan('timestamp', DateTime::addSeconds(new \DateTime(), -15)),
|
||||
]));
|
||||
|
||||
@@ -464,13 +463,13 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) {
|
||||
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId]));
|
||||
$consoleDatabase = getConsoleDB();
|
||||
$project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId));
|
||||
$project = $consoleDatabase->getAuthorization()->skip(fn () => $consoleDatabase->getDocument('projects', $projectId));
|
||||
$database = getProjectDB($project);
|
||||
|
||||
/** @var Appwrite\Utopia\Database\Documents\User $user */
|
||||
$user = $database->getDocument('users', $userId);
|
||||
|
||||
$roles = $user->getRoles();
|
||||
$roles = $user->getRoles($database->getAuthorization());
|
||||
$channels = $realtime->connections[$connection]['channels'];
|
||||
|
||||
$realtime->unsubscribe($connection);
|
||||
@@ -526,6 +525,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
try {
|
||||
/** @var Document $project */
|
||||
$project = $app->getResource('project');
|
||||
$authorization = $app->getResource('authorization');
|
||||
|
||||
/*
|
||||
* Project Check
|
||||
@@ -537,7 +537,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
if (
|
||||
array_key_exists('realtime', $project->getAttribute('apis', []))
|
||||
&& !$project->getAttribute('apis', [])['realtime']
|
||||
&& !(User::isPrivileged(Authorization::getRoles()) || User::isApp(Authorization::getRoles()))
|
||||
&& !(User::isPrivileged($authorization->getRoles()) || User::isApp($authorization->getRoles()))
|
||||
) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
|
||||
}
|
||||
@@ -573,7 +573,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
throw new Exception(Exception::REALTIME_POLICY_VIOLATION, $originValidator->getDescription());
|
||||
}
|
||||
|
||||
$roles = $user->getRoles();
|
||||
$roles = $user->getRoles($authorization);
|
||||
|
||||
$channels = Realtime::convertChannels($request->getQuery('channels', []), $user->getId());
|
||||
|
||||
@@ -586,6 +586,8 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
|
||||
$realtime->subscribe($project->getId(), $connection, $roles, $channels);
|
||||
|
||||
$realtime->connections[$connection]['authorization'] = $authorization;
|
||||
|
||||
$user = empty($user->getId()) ? null : $response->output($user, Response::MODEL_ACCOUNT);
|
||||
|
||||
$server->send([$connection], json_encode([
|
||||
@@ -614,6 +616,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
$code = 500;
|
||||
}
|
||||
|
||||
|
||||
$message = $th->getMessage();
|
||||
|
||||
// sanitize 0 && 5xx errors
|
||||
@@ -643,12 +646,19 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
$server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) {
|
||||
try {
|
||||
$response = new Response(new SwooleResponse());
|
||||
$projectId = $realtime->connections[$connection]['projectId'];
|
||||
$projectId = $realtime->connections[$connection]['projectId'] ?? null;
|
||||
|
||||
// Get authorization from connection (stored during onOpen)
|
||||
$authorization = $realtime->connections[$connection]['authorization'] ?? null;
|
||||
|
||||
$database = getConsoleDB();
|
||||
$database->setAuthorization($authorization);
|
||||
|
||||
if ($projectId !== 'console') {
|
||||
$project = Authorization::skip(fn () => $database->getDocument('projects', $projectId));
|
||||
$project = $authorization->skip(fn () => $database->getDocument('projects', $projectId));
|
||||
|
||||
$database = getProjectDB($project);
|
||||
$database->setAuthorization($authorization);
|
||||
} else {
|
||||
$project = null;
|
||||
}
|
||||
@@ -712,10 +722,19 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Session is not valid.');
|
||||
}
|
||||
|
||||
$roles = $user->getRoles();
|
||||
$roles = $user->getRoles($database->getAuthorization());
|
||||
$channels = Realtime::convertChannels(array_flip($realtime->connections[$connection]['channels']), $user->getId());
|
||||
|
||||
// Preserve authorization before subscribe overwrites the connection array
|
||||
$authorization = $realtime->connections[$connection]['authorization'] ?? null;
|
||||
|
||||
$realtime->subscribe($realtime->connections[$connection]['projectId'], $connection, $roles, $channels);
|
||||
|
||||
// Restore authorization after subscribe
|
||||
if ($authorization !== null) {
|
||||
$realtime->connections[$connection]['authorization'] = $authorization;
|
||||
}
|
||||
|
||||
$user = $response->output($user, Response::MODEL_ACCOUNT);
|
||||
$server->send([$connection], json_encode([
|
||||
'type' => 'response',
|
||||
|
||||
@@ -11,7 +11,6 @@ $httpsPort = $this->getParam('httpsPort', '');
|
||||
$version = $this->getParam('version', '');
|
||||
$organization = $this->getParam('organization', '');
|
||||
$image = $this->getParam('image', '');
|
||||
$enableAssistant = $this->getParam('enableAssistant', false);
|
||||
?>services:
|
||||
traefik:
|
||||
image: traefik:2.11
|
||||
@@ -849,7 +848,6 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
<?php if ($enableAssistant): ?>
|
||||
appwrite-assistant:
|
||||
image: appwrite/assistant:0.8.4
|
||||
container_name: appwrite-assistant
|
||||
@@ -859,7 +857,6 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
environment:
|
||||
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||
<?php endif; ?>
|
||||
|
||||
appwrite-browser:
|
||||
image: appwrite/browser:0.3.2
|
||||
|
||||
+35
-33
@@ -21,8 +21,6 @@ use Appwrite\Utopia\Database\Documents\User;
|
||||
use Executor\Executor;
|
||||
use Swoole\Runtime;
|
||||
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
|
||||
use Utopia\Audit\Adapter\Database as AdapterDatabase;
|
||||
use Utopia\Audit\Audit as UtopiaAudit;
|
||||
use Utopia\Cache\Adapter\Pool as CachePool;
|
||||
use Utopia\Cache\Adapter\Sharding;
|
||||
use Utopia\Cache\Cache;
|
||||
@@ -48,19 +46,30 @@ use Utopia\System\System;
|
||||
use Utopia\Telemetry\Adapter as Telemetry;
|
||||
use Utopia\Telemetry\Adapter\None as NoTelemetry;
|
||||
|
||||
Authorization::disable();
|
||||
Runtime::enableCoroutine();
|
||||
|
||||
Server::setResource('register', fn () => $register);
|
||||
|
||||
Server::setResource('dbForPlatform', function (Cache $cache, Registry $register) {
|
||||
Server::setResource('authorization', function () {
|
||||
$authorization = new Authorization();
|
||||
$authorization->disable();
|
||||
return $authorization;
|
||||
}, []);
|
||||
|
||||
Server::setResource('dbForPlatform', function (Cache $cache, Registry $register, Authorization $authorization) {
|
||||
$pools = $register->get('pools');
|
||||
$adapter = new DatabasePool($pools->get('console'));
|
||||
$dbForPlatform = new Database($adapter, $cache);
|
||||
$dbForPlatform->setNamespace('_console');
|
||||
$dbForPlatform->setDocumentType('users', User::class);
|
||||
|
||||
$dbForPlatform
|
||||
->setAuthorization($authorization)
|
||||
->setNamespace('_console')
|
||||
->setDocumentType('users', User::class)
|
||||
;
|
||||
|
||||
|
||||
return $dbForPlatform;
|
||||
}, ['cache', 'register']);
|
||||
}, ['cache', 'register', 'authorization']);
|
||||
|
||||
Server::setResource('project', function (Message $message, Database $dbForPlatform) {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
@@ -73,7 +82,7 @@ Server::setResource('project', function (Message $message, Database $dbForPlatfo
|
||||
return $dbForPlatform->getDocument('projects', $project->getId());
|
||||
}, ['message', 'dbForPlatform']);
|
||||
|
||||
Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Document $project, Database $dbForPlatform) {
|
||||
Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Document $project, Database $dbForPlatform, Authorization $authorization) {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return $dbForPlatform;
|
||||
}
|
||||
@@ -105,15 +114,17 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register,
|
||||
->setNamespace('_' . $project->getSequence());
|
||||
}
|
||||
|
||||
$database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
|
||||
return $database;
|
||||
}, ['cache', 'register', 'message', 'project', 'dbForPlatform']);
|
||||
}, ['cache', 'register', 'message', 'project', 'dbForPlatform', 'authorization']);
|
||||
|
||||
Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) {
|
||||
Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache, Authorization $authorization) {
|
||||
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
|
||||
|
||||
return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases): Database {
|
||||
return function (Document $project) use ($pools, $dbForPlatform, $cache, $authorization, &$databases): Database {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return $dbForPlatform;
|
||||
}
|
||||
@@ -127,7 +138,7 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf
|
||||
|
||||
if (isset($databases[$dsn->getHost()])) {
|
||||
$database = $databases[$dsn->getHost()];
|
||||
|
||||
$database->setAuthorization($authorization);
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
|
||||
if (\in_array($dsn->getHost(), $sharedTables)) {
|
||||
@@ -164,15 +175,17 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf
|
||||
->setNamespace('_' . $project->getSequence());
|
||||
}
|
||||
|
||||
$database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'dbForPlatform', 'cache']);
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'authorization']);
|
||||
|
||||
Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
Server::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $authorization) {
|
||||
$database = null;
|
||||
return function (?Document $project = null) use ($pools, $cache, $database) {
|
||||
return function (?Document $project = null) use ($pools, $cache, $database, $authorization) {
|
||||
if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
|
||||
$database->setTenant((int)$project->getSequence());
|
||||
return $database;
|
||||
@@ -182,6 +195,7 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$database
|
||||
->setAuthorization($authorization)
|
||||
->setSharedTables(true)
|
||||
->setNamespace('logsV1')
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER)
|
||||
@@ -194,7 +208,7 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'cache']);
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
|
||||
Server::setResource('abuseRetention', function () {
|
||||
return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400); // 1 day
|
||||
@@ -452,19 +466,6 @@ Server::setResource('logError', function (Registry $register, Document $project)
|
||||
|
||||
Server::setResource('executor', fn () => new Executor());
|
||||
|
||||
Server::setResource('getAudit', function (Database $dbForPlatform, callable $getProjectDB) {
|
||||
return function (Document $project) use ($dbForPlatform, $getProjectDB) {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
$adapter = new AdapterDatabase($dbForPlatform);
|
||||
return new UtopiaAudit($adapter);
|
||||
}
|
||||
|
||||
$dbForProject = $getProjectDB($project);
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
return new UtopiaAudit($adapter);
|
||||
};
|
||||
}, ['dbForPlatform', 'getProjectDB']);
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$platform = new Appwrite();
|
||||
$args = $platform->getEnv('argv');
|
||||
@@ -509,7 +510,8 @@ $worker
|
||||
->inject('log')
|
||||
->inject('pools')
|
||||
->inject('project')
|
||||
->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project) use ($worker, $queueName) {
|
||||
->inject('authorization')
|
||||
->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project, Authorization $authorization) use ($worker, $queueName) {
|
||||
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
if ($logger) {
|
||||
@@ -525,7 +527,7 @@ $worker
|
||||
$log->addExtra('file', $error->getFile());
|
||||
$log->addExtra('line', $error->getLine());
|
||||
$log->addExtra('trace', $error->getTraceAsString());
|
||||
$log->addExtra('roles', Authorization::getRoles());
|
||||
$log->addExtra('roles', $authorization->getRoles());
|
||||
|
||||
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php doctor "$@"
|
||||
php /usr/src/code/app/cli.php doctor $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php install "$@"
|
||||
php /usr/src/code/app/cli.php install $@
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php interval "$@"
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php maintenance "$@"
|
||||
php /usr/src/code/app/cli.php maintenance $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php migrate "$@"
|
||||
php /usr/src/code/app/cli.php migrate $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php queue-count --type=failed "$@"
|
||||
php /usr/src/code/app/cli.php queue-count --type=failed $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php queue-count --type=processing "$@"
|
||||
php /usr/src/code/app/cli.php queue-count --type=processing $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php queue-count --type=success "$@"
|
||||
php /usr/src/code/app/cli.php queue-count --type=success $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php queue-retry "$@"
|
||||
php /usr/src/code/app/cli.php queue-retry $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/realtime.php "$@"
|
||||
php /usr/src/code/app/realtime.php $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php schedule-executions "$@"
|
||||
php /usr/src/code/app/cli.php schedule-executions $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php schedule-functions "$@"
|
||||
php /usr/src/code/app/cli.php schedule-functions $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php schedule-messages "$@"
|
||||
php /usr/src/code/app/cli.php schedule-messages $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php screenshot "$@"
|
||||
php /usr/src/code/app/cli.php screenshot $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php sdks "$@"
|
||||
php /usr/src/code/app/cli.php sdks $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php specs "$@"
|
||||
php /usr/src/code/app/cli.php specs $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php ssl "$@"
|
||||
php /usr/src/code/app/cli.php ssl $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php stats-resources "$@"
|
||||
php /usr/src/code/app/cli.php stats-resources $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec /usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml "$@"
|
||||
/usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php upgrade "$@"
|
||||
php /usr/src/code/app/cli.php upgrade $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/cli.php vars "$@"
|
||||
php /usr/src/code/app/cli.php vars $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php audits "$@"
|
||||
php /usr/src/code/app/worker.php audits $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php builds "$@"
|
||||
php /usr/src/code/app/worker.php builds $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php certificates "$@"
|
||||
php /usr/src/code/app/worker.php certificates $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php databases "$@"
|
||||
php /usr/src/code/app/worker.php databases $@
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php deletes "$@"
|
||||
php /usr/src/code/app/worker.php deletes $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php functions "$@"
|
||||
php /usr/src/code/app/worker.php functions $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php mails "$@"
|
||||
php /usr/src/code/app/worker.php mails $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php messaging "$@"
|
||||
php /usr/src/code/app/worker.php messaging $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php migrations "$@"
|
||||
php /usr/src/code/app/worker.php migrations $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php stats-resources "$@"
|
||||
php /usr/src/code/app/worker.php stats-resources $@
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php stats-usage "$@"
|
||||
php /usr/src/code/app/worker.php stats-usage $@
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec php /usr/src/code/app/worker.php webhooks "$@"
|
||||
php /usr/src/code/app/worker.php webhooks $@
|
||||
+4
-4
@@ -47,12 +47,12 @@
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "1.*",
|
||||
"utopia-php/analytics": "0.10.*",
|
||||
"utopia-php/audit": "2.0.2-rc1",
|
||||
"utopia-php/audit": "1.*",
|
||||
"utopia-php/auth": "0.5.*",
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "1.*.*",
|
||||
"utopia-php/database": "3.*.*",
|
||||
"utopia-php/database": "dev-joins8 as 4.3.0",
|
||||
"utopia-php/detector": "0.2.*",
|
||||
"utopia-php/domains": "0.9.*",
|
||||
"utopia-php/emails": "0.6.*",
|
||||
@@ -64,7 +64,7 @@
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
"utopia-php/messaging": "0.20.*",
|
||||
"utopia-php/migration": "1.3.*",
|
||||
"utopia-php/migration": "dev-joins as 1.3.5",
|
||||
"utopia-php/orchestration": "0.9.*",
|
||||
"utopia-php/platform": "0.7.*",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
@@ -109,4 +109,4 @@
|
||||
"tbachert/spi": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+75
-64
@@ -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": "fe779980651e51a4cb8cde7515d14db1",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -756,16 +756,16 @@
|
||||
},
|
||||
{
|
||||
"name": "google/protobuf",
|
||||
"version": "v4.33.2",
|
||||
"version": "v4.33.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/protocolbuffers/protobuf-php.git",
|
||||
"reference": "fbd96b7bf1343f4b0d8fb358526c7ba4d72f1318"
|
||||
"reference": "281537d44d6c270606354e65bfa75a0969dbd629"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/fbd96b7bf1343f4b0d8fb358526c7ba4d72f1318",
|
||||
"reference": "fbd96b7bf1343f4b0d8fb358526c7ba4d72f1318",
|
||||
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/281537d44d6c270606354e65bfa75a0969dbd629",
|
||||
"reference": "281537d44d6c270606354e65bfa75a0969dbd629",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -794,9 +794,9 @@
|
||||
"proto"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.2"
|
||||
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.3"
|
||||
},
|
||||
"time": "2025-12-05T22:12:22+00:00"
|
||||
"time": "2026-01-09T21:49:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/csv",
|
||||
@@ -3552,23 +3552,21 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "2.0.2-rc1",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "7b35dab40bce66bda56eeeacd2bbcbf1e823f05f"
|
||||
"reference": "15656acfddb9d6f03c395b73673fc66c793c10a5"
|
||||
},
|
||||
"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/15656acfddb9d6f03c395b73673fc66c793c10a5",
|
||||
"reference": "15656acfddb9d6f03c395b73673fc66c793c10a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "3.*",
|
||||
"utopia-php/fetch": "^0.4.2",
|
||||
"utopia-php/validators": "^0.1.0"
|
||||
"utopia-php/database": "4.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
@@ -3595,9 +3593,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/1.0.3"
|
||||
},
|
||||
"time": "2025-12-24T01:20:43+00:00"
|
||||
"time": "2025-11-04T11:27:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/auth",
|
||||
@@ -3898,16 +3896,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "3.6.1",
|
||||
"version": "dev-joins8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "c8c1b2f5770245dd4006e2680681e3efbe8b1fa7"
|
||||
"reference": "467a9ea2aed836e83fc435f0379d177c16f8e45c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/c8c1b2f5770245dd4006e2680681e3efbe8b1fa7",
|
||||
"reference": "c8c1b2f5770245dd4006e2680681e3efbe8b1fa7",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/467a9ea2aed836e83fc435f0379d177c16f8e45c",
|
||||
"reference": "467a9ea2aed836e83fc435f0379d177c16f8e45c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3950,9 +3948,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/3.6.1"
|
||||
"source": "https://github.com/utopia-php/database/tree/joins8"
|
||||
},
|
||||
"time": "2025-12-16T09:55:41+00:00"
|
||||
"time": "2025-12-25T08:22:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -4515,16 +4513,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.3.9",
|
||||
"version": "dev-joins",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "c55ec67c74663190cda10fd79297422147be7e85"
|
||||
"reference": "01e06cf23b120b20eff6b159bc6531dd412677d8"
|
||||
},
|
||||
"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/01e06cf23b120b20eff6b159bc6531dd412677d8",
|
||||
"reference": "01e06cf23b120b20eff6b159bc6531dd412677d8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4533,7 +4531,7 @@
|
||||
"ext-openssl": "*",
|
||||
"php": ">=8.1",
|
||||
"utopia-php/console": "0.0.*",
|
||||
"utopia-php/database": "3.*",
|
||||
"utopia-php/database": "dev-joins8 as 4.3.0",
|
||||
"utopia-php/dsn": "0.2.*",
|
||||
"utopia-php/storage": "0.18.*"
|
||||
},
|
||||
@@ -4564,9 +4562,9 @@
|
||||
],
|
||||
"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/joins"
|
||||
},
|
||||
"time": "2025-12-08T08:45:09+00:00"
|
||||
"time": "2025-12-23T05:59:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
@@ -5438,16 +5436,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.8.6",
|
||||
"version": "1.8.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "b6cc29d3bd247e193f3c06b4168dc69d884645f0"
|
||||
"reference": "28217b1d722ad2b217559c3a371eafd4d070614d"
|
||||
},
|
||||
"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/28217b1d722ad2b217559c3a371eafd4d070614d",
|
||||
"reference": "28217b1d722ad2b217559c3a371eafd4d070614d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5483,9 +5481,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.10"
|
||||
},
|
||||
"time": "2025-12-31T10:22:17+00:00"
|
||||
"time": "2026-01-09T11:40:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -5566,30 +5564,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 +5613,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 +5629,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-30T00:23:10+00:00"
|
||||
"time": "2026-01-05T06:47:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
@@ -5713,16 +5710,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 +5730,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 +5773,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 +8559,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 +8600,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 +8620,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-16T16:25:44+00:00"
|
||||
"time": "2025-12-19T10:01:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
@@ -8943,10 +8940,24 @@
|
||||
"time": "2024-03-07T20:33:40+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "utopia-php/database",
|
||||
"version": "dev-joins8",
|
||||
"alias": "4.3.0",
|
||||
"alias_normalized": "4.3.0.0"
|
||||
},
|
||||
{
|
||||
"package": "utopia-php/migration",
|
||||
"version": "dev-joins",
|
||||
"alias": "1.3.5",
|
||||
"alias_normalized": "1.3.5.0"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"utopia-php/audit": 5
|
||||
"utopia-php/database": 20,
|
||||
"utopia-php/migration": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
@@ -8971,5 +8982,5 @@
|
||||
"platform-overrides": {
|
||||
"php": "8.3"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
+21
-42
@@ -555,7 +555,6 @@ services:
|
||||
- _APP_DOMAIN_TARGET_CAA
|
||||
- _APP_DNS
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_EMAIL_CERTIFICATES
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
@@ -754,7 +753,6 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -787,43 +785,6 @@ services:
|
||||
- _APP_MAINTENANCE_START_TIME
|
||||
- _APP_DATABASE_SHARED_TABLES
|
||||
|
||||
appwrite-task-interval:
|
||||
entrypoint: interval
|
||||
<<: *x-logging
|
||||
container_name: appwrite-task-interval
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET_CNAME
|
||||
- _APP_DOMAIN_TARGET_AAAA
|
||||
- _APP_DOMAIN_TARGET_A
|
||||
- _APP_DOMAIN_TARGET_CAA
|
||||
- _APP_DNS
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_DATABASE_SHARED_TABLES
|
||||
- _APP_INTERVAL_DOMAIN_VERIFICATION
|
||||
|
||||
appwrite-task-stats-resources:
|
||||
container_name: appwrite-task-stats-resources
|
||||
entrypoint: stats-resources
|
||||
@@ -1067,6 +1028,27 @@ services:
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET
|
||||
|
||||
openruntimes-proxy:
|
||||
container_name: openruntimes-proxy
|
||||
hostname: proxy
|
||||
<<: *x-logging
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/proxy:0.5.5
|
||||
networks:
|
||||
- appwrite
|
||||
- runtimes
|
||||
environment:
|
||||
- OPR_PROXY_WORKER_PER_CORE=$_APP_WORKER_PER_CORE
|
||||
- OPR_PROXY_ENV=$_APP_ENV
|
||||
- OPR_PROXY_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
|
||||
- OPR_PROXY_SECRET=$_APP_EXECUTOR_SECRET
|
||||
- OPR_PROXY_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
|
||||
- OPR_PROXY_ALGORITHM=random
|
||||
- OPR_PROXY_EXECUTORS=exc1
|
||||
- OPR_PROXY_HEALTHCHECK_INTERVAL=10000
|
||||
- OPR_PROXY_MAX_TIMEOUT=600
|
||||
- OPR_PROXY_HEALTHCHECK=enabled
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.11 # fix issues when upgrading using: mysql_upgrade -u root -p
|
||||
container_name: appwrite-mariadb
|
||||
@@ -1149,9 +1131,6 @@ services:
|
||||
- "traefik.http.routers.appwrite_maildev_https.rule=Host(`mail.localhost`)"
|
||||
- "traefik.http.routers.appwrite_maildev_https.service=appwrite_maildev"
|
||||
- "traefik.http.routers.appwrite_maildev_https.tls=true"
|
||||
environment:
|
||||
- MAILDEV_INCOMING_USER=${_APP_SMTP_USERNAME}
|
||||
- MAILDEV_INCOMING_PASS=${_APP_SMTP_PASSWORD}
|
||||
|
||||
request-catcher-webhook: # used mainly for dev tests (mock HTTP webhook)
|
||||
image: appwrite/requestcatcher:1.0.0
|
||||
|
||||
@@ -152,7 +152,7 @@ As the name implies, `param()` is used to define a request parameter.
|
||||
|
||||
```php
|
||||
App::get('/v1/account/logs')
|
||||
->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 Types([Query::TYPE_LIMIT, Query::TYPE_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)
|
||||
```
|
||||
|
||||
### 6. inject
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
stopOnFailure="true"
|
||||
>
|
||||
<extensions>
|
||||
<extension class="Appwrite\Tests\TestHook" />
|
||||
|
||||
@@ -8,10 +8,6 @@ interface Adapter
|
||||
{
|
||||
public function issueCertificate(string $certName, string $domain, ?string $domainType): ?string;
|
||||
|
||||
public function isInstantGeneration(string $domain, ?string $domainType): bool;
|
||||
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): string;
|
||||
|
||||
public function isRenewRequired(string $domain, ?string $domainType, Log $log): bool;
|
||||
|
||||
public function deleteCertificate(string $domain): void;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Certificates\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
// Exception thrown during certificate status retrieval
|
||||
class CertificateStatus extends Exception
|
||||
{
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Appwrite\Certificates;
|
||||
|
||||
use Appwrite\Certificates\Exception\CertificateStatus as CertificateStatusException;
|
||||
use Exception;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
@@ -85,16 +84,6 @@ class LetsEncrypt implements Adapter
|
||||
return DateTime::addSeconds($dt, -60 * 60 * 24 * 30);
|
||||
}
|
||||
|
||||
public function isInstantGeneration(string $domain, ?string $domainType): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): string
|
||||
{
|
||||
throw new CertificateStatusException('Certificate status retrieval is not supported for LetsEncrypt.');
|
||||
}
|
||||
|
||||
public function isRenewRequired(string $domain, ?string $domainType, Log $log): bool
|
||||
{
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
|
||||
@@ -20,10 +20,12 @@ use Utopia\Database\Validator\Authorization;
|
||||
class TransactionState
|
||||
{
|
||||
private Database $dbForProject;
|
||||
|
||||
public function __construct(Database $dbForProject)
|
||||
private Authorization $authorization;
|
||||
/** @var Authorization $authorization */
|
||||
public function __construct(Database $dbForProject, Authorization $authorization)
|
||||
{
|
||||
$this->dbForProject = $dbForProject;
|
||||
$this->authorization = $authorization;
|
||||
}
|
||||
|
||||
|
||||
@@ -342,12 +344,12 @@ class TransactionState
|
||||
*/
|
||||
private function getTransactionState(string $transactionId): array
|
||||
{
|
||||
$transaction = Authorization::skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId));
|
||||
$transaction = $this->authorization->skip(fn () => $this->dbForProject->getDocument('transactions', $transactionId));
|
||||
if ($transaction->isEmpty() || $transaction->getAttribute('status') !== 'pending') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$operations = Authorization::skip(fn () => $this->dbForProject->find('transactionLogs', [
|
||||
$operations = $this->authorization->skip(fn () => $this->dbForProject->find('transactionLogs', [
|
||||
Query::equal('transactionInternalId', [$transaction->getSequence()]),
|
||||
Query::orderAsc(),
|
||||
Query::limit(PHP_INT_MAX)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Audit extends Event
|
||||
{
|
||||
@@ -20,8 +19,8 @@ class Audit extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_AUDITS_QUEUE_NAME', Event::AUDITS_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_AUDITS_CLASS_NAME', Event::AUDITS_CLASS_NAME));
|
||||
->setQueue(Event::AUDITS_QUEUE_NAME)
|
||||
->setClass(Event::AUDITS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Appwrite\Event;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Build extends Event
|
||||
{
|
||||
@@ -19,8 +18,8 @@ class Build extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_BUILDS_CLASS_NAME', Event::BUILDS_CLASS_NAME));
|
||||
->setQueue(Event::BUILDS_QUEUE_NAME)
|
||||
->setClass(Event::BUILDS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,14 +4,10 @@ namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Certificate extends Event
|
||||
{
|
||||
public const string ACTION_DOMAIN_VERIFICATION = 'verification';
|
||||
public const string ACTION_GENERATION = 'generation';
|
||||
protected bool $skipRenewCheck = false;
|
||||
protected string $action = self::ACTION_GENERATION;
|
||||
protected ?Document $domain = null;
|
||||
protected ?string $validationDomain = null;
|
||||
|
||||
@@ -20,8 +16,8 @@ class Certificate extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_CERTIFICATES_QUEUE_NAME', Event::CERTIFICATES_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_CERTIFICATES_CLASS_NAME', Event::CERTIFICATES_CLASS_NAME));
|
||||
->setQueue(Event::CERTIFICATES_QUEUE_NAME)
|
||||
->setClass(Event::CERTIFICATES_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,28 +90,6 @@ class Certificate extends Event
|
||||
return $this->skipRenewCheck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set action for this certificate event.
|
||||
*
|
||||
* @param string $action
|
||||
* @return self
|
||||
*/
|
||||
public function setAction(string $action): self
|
||||
{
|
||||
$this->action = $action;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get action for this certificate event.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAction(): string
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the payload for the event
|
||||
@@ -128,8 +102,7 @@ class Certificate extends Event
|
||||
'project' => $this->project,
|
||||
'domain' => $this->domain,
|
||||
'skipRenewCheck' => $this->skipRenewCheck,
|
||||
'validationDomain' => $this->validationDomain,
|
||||
'action' => $this->action
|
||||
'validationDomain' => $this->validationDomain
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Appwrite\Event;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Database extends Event
|
||||
{
|
||||
@@ -25,7 +24,7 @@ class Database extends Event
|
||||
{
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this->setClass(System::getEnv('_APP_DATABASE_CLASS_NAME', Event::DATABASE_CLASS_NAME));
|
||||
$this->setClass(Event::DATABASE_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Delete extends Event
|
||||
{
|
||||
@@ -21,8 +20,8 @@ class Delete extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_DELETE_QUEUE_NAME', Event::DELETE_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_DELETE_CLASS_NAME', Event::DELETE_CLASS_NAME));
|
||||
->setQueue(Event::DELETE_QUEUE_NAME)
|
||||
->setClass(Event::DELETE_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Appwrite\Event;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Func extends Event
|
||||
{
|
||||
@@ -26,8 +25,8 @@ class Func extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_FUNCTIONS_QUEUE_NAME', Event::FUNCTIONS_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_FUNCTIONS_CLASS_NAME', Event::FUNCTIONS_CLASS_NAME));
|
||||
->setQueue(Event::FUNCTIONS_QUEUE_NAME)
|
||||
->setClass(Event::FUNCTIONS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Mail extends Event
|
||||
{
|
||||
@@ -25,8 +24,8 @@ class Mail extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_MAILS_QUEUE_NAME', Event::MAILS_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_MAILS_CLASS_NAME', Event::MAILS_CLASS_NAME));
|
||||
->setQueue(Event::MAILS_QUEUE_NAME)
|
||||
->setClass(Event::MAILS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Messaging extends Event
|
||||
{
|
||||
@@ -20,8 +19,8 @@ class Messaging extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_MESSAGING_QUEUE_NAME', Event::MESSAGING_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_MESSAGING_CLASS_NAME', Event::MESSAGING_CLASS_NAME));
|
||||
->setQueue(Event::MESSAGING_QUEUE_NAME)
|
||||
->setClass(Event::MESSAGING_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Appwrite\Event;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Migration extends Event
|
||||
{
|
||||
@@ -17,8 +16,8 @@ class Migration extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_MIGRATIONS_QUEUE_NAME', Event::MIGRATIONS_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_MIGRATIONS_CLASS_NAME', Event::MIGRATIONS_CLASS_NAME));
|
||||
->setQueue(Event::MIGRATIONS_QUEUE_NAME)
|
||||
->setClass(Event::MIGRATIONS_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class StatsResources extends Event
|
||||
{
|
||||
@@ -14,8 +13,8 @@ class StatsResources extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_STATS_RESOURCES_QUEUE_NAME', Event::STATS_RESOURCES_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_STATS_RESOURCES_CLASS_NAME', Event::STATS_RESOURCES_CLASS_NAME));
|
||||
->setQueue(Event::STATS_RESOURCES_QUEUE_NAME)
|
||||
->setClass(Event::STATS_RESOURCES_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class StatsUsage extends Event
|
||||
{
|
||||
@@ -19,8 +18,8 @@ class StatsUsage extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_STATS_USAGE_QUEUE_NAME', Event::STATS_USAGE_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_STATS_USAGE_CLASS_NAME', Event::STATS_USAGE_CLASS_NAME));
|
||||
->setQueue(Event::STATS_USAGE_QUEUE_NAME)
|
||||
->setClass(Event::STATS_USAGE_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Webhook extends Event
|
||||
{
|
||||
@@ -12,8 +11,8 @@ class Webhook extends Event
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_WEBHOOK_QUEUE_NAME', Event::WEBHOOK_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_WEBHOOK_CLASS_NAME', Event::WEBHOOK_CLASS_NAME));
|
||||
->setQueue(Event::WEBHOOK_QUEUE_NAME)
|
||||
->setClass(Event::WEBHOOK_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -99,8 +99,6 @@ abstract class Migration
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
Authorization::disable();
|
||||
Authorization::setDefaultStatus(false);
|
||||
|
||||
$this->collections = Config::getParam('collections', []);
|
||||
|
||||
@@ -128,6 +126,7 @@ abstract class Migration
|
||||
Document $project,
|
||||
Database $dbForProject,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
?callable $getProjectDB = null
|
||||
): self {
|
||||
$this->project = $project;
|
||||
@@ -135,6 +134,9 @@ abstract class Migration
|
||||
$this->dbForPlatform = $dbForPlatform;
|
||||
$this->getProjectDB = $getProjectDB;
|
||||
|
||||
$authorization->disable();
|
||||
$authorization->setDefaultStatus(false);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
# Modules AGENTS.md
|
||||
|
||||
> Before reading this file, also read Appwrite's base [AGENTS.md](../../../AGENTS.md).
|
||||
|
||||
Modules are the building blocks of the Appwrite platform. They are responsible for handling specific tasks, defining background workers, and providing API endpoints. Each module should have its own directory within the `src/Appwrite/Platform/Modules` directory.
|
||||
|
||||
Generally-speaking, each service is its own module, but there are some exceptions. The goal is to always put related code that achieves a specific goal under one roof.
|
||||
|
||||
## Structure and Naming Conventions
|
||||
|
||||
When adding a module, always add a new directory under `src/Appwrite/Platform/Modules`. The directory name should be PascalCase, and if possible, use only one word. For example, `User`, `Database`, `Storage`, etc. Avoid using shorthands, unless they are standardized, such as `DB`, `JWT`, or `SMTP`.
|
||||
|
||||
A module consists of:
|
||||
|
||||
- `Module.php` - Simple register class registering all module's services (from `Services` directory)
|
||||
- `Workers` directory - Contains behavior for module-specific workers
|
||||
- `Tasks` directory - Contains behavior for module-specific CLI tasks
|
||||
- `Http` directory - Contains HTTP endpoints for the module
|
||||
- `Services` directory - Contains register classes for all relevant types of services
|
||||
|
||||
Inside module, the `Services` directory can contain:
|
||||
|
||||
- `Http.php` - Register HTTP endpoints and hooks from `Http` directory
|
||||
- `Workers.php` - Register workers from `Workers` directory
|
||||
- `Tasks.php` - Register CLI tasks from `Tasks` directory
|
||||
|
||||
> After implementing a module, make sure to register it in `src/Appwrite/Platform/Appwrite.php`.
|
||||
|
||||
### HTTP directory structure
|
||||
|
||||
Inside module's `Http` directory, there are multiple rules to follow:
|
||||
|
||||
1. Directly in `Http` directory, there should only be directories for services (and hooks, check point number 2). If a module is a single service, it's okay to only have one directory, with the same name as the service, for example `src/Appwrite/Platform/Modules/Account/Http/Account`. An example with multiple services is `src/Appwrite/Platform/Modules/Databases/Http/Databases` and `src/Appwrite/Platform/Modules/Databases/Http/TablesDB`.
|
||||
|
||||
2. Hooks should live in `Hooks` directory, under `Init`, `Shutdown`, or `Error` directories, inside `Http` directory. For example, an init hook to prevent unauthorized access might live in `src/Appwrite/Platform/Modules/Functions/Http/Hooks/Init/Authentication.php`.
|
||||
|
||||
3. Inside `Http` directories for services, file names can only be `Get.php`, `Update.php`, `Create.php`, `Delete.php` or `XList.php`. We call it `XList`, because `List` is a reserved keyword and PHP would not like that. Never use any other words! Let's say you want a method to be `blockUser`, tempting to add `Users/Block.php`, instead, think of the resource and property it affects. Better naming would be `Users/Status/Update.php` (update user's status). Doing so also nicely reflects in the HTTP endpoint, `PATCH /v1/users/:userId/status`.
|
||||
|
||||
4. It's allowed to nest directories in `Http` service directories. For example, if you want to create a new deployment for a function based on a template, an endpoint might live in `src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployments/Template/Create.php`. In this example, notice functions and deployments are resources, and template is property - both resources and properties can be nested, and have separate directories.
|
||||
|
||||
### Sample module directory structure
|
||||
|
||||
```bash
|
||||
src/Appwrite/Platform/Modules/Functions
|
||||
├── Module.php
|
||||
├── Workers
|
||||
│ └── Builds.php
|
||||
├── Tasks
|
||||
│ └── Block.php
|
||||
├── Http
|
||||
│ └── Functions
|
||||
│ ├── Create.php
|
||||
│ ├── XList.php
|
||||
│ ├── Update.php
|
||||
│ ├── Delete.php
|
||||
│ ├── Get.php
|
||||
│ └── Deployments
|
||||
│ ├── XList.php
|
||||
│ ├── Delete.php
|
||||
│ ├── Get.php
|
||||
│ └── Template
|
||||
│ └── Create.php
|
||||
└── Services
|
||||
├── Http.php
|
||||
├── Workers.php
|
||||
└── Tasks.php
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user