mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
48
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a66b565150 | ||
|
|
ff160871ae | ||
|
|
92a3eca194 | ||
|
|
07135956df | ||
|
|
b5a363a2a7 | ||
|
|
31dc9ff873 | ||
|
|
408f9c2d39 | ||
|
|
dfd5965d25 | ||
|
|
2a38eedc98 | ||
|
|
f875b965be | ||
|
|
2e57e5a868 | ||
|
|
69ce99d1b4 | ||
|
|
6b881d4aaf | ||
|
|
aad7d6dbca | ||
|
|
e3412bc554 | ||
|
|
c1e50c7abd | ||
|
|
6499f436ca | ||
|
|
15dc316535 | ||
|
|
a7724028b3 | ||
|
|
419d56b4b1 | ||
|
|
d2cda9770b | ||
|
|
69430154e6 | ||
|
|
0601305545 | ||
|
|
5519086c29 | ||
|
|
33b9f33f44 | ||
|
|
8baa5cb659 | ||
|
|
cec5cd7bdc | ||
|
|
63c2d72b2e | ||
|
|
801219374c | ||
|
|
dc3459edd0 | ||
|
|
ace9d86744 | ||
|
|
2d3e34fd5a | ||
|
|
69ad4ae930 | ||
|
|
0037305e16 | ||
|
|
1a205c3f3b | ||
|
|
99966b5a24 | ||
|
|
2437d2be77 | ||
|
|
2043470bd0 | ||
|
|
667285d536 | ||
|
|
1199c1fc52 | ||
|
|
f270e47b48 | ||
|
|
5678860d13 | ||
|
|
b83125a41e | ||
|
|
2dcb131778 | ||
|
|
30083598c6 | ||
|
|
a0599d2658 | ||
|
|
c50db111d6 | ||
|
|
9441295510 |
@@ -6,7 +6,7 @@ use Utopia\Database\Helpers\ID;
|
||||
|
||||
$providers = Config::getParam('oAuthProviders', []);
|
||||
|
||||
return [
|
||||
$platformCollections = [
|
||||
'projects' => [
|
||||
'$collection' => ID::custom(Database::METADATA),
|
||||
'$id' => ID::custom('projects'),
|
||||
@@ -643,6 +643,39 @@ return [
|
||||
'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,
|
||||
@@ -718,6 +751,13 @@ return [
|
||||
'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,
|
||||
@@ -1903,3 +1943,31 @@ return [
|
||||
'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;
|
||||
|
||||
@@ -20,7 +20,7 @@ return [
|
||||
'name' => 'Console',
|
||||
'subtitle' => '',
|
||||
'description' => '',
|
||||
'controller' => 'web/console.php',
|
||||
'controller' => '', // Uses modules
|
||||
'sdk' => false,
|
||||
'docs' => false,
|
||||
'docsUrl' => '',
|
||||
@@ -270,9 +270,9 @@ return [
|
||||
'console' => [
|
||||
'key' => 'console',
|
||||
'name' => 'Console',
|
||||
'subtitle' => 'The Console service allows you to interact with console relevant informations.',
|
||||
'subtitle' => 'The Console service allows you to interact with console relevant information.',
|
||||
'description' => '',
|
||||
'controller' => 'api/console.php',
|
||||
'controller' => '', // Uses modules
|
||||
'sdk' => true,
|
||||
'docs' => true,
|
||||
'docsUrl' => '',
|
||||
|
||||
@@ -37,7 +37,7 @@ use libphonenumber\PhoneNumberUtil;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit as EventAudit;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Auth\Hashes\Sha;
|
||||
use Utopia\Auth\Proofs\Code as ProofsCode;
|
||||
use Utopia\Auth\Proofs\Password as ProofsPassword;
|
||||
@@ -3033,7 +3033,8 @@ App::get('/v1/account/logs')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, bool $includeTotal, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject) {
|
||||
->inject('audit')
|
||||
->action(function (array $queries, bool $includeTotal, Response $response, Document $user, Locale $locale, Reader $geodb, Database $dbForProject, Audit $audit) {
|
||||
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
@@ -3041,9 +3042,10 @@ App::get('/v1/account/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new EventAudit($dbForProject);
|
||||
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), $queries);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), offset: $offset, limit: $limit);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -3072,7 +3074,7 @@ App::get('/v1/account/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence(), $queries) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence()) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
<?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);
|
||||
});
|
||||
@@ -1145,7 +1145,8 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $providerId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->inject('audit')
|
||||
->action(function (string $providerId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
@@ -1158,9 +1159,12 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$resource = 'provider/' . $providerId;
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
$output = [];
|
||||
|
||||
foreach ($logs as $i => &$log) {
|
||||
@@ -1207,7 +1211,7 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -2549,7 +2553,8 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $topicId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->inject('audit')
|
||||
->action(function (string $topicId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
$topic = $dbForProject->getDocument('topics', $topicId);
|
||||
|
||||
if ($topic->isEmpty()) {
|
||||
@@ -2562,9 +2567,12 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$resource = 'topic/' . $topicId;
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -2612,7 +2620,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -2966,7 +2974,8 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $subscriberId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->inject('audit')
|
||||
->action(function (string $subscriberId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
$subscriber = $dbForProject->getDocument('subscribers', $subscriberId);
|
||||
|
||||
if ($subscriber->isEmpty()) {
|
||||
@@ -2979,9 +2988,12 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$resource = 'subscriber/' . $subscriberId;
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -3029,7 +3041,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
@@ -3762,7 +3774,8 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $messageId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->inject('audit')
|
||||
->action(function (string $messageId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
$message = $dbForProject->getDocument('messages', $messageId);
|
||||
|
||||
if ($message->isEmpty()) {
|
||||
@@ -3775,9 +3788,12 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$resource = 'message/' . $messageId;
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -3825,7 +3841,7 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ 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;
|
||||
@@ -247,13 +248,15 @@ App::post('/v1/projects')
|
||||
}
|
||||
|
||||
if ($create || $projectTables) {
|
||||
$audit = new Audit($dbForProject);
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
$audit = new Audit($adapter);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
if (!$create && $sharedTablesV1) {
|
||||
$attributes = \array_map(fn ($attribute) => new Document($attribute), Audit::ATTRIBUTES);
|
||||
$indexes = \array_map(fn (array $index) => new Document($index), Audit::INDEXES);
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
$attributes = $adapter->getAttributeDocuments();
|
||||
$indexes = $adapter->getIndexDocuments();
|
||||
$dbForProject->createDocument(Database::METADATA, new Document([
|
||||
'$id' => ID::custom('audit'),
|
||||
'$permissions' => [Permission::create(Role::any())],
|
||||
@@ -1499,6 +1502,9 @@ 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,
|
||||
@@ -1546,7 +1552,13 @@ App::get('/v1/projects/:projectId/keys')
|
||||
}
|
||||
|
||||
$keys = $dbForPlatform->find('keys', [
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
]),
|
||||
Query::limit(5000),
|
||||
]);
|
||||
|
||||
@@ -1587,7 +1599,13 @@ App::get('/v1/projects/:projectId/keys/:keyId')
|
||||
|
||||
$key = $dbForPlatform->findOne('keys', [
|
||||
Query::equal('$id', [$keyId]),
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
])
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
@@ -1631,7 +1649,13 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
||||
|
||||
$key = $dbForPlatform->findOne('keys', [
|
||||
Query::equal('$id', [$keyId]),
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
])
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
@@ -1682,7 +1706,13 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
||||
|
||||
$key = $dbForPlatform->findOne('keys', [
|
||||
Query::equal('$id', [$keyId]),
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
])
|
||||
]);
|
||||
|
||||
if ($key->isEmpty()) {
|
||||
|
||||
@@ -1464,7 +1464,8 @@ App::get('/v1/teams/:teamId/logs')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $teamId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->inject('audit')
|
||||
->action(function (string $teamId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
@@ -1478,9 +1479,12 @@ App::get('/v1/teams/:teamId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$resource = 'team/' . $team->getId();
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -1527,7 +1531,7 @@ App::get('/v1/teams/:teamId/logs')
|
||||
}
|
||||
}
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource, $queries) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByResource($resource) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
@@ -945,7 +945,8 @@ App::get('/v1/users/:userId/logs')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $userId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
->inject('audit')
|
||||
->action(function (string $userId, array $queries, bool $includeTotal, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
@@ -958,8 +959,11 @@ App::get('/v1/users/:userId/logs')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), $queries);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), limit: $limit, offset: $offset);
|
||||
$output = [];
|
||||
foreach ($logs as $i => &$log) {
|
||||
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
@@ -999,7 +1003,7 @@ App::get('/v1/users/:userId/logs')
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence(), $queries) : 0,
|
||||
'total' => $includeTotal ? $audit->countLogsByUser($user->getSequence()) : 0,
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<?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);
|
||||
});
|
||||
+8
-4
@@ -12,6 +12,8 @@ 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;
|
||||
@@ -260,8 +262,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
|
||||
// create appwrite database, `dbForPlatform` is a direct access call.
|
||||
createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections) {
|
||||
if ($dbForPlatform->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
$audit = new Audit($dbForPlatform);
|
||||
if ($dbForPlatform->getCollection(AuditAdapterSQL::COLLECTION)->isEmpty()) {
|
||||
$adapter = new AdapterDatabase($dbForPlatform);
|
||||
$audit = new Audit($adapter);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
@@ -389,8 +392,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
Console::success('[Setup] - Skip: metadata table already exists');
|
||||
}
|
||||
|
||||
if ($dbForProject->getCollection(Audit::COLLECTION)->isEmpty()) {
|
||||
$audit = new Audit($dbForProject);
|
||||
if ($dbForProject->getCollection(AuditAdapterSQL::COLLECTION)->isEmpty()) {
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
$audit = new Audit($adapter);
|
||||
$audit->setup();
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,13 @@ Database::addFilter(
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return $database
|
||||
->find('keys', [
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$document->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$document->getSequence()]),
|
||||
])
|
||||
]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use Ahc\Jwt\JWT;
|
||||
use Ahc\Jwt\JWTException;
|
||||
use Appwrite\Auth\Key;
|
||||
use Appwrite\Databases\TransactionState;
|
||||
use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Audit as AuditEvent;
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
@@ -30,6 +30,8 @@ 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;
|
||||
@@ -146,7 +148,7 @@ App::setResource('queueForStatsUsage', function (Publisher $publisher) {
|
||||
return new StatsUsage($publisher);
|
||||
}, ['publisher']);
|
||||
App::setResource('queueForAudits', function (Publisher $publisher) {
|
||||
return new Audit($publisher);
|
||||
return new AuditEvent($publisher);
|
||||
}, ['publisher']);
|
||||
App::setResource('queueForFunctions', function (Publisher $publisher) {
|
||||
return new Func($publisher);
|
||||
@@ -642,6 +644,11 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
};
|
||||
}, ['pools', 'cache']);
|
||||
|
||||
App::setResource('audit', function ($dbForProject) {
|
||||
$adapter = new AdapterDatabase($dbForProject);
|
||||
return new Audit($adapter);
|
||||
}, ['dbForProject']);
|
||||
|
||||
App::setResource('telemetry', fn () => new NoTelemetry());
|
||||
|
||||
App::setResource('cache', function (Group $pools, Telemetry $telemetry) {
|
||||
|
||||
@@ -11,6 +11,7 @@ $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
|
||||
@@ -848,6 +849,7 @@ $image = $this->getParam('image', '');
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
<?php if ($enableAssistant): ?>
|
||||
appwrite-assistant:
|
||||
image: appwrite/assistant:0.8.4
|
||||
container_name: appwrite-assistant
|
||||
@@ -857,6 +859,7 @@ $image = $this->getParam('image', '');
|
||||
- appwrite
|
||||
environment:
|
||||
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||
<?php endif; ?>
|
||||
|
||||
appwrite-browser:
|
||||
image: appwrite/browser:0.3.2
|
||||
|
||||
@@ -21,6 +21,8 @@ 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;
|
||||
@@ -450,6 +452,19 @@ 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');
|
||||
|
||||
+3
-3
@@ -47,12 +47,12 @@
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "1.*",
|
||||
"utopia-php/analytics": "0.10.*",
|
||||
"utopia-php/audit": "1.*",
|
||||
"utopia-php/audit": "2.0.2-rc1",
|
||||
"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": "3.*.*",
|
||||
"utopia-php/detector": "0.2.*",
|
||||
"utopia-php/domains": "0.9.*",
|
||||
"utopia-php/emails": "0.6.*",
|
||||
@@ -109,4 +109,4 @@
|
||||
"tbachert/spi": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+79
-75
@@ -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": "7c9cb03eb5267f1e7a3ffc037ae22b6a",
|
||||
"content-hash": "b873febd2b03c32ec61a57b690cc44a2",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -2673,16 +2673,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.4.1",
|
||||
"version": "v7.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "26cc224ea7103dda90e9694d9e139a389092d007"
|
||||
"reference": "d01dfac1e0dc99f18da48b18101c23ce57929616"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/26cc224ea7103dda90e9694d9e139a389092d007",
|
||||
"reference": "26cc224ea7103dda90e9694d9e139a389092d007",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/d01dfac1e0dc99f18da48b18101c23ce57929616",
|
||||
"reference": "d01dfac1e0dc99f18da48b18101c23ce57929616",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2750,7 +2750,7 @@
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.1"
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2770,7 +2770,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-04T21:12:57+00:00"
|
||||
"time": "2025-12-23T14:50:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
@@ -3552,21 +3552,23 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "1.0.2",
|
||||
"version": "2.0.2-rc1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "8c17065c2473d4ca799f65585ca74eb53e1be211"
|
||||
"reference": "7b35dab40bce66bda56eeeacd2bbcbf1e823f05f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/8c17065c2473d4ca799f65585ca74eb53e1be211",
|
||||
"reference": "8c17065c2473d4ca799f65585ca74eb53e1be211",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/7b35dab40bce66bda56eeeacd2bbcbf1e823f05f",
|
||||
"reference": "7b35dab40bce66bda56eeeacd2bbcbf1e823f05f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "*"
|
||||
"utopia-php/database": "3.*",
|
||||
"utopia-php/fetch": "^0.4.2",
|
||||
"utopia-php/validators": "^0.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
@@ -3593,9 +3595,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/1.0.2"
|
||||
"source": "https://github.com/utopia-php/audit/tree/2.0.2-rc1"
|
||||
},
|
||||
"time": "2025-10-20T07:14:26+00:00"
|
||||
"time": "2025-12-24T01:20:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/auth",
|
||||
@@ -3654,16 +3656,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
"version": "0.13.1",
|
||||
"version": "0.13.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/cache.git",
|
||||
"reference": "97220cb3b3822b166ee016d1646e2ae2815dc540"
|
||||
"reference": "5768498c9f451482f0bf3eede4d6452ddcd4a0f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/cache/zipball/97220cb3b3822b166ee016d1646e2ae2815dc540",
|
||||
"reference": "97220cb3b3822b166ee016d1646e2ae2815dc540",
|
||||
"url": "https://api.github.com/repos/utopia-php/cache/zipball/5768498c9f451482f0bf3eede4d6452ddcd4a0f6",
|
||||
"reference": "5768498c9f451482f0bf3eede4d6452ddcd4a0f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3672,7 +3674,7 @@
|
||||
"ext-redis": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
"utopia-php/telemetry": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
@@ -3700,9 +3702,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/cache/issues",
|
||||
"source": "https://github.com/utopia-php/cache/tree/0.13.1"
|
||||
"source": "https://github.com/utopia-php/cache/tree/0.13.2"
|
||||
},
|
||||
"time": "2025-05-09T14:43:52+00:00"
|
||||
"time": "2025-12-17T08:55:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cli",
|
||||
@@ -3896,16 +3898,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "3.6.0",
|
||||
"version": "3.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "af15066255a5fd7bd2926de37bcbf3d8500fc155"
|
||||
"reference": "c8c1b2f5770245dd4006e2680681e3efbe8b1fa7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/af15066255a5fd7bd2926de37bcbf3d8500fc155",
|
||||
"reference": "af15066255a5fd7bd2926de37bcbf3d8500fc155",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/c8c1b2f5770245dd4006e2680681e3efbe8b1fa7",
|
||||
"reference": "c8c1b2f5770245dd4006e2680681e3efbe8b1fa7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3948,9 +3950,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/3.6.0"
|
||||
"source": "https://github.com/utopia-php/database/tree/3.6.1"
|
||||
},
|
||||
"time": "2025-12-08T05:23:04+00:00"
|
||||
"time": "2025-12-16T09:55:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -3999,23 +4001,23 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/dns",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/dns.git",
|
||||
"reference": "dce3453364a4524b7250db8d8eb74820b814409e"
|
||||
"reference": "5daf8b683dad877491c4df84c6be24850b2f363b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/dce3453364a4524b7250db8d8eb74820b814409e",
|
||||
"reference": "dce3453364a4524b7250db8d8eb74820b814409e",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/5daf8b683dad877491c4df84c6be24850b2f363b",
|
||||
"reference": "5daf8b683dad877491c4df84c6be24850b2f363b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"utopia-php/console": "0.0.*",
|
||||
"utopia-php/domains": "0.9.*",
|
||||
"utopia-php/telemetry": "0.1.*",
|
||||
"utopia-php/telemetry": "*",
|
||||
"utopia-php/validators": "0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -4050,9 +4052,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/dns/issues",
|
||||
"source": "https://github.com/utopia-php/dns/tree/1.4.0"
|
||||
"source": "https://github.com/utopia-php/dns/tree/1.4.1"
|
||||
},
|
||||
"time": "2025-12-05T10:09:00+00:00"
|
||||
"time": "2025-12-17T09:09:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
@@ -4730,21 +4732,21 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/pools",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/pools.git",
|
||||
"reference": "05c67aba42eb68ac65489cc1e7fc5db83db2dd4d"
|
||||
"reference": "ad7d6ba946376e81c603204285ce9a674b6502b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/pools/zipball/05c67aba42eb68ac65489cc1e7fc5db83db2dd4d",
|
||||
"reference": "05c67aba42eb68ac65489cc1e7fc5db83db2dd4d",
|
||||
"url": "https://api.github.com/repos/utopia-php/pools/zipball/ad7d6ba946376e81c603204285ce9a674b6502b8",
|
||||
"reference": "ad7d6ba946376e81c603204285ce9a674b6502b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
"php": ">=8.4",
|
||||
"utopia-php/telemetry": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
@@ -4776,9 +4778,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/pools/issues",
|
||||
"source": "https://github.com/utopia-php/pools/tree/0.8.2"
|
||||
"source": "https://github.com/utopia-php/pools/tree/0.8.3"
|
||||
},
|
||||
"time": "2025-04-17T02:04:54+00:00"
|
||||
"time": "2025-12-17T09:35:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/preloader",
|
||||
@@ -4835,16 +4837,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/queue",
|
||||
"version": "0.11.1",
|
||||
"version": "0.11.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/queue.git",
|
||||
"reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6"
|
||||
"reference": "a854f7c4abc18e0eca55fc5608cd7088d71eb19f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/queue/zipball/498bbbef418b1db71b51e1bb62f5d1d752ddd8d6",
|
||||
"reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6",
|
||||
"url": "https://api.github.com/repos/utopia-php/queue/zipball/a854f7c4abc18e0eca55fc5608cd7088d71eb19f",
|
||||
"reference": "a854f7c4abc18e0eca55fc5608cd7088d71eb19f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4854,7 +4856,7 @@
|
||||
"utopia-php/fetch": "0.4.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
"utopia-php/telemetry": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-redis": "*",
|
||||
@@ -4895,9 +4897,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/queue/issues",
|
||||
"source": "https://github.com/utopia-php/queue/tree/0.11.1"
|
||||
"source": "https://github.com/utopia-php/queue/tree/0.11.2"
|
||||
},
|
||||
"time": "2025-05-30T11:50:34+00:00"
|
||||
"time": "2025-12-17T09:32:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/registry",
|
||||
@@ -4953,16 +4955,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/storage",
|
||||
"version": "0.18.16",
|
||||
"version": "0.18.18",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/storage.git",
|
||||
"reference": "0c7b8ad68de8e1eb23ccc8af9f27a30eb832930f"
|
||||
"reference": "acaea524f315f87b8811a2c34450fe2b502f49d8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/0c7b8ad68de8e1eb23ccc8af9f27a30eb832930f",
|
||||
"reference": "0c7b8ad68de8e1eb23ccc8af9f27a30eb832930f",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/acaea524f315f87b8811a2c34450fe2b502f49d8",
|
||||
"reference": "acaea524f315f87b8811a2c34450fe2b502f49d8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5005,9 +5007,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/storage/issues",
|
||||
"source": "https://github.com/utopia-php/storage/tree/0.18.16"
|
||||
"source": "https://github.com/utopia-php/storage/tree/0.18.18"
|
||||
},
|
||||
"time": "2025-12-03T02:15:45+00:00"
|
||||
"time": "2025-12-17T07:33:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/swoole",
|
||||
@@ -5436,16 +5438,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.5.9",
|
||||
"version": "1.8.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "ee434aa00a9185380b9a39bb46bf86d7104d3a93"
|
||||
"reference": "b6cc29d3bd247e193f3c06b4168dc69d884645f0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ee434aa00a9185380b9a39bb46bf86d7104d3a93",
|
||||
"reference": "ee434aa00a9185380b9a39bb46bf86d7104d3a93",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/b6cc29d3bd247e193f3c06b4168dc69d884645f0",
|
||||
"reference": "b6cc29d3bd247e193f3c06b4168dc69d884645f0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5481,9 +5483,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.5.9"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.8.6"
|
||||
},
|
||||
"time": "2025-11-25T05:22:25+00:00"
|
||||
"time": "2025-12-31T10:22:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -7931,16 +7933,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v8.0.1",
|
||||
"version": "v8.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "fcb73f69d655b48fcb894a262f074218df08bd58"
|
||||
"reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/fcb73f69d655b48fcb894a262f074218df08bd58",
|
||||
"reference": "fcb73f69d655b48fcb894a262f074218df08bd58",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/6145b304a5c1ea0bdbd0b04d297a5864f9a7d587",
|
||||
"reference": "6145b304a5c1ea0bdbd0b04d297a5864f9a7d587",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7997,7 +7999,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.1"
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8017,7 +8019,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-05T15:25:33+00:00"
|
||||
"time": "2025-12-23T14:52:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
@@ -8091,16 +8093,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v8.0.0",
|
||||
"version": "v8.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291"
|
||||
"reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/7598dd5770580fa3517ec83e8da0c9b9e01f4291",
|
||||
"reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/dd3a2953570a283a2ba4e17063bb98c734cf5b12",
|
||||
"reference": "dd3a2953570a283a2ba4e17063bb98c734cf5b12",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8135,7 +8137,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v8.0.0"
|
||||
"source": "https://github.com/symfony/finder/tree/v8.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8155,7 +8157,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-05T14:36:47+00:00"
|
||||
"time": "2025-12-23T14:52:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
@@ -8943,7 +8945,9 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {
|
||||
"utopia-php/audit": 5
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
@@ -8967,5 +8971,5 @@
|
||||
"platform-overrides": {
|
||||
"php": "8.3"
|
||||
},
|
||||
"plugin-api-version": "2.6.0"
|
||||
"plugin-api-version": "2.9.0"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Assistant;
|
||||
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Create extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'createAssistantQuery';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
|
||||
->setHttpPath('/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')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Init;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Platform\Action;
|
||||
|
||||
class API extends Action
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleAPI';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setType(Action::TYPE_INIT)
|
||||
->groups(['console'])
|
||||
->inject('project')
|
||||
->callback(function (Document $project) {
|
||||
if ($project->getId() !== 'console') {
|
||||
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Init;
|
||||
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Platform\Action;
|
||||
|
||||
class Web extends Action
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleWeb';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setType(Action::TYPE_INIT)
|
||||
->groups(['web'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->callback(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
|
||||
;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\Auth;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectAuth';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/auth/*';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects;
|
||||
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
|
||||
abstract class Base extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
/**
|
||||
* HTTP platform trait doesn't support multiple `aliases`
|
||||
* like legacy controllers so we use independent redirects!
|
||||
*
|
||||
* This helps as a base and a small code logic for maintenance.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getPath(): string;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath($this->getPath())
|
||||
->groups(['web'])
|
||||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(Request $request, Response $response): void
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\Card;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectCard';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/card/*';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\Invite;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectInvite';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/invite';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\Login;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectLogin';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/login';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\MFA;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectMFA';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/mfa';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\Recover;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectRecover';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/recover';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\Register;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectRegister';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/register/*';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Redirects\Root;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Base;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'consoleRedirectRoot';
|
||||
}
|
||||
|
||||
protected function getPath(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Http\Variables;
|
||||
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\IP;
|
||||
|
||||
class Get extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'getVariables';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath('/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')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(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'),
|
||||
'_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);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,19 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Console\Services;
|
||||
|
||||
use Appwrite\Platform\Modules\Console\Http\Assistant\Create as CreateAssistantQuery;
|
||||
use Appwrite\Platform\Modules\Console\Http\Init\API;
|
||||
use Appwrite\Platform\Modules\Console\Http\Init\Web;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Auth\Get as RedirectAuth;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Card\Get as RedirectCard;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Invite\Get as RedirectInvite;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Login\Get as RedirectLogin;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\MFA\Get as RedirectMFA;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Recover\Get as RedirectRecover;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Register\Get as RedirectRegister;
|
||||
use Appwrite\Platform\Modules\Console\Http\Redirects\Root\Get as RedirectRoot;
|
||||
use Appwrite\Platform\Modules\Console\Http\Resources\Get as GetResourceAvailability;
|
||||
use Appwrite\Platform\Modules\Console\Http\Variables\Get as GetVariables;
|
||||
use Utopia\Platform\Service;
|
||||
|
||||
class Http extends Service
|
||||
@@ -10,7 +22,23 @@ class Http extends Service
|
||||
public function __construct()
|
||||
{
|
||||
$this->type = Service::TYPE_HTTP;
|
||||
// Resources
|
||||
|
||||
// API and Web init hooks!
|
||||
$this->addAction(API::getName(), new API());
|
||||
$this->addAction(Web::getName(), new Web());
|
||||
|
||||
$this->addAction(GetVariables::getName(), new GetVariables());
|
||||
$this->addAction(CreateAssistantQuery::getName(), new CreateAssistantQuery());
|
||||
$this->addAction(GetResourceAvailability::getName(), new GetResourceAvailability());
|
||||
|
||||
// web redirects to /console
|
||||
$this->addAction(RedirectRoot::getName(), new RedirectRoot());
|
||||
$this->addAction(RedirectAuth::getName(), new RedirectAuth());
|
||||
$this->addAction(RedirectInvite::getName(), new RedirectInvite());
|
||||
$this->addAction(RedirectLogin::getName(), new RedirectLogin());
|
||||
$this->addAction(RedirectMFA::getName(), new RedirectMFA());
|
||||
$this->addAction(RedirectCard::getName(), new RedirectCard());
|
||||
$this->addAction(RedirectRecover::getName(), new RedirectRecover());
|
||||
$this->addAction(RedirectRegister::getName(), new RedirectRegister());
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -72,10 +72,11 @@ class XList extends Action
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $documentId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void
|
||||
public function action(string $databaseId, string $collectionId, string $documentId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit): void
|
||||
{
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty()) {
|
||||
@@ -98,12 +99,16 @@ class XList extends Action
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$type = $this->getCollectionsEventsContext();
|
||||
$context = $this->getContext();
|
||||
$resource = "database/$databaseId/$type/$collectionId/$context/{$document->getId()}";
|
||||
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -152,7 +157,7 @@ class XList extends Action
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'logs' => $output,
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $audit->countLogsByResource($resource),
|
||||
]), $this->getResponseModel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,10 +71,11 @@ class XList extends Action
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void
|
||||
public function action(string $databaseId, string $collectionId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit): void
|
||||
{
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
@@ -95,10 +96,13 @@ class XList extends Action
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$context = $this->getContext();
|
||||
$resource = "database/$databaseId/$context/$collectionId";
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -147,7 +151,7 @@ class XList extends Action
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'logs' => $output,
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $audit->countLogsByResource($resource),
|
||||
]), $this->getResponseModel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,10 +67,11 @@ class XList extends Action
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void
|
||||
public function action(string $databaseId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit): void
|
||||
{
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
|
||||
@@ -84,9 +85,13 @@ class XList extends Action
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$resource = 'database/' . $databaseId;
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -133,7 +138,7 @@ class XList extends Action
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $audit->countLogsByResource($resource),
|
||||
'logs' => $output,
|
||||
]), UtopiaResponse::MODEL_LOG_LIST);
|
||||
}
|
||||
|
||||
@@ -62,10 +62,11 @@ class XList extends Action
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb): void
|
||||
public function action(string $databaseId, array $queries, UtopiaResponse $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audit): void
|
||||
{
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
|
||||
@@ -79,9 +80,12 @@ class XList extends Action
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$resource = 'database/' . $databaseId;
|
||||
$logs = $audit->getLogsByResource($resource, $queries);
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
@@ -128,7 +132,7 @@ class XList extends Action
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByResource($resource, $queries),
|
||||
'total' => $audit->countLogsByResource($resource),
|
||||
'logs' => $output,
|
||||
]), UtopiaResponse::MODEL_LOG_LIST);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ class XList extends CollectionLogXList
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ class XList extends DocumentLogXList
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->inject('audit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,11 +148,63 @@ class Install extends Action
|
||||
$httpsPort = ($httpsPort) ? $httpsPort : $defaultHTTPSPort;
|
||||
}
|
||||
|
||||
$enableAssistant = false;
|
||||
$assistantExistsInOldCompose = false;
|
||||
|
||||
if ($data !== false && isset($compose)) {
|
||||
try {
|
||||
$assistantService = $compose->getService('appwrite-assistant');
|
||||
$assistantExistsInOldCompose = $assistantService !== null;
|
||||
} catch (\Throwable) {
|
||||
// assistant service doesn't exist, keep default false
|
||||
}
|
||||
}
|
||||
|
||||
if ($interactive == 'Y' && Console::isInteractive()) {
|
||||
$prompt = 'Add Appwrite Assistant? (Y/n)' . ($assistantExistsInOldCompose ? ' [Currently enabled]' : '');
|
||||
$answer = Console::confirm($prompt);
|
||||
|
||||
if (empty($answer)) {
|
||||
$enableAssistant = $assistantExistsInOldCompose;
|
||||
} else {
|
||||
$enableAssistant = \strtolower($answer) === 'y';
|
||||
}
|
||||
} elseif ($assistantExistsInOldCompose) {
|
||||
$enableAssistant = true;
|
||||
}
|
||||
|
||||
$input = [];
|
||||
|
||||
$password = new Password();
|
||||
$token = new Token();
|
||||
foreach ($vars as $var) {
|
||||
if ($var['name'] === '_APP_ASSISTANT_OPENAI_API_KEY') {
|
||||
if (!$enableAssistant) {
|
||||
$input[$var['name']] = '';
|
||||
continue;
|
||||
}
|
||||
|
||||
// key already exists
|
||||
if (!empty($var['default'])) {
|
||||
$input[$var['name']] = $var['default'];
|
||||
continue;
|
||||
}
|
||||
|
||||
// if assistant enabled and no key, ask for it
|
||||
if (Console::isInteractive() && $interactive === 'Y') {
|
||||
$input[$var['name']] = Console::confirm('Enter your OpenAI API key for Appwrite Assistant:');
|
||||
if (empty($input[$var['name']])) {
|
||||
Console::warning('No API key provided. Assistant will be disabled.');
|
||||
$enableAssistant = false;
|
||||
$input[$var['name']] = '';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$input[$var['name']] = '';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) {
|
||||
if ($data && $var['default'] !== null) {
|
||||
$input[$var['name']] = $var['default'];
|
||||
@@ -199,7 +251,8 @@ class Install extends Action
|
||||
->setParam('httpsPort', $httpsPort)
|
||||
->setParam('version', APP_VERSION_STABLE)
|
||||
->setParam('organization', $organization)
|
||||
->setParam('image', $image);
|
||||
->setParam('image', $image)
|
||||
->setParam('enableAssistant', $enableAssistant);
|
||||
|
||||
$templateForEnv->setParam('vars', $input);
|
||||
|
||||
|
||||
@@ -75,15 +75,10 @@ class SDKs extends Action
|
||||
$git = ($git === 'yes');
|
||||
|
||||
$prUrls = [];
|
||||
$createPr = false;
|
||||
|
||||
if ($git) {
|
||||
$production ??= Console::confirm('Type "Appwrite" to push code to production git repos');
|
||||
$production = $production === 'Appwrite';
|
||||
$production = ($production === 'yes');
|
||||
$message ??= Console::confirm('Please enter your commit message:');
|
||||
|
||||
$createPr = Console::confirm('Should we create pull request automatically? (yes/no)');
|
||||
$createPr = ($createPr === 'yes');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +447,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
');
|
||||
|
||||
Console::success("Pushed {$language['name']} SDK to {$gitUrl}");
|
||||
if ($createPr) {
|
||||
if ($git) {
|
||||
$prTitle = "feat: {$language['name']} SDK update for version {$language['version']}";
|
||||
$prBody = "This PR contains updates to the {$language['name']} SDK for version {$language['version']}.";
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Appwrite\Platform\Workers;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Authorization;
|
||||
@@ -42,8 +41,8 @@ class Audits extends Action
|
||||
$this
|
||||
->desc('Audits worker')
|
||||
->inject('message')
|
||||
->inject('getProjectDB')
|
||||
->inject('project')
|
||||
->inject('getAudit')
|
||||
->callback($this->action(...));
|
||||
|
||||
$this->lastTriggeredTime = time();
|
||||
@@ -54,13 +53,14 @@ class Audits extends Action
|
||||
* @param Message $message
|
||||
* @param callable $getProjectDB
|
||||
* @param Document $project
|
||||
* @param callable $getAudit
|
||||
* @return Commit|NoCommit
|
||||
* @throws Throwable
|
||||
* @throws \Utopia\Database\Exception
|
||||
* @throws Authorization
|
||||
* @throws Structure
|
||||
*/
|
||||
public function action(Message $message, callable $getProjectDB, Document $project): Commit|NoCommit
|
||||
public function action(Message $message, Document $project, callable $getAudit): Commit|NoCommit
|
||||
{
|
||||
$payload = $message->getPayload() ?? [];
|
||||
|
||||
@@ -102,7 +102,7 @@ class Audits extends Action
|
||||
'mode' => $mode,
|
||||
'data' => $auditPayload,
|
||||
],
|
||||
'timestamp' => date("Y-m-d H:i:s", $message->getTimestamp()),
|
||||
'time' => date("Y-m-d H:i:s", $message->getTimestamp()),
|
||||
];
|
||||
|
||||
if (isset($this->logs[$project->getSequence()])) {
|
||||
@@ -135,8 +135,7 @@ class Audits extends Action
|
||||
Console::log('Processing Project "' . $sequence . '" batch with ' . count($projectLogs['logs']) . ' events');
|
||||
|
||||
$projectDocument = $projectLogs['project'];
|
||||
$dbForProject = $getProjectDB($projectDocument);
|
||||
$audit = new Audit($dbForProject);
|
||||
$audit = $getAudit($projectDocument);
|
||||
$audit->logBatch($projectLogs['logs']);
|
||||
|
||||
Console::success('Audit logs processed successfully');
|
||||
|
||||
@@ -9,6 +9,7 @@ use Appwrite\Extend\Exception;
|
||||
use Executor\Executor;
|
||||
use Throwable;
|
||||
use Utopia\Abuse\Adapters\TimeLimit\Database as AbuseDatabase;
|
||||
use Utopia\Audit\Adapter\SQL;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
@@ -62,6 +63,7 @@ class Deletes extends Action
|
||||
->inject('executionRetention')
|
||||
->inject('auditRetention')
|
||||
->inject('log')
|
||||
->inject('getAudit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -84,7 +86,8 @@ class Deletes extends Action
|
||||
Executor $executor,
|
||||
string $executionRetention,
|
||||
string $auditRetention,
|
||||
Log $log
|
||||
Log $log,
|
||||
callable $getAudit,
|
||||
): void {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
|
||||
@@ -145,7 +148,7 @@ class Deletes extends Action
|
||||
break;
|
||||
case DELETE_TYPE_AUDIT:
|
||||
if (!$project->isEmpty()) {
|
||||
$this->deleteAuditLogs($project, $getProjectDB, $auditRetention);
|
||||
$this->deleteAuditLogs($project, $auditRetention, $getAudit);
|
||||
}
|
||||
break;
|
||||
case DELETE_TYPE_REALTIME:
|
||||
@@ -517,7 +520,7 @@ class Deletes extends Action
|
||||
|
||||
$projectCollectionIds = [
|
||||
...\array_keys(Config::getParam('collections', [])['projects']),
|
||||
Audit::COLLECTION,
|
||||
SQL::COLLECTION,
|
||||
AbuseDatabase::COLLECTION,
|
||||
];
|
||||
|
||||
@@ -565,7 +568,13 @@ class Deletes extends Action
|
||||
|
||||
// Delete Keys
|
||||
$this->deleteByGroup('keys', [
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$projectInternalId]),
|
||||
])
|
||||
]),
|
||||
Query::orderAsc()
|
||||
], $dbForPlatform);
|
||||
|
||||
@@ -777,23 +786,20 @@ class Deletes extends Action
|
||||
* @param Database $dbForPlatform
|
||||
* @param callable $getProjectDB
|
||||
* @param string $auditRetention
|
||||
* @param callable $getAudit
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function deleteAuditLogs(Document $project, callable $getProjectDB, string $auditRetention): void
|
||||
private function deleteAuditLogs(Document $project, string $auditRetention, callable $getAudit): void
|
||||
{
|
||||
$projectId = $project->getId();
|
||||
$dbForProject = $getProjectDB($project);
|
||||
/** @var Audit $audit */
|
||||
$audit = $getAudit($project);
|
||||
|
||||
try {
|
||||
$this->deleteByGroup(Audit::COLLECTION, [
|
||||
Query::select([...$this->selects, 'time']),
|
||||
Query::lessThan('time', $auditRetention),
|
||||
Query::orderDesc('time'),
|
||||
Query::orderAsc(),
|
||||
], $dbForProject);
|
||||
} catch (DatabaseException $e) {
|
||||
Console::error('Failed to delete audit logs for project ' . $projectId . ': ' . $e->getMessage());
|
||||
$audit->cleanup(new \DateTime($auditRetention));
|
||||
} catch (Throwable $th) {
|
||||
Console::error('Failed to delete audit logs for project ' . $projectId . ': ' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -200,7 +200,8 @@ class Migrations extends Action
|
||||
default => throw new \Exception('Invalid source type'),
|
||||
};
|
||||
|
||||
$this->sourceReport = $migrationSource->report();
|
||||
$resources = $migration->getAttribute('resources', []);
|
||||
$this->sourceReport = $migrationSource->report($resources);
|
||||
|
||||
return $migrationSource;
|
||||
}
|
||||
@@ -362,10 +363,10 @@ class Migrations extends Action
|
||||
$migration->getAttribute('resourceId'),
|
||||
$migration->getAttribute('resourceType')
|
||||
);
|
||||
}
|
||||
|
||||
$destination->shutdown();
|
||||
$source->shutdown();
|
||||
$destination->shutdown();
|
||||
$source->shutdown();
|
||||
}
|
||||
|
||||
$sourceErrors = $source->getErrors();
|
||||
$destinationErrors = $destination->getErrors();
|
||||
|
||||
@@ -111,7 +111,13 @@ class StatsResources extends Action
|
||||
Query::equal('projectInternalId', [$project->getSequence()])
|
||||
]);
|
||||
$keys = $dbForPlatform->count('keys', [
|
||||
Query::equal('projectInternalId', [$project->getSequence()])
|
||||
Query::or([
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::and([
|
||||
Query::equal('resourceType', ['projects']),
|
||||
Query::equal('resourceInternalId', [$project->getSequence()]),
|
||||
])
|
||||
]),
|
||||
]);
|
||||
|
||||
$domains = $dbForPlatform->count('rules', [
|
||||
|
||||
@@ -1851,6 +1851,8 @@ class ProjectsConsoleClientTest extends Scope
|
||||
$sessionCookie = $response['headers']['set-cookie'];
|
||||
$sessionId2 = $response['body']['$id'];
|
||||
|
||||
sleep(5); // fixes flaky tests.
|
||||
|
||||
/**
|
||||
* List sessions
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user