mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch 'master' of github.com:appwrite/appwrite into feat-add-console
This commit is contained in:
@@ -352,19 +352,19 @@ class Auth
|
||||
*
|
||||
* @param array $sessions
|
||||
* @param string $secret
|
||||
* @param string $expires
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function sessionVerify(array $sessions, string $secret)
|
||||
public static function sessionVerify(array $sessions, string $secret, int $expires)
|
||||
{
|
||||
foreach ($sessions as $session) {
|
||||
/** @var Document $session */
|
||||
if (
|
||||
$session->isSet('secret') &&
|
||||
$session->isSet('expire') &&
|
||||
$session->isSet('provider') &&
|
||||
$session->getAttribute('secret') === self::hash($secret) &&
|
||||
DateTime::formatTz($session->getAttribute('expire')) >= DateTime::formatTz(DateTime::now())
|
||||
DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $expires)) >= DateTime::formatTz(DateTime::now())
|
||||
) {
|
||||
return $session->getId();
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ class Delete extends Event
|
||||
protected ?Document $document = null;
|
||||
protected ?string $resource = null;
|
||||
protected ?string $datetime = null;
|
||||
protected ?string $dateTime30m = null;
|
||||
protected ?string $dateTime1d = null;
|
||||
protected ?string $hourlyUsageRetentionDatetime = null;
|
||||
|
||||
|
||||
public function __construct()
|
||||
@@ -56,26 +55,14 @@ class Delete extends Event
|
||||
}
|
||||
|
||||
/**
|
||||
* Set datetime for 1 day interval.
|
||||
* Sets datetime for 1h interval.
|
||||
*
|
||||
* @param string $datetime
|
||||
* @return self
|
||||
*/
|
||||
public function setDateTime1d(string $datetime): self
|
||||
public function setUsageRetentionHourlyDateTime(string $datetime): self
|
||||
{
|
||||
$this->dateTime1d = $datetime;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets datetime for 30m interval.
|
||||
*
|
||||
* @param string $datetime
|
||||
* @return self
|
||||
*/
|
||||
public function setDateTime30m(string $datetime): self
|
||||
{
|
||||
$this->dateTime30m = $datetime;
|
||||
$this->hourlyUsageRetentionDatetime = $datetime;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -140,8 +127,7 @@ class Delete extends Event
|
||||
'document' => $this->document,
|
||||
'resource' => $this->resource,
|
||||
'datetime' => $this->datetime,
|
||||
'dateTime1d' => $this->dateTime1d,
|
||||
'dateTime30m' => $this->dateTime30m,
|
||||
'hourlyUsageRetentionDatetime' => $this->hourlyUsageRetentionDatetime,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ abstract class Migration
|
||||
'1.0.0-RC1' => 'V15',
|
||||
'1.0.0' => 'V15',
|
||||
'1.0.1' => 'V15',
|
||||
'1.0.3' => 'V15'
|
||||
'1.0.3' => 'V15',
|
||||
'1.1.0' => 'V16',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Migration\Version;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Migration\Migration;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class V16 extends Migration
|
||||
{
|
||||
public function execute(): void
|
||||
{
|
||||
/**
|
||||
* Disable SubQueries for Performance.
|
||||
*/
|
||||
foreach (['subQueryIndexes', 'subQueryPlatforms', 'subQueryDomains', 'subQueryKeys', 'subQueryWebhooks', 'subQuerySessions', 'subQueryTokens', 'subQueryMemberships', 'subqueryVariables'] as $name) {
|
||||
Database::addFilter(
|
||||
$name,
|
||||
fn () => null,
|
||||
fn () => []
|
||||
);
|
||||
}
|
||||
|
||||
Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')');
|
||||
|
||||
Console::info('Migrating Collections');
|
||||
$this->migrateCollections();
|
||||
|
||||
Console::info('Migrating Documents');
|
||||
$this->forEachDocument([$this, 'fixDocument']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate all Collections.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function migrateCollections(): void
|
||||
{
|
||||
foreach ($this->collections as $collection) {
|
||||
$id = $collection['$id'];
|
||||
|
||||
Console::log("Migrating Collection \"{$id}\"");
|
||||
|
||||
$this->projectDB->setNamespace("_{$this->project->getInternalId()}");
|
||||
|
||||
switch ($id) {
|
||||
case 'sessions':
|
||||
try {
|
||||
/**
|
||||
* Create 'expire' attribute
|
||||
*/
|
||||
$this->projectDB->deleteAttribute($id, 'expire');
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning("'expire' from {$id}: {$th->getMessage()}");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'projects':
|
||||
try {
|
||||
/**
|
||||
* Create 'region' attribute
|
||||
*/
|
||||
$this->createAttributeFromCollection($this->projectDB, $id, 'region');
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning("'region' from {$id}: {$th->getMessage()}");
|
||||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
* Create '_key_team' index
|
||||
*/
|
||||
$this->createIndexFromCollection($this->projectDB, $id, '_key_team');
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning("'_key_team' from {$id}: {$th->getMessage()}");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'stats':
|
||||
try {
|
||||
/**
|
||||
* Create 'region' attribute
|
||||
*/
|
||||
$this->createAttributeFromCollection($this->projectDB, $id, 'region');
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning("'region' from {$id}: {$th->getMessage()}");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(50000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix run on each document
|
||||
*
|
||||
* @param \Utopia\Database\Document $document
|
||||
* @return \Utopia\Database\Document
|
||||
*/
|
||||
protected function fixDocument(Document $document)
|
||||
{
|
||||
switch ($document->getCollection()) {
|
||||
case 'projects':
|
||||
/**
|
||||
* Bump version number.
|
||||
*/
|
||||
$document->setAttribute('version', '1.1.0');
|
||||
|
||||
/**
|
||||
* Set default authDuration
|
||||
*/
|
||||
$document->setAttribute('auths', array_merge($document->getAttribute('auths', []), [
|
||||
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG
|
||||
]));
|
||||
|
||||
|
||||
$authProviders = $document->getAttribute('authProviders', []);
|
||||
|
||||
foreach (Config::getParam('providers') as $provider => $value) {
|
||||
if (!$value['enabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (($authProviders[$provider . 'Appid'] ?? false) && ($authProviders[$provider . 'Secret'] ?? false)) {
|
||||
$authProviders[$provider . 'Enabled'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $document;
|
||||
}
|
||||
}
|
||||
@@ -57,12 +57,11 @@ class Maintenance extends Action
|
||||
->trigger();
|
||||
}
|
||||
|
||||
function notifyDeleteUsageStats(int $interval30m, int $interval1d)
|
||||
function notifyDeleteUsageStats(int $usageStatsRetentionHourly)
|
||||
{
|
||||
(new Delete())
|
||||
->setType(DELETE_TYPE_USAGE)
|
||||
->setDateTime1d(DateTime::addSeconds(new \DateTime(), -1 * $interval1d))
|
||||
->setDateTime30m(DateTime::addSeconds(new \DateTime(), -1 * $interval30m))
|
||||
->setUsageRetentionHourlyDateTime(DateTime::addSeconds(new \DateTime(), -1 * $usageStatsRetentionHourly))
|
||||
->trigger();
|
||||
}
|
||||
|
||||
@@ -78,7 +77,7 @@ class Maintenance extends Action
|
||||
{
|
||||
(new Delete())
|
||||
->setType(DELETE_TYPE_SESSIONS)
|
||||
->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * Auth::TOKEN_EXPIRATION_LOGIN_LONG))
|
||||
->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * Auth::TOKEN_EXPIRATION_LOGIN_LONG)) //TODO: Update to use project session expiration instead of default.
|
||||
->trigger();
|
||||
}
|
||||
|
||||
@@ -132,19 +131,19 @@ class Maintenance extends Action
|
||||
$executionLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', '1209600');
|
||||
$auditLogRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_AUDIT', '1209600');
|
||||
$abuseLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', '86400');
|
||||
$usageStatsRetention30m = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_30M', '129600'); //36 hours
|
||||
$usageStatsRetention1d = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_1D', '8640000'); // 100 days
|
||||
$usageStatsRetentionHourly = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_HOURLY', '8640000'); //100 days
|
||||
|
||||
$cacheRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_CACHE', '2592000'); // 30 days
|
||||
$schedulesDeletionRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_SCHEDULES', '86400'); // 1 Day
|
||||
|
||||
Console::loop(function () use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d, $cacheRetention, $schedulesDeletionRetention, $dbForConsole) {
|
||||
Console::loop(function () use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetentionHourly, $cacheRetention, $schedulesDeletionRetention, $dbForConsole) {
|
||||
$time = DateTime::now();
|
||||
|
||||
Console::info("[{$time}] Notifying workers with maintenance tasks every {$interval} seconds");
|
||||
notifyDeleteExecutionLogs($executionLogsRetention);
|
||||
notifyDeleteAbuseLogs($abuseLogsRetention);
|
||||
notifyDeleteAuditLogs($auditLogRetention);
|
||||
notifyDeleteUsageStats($usageStatsRetention30m, $usageStatsRetention1d);
|
||||
notifyDeleteUsageStats($usageStatsRetentionHourly);
|
||||
notifyDeleteConnections();
|
||||
notifyDeleteExpiredSessions();
|
||||
renewCertificates($dbForConsole);
|
||||
|
||||
@@ -8,6 +8,7 @@ use Appwrite\Migration\Migration;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Registry\Registry;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -23,11 +24,21 @@ class Migrate extends Action
|
||||
{
|
||||
$this
|
||||
->desc('Migrate Appwrite to new version')
|
||||
/** @TODO APP_VERSION_STABLE needs to be defined */
|
||||
->param('version', APP_VERSION_STABLE, new Text(8), 'Version to migrate to.', true)
|
||||
->inject('register')
|
||||
->callback(fn ($version, $register) => $this->action($version, $register));
|
||||
}
|
||||
|
||||
private function clearProjectsCache(Redis $redis, Document $project)
|
||||
{
|
||||
try {
|
||||
$redis->del($redis->keys("cache-_{$project->getInternalId()}:*"));
|
||||
} catch (\Throwable $th) {
|
||||
Console::error('Failed to clear project ("' . $project->getId() . '") cache with error: ' . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function action(string $version, Registry $register)
|
||||
{
|
||||
Authorization::disable();
|
||||
@@ -43,7 +54,7 @@ class Migrate extends Action
|
||||
|
||||
$dbPool = $register->get('dbPool', true);
|
||||
$redis = $register->get('cache', true);
|
||||
$redis->flushAll();
|
||||
|
||||
$cache = new Cache(new RedisCache($redis));
|
||||
|
||||
$dbForConsole = $dbPool->getDB('console', $cache);
|
||||
@@ -79,6 +90,8 @@ class Migrate extends Action
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->clearProjectsCache($redis, $project);
|
||||
|
||||
try {
|
||||
// TODO: Iterate through all project DBs
|
||||
$projectDB = $dbPool->getDB($project->getId(), $cache);
|
||||
@@ -89,6 +102,8 @@ class Migrate extends Action
|
||||
throw $th;
|
||||
Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage());
|
||||
}
|
||||
|
||||
$this->clearProjectsCache($redis, $project);
|
||||
}
|
||||
|
||||
$sum = \count($projects);
|
||||
@@ -101,7 +116,6 @@ class Migrate extends Action
|
||||
}
|
||||
|
||||
Swoole\Event::wait(); // Wait for Coroutines to finish
|
||||
$redis->flushAll();
|
||||
Console::success('Data Migration Completed');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class SDKs extends Action
|
||||
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
|
||||
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
|
||||
|
||||
if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', 'latest'])) {
|
||||
if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', 'latest'])) {
|
||||
throw new Exception('Unknown version given');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\SMS;
|
||||
|
||||
abstract class Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $user;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $secret;
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*/
|
||||
public function __construct(string $user, string $secret)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Message to phone.
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
abstract public function send(string $from, string $to, string $message): void;
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param array $headers
|
||||
* @param string $payload
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function request(string $method, string $url, array $headers = [], ?string $payload = null, ?string $userpwd = null): string
|
||||
{
|
||||
$ch = \curl_init($url);
|
||||
|
||||
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
\curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
\curl_setopt($ch, CURLOPT_USERAGENT, 'Appwrite Phone Authentication');
|
||||
|
||||
if (!is_null($payload)) {
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
}
|
||||
|
||||
if (!is_null($userpwd)) {
|
||||
\curl_setopt($ch, CURLOPT_USERPWD, $userpwd);
|
||||
}
|
||||
|
||||
$headers[] = 'Content-length: ' . \strlen($payload);
|
||||
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
$response = (string) \curl_exec($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
if ($code >= 400) {
|
||||
throw new \Exception($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\SMS\Adapter;
|
||||
|
||||
use Appwrite\SMS\Adapter;
|
||||
|
||||
// Mock adapter used to E2E test worker
|
||||
class Mock extends Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $endpoint = 'http://request-catcher:5000/mock-sms';
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function send(string $from, string $to, string $message): void
|
||||
{
|
||||
$this->request(
|
||||
method: 'POST',
|
||||
url: $this->endpoint,
|
||||
payload: \json_encode([
|
||||
'message' => $message,
|
||||
'from' => $from,
|
||||
'to' => $to
|
||||
]),
|
||||
headers: [
|
||||
"content-type: application/json",
|
||||
"x-username: {$this->user}",
|
||||
"x-key: {$this->secret}",
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\SMS\Adapter;
|
||||
|
||||
use Appwrite\SMS\Adapter;
|
||||
|
||||
// Reference Material
|
||||
// https://docs.msg91.com/p/tf9GTextN/e/Irz7-x1PK/MSG91
|
||||
|
||||
class Msg91 extends Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $endpoint = 'https://api.msg91.com/api/v5/flow/';
|
||||
|
||||
/**
|
||||
* For Flow based sending SMS sender ID should not be set in flow
|
||||
* In environment _APP_SMS_PROVIDER format is 'sms://[senderID]:[authKey]@msg91'.
|
||||
* _APP_SMS_FROM value is flow ID created in Msg91
|
||||
* Eg. _APP_SMS_PROVIDER = sms://DINESH:5e1e93cad6fc054d8e759a5b@msg91
|
||||
* _APP_SMS_FROM = 3968636f704b303135323339
|
||||
* @param string $from-> utilized from for flow id
|
||||
* @param string $to
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function send(string $from, string $to, string $message): void
|
||||
{
|
||||
$to = ltrim($to, '+');
|
||||
$this->request(
|
||||
method: 'POST',
|
||||
url: $this->endpoint,
|
||||
payload: json_encode([
|
||||
'sender' => $this->user,
|
||||
'otp' => $message,
|
||||
'flow_id' => $from,
|
||||
'mobiles' => $to
|
||||
]),
|
||||
headers: [
|
||||
"content-type: application/JSON",
|
||||
"authkey: {$this->secret}",
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\SMS\Adapter;
|
||||
|
||||
use Appwrite\SMS\Adapter;
|
||||
|
||||
// Reference Material
|
||||
// https://developer.telesign.com/enterprise/docs/sms-api-send-an-sms
|
||||
|
||||
class Telesign extends Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $endpoint = 'https://rest-api.telesign.com/v1/messaging';
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @param string $message
|
||||
* @return void
|
||||
* @throws \Appwrite\Extend\Exception
|
||||
*/
|
||||
public function send(string $from, string $to, string $message): void
|
||||
{
|
||||
$to = ltrim($to, '+');
|
||||
|
||||
$this->request(
|
||||
method: 'POST',
|
||||
url: $this->endpoint,
|
||||
payload: \http_build_query([
|
||||
'message' => $message,
|
||||
'message_type' => 'otp',
|
||||
'phone_number' => $to
|
||||
]),
|
||||
userpwd: "{$this->user}:{$this->secret}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\SMS\Adapter;
|
||||
|
||||
use Appwrite\SMS\Adapter;
|
||||
|
||||
// Reference Material
|
||||
// https://www.textmagic.com/docs/api/start/
|
||||
|
||||
class TextMagic extends Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $endpoint = 'https://rest.textmagic.com/api/v2';
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function send(string $from, string $to, string $message): void
|
||||
{
|
||||
$to = ltrim($to, '+');
|
||||
$from = ltrim($from, '+');
|
||||
|
||||
$this->request(
|
||||
method: 'POST',
|
||||
url: $this->endpoint . '/messages',
|
||||
payload: \http_build_query([
|
||||
'text' => $message,
|
||||
'from' => $from,
|
||||
'phones' => $to
|
||||
]),
|
||||
headers: [
|
||||
"X-TM-Username: {$this->user}",
|
||||
"X-TM-Key: {$this->secret}",
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\SMS\Adapter;
|
||||
|
||||
use Appwrite\SMS\Adapter;
|
||||
|
||||
// Reference Material
|
||||
// https://www.twilio.com/docs/sms/api
|
||||
|
||||
class Twilio extends Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $endpoint = 'https://api.twilio.com/2010-04-01';
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function send(string $from, string $to, string $message): void
|
||||
{
|
||||
$this->request(
|
||||
method: 'POST',
|
||||
url: "{$this->endpoint}/Accounts/{$this->user}/Messages.json",
|
||||
payload: \http_build_query([
|
||||
'Body' => $message,
|
||||
'From' => $from,
|
||||
'To' => $to
|
||||
]),
|
||||
userpwd: "{$this->user}:{$this->secret}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\SMS\Adapter;
|
||||
|
||||
use Appwrite\SMS\Adapter;
|
||||
|
||||
// Reference Material
|
||||
// https://developer.vonage.com/api/sms
|
||||
|
||||
class Vonage extends Adapter
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $endpoint = 'https://rest.nexmo.com/sms/json';
|
||||
|
||||
/**
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function send(string $from, string $to, string $message): void
|
||||
{
|
||||
$to = ltrim($to, '+');
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
|
||||
$this->request(
|
||||
method: 'POST',
|
||||
url: $this->endpoint,
|
||||
headers: $headers,
|
||||
payload: \http_build_query([
|
||||
'text' => $message,
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
'api_key' => $this->user,
|
||||
'api_secret' => $this->secret
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,12 @@ namespace Appwrite\Usage;
|
||||
|
||||
abstract class Calculator
|
||||
{
|
||||
protected string $region;
|
||||
|
||||
public function __construct(string $region)
|
||||
{
|
||||
$this->region = $region;
|
||||
}
|
||||
|
||||
abstract public function collect(): void;
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Usage\Calculators;
|
||||
|
||||
use DateTime;
|
||||
use Utopia\Database\Database as UtopiaDatabase;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class Aggregator extends Database
|
||||
{
|
||||
protected function aggregateDatabaseMetrics(string $projectId): void
|
||||
{
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
$databasesGeneralMetrics = [
|
||||
'databases.$all.requests.create',
|
||||
'databases.$all.requests.read',
|
||||
'databases.$all.requests.update',
|
||||
'databases.$all.requests.delete',
|
||||
'collections.$all.requests.create',
|
||||
'collections.$all.requests.read',
|
||||
'collections.$all.requests.update',
|
||||
'collections.$all.requests.delete',
|
||||
'documents.$all.requests.create',
|
||||
'documents.$all.requests.read',
|
||||
'documents.$all.requests.update',
|
||||
'documents.$all.requests.delete'
|
||||
];
|
||||
|
||||
foreach ($databasesGeneralMetrics as $metric) {
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
|
||||
$databasesDatabaseMetrics = [
|
||||
'collections.databaseId.requests.create',
|
||||
'collections.databaseId.requests.read',
|
||||
'collections.databaseId.requests.update',
|
||||
'collections.databaseId.requests.delete',
|
||||
'documents.databaseId.requests.create',
|
||||
'documents.databaseId.requests.read',
|
||||
'documents.databaseId.requests.update',
|
||||
'documents.databaseId.requests.delete',
|
||||
];
|
||||
|
||||
$this->foreachDocument($projectId, 'databases', [], function (Document $database) use ($databasesDatabaseMetrics, $projectId) {
|
||||
$databaseId = $database->getId();
|
||||
foreach ($databasesDatabaseMetrics as $metric) {
|
||||
$metric = str_replace('databaseId', $databaseId, $metric);
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
|
||||
$databasesCollectionMetrics = [
|
||||
'documents.' . $databaseId . '/collectionId.requests.create',
|
||||
'documents.' . $databaseId . '/collectionId.requests.read',
|
||||
'documents.' . $databaseId . '/collectionId.requests.update',
|
||||
'documents.' . $databaseId . '/collectionId.requests.delete',
|
||||
];
|
||||
|
||||
$this->foreachDocument($projectId, 'database_' . $database->getInternalId(), [], function (Document $collection) use ($databasesCollectionMetrics, $projectId) {
|
||||
$collectionId = $collection->getId();
|
||||
foreach ($databasesCollectionMetrics as $metric) {
|
||||
$metric = str_replace('collectionId', $collectionId, $metric);
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected function aggregateStorageMetrics(string $projectId): void
|
||||
{
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
$storageGeneralMetrics = [
|
||||
'buckets.$all.requests.create',
|
||||
'buckets.$all.requests.read',
|
||||
'buckets.$all.requests.update',
|
||||
'buckets.$all.requests.delete',
|
||||
'files.$all.requests.create',
|
||||
'files.$all.requests.read',
|
||||
'files.$all.requests.update',
|
||||
'files.$all.requests.delete',
|
||||
];
|
||||
|
||||
foreach ($storageGeneralMetrics as $metric) {
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
|
||||
$storageBucketMetrics = [
|
||||
'files.bucketId.requests.create',
|
||||
'files.bucketId.requests.read',
|
||||
'files.bucketId.requests.update',
|
||||
'files.bucketId.requests.delete',
|
||||
];
|
||||
|
||||
$this->foreachDocument($projectId, 'buckets', [], function (Document $bucket) use ($storageBucketMetrics, $projectId) {
|
||||
$bucketId = $bucket->getId();
|
||||
foreach ($storageBucketMetrics as $metric) {
|
||||
$metric = str_replace('bucketId', $bucketId, $metric);
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function aggregateFunctionMetrics(string $projectId): void
|
||||
{
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
$functionsGeneralMetrics = [
|
||||
'project.$all.compute.total',
|
||||
'project.$all.compute.time',
|
||||
'executions.$all.compute.total',
|
||||
'executions.$all.compute.success',
|
||||
'executions.$all.compute.failure',
|
||||
'executions.$all.compute.time',
|
||||
'builds.$all.compute.total',
|
||||
'builds.$all.compute.success',
|
||||
'builds.$all.compute.failure',
|
||||
'builds.$all.compute.time',
|
||||
];
|
||||
|
||||
foreach ($functionsGeneralMetrics as $metric) {
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
|
||||
$functionMetrics = [
|
||||
'executions.functionId.compute.total',
|
||||
'executions.functionId.compute.success',
|
||||
'executions.functionId.compute.failure',
|
||||
'executions.functionId.compute.time',
|
||||
'builds.functionId.compute.total',
|
||||
'builds.functionId.compute.success',
|
||||
'builds.functionId.compute.failure',
|
||||
'builds.functionId.compute.time',
|
||||
];
|
||||
|
||||
$this->foreachDocument($projectId, 'functions', [], function (Document $function) use ($functionMetrics, $projectId) {
|
||||
$functionId = $function->getId();
|
||||
foreach ($functionMetrics as $metric) {
|
||||
$metric = str_replace('functionId', $functionId, $metric);
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function aggregateUsersMetrics(string $projectId): void
|
||||
{
|
||||
$metrics = [
|
||||
'users.$all.requests.create',
|
||||
'users.$all.requests.read',
|
||||
'users.$all.requests.update',
|
||||
'users.$all.requests.delete',
|
||||
'sessions.$all.requests.create',
|
||||
'sessions.$all.requests.delete'
|
||||
];
|
||||
|
||||
foreach ($metrics as $metric) {
|
||||
$this->aggregateDailyMetric($projectId, $metric);
|
||||
$this->aggregateMonthlyMetric($projectId, $metric);
|
||||
}
|
||||
}
|
||||
|
||||
protected function aggregateGeneralMetrics(string $projectId): void
|
||||
{
|
||||
$this->aggregateDailyMetric($projectId, 'project.$all.network.requests');
|
||||
$this->aggregateDailyMetric($projectId, 'project.$all.network.bandwidth');
|
||||
$this->aggregateDailyMetric($projectId, 'project.$all.network.inbound');
|
||||
$this->aggregateDailyMetric($projectId, 'project.$all.network.outbound');
|
||||
$this->aggregateMonthlyMetric($projectId, 'project.$all.network.requests');
|
||||
$this->aggregateMonthlyMetric($projectId, 'project.$all.network.bandwidth');
|
||||
$this->aggregateMonthlyMetric($projectId, 'project.$all.network.inbound');
|
||||
$this->aggregateMonthlyMetric($projectId, 'project.$all.network.outbound');
|
||||
}
|
||||
|
||||
protected function aggregateDailyMetric(string $projectId, string $metric): void
|
||||
{
|
||||
$beginOfDay = DateTime::createFromFormat('Y-m-d\TH:i:s.v', \date('Y-m-d\T00:00:00.000'))->format(DateTime::RFC3339);
|
||||
$endOfDay = DateTime::createFromFormat('Y-m-d\TH:i:s.v', \date('Y-m-d\T23:59:59.999'))->format(DateTime::RFC3339);
|
||||
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
$value = (int) $this->database->sum('stats', 'value', [
|
||||
Query::equal('metric', [$metric]),
|
||||
Query::equal('period', ['30m']),
|
||||
Query::greaterThanEqual('time', $beginOfDay),
|
||||
Query::lessThanEqual('time', $endOfDay),
|
||||
]);
|
||||
$this->createOrUpdateMetric($projectId, $metric, '1d', $beginOfDay, $value);
|
||||
}
|
||||
|
||||
protected function aggregateMonthlyMetric(string $projectId, string $metric): void
|
||||
{
|
||||
$beginOfMonth = DateTime::createFromFormat('Y-m-d\TH:i:s.v', \date('Y-m-01\T00:00:00.000'))->format(DateTime::RFC3339);
|
||||
$endOfMonth = DateTime::createFromFormat('Y-m-d\TH:i:s.v', \date('Y-m-t\T23:59:59.999'))->format(DateTime::RFC3339);
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
$value = (int) $this->database->sum('stats', 'value', [
|
||||
Query::equal('metric', [$metric]),
|
||||
Query::equal('period', ['1d']),
|
||||
Query::greaterThanEqual('time', $beginOfMonth),
|
||||
Query::lessThanEqual('time', $endOfMonth),
|
||||
]);
|
||||
$this->createOrUpdateMetric($projectId, $metric, '1mo', $beginOfMonth, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Stats
|
||||
* Collect all database related stats
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function collect(): void
|
||||
{
|
||||
$this->foreachDocument('console', 'projects', [], function (Document $project) {
|
||||
$projectId = $project->getInternalId();
|
||||
|
||||
// Aggregate new metrics from already collected usage metrics
|
||||
// for lower time period (1day and 1 month metric from 30 minute metrics)
|
||||
$this->aggregateGeneralMetrics($projectId);
|
||||
$this->aggregateFunctionMetrics($projectId);
|
||||
$this->aggregateDatabaseMetrics($projectId);
|
||||
$this->aggregateStorageMetrics($projectId);
|
||||
$this->aggregateUsersMetrics($projectId);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,360 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Usage\Calculators;
|
||||
|
||||
use Exception;
|
||||
use Appwrite\Usage\Calculator;
|
||||
use DateTime;
|
||||
use Utopia\Database\Database as UtopiaDatabase;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Authorization;
|
||||
use Utopia\Database\Exception\Structure;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class Database extends Calculator
|
||||
{
|
||||
protected array $periods = [
|
||||
[
|
||||
'key' => '30m',
|
||||
'multiplier' => 1800,
|
||||
],
|
||||
[
|
||||
'key' => '1d',
|
||||
'multiplier' => 86400,
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct(UtopiaDatabase $database, callable $errorHandler = null)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->errorHandler = $errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Per Period Metric
|
||||
*
|
||||
* Create given metric for each defined period
|
||||
*
|
||||
* @param string $projectId
|
||||
* @param string $metric
|
||||
* @param int $value
|
||||
* @param bool $monthly
|
||||
* @return void
|
||||
* @throws Authorization
|
||||
* @throws Structure
|
||||
*/
|
||||
protected function createPerPeriodMetric(string $projectId, string $metric, int $value, bool $monthly = false): void
|
||||
{
|
||||
foreach ($this->periods as $options) {
|
||||
$period = $options['key'];
|
||||
$date = new \DateTime();
|
||||
if ($period === '30m') {
|
||||
$minutes = $date->format('i') >= '30' ? "30" : "00";
|
||||
$time = $date->format('Y-m-d H:' . $minutes . ':00');
|
||||
} elseif ($period === '1d') {
|
||||
$time = $date->format('Y-m-d 00:00:00');
|
||||
} else {
|
||||
throw new Exception("Period type not found", 500);
|
||||
}
|
||||
$this->createOrUpdateMetric($projectId, $metric, $period, $time, $value);
|
||||
}
|
||||
|
||||
// Required for billing
|
||||
if ($monthly) {
|
||||
$time = DateTime::createFromFormat('Y-m-d\TH:i:s.v', \date('Y-m-01\T00:00:00.000'))->format(DateTime::RFC3339);
|
||||
$this->createOrUpdateMetric($projectId, $metric, '1mo', $time, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or Update Metric
|
||||
*
|
||||
* Create or update each metric in the stats collection for the given project
|
||||
*
|
||||
* @param string $projectId
|
||||
* @param string $metric
|
||||
* @param string $period
|
||||
* @param string $time
|
||||
* @param int $value
|
||||
*
|
||||
* @return void
|
||||
* @throws Authorization
|
||||
* @throws Structure
|
||||
*/
|
||||
protected function createOrUpdateMetric(string $projectId, string $metric, string $period, string $time, int $value): void
|
||||
{
|
||||
$id = \md5("{$time}_{$period}_{$metric}");
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
try {
|
||||
$document = $this->database->getDocument('stats', $id);
|
||||
if ($document->isEmpty()) {
|
||||
$this->database->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'period' => $period,
|
||||
'time' => $time,
|
||||
'metric' => $metric,
|
||||
'value' => $value,
|
||||
'type' => 2, // these are cumulative metrics
|
||||
]));
|
||||
} else {
|
||||
$this->database->updateDocument(
|
||||
'stats',
|
||||
$document->getId(),
|
||||
$document->setAttribute('value', $value)
|
||||
);
|
||||
}
|
||||
} catch (\Exception$e) { // if projects are deleted this might fail
|
||||
if (is_callable($this->errorHandler)) {
|
||||
call_user_func($this->errorHandler, $e, "sync_project_{$projectId}_metric_{$metric}");
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Foreach Document
|
||||
*
|
||||
* Call provided callback for each document in the collection
|
||||
*
|
||||
* @param string $projectId
|
||||
* @param string $collection
|
||||
* @param array $queries
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function foreachDocument(string $projectId, string $collection, array $queries, callable $callback): void
|
||||
{
|
||||
$limit = 50;
|
||||
$results = [];
|
||||
$sum = $limit;
|
||||
$latestDocument = null;
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
while ($sum === $limit) {
|
||||
try {
|
||||
$paginationQueries = [Query::limit($limit)];
|
||||
if ($latestDocument !== null) {
|
||||
$paginationQueries[] = Query::cursorAfter($latestDocument);
|
||||
}
|
||||
$results = $this->database->find($collection, \array_merge($paginationQueries, $queries));
|
||||
} catch (\Exception $e) {
|
||||
if (is_callable($this->errorHandler)) {
|
||||
call_user_func($this->errorHandler, $e, "fetch_documents_project_{$projectId}_collection_{$collection}");
|
||||
return;
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
if (empty($results)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sum = count($results);
|
||||
|
||||
foreach ($results as $document) {
|
||||
if (is_callable($callback)) {
|
||||
$callback($document);
|
||||
}
|
||||
}
|
||||
$latestDocument = $results[array_key_last($results)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sum
|
||||
*
|
||||
* Calculate sum of an attribute of documents in collection
|
||||
*
|
||||
* @param string $projectId
|
||||
* @param string $collection
|
||||
* @param string $attribute
|
||||
* @param string|null $metric
|
||||
* @param int $multiplier
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
private function sum(string $projectId, string $collection, string $attribute, string $metric = null, int $multiplier = 1): int
|
||||
{
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
try {
|
||||
$sum = $this->database->sum($collection, $attribute);
|
||||
$sum = (int) ($sum * $multiplier);
|
||||
|
||||
if (!is_null($metric)) {
|
||||
$this->createPerPeriodMetric($projectId, $metric, $sum);
|
||||
}
|
||||
return $sum;
|
||||
} catch (Exception $e) {
|
||||
if (is_callable($this->errorHandler)) {
|
||||
call_user_func($this->errorHandler, $e, "fetch_sum_project_{$projectId}_collection_{$collection}");
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count
|
||||
*
|
||||
* Count number of documents in collection
|
||||
*
|
||||
* @param string $projectId
|
||||
* @param string $collection
|
||||
* @param ?string $metric
|
||||
*
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
private function count(string $projectId, string $collection, ?string $metric = null): int
|
||||
{
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
try {
|
||||
$count = $this->database->count($collection);
|
||||
if (!is_null($metric)) {
|
||||
$this->createPerPeriodMetric($projectId, (string) $metric, $count);
|
||||
}
|
||||
return $count;
|
||||
} catch (Exception $e) {
|
||||
if (is_callable($this->errorHandler)) {
|
||||
call_user_func($this->errorHandler, $e, "fetch_count_project_{$projectId}_collection_{$collection}");
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deployments Total
|
||||
*
|
||||
* Total sum of storage used by deployments
|
||||
*
|
||||
* @param string $projectId
|
||||
*
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
private function deploymentsTotal(string $projectId): int
|
||||
{
|
||||
return $this->sum($projectId, 'deployments', 'size', 'deployments.$all.storage.size');
|
||||
}
|
||||
|
||||
/**
|
||||
* Users Stats
|
||||
*
|
||||
* Metric: users.count
|
||||
*
|
||||
* @param string $projectId
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
private function usersStats(string $projectId): void
|
||||
{
|
||||
$this->count($projectId, 'users', 'users.$all.count.total');
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage Stats
|
||||
*
|
||||
* Metrics: buckets.$all.count.total, files.$all.count.total, files.bucketId,count.total,
|
||||
* files.$all.storage.size, files.bucketId.storage.size, project.$all.storage.size
|
||||
*
|
||||
* @param string $projectId
|
||||
*
|
||||
* @return void
|
||||
* @throws Authorization
|
||||
* @throws Structure
|
||||
*/
|
||||
private function storageStats(string $projectId): void
|
||||
{
|
||||
$projectFilesTotal = 0;
|
||||
$projectFilesCount = 0;
|
||||
|
||||
$metric = 'buckets.$all.count.total';
|
||||
$this->count($projectId, 'buckets', $metric);
|
||||
|
||||
$this->foreachDocument($projectId, 'buckets', [], function ($bucket) use (&$projectFilesCount, &$projectFilesTotal, $projectId,) {
|
||||
$metric = "files.{$bucket->getId()}.count.total";
|
||||
$count = $this->count($projectId, 'bucket_' . $bucket->getInternalId(), $metric);
|
||||
$projectFilesCount += $count;
|
||||
|
||||
$metric = "files.{$bucket->getId()}.storage.size";
|
||||
$sum = $this->sum($projectId, 'bucket_' . $bucket->getInternalId(), 'sizeOriginal', $metric);
|
||||
$projectFilesTotal += $sum;
|
||||
});
|
||||
|
||||
$this->createPerPeriodMetric($projectId, 'files.$all.count.total', $projectFilesCount);
|
||||
$this->createPerPeriodMetric($projectId, 'files.$all.storage.size', $projectFilesTotal);
|
||||
|
||||
$deploymentsTotal = $this->deploymentsTotal($projectId);
|
||||
$this->createPerPeriodMetric($projectId, 'project.$all.storage.size', $projectFilesTotal + $deploymentsTotal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Database Stats
|
||||
*
|
||||
* Collect all database stats
|
||||
* Metrics: databases.$all.count.total, collections.$all.count.total, collections.databaseId.count.total,
|
||||
* documents.$all.count.all, documents.databaseId.count.total, documents.databaseId/collectionId.count.total
|
||||
*
|
||||
* @param string $projectId
|
||||
*
|
||||
* @return void
|
||||
* @throws Authorization
|
||||
* @throws Structure
|
||||
*/
|
||||
private function databaseStats(string $projectId): void
|
||||
{
|
||||
$projectDocumentsCount = 0;
|
||||
$projectCollectionsCount = 0;
|
||||
|
||||
$this->count($projectId, 'databases', 'databases.$all.count.total');
|
||||
|
||||
$this->foreachDocument($projectId, 'databases', [], function ($database) use (&$projectDocumentsCount, &$projectCollectionsCount, $projectId) {
|
||||
$metric = "collections.{$database->getId()}.count.total";
|
||||
$count = $this->count($projectId, 'database_' . $database->getInternalId(), $metric);
|
||||
$projectCollectionsCount += $count;
|
||||
$databaseDocumentsCount = 0;
|
||||
|
||||
$this->foreachDocument($projectId, 'database_' . $database->getInternalId(), [], function ($collection) use (&$projectDocumentsCount, &$databaseDocumentsCount, $projectId, $database) {
|
||||
$metric = "documents.{$database->getId()}/{$collection->getId()}.count.total";
|
||||
|
||||
$count = $this->count($projectId, 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $metric);
|
||||
$projectDocumentsCount += $count;
|
||||
$databaseDocumentsCount += $count;
|
||||
});
|
||||
|
||||
$this->createPerPeriodMetric($projectId, "documents.{$database->getId()}.count.total", $databaseDocumentsCount);
|
||||
});
|
||||
|
||||
$this->createPerPeriodMetric($projectId, 'collections.$all.count.total', $projectCollectionsCount);
|
||||
$this->createPerPeriodMetric($projectId, 'documents.$all.count.total', $projectDocumentsCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect Stats
|
||||
*
|
||||
* Collect all database related stats
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function collect(): void
|
||||
{
|
||||
$this->foreachDocument('console', 'projects', [], function (Document $project) {
|
||||
$projectId = $project->getInternalId();
|
||||
|
||||
$this->usersStats($projectId);
|
||||
$this->databaseStats($projectId);
|
||||
$this->storageStats($projectId);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Appwrite\Usage\Calculators;
|
||||
|
||||
use Utopia\App;
|
||||
use Appwrite\Usage\Calculator;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
@@ -10,12 +11,54 @@ use DateTime;
|
||||
|
||||
class TimeSeries extends Calculator
|
||||
{
|
||||
/**
|
||||
* InfluxDB
|
||||
*
|
||||
* @var InfluxDatabase
|
||||
*/
|
||||
protected InfluxDatabase $influxDB;
|
||||
|
||||
/**
|
||||
* Utopia Database
|
||||
*
|
||||
* @var Database
|
||||
*/
|
||||
protected Database $database;
|
||||
|
||||
/**
|
||||
* Error Handler Callback
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $errorHandler;
|
||||
|
||||
/**
|
||||
* Latest times for metric that was synced to the database
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $latestTime = [];
|
||||
|
||||
// all the mertics that we are collecting
|
||||
/**
|
||||
* Periods the metrics are collected for
|
||||
* @var array
|
||||
*/
|
||||
protected array $periods = [
|
||||
[
|
||||
'key' => '1h',
|
||||
'startTime' => '-24 hours'
|
||||
],
|
||||
[
|
||||
'key' => '1d',
|
||||
'startTime' => '-30 days'
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* All the metrics that we are collecting
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $metrics = [
|
||||
'project.$all.network.requests' => [
|
||||
'table' => 'appwrite_usage_project_{scope}_network_requests',
|
||||
@@ -189,12 +232,6 @@ class TimeSeries extends Calculator
|
||||
'executions.$all.compute.total' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute',
|
||||
],
|
||||
'builds.$all.compute.time' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute_time',
|
||||
],
|
||||
'executions.$all.compute.time' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute_time',
|
||||
],
|
||||
'builds.$all.compute.total' => [
|
||||
'table' => 'appwrite_usage_builds_{scope}_compute',
|
||||
],
|
||||
@@ -230,14 +267,7 @@ class TimeSeries extends Calculator
|
||||
'table' => 'appwrite_usage_builds_{scope}_compute',
|
||||
'groupBy' => ['functionId'],
|
||||
],
|
||||
'executions.functionId.compute.time' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute_time',
|
||||
'groupBy' => ['functionId'],
|
||||
],
|
||||
'builds.functionId.compute.time' => [
|
||||
'table' => 'appwrite_usage_builds_{scope}_compute_time',
|
||||
'groupBy' => ['functionId'],
|
||||
],
|
||||
|
||||
'executions.functionId.compute.failure' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute',
|
||||
'groupBy' => ['functionId'],
|
||||
@@ -267,19 +297,94 @@ class TimeSeries extends Calculator
|
||||
],
|
||||
],
|
||||
|
||||
// counters
|
||||
'users.$all.count.total' => [
|
||||
'table' => 'appwrite_usage_users_{scope}_count_total',
|
||||
],
|
||||
'buckets.$all.count.total' => [
|
||||
'table' => 'appwrite_usage_buckets_{scope}_count_total',
|
||||
],
|
||||
'files.$all.count.total' => [
|
||||
'table' => 'appwrite_usage_files_{scope}_count_total',
|
||||
],
|
||||
'files.bucketId.count.total' => [
|
||||
'table' => 'appwrite_usage_files_{scope}_count_total',
|
||||
'groupBy' => ['bucketId']
|
||||
],
|
||||
'databases.$all.count.total' => [
|
||||
'table' => 'appwrite_usage_databases_{scope}_count_total',
|
||||
],
|
||||
'collections.$all.count.total' => [
|
||||
'table' => 'appwrite_usage_collections_{scope}_count_total',
|
||||
],
|
||||
'documents.$all.count.total' => [
|
||||
'table' => 'appwrite_usage_documents_{scope}_count_total',
|
||||
],
|
||||
'collections.databaseId.count.total' => [
|
||||
'table' => 'appwrite_usage_collections_{scope}_count_total',
|
||||
'groupBy' => ['databaseId']
|
||||
],
|
||||
'documents.databaseId.count.total' => [
|
||||
'table' => 'appwrite_usage_documents_{scope}_count_total',
|
||||
'groupBy' => ['databaseId']
|
||||
],
|
||||
'documents.databaseId/collectionId.count.total' => [
|
||||
'table' => 'appwrite_usage_documents_{scope}_count_total',
|
||||
'groupBy' => ['databaseId', 'collectionId']
|
||||
],
|
||||
'deployments.$all.storage.size' => [
|
||||
'table' => 'appwrite_usage_deployments_{scope}_storage_size',
|
||||
],
|
||||
'project.$all.storage.size' => [
|
||||
'table' => 'appwrite_usage_project_{scope}_storage_size',
|
||||
],
|
||||
'files.$all.storage.size' => [
|
||||
'table' => 'appwrite_usage_files_{scope}_storage_size',
|
||||
],
|
||||
'files.$bucketId.storage.size' => [
|
||||
'table' => 'appwrite_usage_files_{scope}_storage_size',
|
||||
'groupBy' => ['bucketId']
|
||||
],
|
||||
|
||||
'builds.$all.compute.time' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute_time',
|
||||
],
|
||||
'executions.$all.compute.time' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute_time',
|
||||
],
|
||||
|
||||
'executions.functionId.compute.time' => [
|
||||
'table' => 'appwrite_usage_executions_{scope}_compute_time',
|
||||
'groupBy' => ['functionId'],
|
||||
],
|
||||
'builds.functionId.compute.time' => [
|
||||
'table' => 'appwrite_usage_builds_{scope}_compute_time',
|
||||
'groupBy' => ['functionId'],
|
||||
],
|
||||
|
||||
'project.$all.compute.time' => [ // Built time + execution time
|
||||
'table' => 'appwrite_usage_project_{scope}_compute_time',
|
||||
'groupBy' => ['functionId'],
|
||||
],
|
||||
|
||||
'deployments.$all.storage.size' => [
|
||||
'table' => 'appwrite_usage_deployments_{scope}_storage_size'
|
||||
],
|
||||
'project.$all.storage.size' => [
|
||||
'table' => 'appwrite_usage_project_{scope}_storage_size'
|
||||
],
|
||||
'files.$all.storage.size' => [
|
||||
'table' => 'appwrite_usage_files_{scope}_storage_size'
|
||||
],
|
||||
'files.bucketId.storage.size' => [
|
||||
'table' => 'appwrite_usage_files_{scope}_storage_size',
|
||||
'groupBy' => ['bucketId']
|
||||
]
|
||||
];
|
||||
|
||||
protected array $period = [
|
||||
'key' => '30m',
|
||||
'startTime' => '-24 hours',
|
||||
];
|
||||
|
||||
public function __construct(Database $database, InfluxDatabase $influxDB, callable $errorHandler = null)
|
||||
public function __construct(string $region, Database $database, InfluxDatabase $influxDB, callable $errorHandler = null)
|
||||
{
|
||||
parent::__construct($region);
|
||||
$this->database = $database;
|
||||
$this->influxDB = $influxDB;
|
||||
$this->errorHandler = $errorHandler;
|
||||
@@ -301,9 +406,7 @@ class TimeSeries extends Calculator
|
||||
private function createOrUpdateMetric(string $projectId, string $time, string $period, string $metric, int $value, int $type): void
|
||||
{
|
||||
$id = \md5("{$time}_{$period}_{$metric}");
|
||||
$this->database->setNamespace('_console');
|
||||
$project = $this->database->getDocument('projects', $projectId);
|
||||
$this->database->setNamespace('_' . $project->getInternalId());
|
||||
$this->database->setNamespace('_' . $projectId);
|
||||
|
||||
try {
|
||||
$document = $this->database->getDocument('stats', $id);
|
||||
@@ -315,6 +418,7 @@ class TimeSeries extends Calculator
|
||||
'metric' => $metric,
|
||||
'value' => $value,
|
||||
'type' => $type,
|
||||
'region' => $this->region,
|
||||
]));
|
||||
} else {
|
||||
$this->database->updateDocument(
|
||||
@@ -365,7 +469,7 @@ class TimeSeries extends Calculator
|
||||
$query .= "WHERE \"time\" > '{$start}' ";
|
||||
$query .= "AND \"time\" < '{$end}' ";
|
||||
$query .= "AND \"metric_type\"='counter' {$filters} ";
|
||||
$query .= "GROUP BY time({$period['key']}), \"projectId\" {$groupBy} ";
|
||||
$query .= "GROUP BY time({$period['key']}), \"projectId\", \"projectInternalId\" {$groupBy} ";
|
||||
$query .= "FILL(null)";
|
||||
|
||||
try {
|
||||
@@ -387,9 +491,11 @@ class TimeSeries extends Calculator
|
||||
}
|
||||
|
||||
$value = (!empty($point['value'])) ? $point['value'] : 0;
|
||||
|
||||
if (empty($point['projectInternalId'] ?? null)) {
|
||||
continue;
|
||||
}
|
||||
$this->createOrUpdateMetric(
|
||||
$projectId,
|
||||
$point['projectInternalId'],
|
||||
$point['time'],
|
||||
$period['key'],
|
||||
$metricUpdated,
|
||||
@@ -416,14 +522,16 @@ class TimeSeries extends Calculator
|
||||
*/
|
||||
public function collect(): void
|
||||
{
|
||||
foreach ($this->metrics as $metric => $options) { //for each metrics
|
||||
try {
|
||||
$this->syncFromInfluxDB($metric, $options, $this->period);
|
||||
} catch (\Exception $e) {
|
||||
if (is_callable($this->errorHandler)) {
|
||||
call_user_func($this->errorHandler, $e);
|
||||
} else {
|
||||
throw $e;
|
||||
foreach ($this->periods as $period) {
|
||||
foreach ($this->metrics as $metric => $options) { //for each metrics
|
||||
try {
|
||||
$this->syncFromInfluxDB($metric, $options, $period);
|
||||
} catch (\Exception $e) {
|
||||
if (is_callable($this->errorHandler)) {
|
||||
call_user_func($this->errorHandler, $e);
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,11 +76,14 @@ class Stats
|
||||
|
||||
/**
|
||||
* Submit data to StatsD.
|
||||
* Send various metrics to StatsD based on the parameters that are set
|
||||
* @return void
|
||||
*/
|
||||
public function submit(): void
|
||||
{
|
||||
$projectId = $this->params['projectId'] ?? '';
|
||||
$tags = ",projectId={$projectId},version=" . App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
$projectInternalId = $this->params['projectInternalId'];
|
||||
$tags = ",projectInternalId={$projectInternalId},projectId={$projectId},version=" . App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
// the global namespace is prepended to every key (optional)
|
||||
$this->statsd->setNamespace($this->namespace);
|
||||
@@ -91,8 +94,8 @@ class Stats
|
||||
$this->statsd->increment('project.{scope}.network.requests' . $tags . ',method=' . \strtolower($httpMethod));
|
||||
}
|
||||
|
||||
$inbound = $this->params['networkRequestSize'] ?? 0;
|
||||
$outbound = $this->params['networkResponseSize'] ?? 0;
|
||||
$inbound = $this->params['project.{scope}.network.inbound'] ?? 0;
|
||||
$outbound = $this->params['project.{scope}.network.outbound'] ?? 0;
|
||||
$this->statsd->count('project.{scope}.network.inbound' . $tags, $inbound);
|
||||
$this->statsd->count('project.{scope}.network.outbound' . $tags, $outbound);
|
||||
$this->statsd->count('project.{scope}.network.bandwidth' . $tags, $inbound + $outbound);
|
||||
@@ -102,12 +105,13 @@ class Stats
|
||||
'users.{scope}.requests.read',
|
||||
'users.{scope}.requests.update',
|
||||
'users.{scope}.requests.delete',
|
||||
'users.{scope}.count.total',
|
||||
];
|
||||
|
||||
foreach ($usersMetrics as $metric) {
|
||||
$value = $this->params[$metric] ?? 0;
|
||||
if ($value >= 1) {
|
||||
$this->statsd->increment($metric . $tags);
|
||||
if ($value === 1 || $value === -1) {
|
||||
$this->statsd->count($metric . $tags, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,13 +128,16 @@ class Stats
|
||||
'documents.{scope}.requests.read',
|
||||
'documents.{scope}.requests.update',
|
||||
'documents.{scope}.requests.delete',
|
||||
'databases.{scope}.count.total',
|
||||
'collections.{scope}.count.total',
|
||||
'documents.{scope}.count.total'
|
||||
];
|
||||
|
||||
foreach ($dbMetrics as $metric) {
|
||||
$value = $this->params[$metric] ?? 0;
|
||||
if ($value >= 1) {
|
||||
if ($value === 1 || $value === -1) {
|
||||
$dbTags = $tags . ",collectionId=" . ($this->params['collectionId'] ?? '') . ",databaseId=" . ($this->params['databaseId'] ?? '');
|
||||
$this->statsd->increment($metric . $dbTags);
|
||||
$this->statsd->count($metric . $dbTags, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,13 +150,16 @@ class Stats
|
||||
'files.{scope}.requests.read',
|
||||
'files.{scope}.requests.update',
|
||||
'files.{scope}.requests.delete',
|
||||
'buckets.{scope}.count.total',
|
||||
'files.{scope}.count.total',
|
||||
'files.{scope}.storage.size'
|
||||
];
|
||||
|
||||
foreach ($storageMertics as $metric) {
|
||||
$value = $this->params[$metric] ?? 0;
|
||||
if ($value >= 1) {
|
||||
if ($value !== 0) {
|
||||
$storageTags = $tags . ",bucketId=" . ($this->params['bucketId'] ?? '');
|
||||
$this->statsd->increment($metric . $storageTags);
|
||||
$this->statsd->count($metric . $storageTags, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,19 +186,30 @@ class Stats
|
||||
$functionBuildTime = ($this->params['buildTime'] ?? 0) * 1000; // ms
|
||||
$functionBuildStatus = $this->params['buildStatus'] ?? '';
|
||||
$functionCompute = $functionExecutionTime + $functionBuildTime;
|
||||
$functionTags = $tags . ',functionId=' . $functionId;
|
||||
|
||||
$deploymentSize = $this->params['deployment.{scope}.storage.size'] ?? 0;
|
||||
$storageSize = $this->params['files.{scope}.storage.size'] ?? 0;
|
||||
if ($deploymentSize + $storageSize > 0 || $deploymentSize + $storageSize <= -1) {
|
||||
$this->statsd->count('project.{scope}.storage.size' . $tags, $deploymentSize + $storageSize);
|
||||
}
|
||||
|
||||
if ($deploymentSize !== 0) {
|
||||
$this->statsd->count('deployments.{scope}.storage.size' . $functionTags, $deploymentSize);
|
||||
}
|
||||
|
||||
if ($functionExecution >= 1) {
|
||||
$this->statsd->increment('executions.{scope}.compute' . $tags . ',functionId=' . $functionId . ',functionStatus=' . $functionExecutionStatus);
|
||||
$this->statsd->increment('executions.{scope}.compute' . $functionTags . ',functionStatus=' . $functionExecutionStatus);
|
||||
if ($functionExecutionTime > 0) {
|
||||
$this->statsd->count('executions.{scope}.compute.time' . $tags . ',functionId=' . $functionId, $functionExecutionTime);
|
||||
$this->statsd->count('executions.{scope}.compute.time' . $functionTags, $functionExecutionTime);
|
||||
}
|
||||
}
|
||||
if ($functionBuild >= 1) {
|
||||
$this->statsd->increment('builds.{scope}.compute' . $tags . ',functionId=' . $functionId . ',functionBuildStatus=' . $functionBuildStatus);
|
||||
$this->statsd->count('builds.{scope}.compute.time' . $tags . ',functionId=' . $functionId, $functionBuildTime);
|
||||
$this->statsd->increment('builds.{scope}.compute' . $functionTags . ',functionBuildStatus=' . $functionBuildStatus);
|
||||
$this->statsd->count('builds.{scope}.compute.time' . $functionTags, $functionBuildTime);
|
||||
}
|
||||
if ($functionBuild + $functionExecution >= 1) {
|
||||
$this->statsd->count('project.{scope}.compute.time' . $tags . ',functionId=' . $functionId, $functionCompute);
|
||||
$this->statsd->count('project.{scope}.compute.time' . $functionTags, $functionCompute);
|
||||
}
|
||||
|
||||
$this->reset();
|
||||
|
||||
@@ -7,7 +7,8 @@ use Appwrite\Utopia\Database\Validator\Queries\Base;
|
||||
class Projects extends Base
|
||||
{
|
||||
public const ALLOWED_ATTRIBUTES = [
|
||||
'name'
|
||||
'name',
|
||||
'teamId'
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,6 +70,7 @@ use Appwrite\Utopia\Response\Model\HealthStatus;
|
||||
use Appwrite\Utopia\Response\Model\HealthTime;
|
||||
use Appwrite\Utopia\Response\Model\HealthVersion;
|
||||
use Appwrite\Utopia\Response\Model\Mock; // Keep last
|
||||
use Appwrite\Utopia\Response\Model\Provider;
|
||||
use Appwrite\Utopia\Response\Model\Runtime;
|
||||
use Appwrite\Utopia\Response\Model\UsageBuckets;
|
||||
use Appwrite\Utopia\Response\Model\UsageCollection;
|
||||
@@ -194,6 +195,8 @@ class Response extends SwooleResponse
|
||||
public const MODEL_WEBHOOK_LIST = 'webhookList';
|
||||
public const MODEL_KEY = 'key';
|
||||
public const MODEL_KEY_LIST = 'keyList';
|
||||
public const MODEL_PROVIDER = 'provider';
|
||||
public const MODEL_PROVIDER_LIST = 'providerList';
|
||||
public const MODEL_PLATFORM = 'platform';
|
||||
public const MODEL_PLATFORM_LIST = 'platformList';
|
||||
public const MODEL_DOMAIN = 'domain';
|
||||
@@ -260,6 +263,7 @@ class Response extends SwooleResponse
|
||||
->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false))
|
||||
->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false))
|
||||
->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false))
|
||||
->setModel(new BaseList('Providers List', self::MODEL_PROVIDER_LIST, 'platforms', self::MODEL_PROVIDER, true, false))
|
||||
->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false))
|
||||
->setModel(new BaseList('Domains List', self::MODEL_DOMAIN_LIST, 'domains', self::MODEL_DOMAIN, true, false))
|
||||
->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY))
|
||||
@@ -314,6 +318,7 @@ class Response extends SwooleResponse
|
||||
->setModel(new Webhook())
|
||||
->setModel(new Key())
|
||||
->setModel(new Domain())
|
||||
->setModel(new Provider())
|
||||
->setModel(new Platform())
|
||||
->setModel(new Variable())
|
||||
->setModel(new Country())
|
||||
|
||||
@@ -82,6 +82,12 @@ class Deployment extends Model
|
||||
'default' => '',
|
||||
'example' => 'enabled',
|
||||
])
|
||||
->addRule('buildTime', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'The current build time in seconds.',
|
||||
'default' => 0,
|
||||
'example' => 128,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use Utopia\Config\Config;
|
||||
@@ -101,12 +102,25 @@ class Project extends Model
|
||||
'default' => '',
|
||||
'example' => '131102020',
|
||||
])
|
||||
->addRule('authDuration', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Session duration in seconds.',
|
||||
'default' => Auth::TOKEN_EXPIRATION_LOGIN_LONG,
|
||||
'example' => 60,
|
||||
])
|
||||
->addRule('authLimit', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Max users allowed. 0 is unlimited.',
|
||||
'default' => 0,
|
||||
'example' => 100,
|
||||
])
|
||||
->addRule('providers', [
|
||||
'type' => Response::MODEL_PROVIDER,
|
||||
'description' => 'List of Providers.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('platforms', [
|
||||
'type' => Response::MODEL_PLATFORM,
|
||||
'description' => 'List of Platforms.',
|
||||
@@ -138,32 +152,8 @@ class Project extends Model
|
||||
;
|
||||
|
||||
$services = Config::getParam('services', []);
|
||||
$providers = Config::getParam('providers', []);
|
||||
$auth = Config::getParam('auth', []);
|
||||
|
||||
foreach ($providers as $index => $provider) {
|
||||
if (!$provider['enabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = (isset($provider['name'])) ? $provider['name'] : 'Unknown';
|
||||
|
||||
$this
|
||||
->addRule('provider' . \ucfirst($index) . 'Appid', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => $name . ' OAuth app ID.',
|
||||
'example' => '123247283472834787438',
|
||||
'default' => '',
|
||||
])
|
||||
->addRule('provider' . \ucfirst($index) . 'Secret', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => $name . ' OAuth secret ID.',
|
||||
'example' => 'djsgudsdsewe43434343dd34...',
|
||||
'default' => '',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
foreach ($auth as $index => $method) {
|
||||
$name = $method['name'] ?? '';
|
||||
$key = $method['key'] ?? '';
|
||||
@@ -224,6 +214,7 @@ class Project extends Model
|
||||
*/
|
||||
public function filter(Document $document): Document
|
||||
{
|
||||
// Services
|
||||
$values = $document->getAttribute('services', []);
|
||||
$services = Config::getParam('services', []);
|
||||
|
||||
@@ -236,10 +227,12 @@ class Project extends Model
|
||||
$document->setAttribute('serviceStatusFor' . ucfirst($key), $value);
|
||||
}
|
||||
|
||||
// Auth
|
||||
$authValues = $document->getAttribute('auths', []);
|
||||
$auth = Config::getParam('auth', []);
|
||||
|
||||
$document->setAttribute('authLimit', $authValues['limit'] ?? 0);
|
||||
$document->setAttribute('authDuration', $authValues['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG);
|
||||
|
||||
foreach ($auth as $index => $method) {
|
||||
$key = $method['key'];
|
||||
@@ -247,17 +240,27 @@ class Project extends Model
|
||||
$document->setAttribute('auth' . ucfirst($key), $value);
|
||||
}
|
||||
|
||||
// Providers
|
||||
$providers = Config::getParam('providers', []);
|
||||
$providerValues = $document->getAttribute('authProviders', []);
|
||||
$projectProviders = [];
|
||||
|
||||
foreach ($providers as $key => $provider) {
|
||||
if (!$provider['enabled']) {
|
||||
// Disabled by Appwrite configuration, exclude from response
|
||||
continue;
|
||||
}
|
||||
$appId = $providerValues[$key . 'Appid'] ?? '';
|
||||
$secret = $providerValues[$key . 'Secret'] ?? '';
|
||||
$document->setAttribute('provider' . ucfirst($key) . 'Appid', $appId)->setAttribute('provider' . ucfirst($key) . 'Secret', $secret);
|
||||
|
||||
$projectProviders[] = new Document([
|
||||
'name' => ucfirst($key),
|
||||
'appId' => $providerValues[$key . 'Appid'] ?? '',
|
||||
'secret' => $providerValues[$key . 'Secret'] ?? '',
|
||||
'enabled' => $providerValues[$key . 'Enabled'] ?? false,
|
||||
]);
|
||||
}
|
||||
|
||||
$document->setAttribute("providers", $projectProviders);
|
||||
|
||||
return $document;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class Provider extends Model
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $public = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Provider name.',
|
||||
'default' => '',
|
||||
'example' => 'GitHub',
|
||||
])
|
||||
->addRule('appId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OAuth 2.0 application ID.',
|
||||
'default' => '',
|
||||
'example' => '259125845563242502',
|
||||
])
|
||||
->addRule('secret', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.',
|
||||
'default' => '',
|
||||
'example' => 'Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ',
|
||||
])
|
||||
->addRule('enabled', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Provider is active and can be used to create session.',
|
||||
'example' => '',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Provider';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_PROVIDER;
|
||||
}
|
||||
}
|
||||
@@ -17,45 +17,45 @@ class UsageBuckets extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('filesCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of files in this bucket.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesStorage', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total storage of files in this bucket.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,38 +17,38 @@ class UsageCollection extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('documentsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,73 +17,73 @@ class UsageDatabase extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('documentsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of collections.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections delete.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,108 +17,108 @@ class UsageDatabases extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('databasesCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of documents.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of collections.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('databasesDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of collections.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documentsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for documents deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collectionsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for collections delete.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,59 +17,59 @@ class UsageFunction extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('executionsTotal', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of function executions.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsFailure', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function execution failures.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsSuccess', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function execution successes.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsTime', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function execution duration.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsTotal', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of function builds.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsFailure', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function build failures.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsSuccess', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function build successes.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsTime', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function build duration.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,59 +17,59 @@ class UsageFunctions extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('executionsTotal', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of function executions.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsFailure', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function execution failures.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsSuccess', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function execution successes.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executionsTime', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function execution duration.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsTotal', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of function builds.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsFailure', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function build failures.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsSuccess', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function build successes.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buildsTime', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function build duration.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,52 +17,59 @@ class UsageProject extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('requests', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of requests.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('network', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for consumed bandwidth.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('executions', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for function executions.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('documents', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of documents.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('collections', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for number of collections.',
|
||||
->addRule('databases', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of databases.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('users', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of users.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('storage', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for the occupied storage size (in bytes).',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('buckets', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for number of buckets.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,80 +17,80 @@ class UsageStorage extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('storage', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for the occupied storage size (in bytes).',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of files.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('bucketsCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of buckets.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('bucketsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for buckets created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('bucketsRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for buckets read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('bucketsUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for buckets updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('bucketsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for buckets deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('filesDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for files deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
@@ -17,59 +17,59 @@ class UsageUsers extends Model
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('usersCount', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for total number of users.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('usersCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for users created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('usersRead', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for users read.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('usersUpdate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for users updated.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('usersDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for users deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('sessionsCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for sessions created.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('sessionsProviderCreate', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for sessions created for a provider ( email, anonymous or oauth2 ).',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('sessionsDelete', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated stats for sessions deleted.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass(),
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
|
||||
Reference in New Issue
Block a user