diff --git a/app/config/collections.php b/app/config/collections.php index e02e25829f..d0c3df165e 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -4343,6 +4343,17 @@ $consoleCollections = array_merge([ 'array' => false, 'filters' => [], ], + [ + '$id' => 'accessedAt', + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], [ '$id' => ID::custom('services'), 'type' => Database::VAR_STRING, diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 265efbbfae..af588fffc4 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -22,6 +22,7 @@ use Utopia\Audit\Audit; use Utopia\Cache\Cache; use Utopia\Config\Config; use Utopia\Database\Database; +use Utopia\Database\DateTime; use Utopia\Database\Document; use Utopia\Database\Exception\Duplicate; use Utopia\Database\Exception\Query as QueryException; @@ -172,6 +173,7 @@ App::post('/v1/projects') 'webhooks' => null, 'keys' => null, 'auths' => $auths, + 'accessedAt' => DateTime::now(), 'search' => implode(' ', [$projectId, $name]), 'database' => $dsn, ])); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index bcf7c47d0b..583a0160a1 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -270,7 +270,7 @@ App::init() Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys. $accessedAt = $key->getAttribute('accessedAt', ''); - if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_KEY_ACCCESS)) > $accessedAt) { + if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) { $key->setAttribute('accessedAt', DateTime::now()); $dbForConsole->updateDocument('keys', $key->getId(), $key); $dbForConsole->purgeCachedDocument('projects', $project->getId()); @@ -760,12 +760,23 @@ App::shutdown() ->trigger(); } + /** + * Update project last activity + */ + if (!$project->isEmpty() && $project->getId() !== 'console') { + $accessedAt = $project->getAttribute('accessedAt', ''); + if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) { + $project->setAttribute('accessedAt', DateTime::now()); + Authorization::skip(fn () => $dbForConsole->updateDocument('projects', $project->getId(), $project)); + } + } + /** * Update user last activity */ if (!$user->isEmpty()) { $accessedAt = $user->getAttribute('accessedAt', ''); - if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCCESS)) > $accessedAt) { + if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCESS)) > $accessedAt) { $user->setAttribute('accessedAt', DateTime::now()); if (APP_MODE_ADMIN !== $mode) { diff --git a/app/init.php b/app/init.php index 2166fa812b..a0e71f041b 100644 --- a/app/init.php +++ b/app/init.php @@ -113,8 +113,9 @@ const APP_LIMIT_SUBSCRIBERS_SUBQUERY = 1_000_000; const APP_LIMIT_WRITE_RATE_DEFAULT = 60; // Default maximum write rate per rate period const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate period in seconds const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return in list API calls -const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours -const APP_USER_ACCCESS = 24 * 60 * 60; // 24 hours +const APP_KEY_ACCESS = 24 * 60 * 60; // 24 hours +const APP_USER_ACCESS = 24 * 60 * 60; // 24 hours +const APP_PROJECT_ACCESS = 24 * 60 * 60; // 24 hours const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours const APP_CACHE_BUSTER = 4314; const APP_VERSION_STABLE = '1.5.7'; diff --git a/src/Appwrite/Utopia/Response/Model/Key.php b/src/Appwrite/Utopia/Response/Model/Key.php index 1179a73d62..1adab4417b 100644 --- a/src/Appwrite/Utopia/Response/Model/Key.php +++ b/src/Appwrite/Utopia/Response/Model/Key.php @@ -60,7 +60,7 @@ class Key extends Model ]) ->addRule('accessedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_KEY_ACCCESS / 60 / 60 . ' hours.', + 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_KEY_ACCESS / 60 / 60 . ' hours.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE ]) diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index 34e7c31621..672b8885a0 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -135,7 +135,7 @@ class User extends Model ]) ->addRule('accessedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_USER_ACCCESS / 60 / 60 . ' hours.', + 'description' => 'Most recent access date in ISO 8601 format. This attribute is only updated again after ' . APP_USER_ACCESS / 60 / 60 . ' hours.', 'default' => '', 'example' => self::TYPE_DATETIME_EXAMPLE, ])