mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46d606f1e4 | ||
|
|
72688a6828 | ||
|
|
ca36a7d58c | ||
|
|
60dda27722 | ||
|
|
e8556755de | ||
|
|
747cca2679 | ||
|
|
998fe08a8d | ||
|
|
7493e16bac | ||
|
|
d1f1c58073 |
@@ -82,7 +82,7 @@ _APP_EXECUTOR_SECRET=your-secret-key
|
||||
_APP_EXECUTOR_HOST=http://proxy/v1
|
||||
_APP_FUNCTIONS_RUNTIMES=php-8.0,node-18.0,python-3.9,ruby-3.1
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
_APP_MAINTENANCE_START_TIME=12:00
|
||||
_APP_MAINTENANCE_DELAY=
|
||||
_APP_MAINTENANCE_RETENTION_CACHE=2592000
|
||||
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400
|
||||
|
||||
@@ -1030,22 +1030,13 @@ return [
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_DELAY',
|
||||
'description' => 'Deprecated with 1.6.2 use _APP_MAINTENANCE_START_TIME instead to run the maintenance at a specific time per day.',
|
||||
'description' => 'Delay value containing the number of seconds that the Appwrite maintenance process should wait before executing system cleanups and optimizations. The default value is 0 seconds.',
|
||||
'introduction' => '1.5.0',
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_START_TIME',
|
||||
'description' => 'The time of day (in 24-hour format) when the maintenance process should start. The default value is 00:00.',
|
||||
'introduction' => '1.6.2',
|
||||
'default' => '00:00',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_CACHE',
|
||||
'description' => 'The maximum duration (in seconds) upto which to retain cached files. The default value is 2592000 seconds (30 days).',
|
||||
|
||||
@@ -144,7 +144,6 @@ $image = $this->getParam('image', '');
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_MAINTENANCE_INTERVAL
|
||||
- _APP_MAINTENANCE_DELAY
|
||||
- _APP_MAINTENANCE_START_TIME
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
|
||||
Generated
+6
-6
@@ -4769,16 +4769,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "0.40.15",
|
||||
"version": "0.40.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "65c708b931b29b3e01c5cc7504a734ce2cc3dc95"
|
||||
"reference": "f1f506da74033f0cb5a11e3dffcfd1ee8daf237d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/65c708b931b29b3e01c5cc7504a734ce2cc3dc95",
|
||||
"reference": "65c708b931b29b3e01c5cc7504a734ce2cc3dc95",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/f1f506da74033f0cb5a11e3dffcfd1ee8daf237d",
|
||||
"reference": "f1f506da74033f0cb5a11e3dffcfd1ee8daf237d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4814,9 +4814,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/0.40.15"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.40.16"
|
||||
},
|
||||
"time": "2025-04-25T08:50:44+00:00"
|
||||
"time": "2025-05-09T12:06:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
|
||||
+1
-1
@@ -732,7 +732,7 @@ services:
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE
|
||||
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||
- _APP_MAINTENANCE_START_TIME
|
||||
- _APP_MAINTENANCE_DELAY
|
||||
- _APP_DATABASE_SHARED_TABLES
|
||||
|
||||
appwrite-task-stats-resources:
|
||||
|
||||
@@ -35,27 +35,12 @@ class Maintenance extends Action
|
||||
Console::title('Maintenance V1');
|
||||
Console::success(APP_NAME . ' maintenance process v1 has started');
|
||||
|
||||
$interval = (int) System::getEnv('_APP_MAINTENANCE_INTERVAL', '86400'); // 1 day
|
||||
// # of days in seconds (1 day = 86400s)
|
||||
$interval = (int) System::getEnv('_APP_MAINTENANCE_INTERVAL', '86400');
|
||||
$delay = (int) System::getEnv('_APP_MAINTENANCE_DELAY', '0');
|
||||
$usageStatsRetentionHourly = (int) System::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_HOURLY', '8640000'); //100 days
|
||||
$cacheRetention = (int) System::getEnv('_APP_MAINTENANCE_RETENTION_CACHE', '2592000'); // 30 days
|
||||
$schedulesDeletionRetention = (int) System::getEnv('_APP_MAINTENANCE_RETENTION_SCHEDULES', '86400'); // 1 Day
|
||||
$jobInitTime = System::getEnv('_APP_MAINTENANCE_START_TIME', '00:00'); // (hour:minutes)
|
||||
|
||||
$now = new \DateTime();
|
||||
$now->setTimezone(new \DateTimeZone(date_default_timezone_get()));
|
||||
$next = new \DateTime($now->format("Y-m-d $jobInitTime"));
|
||||
$next->setTimezone(new \DateTimeZone(date_default_timezone_get()));
|
||||
$delay = $next->getTimestamp() - $now->getTimestamp();
|
||||
|
||||
/**
|
||||
* If time passed for the target day.
|
||||
*/
|
||||
if ($delay <= 0) {
|
||||
$next->add(\DateInterval::createFromDateString('1 days'));
|
||||
$delay = $next->getTimestamp() - $now->getTimestamp();
|
||||
}
|
||||
|
||||
Console::info('Setting loop start time to ' . $next->format("Y-m-d H:i:s.v") . '. Delaying for ' . $delay . ' seconds.');
|
||||
|
||||
Console::loop(function () use ($interval, $cacheRetention, $schedulesDeletionRetention, $usageStatsRetentionHourly, $dbForPlatform, $console, $queueForDeletes, $queueForCertificates) {
|
||||
$time = DateTime::now();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Appwrite\Utopia;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\Utopia\Request\Filter;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
@@ -29,37 +30,50 @@ class Request extends UtopiaRequest
|
||||
{
|
||||
$parameters = parent::getParams();
|
||||
|
||||
if ($this->hasFilters() && self::hasRoute()) {
|
||||
$methods = self::getRoute()->getLabel('sdk', null);
|
||||
if (!$this->hasFilters() || !self::hasRoute()) {
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
if (!\is_array($methods)) {
|
||||
$methods = [$methods];
|
||||
$methods = self::getRoute()->getLabel('sdk', null);
|
||||
$methods = \is_array($methods) ? $methods : [$methods];
|
||||
$matched = null;
|
||||
|
||||
foreach ($methods as $method) {
|
||||
/** @var Method|null $method */
|
||||
if ($method === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$params = [];
|
||||
// Find the method that matches the parameters passed
|
||||
$methodParamNames = \array_map(fn($param) => $param->getName(), $method->getParameters());
|
||||
$invalidParams = \array_diff(\array_keys($parameters), $methodParamNames);
|
||||
|
||||
foreach ($methods as $method) {
|
||||
/** @var \Appwrite\SDK\Method $method */
|
||||
if (empty($method)) {
|
||||
$endpointIdentifier = 'unknown.unknown';
|
||||
} else {
|
||||
$endpointIdentifier = $method->getNamespace() . '.' . $method->getMethodName();
|
||||
}
|
||||
|
||||
$params += $method->getParameters();
|
||||
// No params defined, or all params are valid
|
||||
if (empty($methodParamNames) || empty($invalidParams)) {
|
||||
$matched = $method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($params)) {
|
||||
$parameters = array_filter($parameters, function ($key) use ($params) {
|
||||
return array_key_exists($key, $params);
|
||||
}, \ARRAY_FILTER_USE_KEY);
|
||||
}
|
||||
$endpointIdentifier = $matched !== null
|
||||
? $matched->getNamespace() . '.' . $matched->getMethodName()
|
||||
: 'unknown.unknown';
|
||||
|
||||
foreach ($this->getFilters() as $filter) {
|
||||
$parameters = $filter->parse($parameters, $endpointIdentifier);
|
||||
// Filter params to valid keys
|
||||
if ($matched !== null) {
|
||||
$definedNames = \array_map(fn($param) => $param->getName(), $matched->getParameters());
|
||||
|
||||
// If matched method has explicit params, remove all other params
|
||||
if (!empty($definedNames)) {
|
||||
$parameters = \array_intersect_key($parameters, \array_flip($definedNames));
|
||||
}
|
||||
}
|
||||
|
||||
// Apply filters
|
||||
foreach ($this->getFilters() as $filter) {
|
||||
$parameters = $filter->parse($parameters, $endpointIdentifier);
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Tests\Unit\Utopia;
|
||||
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Parameter;
|
||||
use Appwrite\Utopia\Request;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
@@ -57,4 +58,130 @@ class RequestTest extends TestCase
|
||||
$this->assertTrue($output['second']);
|
||||
$this->assertArrayNotHasKey('deleted', $output);
|
||||
}
|
||||
|
||||
public function testGetParamsWithMultipleMethods(): void
|
||||
{
|
||||
$this->setupMultiMethodRoute();
|
||||
|
||||
// Pass only "foo", should match Method A
|
||||
$this->request->setQueryString([
|
||||
'foo' => 'valueFoo',
|
||||
]);
|
||||
|
||||
$params = $this->request->getParams();
|
||||
|
||||
$this->assertArrayHasKey('foo', $params);
|
||||
$this->assertSame('valueFoo', $params['foo']);
|
||||
$this->assertArrayNotHasKey('baz', $params);
|
||||
}
|
||||
|
||||
public function testGetParamsWithAllRequired(): void
|
||||
{
|
||||
$this->setupMultiMethodRoute();
|
||||
|
||||
// Pass "foo" and "bar", should match Method A
|
||||
$this->request->setQueryString([
|
||||
'foo' => 'valueFoo',
|
||||
'bar' => 'valueBar',
|
||||
]);
|
||||
|
||||
$params = $this->request->getParams();
|
||||
$this->assertArrayHasKey('foo', $params);
|
||||
$this->assertSame('valueFoo', $params['foo']);
|
||||
$this->assertArrayHasKey('bar', $params);
|
||||
$this->assertSame('valueBar', $params['bar']);
|
||||
$this->assertArrayNotHasKey('baz', $params);
|
||||
}
|
||||
|
||||
public function testGetParamsWithAllOptional(): void
|
||||
{
|
||||
$this->setupMultiMethodRoute();
|
||||
|
||||
// Pass only "bar", should match Method A
|
||||
$this->request->setQueryString([
|
||||
'bar' => 'valueBar',
|
||||
]);
|
||||
|
||||
$params = $this->request->getParams();
|
||||
|
||||
$this->assertArrayHasKey('bar', $params);
|
||||
$this->assertSame('valueBar', $params['bar']);
|
||||
$this->assertArrayNotHasKey('foo', $params);
|
||||
$this->assertArrayNotHasKey('baz', $params);
|
||||
}
|
||||
|
||||
public function testGetParamsMatchesMethodB(): void
|
||||
{
|
||||
$this->setupMultiMethodRoute();
|
||||
|
||||
// Pass only "baz", should match Method B
|
||||
$this->request->setQueryString([
|
||||
'baz' => 'valueBaz',
|
||||
]);
|
||||
|
||||
$params = $this->request->getParams();
|
||||
|
||||
$this->assertArrayHasKey('baz', $params);
|
||||
$this->assertSame('valueBaz', $params['baz']);
|
||||
$this->assertArrayNotHasKey('foo', $params);
|
||||
}
|
||||
|
||||
public function testGetParamsFallbackForMixedAndUnknown(): void
|
||||
{
|
||||
$this->setupMultiMethodRoute();
|
||||
|
||||
// Mixed and unknown should fallback to raw params
|
||||
$this->request->setQueryString([
|
||||
'foo' => 'valueFoo',
|
||||
'baz' => 'valueBaz',
|
||||
'extra' => 'unexpected',
|
||||
]);
|
||||
|
||||
$params = $this->request->getParams();
|
||||
|
||||
$this->assertArrayHasKey('foo', $params);
|
||||
$this->assertSame('valueFoo', $params['foo']);
|
||||
$this->assertArrayHasKey('baz', $params);
|
||||
$this->assertSame('valueBaz', $params['baz']);
|
||||
$this->assertArrayHasKey('extra', $params);
|
||||
$this->assertSame('unexpected', $params['extra']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to attach a route with multiple SDK methods to the request.
|
||||
*/
|
||||
private function setupMultiMethodRoute(): void
|
||||
{
|
||||
$route = new Route(Request::METHOD_GET, '/multi');
|
||||
|
||||
$methodA = new Method(
|
||||
namespace: 'namespace',
|
||||
group: 'group',
|
||||
name: 'methodA',
|
||||
description: 'desc',
|
||||
auth: [],
|
||||
responses: [],
|
||||
parameters: [
|
||||
new Parameter('foo'),
|
||||
new Parameter('bar', optional: true),
|
||||
],
|
||||
);
|
||||
|
||||
$methodB = new Method(
|
||||
namespace: 'namespace',
|
||||
group: 'group',
|
||||
name: 'methodB',
|
||||
description: 'desc',
|
||||
auth: [],
|
||||
responses: [],
|
||||
parameters: [
|
||||
new Parameter('baz'),
|
||||
],
|
||||
);
|
||||
|
||||
$route->label('sdk', [$methodA, $methodB]);
|
||||
$this->request->addFilter(new First());
|
||||
$this->request->addFilter(new Second());
|
||||
$this->request->setRoute($route);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user