diff --git a/.env b/.env index 096bde5c52..73990bc91c 100644 --- a/.env +++ b/.env @@ -47,6 +47,7 @@ _APP_SMTP_USERNAME= _APP_SMTP_PASSWORD= _APP_HAMSTER_RECIPIENTS= _APP_HAMSTER_INTERVAL=86400 +_APP_MIXPANEL_TOKEN= _APP_SMS_PROVIDER=sms://username:password@mock _APP_SMS_FROM=+123456789 _APP_STORAGE_LIMIT=30000000 diff --git a/composer.json b/composer.json index f505291643..f947592f9e 100644 --- a/composer.json +++ b/composer.json @@ -44,10 +44,10 @@ "appwrite/php-clamav": "1.1.*", "appwrite/php-runtimes": "0.11.*", "utopia-php/abuse": "0.16.*", - "utopia-php/analytics": "0.2.*", + "utopia-php/analytics": "0.10.1", "utopia-php/audit": "0.17.*", "utopia-php/cache": "0.8.*", - "utopia-php/cli": "0.14.*", + "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", "utopia-php/database": "0.28.*", "utopia-php/queue": "0.5.*", @@ -56,7 +56,7 @@ "utopia-php/pools": "0.4.*", "utopia-php/preloader": "0.2.*", "utopia-php/domains": "1.1.*", - "utopia-php/framework": "0.25.*", + "utopia-php/framework": "0.26.*", "utopia-php/image": "0.5.*", "utopia-php/dsn": "0.1.*", "utopia-php/locale": "0.4.*", @@ -73,8 +73,7 @@ "phpmailer/phpmailer": "6.6.0", "chillerlan/php-qrcode": "4.3.3", "adhocore/jwt": "1.1.2", - "slickdeals/statsd": "3.1.0", - "league/csv": "^9.0.0" + "slickdeals/statsd": "3.1.0" }, "repositories": [ { diff --git a/composer.lock b/composer.lock index 4c23baa2b5..a54754a036 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "55eaba9ed1fd51ed74a18ee488c3fdd1", + "content-hash": "f409ee69f8040b1928cbc618ff3e8a43", "packages": [ { "name": "adhocore/jwt", @@ -620,16 +620,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.4.3", + "version": "2.4.4", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "67c26b443f348a51926030c83481b85718457d3d" + "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d", - "reference": "67c26b443f348a51926030c83481b85718457d3d", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", + "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", "shasum": "" }, "require": { @@ -719,7 +719,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.4.3" + "source": "https://github.com/guzzle/psr7/tree/2.4.4" }, "funding": [ { @@ -735,7 +735,7 @@ "type": "tidelift" } ], - "time": "2022-10-26T14:07:24+00:00" + "time": "2023-03-09T13:19:02+00:00" }, { "name": "influxdb/influxdb-php", @@ -870,90 +870,6 @@ }, "time": "2022-11-29T16:25:20+00:00" }, - { - "name": "league/csv", - "version": "9.8.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/csv.git", - "reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/9d2e0265c5d90f5dd601bc65ff717e05cec19b47", - "reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "ext-curl": "*", - "ext-dom": "*", - "friendsofphp/php-cs-fixer": "^v3.4.0", - "phpstan/phpstan": "^1.3.0", - "phpstan/phpstan-phpunit": "^1.0.0", - "phpstan/phpstan-strict-rules": "^1.1.0", - "phpunit/phpunit": "^9.5.11" - }, - "suggest": { - "ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", - "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.x-dev" - } - }, - "autoload": { - "files": [ - "src/functions_include.php" - ], - "psr-4": { - "League\\Csv\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://github.com/nyamsprod/", - "role": "Developer" - } - ], - "description": "CSV data manipulation made easy in PHP", - "homepage": "https://csv.thephpleague.com", - "keywords": [ - "convert", - "csv", - "export", - "filter", - "import", - "read", - "transform", - "write" - ], - "support": { - "docs": "https://csv.thephpleague.com", - "issues": "https://github.com/thephpleague/csv/issues", - "rss": "https://github.com/thephpleague/csv/releases.atom", - "source": "https://github.com/thephpleague/csv" - }, - "funding": [ - { - "url": "https://github.com/sponsors/nyamsprod", - "type": "github" - } - ], - "time": "2022-01-04T00:13:07+00:00" - }, { "name": "matomo/device-detector", "version": "6.0.0", @@ -1667,24 +1583,25 @@ }, { "name": "utopia-php/analytics", - "version": "0.2.0", + "version": "0.10.1", "source": { "type": "git", "url": "https://github.com/utopia-php/analytics.git", - "reference": "adfc2d057a7f6ab618a77c8a20ed3e35485ff416" + "reference": "70ada5e6b192ae27e6d5467899a4cdd886003835" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/analytics/zipball/adfc2d057a7f6ab618a77c8a20ed3e35485ff416", - "reference": "adfc2d057a7f6ab618a77c8a20ed3e35485ff416", + "url": "https://api.github.com/repos/utopia-php/analytics/zipball/70ada5e6b192ae27e6d5467899a4cdd886003835", + "reference": "70ada5e6b192ae27e6d5467899a4cdd886003835", "shasum": "" }, "require": { - "php": ">=7.4" + "php": ">=8.0", + "utopia-php/cli": "^0.15.0" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "vimeo/psalm": "4.0.1" + "laravel/pint": "dev-main", + "phpunit/phpunit": "^9.3" }, "type": "library", "autoload": { @@ -1696,16 +1613,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - }, - { - "name": "Torsten Dittmann", - "email": "torsten@appwrite.io" - } - ], "description": "A simple library to track events & users.", "keywords": [ "analytics", @@ -1716,9 +1623,9 @@ ], "support": { "issues": "https://github.com/utopia-php/analytics/issues", - "source": "https://github.com/utopia-php/analytics/tree/0.2.0" + "source": "https://github.com/utopia-php/analytics/tree/0.10.1" }, - "time": "2021-03-23T21:33:07+00:00" + "time": "2023-03-17T14:42:35+00:00" }, { "name": "utopia-php/audit", @@ -1818,16 +1725,16 @@ }, { "name": "utopia-php/cli", - "version": "0.14.0", + "version": "0.15.0", "source": { "type": "git", "url": "https://github.com/utopia-php/cli.git", - "reference": "c30ef985a4e739758a0d95eb0706b357b6d8c086" + "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cli/zipball/c30ef985a4e739758a0d95eb0706b357b6d8c086", - "reference": "c30ef985a4e739758a0d95eb0706b357b6d8c086", + "url": "https://api.github.com/repos/utopia-php/cli/zipball/ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea", + "reference": "ccb7c8125ffe0254fef8f25744bfa376eb7bd0ea", "shasum": "" }, "require": { @@ -1835,8 +1742,10 @@ "utopia-php/framework": "0.*.*" }, "require-dev": { + "laravel/pint": "1.2.*", "phpunit/phpunit": "^9.3", - "squizlabs/php_codesniffer": "^3.6" + "squizlabs/php_codesniffer": "^3.6", + "vimeo/psalm": "4.0.1" }, "type": "library", "autoload": { @@ -1848,12 +1757,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - } - ], "description": "A simple CLI library to manage command line applications", "keywords": [ "cli", @@ -1865,9 +1768,9 @@ ], "support": { "issues": "https://github.com/utopia-php/cli/issues", - "source": "https://github.com/utopia-php/cli/tree/0.14.0" + "source": "https://github.com/utopia-php/cli/tree/0.15.0" }, - "time": "2022-10-09T10:19:07+00:00" + "time": "2023-03-01T05:55:14+00:00" }, { "name": "utopia-php/config", @@ -2077,16 +1980,16 @@ }, { "name": "utopia-php/framework", - "version": "0.25.1", + "version": "0.26.0", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "2391b397135586b2100d39e338827bef8d2f4ad0" + "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/2391b397135586b2100d39e338827bef8d2f4ad0", - "reference": "2391b397135586b2100d39e338827bef8d2f4ad0", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/e8da5576370366d3bf9c574ec855f8c96fe4f34e", + "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e", "shasum": "" }, "require": { @@ -2115,9 +2018,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.25.1" + "source": "https://github.com/utopia-php/framework/tree/0.26.0" }, - "time": "2022-11-23T18:22:23+00:00" + "time": "2023-01-13T08:14:43+00:00" }, { "name": "utopia-php/image", @@ -2325,23 +2228,24 @@ }, { "name": "utopia-php/orchestration", - "version": "0.9.0", + "version": "0.9.1", "source": { "type": "git", "url": "https://github.com/utopia-php/orchestration.git", - "reference": "1d4f66684b8c4927f31b695817eae6d84aafd172" + "reference": "55f43513b3f940a3f4f9c2cde7682d0c2581beb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/orchestration/zipball/1d4f66684b8c4927f31b695817eae6d84aafd172", - "reference": "1d4f66684b8c4927f31b695817eae6d84aafd172", + "url": "https://api.github.com/repos/utopia-php/orchestration/zipball/55f43513b3f940a3f4f9c2cde7682d0c2581beb0", + "reference": "55f43513b3f940a3f4f9c2cde7682d0c2581beb0", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/cli": "0.14.*" + "utopia-php/cli": "0.15.*" }, "require-dev": { + "laravel/pint": "^1.2", "phpunit/phpunit": "^9.3", "vimeo/psalm": "4.0.1" }, @@ -2368,34 +2272,34 @@ ], "support": { "issues": "https://github.com/utopia-php/orchestration/issues", - "source": "https://github.com/utopia-php/orchestration/tree/0.9.0" + "source": "https://github.com/utopia-php/orchestration/tree/0.9.1" }, - "time": "2022-11-09T17:38:00+00:00" + "time": "2023-03-17T15:05:06+00:00" }, { "name": "utopia-php/platform", - "version": "0.3.1", + "version": "0.3.3", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "fe9f64420957dc8fb6201d22b499572f021411e4" + "reference": "a9e7a501f33e0da59779782359a747cb8d34cf6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/fe9f64420957dc8fb6201d22b499572f021411e4", - "reference": "fe9f64420957dc8fb6201d22b499572f021411e4", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/a9e7a501f33e0da59779782359a747cb8d34cf6f", + "reference": "a9e7a501f33e0da59779782359a747cb8d34cf6f", "shasum": "" }, "require": { "ext-json": "*", "ext-redis": "*", "php": ">=8.0", - "utopia-php/cli": "0.14.*", - "utopia-php/framework": "0.25.*" + "utopia-php/cli": "0.15.*", + "utopia-php/framework": "0.26.*" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "squizlabs/php_codesniffer": "^3.6" + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3" }, "type": "library", "autoload": { @@ -2417,9 +2321,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.3.1" + "source": "https://github.com/utopia-php/platform/tree/0.3.3" }, - "time": "2022-11-10T07:04:24+00:00" + "time": "2023-03-07T08:52:22+00:00" }, { "name": "utopia-php/pools", @@ -2527,21 +2431,21 @@ }, { "name": "utopia-php/queue", - "version": "0.5.1", + "version": "0.5.2", "source": { "type": "git", "url": "https://github.com/utopia-php/queue.git", - "reference": "4b39e1f232b2e619b0d7fb4004f2356df334ddc1" + "reference": "310271c5cd477541208d7fa74a4dea64df8e04a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/queue/zipball/4b39e1f232b2e619b0d7fb4004f2356df334ddc1", - "reference": "4b39e1f232b2e619b0d7fb4004f2356df334ddc1", + "url": "https://api.github.com/repos/utopia-php/queue/zipball/310271c5cd477541208d7fa74a4dea64df8e04a0", + "reference": "310271c5cd477541208d7fa74a4dea64df8e04a0", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/cli": "0.14.*", + "utopia-php/cli": "0.15.*", "utopia-php/framework": "0.*.*" }, "require-dev": { @@ -2582,9 +2486,9 @@ ], "support": { "issues": "https://github.com/utopia-php/queue/issues", - "source": "https://github.com/utopia-php/queue/tree/0.5.1" + "source": "https://github.com/utopia-php/queue/tree/0.5.2" }, - "time": "2022-11-16T19:47:26+00:00" + "time": "2023-03-07T08:54:10+00:00" }, { "name": "utopia-php/registry", @@ -2969,6 +2873,49 @@ }, "time": "2022-09-22T09:15:54+00:00" }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" + }, { "name": "doctrine/instantiator", "version": "1.5.0", @@ -3501,24 +3448,27 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.2", + "version": "1.7.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" + "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", - "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", + "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.0", "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" }, "require-dev": { "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", @@ -3550,9 +3500,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.0" }, - "time": "2022-10-14T12:47:21+00:00" + "time": "2023-03-12T10:13:29+00:00" }, { "name": "phpspec/prophecy", @@ -3622,6 +3572,51 @@ }, "time": "2023-02-02T15:41:36+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.16.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" + }, + "time": "2023-02-07T18:11:17+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.26", diff --git a/docker-compose.yml b/docker-compose.yml index a6b8af4d74..e238f79983 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -576,6 +576,7 @@ services: - _APP_CONNECTIONS_CACHE - _APP_HAMSTER_RECIPIENTS - _APP_HAMSTER_INTERVAL + - _APP_MIXPANEL_TOKEN appwrite-maintenance: entrypoint: maintenance diff --git a/src/Appwrite/Platform/Tasks/Hamster.php b/src/Appwrite/Platform/Tasks/Hamster.php index 723f3e0e47..7097cd731a 100644 --- a/src/Appwrite/Platform/Tasks/Hamster.php +++ b/src/Appwrite/Platform/Tasks/Hamster.php @@ -10,53 +10,36 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; -use League\Csv\Writer; -use PHPMailer\PHPMailer\PHPMailer; +use Utopia\Analytics\Adapter\Mixpanel; +use Utopia\Analytics\Event; use Utopia\Database\Document; use Utopia\Pools\Group; use Utopia\Registry\Registry; class Hamster extends Action { - private array $columns = [ - 'Project ID', - 'Project Name', - 'Functions', - 'Deployments', - 'Members', - 'Domains', - 'Files', - 'Buckets', - 'Databases', - 'Documents', - 'Collections', - 'Storage', - 'Requests', - 'Bandwidth', - 'Users', - 'Sessions', - 'Executions' - ]; - private array $usageStats = [ - 'Files' => 'files.$all.count.total', - 'Buckets' => 'buckets.$all.count.total', - 'Databases' => 'databases.$all.count.total', - 'Documents' => 'documents.$all.count.total', - 'Collections' => 'collections.$all.count.total', - 'Storage' => 'project.$all.storage.size', - 'Requests' => 'project.$all.network.requests', - 'Bandwidth' => 'project.$all.network.bandwidth', - 'Users' => 'users.$all.count.total', - 'Sessions' => 'sessions.$all.requests.create', - 'Executions' => 'executions.$all.compute.total', + 'files' => 'files.$all.count.total', + 'buckets' => 'buckets.$all.count.total', + 'databases' => 'databases.$all.count.total', + 'documents' => 'documents.$all.count.total', + 'collections' => 'collections.$all.count.total', + 'storage' => 'project.$all.storage.size', + 'requests' => 'project.$all.network.requests', + 'bandwidth' => 'project.$all.network.bandwidth', + 'users' => 'users.$all.count.total', + 'sessions' => 'sessions.email.requests.create', + 'executions' => 'executions.$all.compute.total', ]; protected string $directory = '/usr/local'; + protected string $path; protected string $date; + protected Mixpanel $mixpanel; + public static function getName(): string { return 'hamster'; @@ -64,6 +47,8 @@ class Hamster extends Action public function __construct() { + $this->mixpanel = new Mixpanel(App::getEnv('_APP_MIXPANEL_TOKEN', '')); + $this ->desc('Get stats for projects') ->inject('register') @@ -79,30 +64,71 @@ class Hamster extends Action { $stats = []; + $stats['time'] = microtime(true); + /** Get Project ID */ - $stats['Project ID'] = $project->getId(); + $stats['projectId'] = $project->getId(); /** Get Project Name */ - $stats['Project Name'] = $project->getAttribute('name'); + $stats['projectName'] = $project->getAttribute('name'); /** Get Total Functions */ - $stats['Functions'] = $dbForProject->count('functions', [], APP_LIMIT_COUNT); + $stats['functions'] = $dbForProject->count('functions', [], APP_LIMIT_COUNT); /** Get Total Deployments */ - $stats['Deployments'] = $dbForProject->count('deployments', [], APP_LIMIT_COUNT); + $stats['deployments'] = $dbForProject->count('deployments', [], APP_LIMIT_COUNT); /** Get Total Members */ $teamInternalId = $project->getAttribute('teamInternalId', null); if ($teamInternalId) { - $stats['Members'] = $dbForConsole->count('memberships', [ + $stats['members'] = $dbForConsole->count('memberships', [ Query::equal('teamInternalId', [$teamInternalId]) ], APP_LIMIT_COUNT); } else { - $stats['Members'] = 0; + $stats['members'] = 0; + } + + /** Get Email and Name of the project owner */ + if ($teamInternalId) { + $membership = $dbForConsole->findOne('memberships', [ + Query::equal('teamInternalId', [$teamInternalId]), + ]); + + $userInternalId = $membership->getAttribute('userInternalId', null); + if ($userInternalId) { + $user = $dbForConsole->findOne('users', [ + Query::equal('_id', [$userInternalId]), + ]); + + $stats['email'] = $user->getAttribute('email', null); + $stats['name'] = $user->getAttribute('name', null); + } } /** Get Domains */ - $stats['Domains'] = $dbForProject->count('domains', [], APP_LIMIT_COUNT); + $stats['domains'] = $dbForProject->count('domains', [], APP_LIMIT_COUNT); + + /** Get Platforms */ + $platforms = $dbForConsole->find('platforms', [ + Query::equal('projectInternalId', [$project->getInternalId()]), + Query::limit(APP_LIMIT_COUNT) + ]); + + $stats['platforms_web'] = sizeof(array_filter($platforms, function ($platform) { + return $platform['type'] === 'web'; + })); + + $stats['platforms_android'] = sizeof(array_filter($platforms, function ($platform) { + return $platform['type'] === 'android'; + })); + + $stats['platforms_iOS'] = sizeof(array_filter($platforms, function ($platform) { + return str_contains($platform['type'], 'apple'); + })); + + $stats['platforms_flutter'] = sizeof(array_filter($platforms, function ($platform) { + return str_contains($platform['type'], 'flutter'); + })); /** Get Usage stats */ $range = '90d'; @@ -147,26 +173,36 @@ class Hamster extends Action { Console::title('Cloud Hamster V1'); - Console::success(APP_NAME . ' cloud hamster process v1 has started'); + Console::success(APP_NAME . ' cloud hamster process has started'); - $interval = (int) App::getEnv('_APP_HAMSTER_INTERVAL', '30'); // 30 seconds (by default) + $sleep = (int) App::getEnv('_APP_HAMSTER_INTERVAL', '30'); // 30 seconds (by default) - Console::loop(function () use ($register, $pools, $cache, $dbForConsole, $interval) { + $jobInitTime = '22:00'; // (hour:minutes) + $now = new \DateTime(); + $now->setTimezone(new \DateTimeZone(date_default_timezone_get())); + $next = new \DateTime($now->format("Y-m-d $jobInitTime")); + $next->setTimezone(new \DateTimeZone(date_default_timezone_get())); + $delay = $next->getTimestamp() - $now->getTimestamp(); + /** + * If time passed for the target day. + */ + if ($delay <= 0) { + $next->add(\DateInterval::createFromDateString('1 days')); + $delay = $next->getTimestamp() - $now->getTimestamp(); + } + + Console::log('[' . $now->format("Y-m-d H:i:s.v") . '] Delaying for ' . $delay . ' setting loop to [' . $next->format("Y-m-d H:i:s.v") . ']'); + + Console::loop(function () use ($register, $pools, $cache, $dbForConsole, $sleep) { $now = date('d-m-Y H:i:s', time()); - Console::info("[{$now}] Getting Cloud Usage Stats every {$interval} seconds"); + Console::info("[{$now}] Getting Cloud Usage Stats every {$sleep} seconds"); $loopStart = microtime(true); /* Initialise new Utopia app */ $app = new App('UTC'); $console = $app->getResource('console'); - /** CSV stuff */ - $this->date = date('Y-m-d'); - $this->path = "{$this->directory}/stats_{$this->date}.csv"; - $csv = Writer::createFromPath($this->path, 'w'); - $csv->insertOne($this->columns); - /** Database connections */ $totalProjects = $dbForConsole->count('projects') + 1; Console::success("Found a total of: {$totalProjects} projects"); @@ -199,7 +235,25 @@ class Hamster extends Action $dbForProject->setNamespace('_' . $project->getInternalId()); $statsPerProject = $this->getStats($dbForConsole, $dbForProject, $project); - $csv->insertOne(array_values($statsPerProject)); + + /** Send data to mixpanel */ + $res = $this->mixpanel->createProfile($statsPerProject['email'], '', [ + 'name' => $statsPerProject['name'], + 'email' => $statsPerProject['email'] + ]); + + if (!$res) { + Console::error('Failed to create user profile for project: ' . $project->getId()); + } + + $event = new Event(); + $event + ->setName('Appwrite Cloud Project Stats') + ->setProps($statsPerProject); + $res = $this->mixpanel->createEvent($event); + if (!$res) { + Console::error('Failed to create event for project: ' . $project->getId()); + } } catch (\Throwable $th) { throw $th; Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); @@ -223,7 +277,6 @@ class Hamster extends Action Console::log('Iterated through ' . $count . '/' . $totalProjects . ' projects...'); } - $this->sendEmail($register); $pools ->get('console') @@ -232,40 +285,6 @@ class Hamster extends Action $loopTook = microtime(true) - $loopStart; $now = date('d-m-Y H:i:s', time()); Console::info("[{$now}] Cloud Stats took {$loopTook} seconds"); - }, $interval); - } - - private function sendEmail(Registry $register) - { - /** @var \PHPMailer\PHPMailer\PHPMailer $mail */ - $mail = $register->get('smtp'); - - $mail->clearAddresses(); - $mail->clearAllRecipients(); - $mail->clearReplyTos(); - $mail->clearAttachments(); - $mail->clearBCCs(); - $mail->clearCCs(); - - try { - /** Addresses */ - $mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), 'Appwrite Cloud Hamster'); - $recipients = explode(',', App::getEnv('_APP_HAMSTER_RECIPIENTS', '')); - foreach ($recipients as $recipient) { - $mail->addAddress($recipient); - } - - /** Attachments */ - $mail->addAttachment($this->path); - - /** Content */ - $mail->Subject = "Cloud Report for {$this->date}"; - $mail->Body = "Please find the daily cloud report atttached"; - - $mail->send(); - Console::success('Email has been sent!'); - } catch (Exception $e) { - Console::error("Message could not be sent. Mailer Error: {$mail->ErrorInfo}"); - } + }, $sleep, $delay); } }