mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Pint linter ran
This commit is contained in:
+15
-16
@@ -1,27 +1,27 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
require_once __DIR__ . '/controllers/general.php';
|
||||
require_once __DIR__.'/init.php';
|
||||
require_once __DIR__.'/controllers/general.php';
|
||||
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Platform\Appwrite;
|
||||
use Utopia\CLI\CLI;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Platform\Service;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Cache\Adapter\Sharding;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\CLI;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Platform\Service;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Registry\Registry;
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
CLI::setResource('register', fn()=>$register);
|
||||
CLI::setResource('register', fn () => $register);
|
||||
|
||||
CLI::setResource('cache', function ($pools) {
|
||||
$list = Config::getParam('pools-cache', []);
|
||||
@@ -31,8 +31,7 @@ CLI::setResource('cache', function ($pools) {
|
||||
$adapters[] = $pools
|
||||
->get($value)
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
}
|
||||
|
||||
return new Cache(new Sharding($adapters));
|
||||
@@ -64,7 +63,7 @@ CLI::setResource('dbForConsole', function ($pools, $cache) {
|
||||
$collections = Config::getParam('collections', [])['console'];
|
||||
$last = \array_key_last($collections);
|
||||
|
||||
if (!($dbForConsole->exists($dbForConsole->getDefaultDatabase(), $last))) { /** TODO cache ready variable using registry */
|
||||
if (! ($dbForConsole->exists($dbForConsole->getDefaultDatabase(), $last))) { /** TODO cache ready variable using registry */
|
||||
throw new Exception('Tables not ready yet.');
|
||||
}
|
||||
|
||||
@@ -76,8 +75,8 @@ CLI::setResource('dbForConsole', function ($pools, $cache) {
|
||||
}
|
||||
} while ($attempts < $maxAttempts);
|
||||
|
||||
if (!$ready) {
|
||||
throw new Exception("Console is not ready yet. Please try again later.");
|
||||
if (! $ready) {
|
||||
throw new Exception('Console is not ready yet. Please try again later.');
|
||||
}
|
||||
|
||||
return $dbForConsole;
|
||||
@@ -95,7 +94,8 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
|
||||
|
||||
if (isset($databases[$databaseName])) {
|
||||
$database = $databases[$databaseName];
|
||||
$database->setNamespace('_' . $project->getInternalId());
|
||||
$database->setNamespace('_'.$project->getInternalId());
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
|
||||
|
||||
$databases[$databaseName] = $database;
|
||||
|
||||
$database->setNamespace('_' . $project->getInternalId());
|
||||
$database->setNamespace('_'.$project->getInternalId());
|
||||
|
||||
return $database;
|
||||
};
|
||||
@@ -116,7 +116,6 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForConsole,
|
||||
return $getProjectDB;
|
||||
}, ['pools', 'dbForConsole', 'cache']);
|
||||
|
||||
|
||||
CLI::setResource('queueForFunctions', function (Group $pools) {
|
||||
return new Func($pools->get('queue')->pop()->getResource());
|
||||
}, ['pools']);
|
||||
@@ -149,7 +148,7 @@ CLI::setResource('logError', function (Registry $register) {
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Usage stats log pushed with status code: ' . $responseCode);
|
||||
Console::info('Usage stats log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::warning("Failed: {$error->getMessage()}");
|
||||
|
||||
@@ -69,7 +69,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'box' => [
|
||||
'name' => 'Box',
|
||||
@@ -79,7 +79,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'dailymotion' => [
|
||||
'name' => 'Dailymotion',
|
||||
@@ -89,7 +89,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'discord' => [
|
||||
'name' => 'Discord',
|
||||
@@ -229,7 +229,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'paypalSandbox' => [
|
||||
'name' => 'PayPal Sandbox',
|
||||
@@ -239,7 +239,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => true,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'podio' => [
|
||||
'name' => 'Podio',
|
||||
@@ -289,7 +289,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'tradeshift' => [
|
||||
'name' => 'Tradeshift',
|
||||
@@ -329,7 +329,7 @@ return [ // Ordered by ABC.
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false
|
||||
'mock' => false,
|
||||
],
|
||||
'yahoo' => [
|
||||
'name' => 'Yahoo',
|
||||
|
||||
@@ -2,21 +2,20 @@
|
||||
|
||||
return [
|
||||
// Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php
|
||||
'aa' => ['name' => 'Avant Browser', 'path' => __DIR__ . '/browsers/avant.png'],
|
||||
'an' => ['name' => 'Android WebView Beta', 'path' => __DIR__ . '/browsers/android-webview-beta.png'],
|
||||
'ch' => ['name' => 'Google Chrome', 'path' => __DIR__ . '/browsers/chrome.png'],
|
||||
'ci' => ['name' => 'Google Chrome (iOS)', 'path' => __DIR__ . '/browsers/chrome.png'],
|
||||
'cm' => ['name' => 'Google Chrome (Mobile)', 'path' => __DIR__ . '/browsers/chrome.png'],
|
||||
'cr' => ['name' => 'Chromium', 'path' => __DIR__ . '/browsers/chromium.png'],
|
||||
'ff' => ['name' => 'Mozilla Firefox', 'path' => __DIR__ . '/browsers/firefox.png'],
|
||||
'sf' => ['name' => 'Safari', 'path' => __DIR__ . '/browsers/safari.png'],
|
||||
'mf' => ['name' => 'Mobile Safari', 'path' => __DIR__ . '/browsers/safari.png'],
|
||||
'ps' => ['name' => 'Microsoft Edge', 'path' => __DIR__ . '/browsers/edge.png'],
|
||||
'oi' => ['name' => 'Microsoft Edge (iOS)', 'path' => __DIR__ . '/browsers/edge.png'],
|
||||
'om' => ['name' => 'Opera Mini', 'path' => __DIR__ . '/browsers/opera-mini.png'],
|
||||
'op' => ['name' => 'Opera', 'path' => __DIR__ . '/browsers/opera.png'],
|
||||
'on' => ['name' => 'Opera (Next)', 'path' => __DIR__ . '/browsers/opera.png'],
|
||||
|
||||
'aa' => ['name' => 'Avant Browser', 'path' => __DIR__.'/browsers/avant.png'],
|
||||
'an' => ['name' => 'Android WebView Beta', 'path' => __DIR__.'/browsers/android-webview-beta.png'],
|
||||
'ch' => ['name' => 'Google Chrome', 'path' => __DIR__.'/browsers/chrome.png'],
|
||||
'ci' => ['name' => 'Google Chrome (iOS)', 'path' => __DIR__.'/browsers/chrome.png'],
|
||||
'cm' => ['name' => 'Google Chrome (Mobile)', 'path' => __DIR__.'/browsers/chrome.png'],
|
||||
'cr' => ['name' => 'Chromium', 'path' => __DIR__.'/browsers/chromium.png'],
|
||||
'ff' => ['name' => 'Mozilla Firefox', 'path' => __DIR__.'/browsers/firefox.png'],
|
||||
'sf' => ['name' => 'Safari', 'path' => __DIR__.'/browsers/safari.png'],
|
||||
'mf' => ['name' => 'Mobile Safari', 'path' => __DIR__.'/browsers/safari.png'],
|
||||
'ps' => ['name' => 'Microsoft Edge', 'path' => __DIR__.'/browsers/edge.png'],
|
||||
'oi' => ['name' => 'Microsoft Edge (iOS)', 'path' => __DIR__.'/browsers/edge.png'],
|
||||
'om' => ['name' => 'Opera Mini', 'path' => __DIR__.'/browsers/opera-mini.png'],
|
||||
'op' => ['name' => 'Opera', 'path' => __DIR__.'/browsers/opera.png'],
|
||||
'on' => ['name' => 'Opera (Next)', 'path' => __DIR__.'/browsers/opera.png'],
|
||||
|
||||
/*
|
||||
'36' => '360 Phone Browser',
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'amex' => ['name' => 'American Express', 'path' => __DIR__ . '/credit-cards/amex.png'],
|
||||
'argencard' => ['name' => 'Argencard', 'path' => __DIR__ . '/credit-cards/argencard.png'],
|
||||
'cabal' => ['name' => 'Cabal', 'path' => __DIR__ . '/credit-cards/cabal.png'],
|
||||
'censosud' => ['name' => 'Consosud', 'path' => __DIR__ . '/credit-cards/consosud.png'],
|
||||
'diners' => ['name' => 'Diners Club', 'path' => __DIR__ . '/credit-cards/diners.png'],
|
||||
'discover' => ['name' => 'Discover', 'path' => __DIR__ . '/credit-cards/discover.png'],
|
||||
'elo' => ['name' => 'Elo', 'path' => __DIR__ . '/credit-cards/elo.png'],
|
||||
'hipercard' => ['name' => 'Hipercard', 'path' => __DIR__ . '/credit-cards/hipercard.png'],
|
||||
'jcb' => ['name' => 'JCB', 'path' => __DIR__ . '/credit-cards/jcb.png'],
|
||||
'mastercard' => ['name' => 'Mastercard', 'path' => __DIR__ . '/credit-cards/mastercard.png'],
|
||||
'naranja' => ['name' => 'Naranja', 'path' => __DIR__ . '/credit-cards/naranja.png'],
|
||||
'targeta-shopping' => ['name' => 'Tarjeta Shopping', 'path' => __DIR__ . '/credit-cards/tarjeta-shopping.png'],
|
||||
'union-china-pay' => ['name' => 'Union China Pay', 'path' => __DIR__ . '/credit-cards/union-china-pay.png'],
|
||||
'visa' => ['name' => 'Visa', 'path' => __DIR__ . '/credit-cards/visa.png'],
|
||||
'mir' => ['name' => 'MIR', 'path' => __DIR__ . '/credit-cards/mir.png'],
|
||||
'maestro' => ['name' => 'Maestro', 'path' => __DIR__ . '/credit-cards/maestro.png']
|
||||
];
|
||||
'amex' => ['name' => 'American Express', 'path' => __DIR__.'/credit-cards/amex.png'],
|
||||
'argencard' => ['name' => 'Argencard', 'path' => __DIR__.'/credit-cards/argencard.png'],
|
||||
'cabal' => ['name' => 'Cabal', 'path' => __DIR__.'/credit-cards/cabal.png'],
|
||||
'censosud' => ['name' => 'Consosud', 'path' => __DIR__.'/credit-cards/consosud.png'],
|
||||
'diners' => ['name' => 'Diners Club', 'path' => __DIR__.'/credit-cards/diners.png'],
|
||||
'discover' => ['name' => 'Discover', 'path' => __DIR__.'/credit-cards/discover.png'],
|
||||
'elo' => ['name' => 'Elo', 'path' => __DIR__.'/credit-cards/elo.png'],
|
||||
'hipercard' => ['name' => 'Hipercard', 'path' => __DIR__.'/credit-cards/hipercard.png'],
|
||||
'jcb' => ['name' => 'JCB', 'path' => __DIR__.'/credit-cards/jcb.png'],
|
||||
'mastercard' => ['name' => 'Mastercard', 'path' => __DIR__.'/credit-cards/mastercard.png'],
|
||||
'naranja' => ['name' => 'Naranja', 'path' => __DIR__.'/credit-cards/naranja.png'],
|
||||
'targeta-shopping' => ['name' => 'Tarjeta Shopping', 'path' => __DIR__.'/credit-cards/tarjeta-shopping.png'],
|
||||
'union-china-pay' => ['name' => 'Union China Pay', 'path' => __DIR__.'/credit-cards/union-china-pay.png'],
|
||||
'visa' => ['name' => 'Visa', 'path' => __DIR__.'/credit-cards/visa.png'],
|
||||
'mir' => ['name' => 'MIR', 'path' => __DIR__.'/credit-cards/mir.png'],
|
||||
'maestro' => ['name' => 'Maestro', 'path' => __DIR__.'/credit-cards/maestro.png'],
|
||||
];
|
||||
|
||||
+194
-194
@@ -1,198 +1,198 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'af' => ['name' => 'Afghanistan', 'path' => __DIR__ . '/flags/af.png'],
|
||||
'ao' => ['name' => 'Angola', 'path' => __DIR__ . '/flags/ao.png'],
|
||||
'al' => ['name' => 'Albania', 'path' => __DIR__ . '/flags/al.png'],
|
||||
'ad' => ['name' => 'Andorra', 'path' => __DIR__ . '/flags/ad.png'],
|
||||
'ae' => ['name' => 'United Arab Emirates', 'path' => __DIR__ . '/flags/ae.png'],
|
||||
'ar' => ['name' => 'Argentina', 'path' => __DIR__ . '/flags/ar.png'],
|
||||
'am' => ['name' => 'Armenia', 'path' => __DIR__ . '/flags/am.png'],
|
||||
'ag' => ['name' => 'Antigua and Barbuda', 'path' => __DIR__ . '/flags/ag.png'],
|
||||
'au' => ['name' => 'Australia', 'path' => __DIR__ . '/flags/au.png'],
|
||||
'at' => ['name' => 'Austria', 'path' => __DIR__ . '/flags/at.png'],
|
||||
'az' => ['name' => 'Azerbaijan', 'path' => __DIR__ . '/flags/az.png'],
|
||||
'bi' => ['name' => 'Burundi', 'path' => __DIR__ . '/flags/bi.png'],
|
||||
'be' => ['name' => 'Belgium', 'path' => __DIR__ . '/flags/be.png'],
|
||||
'bj' => ['name' => 'Benin', 'path' => __DIR__ . '/flags/bj.png'],
|
||||
'bf' => ['name' => 'Burkina Faso', 'path' => __DIR__ . '/flags/bf.png'],
|
||||
'bd' => ['name' => 'Bangladesh', 'path' => __DIR__ . '/flags/bd.png'],
|
||||
'bg' => ['name' => 'Bulgaria', 'path' => __DIR__ . '/flags/bg.png'],
|
||||
'bh' => ['name' => 'Bahrain', 'path' => __DIR__ . '/flags/bh.png'],
|
||||
'bs' => ['name' => 'Bahamas', 'path' => __DIR__ . '/flags/bs.png'],
|
||||
'ba' => ['name' => 'Bosnia and Herzegovina', 'path' => __DIR__ . '/flags/ba.png'],
|
||||
'by' => ['name' => 'Belarus', 'path' => __DIR__ . '/flags/by.png'],
|
||||
'bz' => ['name' => 'Belize', 'path' => __DIR__ . '/flags/bz.png'],
|
||||
'bo' => ['name' => 'Bolivia', 'path' => __DIR__ . '/flags/bo.png'],
|
||||
'br' => ['name' => 'Brazil', 'path' => __DIR__ . '/flags/br.png'],
|
||||
'bb' => ['name' => 'Barbados', 'path' => __DIR__ . '/flags/bb.png'],
|
||||
'bn' => ['name' => 'Brunei Darussalam', 'path' => __DIR__ . '/flags/bn.png'],
|
||||
'bt' => ['name' => 'Bhutan', 'path' => __DIR__ . '/flags/bt.png'],
|
||||
'bw' => ['name' => 'Botswana', 'path' => __DIR__ . '/flags/bw.png'],
|
||||
'cf' => ['name' => 'Central African Republic', 'path' => __DIR__ . '/flags/cf.png'],
|
||||
'ca' => ['name' => 'Canada', 'path' => __DIR__ . '/flags/ca.png'],
|
||||
'ch' => ['name' => 'Switzerland', 'path' => __DIR__ . '/flags/ch.png'],
|
||||
'cl' => ['name' => 'Chile', 'path' => __DIR__ . '/flags/cl.png'],
|
||||
'cn' => ['name' => 'China', 'path' => __DIR__ . '/flags/cn.png'],
|
||||
'ci' => ['name' => 'Côte d\'Ivoire', 'path' => __DIR__ . '/flags/ci.png'],
|
||||
'cm' => ['name' => 'Cameroon', 'path' => __DIR__ . '/flags/cm.png'],
|
||||
'cd' => ['name' => 'Democratic Republic of the Congo', 'path' => __DIR__ . '/flags/cd.png'],
|
||||
'cg' => ['name' => 'Republic of the Congo', 'path' => __DIR__ . '/flags/cg.png'],
|
||||
'co' => ['name' => 'Colombia', 'path' => __DIR__ . '/flags/co.png'],
|
||||
'km' => ['name' => 'Comoros', 'path' => __DIR__ . '/flags/km.png'],
|
||||
'cv' => ['name' => 'Cape Verde', 'path' => __DIR__ . '/flags/cv.png'],
|
||||
'cr' => ['name' => 'Costa Rica', 'path' => __DIR__ . '/flags/cr.png'],
|
||||
'cu' => ['name' => 'Cuba', 'path' => __DIR__ . '/flags/cu.png'],
|
||||
'cy' => ['name' => 'Cyprus', 'path' => __DIR__ . '/flags/cy.png'],
|
||||
'cz' => ['name' => 'Czech Republic', 'path' => __DIR__ . '/flags/cz.png'],
|
||||
'de' => ['name' => 'Germany', 'path' => __DIR__ . '/flags/de.png'],
|
||||
'dj' => ['name' => 'Djibouti', 'path' => __DIR__ . '/flags/dj.png'],
|
||||
'dm' => ['name' => 'Dominica', 'path' => __DIR__ . '/flags/dm.png'],
|
||||
'dk' => ['name' => 'Denmark', 'path' => __DIR__ . '/flags/dk.png'],
|
||||
'do' => ['name' => 'Dominican Republic', 'path' => __DIR__ . '/flags/do.png'],
|
||||
'dz' => ['name' => 'Algeria', 'path' => __DIR__ . '/flags/dz.png'],
|
||||
'ec' => ['name' => 'Ecuador', 'path' => __DIR__ . '/flags/ec.png'],
|
||||
'eg' => ['name' => 'Egypt', 'path' => __DIR__ . '/flags/eg.png'],
|
||||
'er' => ['name' => 'Eritrea', 'path' => __DIR__ . '/flags/er.png'],
|
||||
'es' => ['name' => 'Spain', 'path' => __DIR__ . '/flags/es.png'],
|
||||
'ee' => ['name' => 'Estonia', 'path' => __DIR__ . '/flags/ee.png'],
|
||||
'et' => ['name' => 'Ethiopia', 'path' => __DIR__ . '/flags/et.png'],
|
||||
'fi' => ['name' => 'Finland', 'path' => __DIR__ . '/flags/fi.png'],
|
||||
'fj' => ['name' => 'Fiji', 'path' => __DIR__ . '/flags/fj.png'],
|
||||
'fr' => ['name' => 'France', 'path' => __DIR__ . '/flags/fr.png'],
|
||||
'fm' => ['name' => 'Micronesia (Federated States of)', 'path' => __DIR__ . '/flags/fm.png'],
|
||||
'ga' => ['name' => 'Gabon', 'path' => __DIR__ . '/flags/ga.png'],
|
||||
'gb' => ['name' => 'United Kingdom', 'path' => __DIR__ . '/flags/gb.png'],
|
||||
'ge' => ['name' => 'Georgia', 'path' => __DIR__ . '/flags/ge.png'],
|
||||
'gh' => ['name' => 'Ghana', 'path' => __DIR__ . '/flags/gh.png'],
|
||||
'gn' => ['name' => 'Guinea', 'path' => __DIR__ . '/flags/gn.png'],
|
||||
'gm' => ['name' => 'Gambia', 'path' => __DIR__ . '/flags/gm.png'],
|
||||
'gw' => ['name' => 'Guinea-Bissau', 'path' => __DIR__ . '/flags/gw.png'],
|
||||
'gq' => ['name' => 'Equatorial Guinea', 'path' => __DIR__ . '/flags/gq.png'],
|
||||
'gr' => ['name' => 'Greece', 'path' => __DIR__ . '/flags/gr.png'],
|
||||
'gd' => ['name' => 'Grenada', 'path' => __DIR__ . '/flags/gd.png'],
|
||||
'gt' => ['name' => 'Guatemala', 'path' => __DIR__ . '/flags/gt.png'],
|
||||
'gy' => ['name' => 'Guyana', 'path' => __DIR__ . '/flags/gy.png'],
|
||||
'hn' => ['name' => 'Honduras', 'path' => __DIR__ . '/flags/hn.png'],
|
||||
'hr' => ['name' => 'Croatia', 'path' => __DIR__ . '/flags/hr.png'],
|
||||
'ht' => ['name' => 'Haiti', 'path' => __DIR__ . '/flags/ht.png'],
|
||||
'hu' => ['name' => 'Hungary', 'path' => __DIR__ . '/flags/hu.png'],
|
||||
'id' => ['name' => 'Indonesia', 'path' => __DIR__ . '/flags/id.png'],
|
||||
'in' => ['name' => 'India', 'path' => __DIR__ . '/flags/in.png'],
|
||||
'ie' => ['name' => 'Ireland', 'path' => __DIR__ . '/flags/ie.png'],
|
||||
'ir' => ['name' => 'Iran (Islamic Republic of)', 'path' => __DIR__ . '/flags/ir.png'],
|
||||
'iq' => ['name' => 'Iraq', 'path' => __DIR__ . '/flags/iq.png'],
|
||||
'is' => ['name' => 'Iceland', 'path' => __DIR__ . '/flags/is.png'],
|
||||
'il' => ['name' => 'Israel', 'path' => __DIR__ . '/flags/il.png'],
|
||||
'it' => ['name' => 'Italy', 'path' => __DIR__ . '/flags/it.png'],
|
||||
'jm' => ['name' => 'Jamaica', 'path' => __DIR__ . '/flags/jm.png'],
|
||||
'jo' => ['name' => 'Jordan', 'path' => __DIR__ . '/flags/jo.png'],
|
||||
'jp' => ['name' => 'Japan', 'path' => __DIR__ . '/flags/jp.png'],
|
||||
'kz' => ['name' => 'Kazakhstan', 'path' => __DIR__ . '/flags/kz.png'],
|
||||
'ke' => ['name' => 'Kenya', 'path' => __DIR__ . '/flags/ke.png'],
|
||||
'kg' => ['name' => 'Kyrgyzstan', 'path' => __DIR__ . '/flags/kg.png'],
|
||||
'kh' => ['name' => 'Cambodia', 'path' => __DIR__ . '/flags/kh.png'],
|
||||
'ki' => ['name' => 'Kiribati', 'path' => __DIR__ . '/flags/ki.png'],
|
||||
'kn' => ['name' => 'Saint Kitts and Nevis', 'path' => __DIR__ . '/flags/kn.png'],
|
||||
'kr' => ['name' => 'South Korea', 'path' => __DIR__ . '/flags/kr.png'],
|
||||
'kw' => ['name' => 'Kuwait', 'path' => __DIR__ . '/flags/kw.png'],
|
||||
'la' => ['name' => 'Lao People\'s Democratic Republic', 'path' => __DIR__ . '/flags/la.png'],
|
||||
'lb' => ['name' => 'Lebanon', 'path' => __DIR__ . '/flags/lb.png'],
|
||||
'lr' => ['name' => 'Liberia', 'path' => __DIR__ . '/flags/lr.png'],
|
||||
'ly' => ['name' => 'Libya', 'path' => __DIR__ . '/flags/ly.png'],
|
||||
'lc' => ['name' => 'Saint Lucia', 'path' => __DIR__ . '/flags/lc.png'],
|
||||
'li' => ['name' => 'Liechtenstein', 'path' => __DIR__ . '/flags/li.png'],
|
||||
'lk' => ['name' => 'Sri Lanka', 'path' => __DIR__ . '/flags/lk.png'],
|
||||
'ls' => ['name' => 'Lesotho', 'path' => __DIR__ . '/flags/ls.png'],
|
||||
'lt' => ['name' => 'Lithuania', 'path' => __DIR__ . '/flags/lt.png'],
|
||||
'lu' => ['name' => 'Luxembourg', 'path' => __DIR__ . '/flags/lu.png'],
|
||||
'lv' => ['name' => 'Latvia', 'path' => __DIR__ . '/flags/lv.png'],
|
||||
'ma' => ['name' => 'Morocco', 'path' => __DIR__ . '/flags/ma.png'],
|
||||
'mc' => ['name' => 'Monaco', 'path' => __DIR__ . '/flags/mc.png'],
|
||||
'md' => ['name' => 'Moldova', 'path' => __DIR__ . '/flags/md.png'],
|
||||
'mg' => ['name' => 'Madagascar', 'path' => __DIR__ . '/flags/mg.png'],
|
||||
'mv' => ['name' => 'Maldives', 'path' => __DIR__ . '/flags/mv.png'],
|
||||
'mx' => ['name' => 'Mexico', 'path' => __DIR__ . '/flags/mx.png'],
|
||||
'mh' => ['name' => 'Marshall Islands', 'path' => __DIR__ . '/flags/mh.png'],
|
||||
'mk' => ['name' => 'North Macedonia', 'path' => __DIR__ . '/flags/mk.png'],
|
||||
'ml' => ['name' => 'Mali', 'path' => __DIR__ . '/flags/ml.png'],
|
||||
'mt' => ['name' => 'Malta', 'path' => __DIR__ . '/flags/mt.png'],
|
||||
'mm' => ['name' => 'Myanmar', 'path' => __DIR__ . '/flags/mm.png'],
|
||||
'me' => ['name' => 'Montenegro', 'path' => __DIR__ . '/flags/me.png'],
|
||||
'mn' => ['name' => 'Mongolia', 'path' => __DIR__ . '/flags/mn.png'],
|
||||
'mz' => ['name' => 'Mozambique', 'path' => __DIR__ . '/flags/mz.png'],
|
||||
'mr' => ['name' => 'Mauritania', 'path' => __DIR__ . '/flags/mr.png'],
|
||||
'mu' => ['name' => 'Mauritius', 'path' => __DIR__ . '/flags/mu.png'],
|
||||
'mw' => ['name' => 'Malawi', 'path' => __DIR__ . '/flags/mw.png'],
|
||||
'my' => ['name' => 'Malaysia', 'path' => __DIR__ . '/flags/my.png'],
|
||||
'na' => ['name' => 'Namibia', 'path' => __DIR__ . '/flags/na.png'],
|
||||
'ne' => ['name' => 'Niger', 'path' => __DIR__ . '/flags/ne.png'],
|
||||
'ng' => ['name' => 'Nigeria', 'path' => __DIR__ . '/flags/ng.png'],
|
||||
'ni' => ['name' => 'Nicaragua', 'path' => __DIR__ . '/flags/ni.png'],
|
||||
'nl' => ['name' => 'Netherlands', 'path' => __DIR__ . '/flags/nl.png'],
|
||||
'no' => ['name' => 'Norway', 'path' => __DIR__ . '/flags/no.png'],
|
||||
'np' => ['name' => 'Nepal', 'path' => __DIR__ . '/flags/np.png'],
|
||||
'nr' => ['name' => 'Nauru', 'path' => __DIR__ . '/flags/nr.png'],
|
||||
'nz' => ['name' => 'New Zealand', 'path' => __DIR__ . '/flags/nz.png'],
|
||||
'om' => ['name' => 'Oman', 'path' => __DIR__ . '/flags/om.png'],
|
||||
'pk' => ['name' => 'Pakistan', 'path' => __DIR__ . '/flags/pk.png'],
|
||||
'pa' => ['name' => 'Panama', 'path' => __DIR__ . '/flags/pa.png'],
|
||||
'pe' => ['name' => 'Peru', 'path' => __DIR__ . '/flags/pe.png'],
|
||||
'ph' => ['name' => 'Philippines', 'path' => __DIR__ . '/flags/ph.png'],
|
||||
'pw' => ['name' => 'Palau', 'path' => __DIR__ . '/flags/pw.png'],
|
||||
'pg' => ['name' => 'Papua New Guinea', 'path' => __DIR__ . '/flags/pg.png'],
|
||||
'pl' => ['name' => 'Poland', 'path' => __DIR__ . '/flags/pl.png'],
|
||||
'kp' => ['name' => 'North Korea', 'path' => __DIR__ . '/flags/kp.png'],
|
||||
'pt' => ['name' => 'Portugal', 'path' => __DIR__ . '/flags/pt.png'],
|
||||
'py' => ['name' => 'Paraguay', 'path' => __DIR__ . '/flags/py.png'],
|
||||
'qa' => ['name' => 'Qatar', 'path' => __DIR__ . '/flags/qa.png'],
|
||||
'ro' => ['name' => 'Romania', 'path' => __DIR__ . '/flags/ro.png'],
|
||||
'ru' => ['name' => 'Russia', 'path' => __DIR__ . '/flags/ru.png'],
|
||||
'rw' => ['name' => 'Rwanda', 'path' => __DIR__ . '/flags/rw.png'],
|
||||
'sa' => ['name' => 'Saudi Arabia', 'path' => __DIR__ . '/flags/sa.png'],
|
||||
'sd' => ['name' => 'Sudan', 'path' => __DIR__ . '/flags/sd.png'],
|
||||
'sn' => ['name' => 'Senegal', 'path' => __DIR__ . '/flags/sn.png'],
|
||||
'sg' => ['name' => 'Singapore', 'path' => __DIR__ . '/flags/sg.png'],
|
||||
'sb' => ['name' => 'Solomon Islands', 'path' => __DIR__ . '/flags/sb.png'],
|
||||
'sl' => ['name' => 'Sierra Leone', 'path' => __DIR__ . '/flags/sl.png'],
|
||||
'sv' => ['name' => 'El Salvador', 'path' => __DIR__ . '/flags/sv.png'],
|
||||
'sm' => ['name' => 'San Marino', 'path' => __DIR__ . '/flags/sm.png'],
|
||||
'so' => ['name' => 'Somalia', 'path' => __DIR__ . '/flags/so.png'],
|
||||
'rs' => ['name' => 'Serbia', 'path' => __DIR__ . '/flags/rs.png'],
|
||||
'ss' => ['name' => 'South Sudan', 'path' => __DIR__ . '/flags/ss.png'],
|
||||
'st' => ['name' => 'Sao Tome and Principe', 'path' => __DIR__ . '/flags/st.png'],
|
||||
'sr' => ['name' => 'Suriname', 'path' => __DIR__ . '/flags/sr.png'],
|
||||
'sk' => ['name' => 'Slovakia', 'path' => __DIR__ . '/flags/sk.png'],
|
||||
'si' => ['name' => 'Slovenia', 'path' => __DIR__ . '/flags/si.png'],
|
||||
'se' => ['name' => 'Sweden', 'path' => __DIR__ . '/flags/se.png'],
|
||||
'sz' => ['name' => 'Eswatini', 'path' => __DIR__ . '/flags/sz.png'],
|
||||
'sc' => ['name' => 'Seychelles', 'path' => __DIR__ . '/flags/sc.png'],
|
||||
'sy' => ['name' => 'Syria', 'path' => __DIR__ . '/flags/sy.png'],
|
||||
'td' => ['name' => 'Chad', 'path' => __DIR__ . '/flags/td.png'],
|
||||
'tg' => ['name' => 'Togo', 'path' => __DIR__ . '/flags/tg.png'],
|
||||
'th' => ['name' => 'Thailand', 'path' => __DIR__ . '/flags/th.png'],
|
||||
'tj' => ['name' => 'Tajikistan', 'path' => __DIR__ . '/flags/tj.png'],
|
||||
'tm' => ['name' => 'Turkmenistan', 'path' => __DIR__ . '/flags/tm.png'],
|
||||
'tl' => ['name' => 'Timor-Leste', 'path' => __DIR__ . '/flags/tl.png'],
|
||||
'to' => ['name' => 'Tonga', 'path' => __DIR__ . '/flags/to.png'],
|
||||
'tt' => ['name' => 'Trinidad and Tobago', 'path' => __DIR__ . '/flags/tt.png'],
|
||||
'tn' => ['name' => 'Tunisia', 'path' => __DIR__ . '/flags/tn.png'],
|
||||
'tr' => ['name' => 'Turkey', 'path' => __DIR__ . '/flags/tr.png'],
|
||||
'tv' => ['name' => 'Tuvalu', 'path' => __DIR__ . '/flags/tv.png'],
|
||||
'tz' => ['name' => 'Tanzania', 'path' => __DIR__ . '/flags/tz.png'],
|
||||
'ug' => ['name' => 'Uganda', 'path' => __DIR__ . '/flags/ug.png'],
|
||||
'ua' => ['name' => 'Ukraine', 'path' => __DIR__ . '/flags/ua.png'],
|
||||
'uy' => ['name' => 'Uruguay', 'path' => __DIR__ . '/flags/uy.png'],
|
||||
'us' => ['name' => 'United States', 'path' => __DIR__ . '/flags/us.png'],
|
||||
'uz' => ['name' => 'Uzbekistan', 'path' => __DIR__ . '/flags/uz.png'],
|
||||
'va' => ['name' => 'Vatican City', 'path' => __DIR__ . '/flags/va.png'],
|
||||
'vc' => ['name' => 'Saint Vincent and the Grenadines', 'path' => __DIR__ . '/flags/vc.png'],
|
||||
've' => ['name' => 'Venezuela', 'path' => __DIR__ . '/flags/ve.png'],
|
||||
'vn' => ['name' => 'Vietnam', 'path' => __DIR__ . '/flags/vn.png'],
|
||||
'vu' => ['name' => 'Vanuatu', 'path' => __DIR__ . '/flags/vu.png'],
|
||||
'ws' => ['name' => 'Samoa', 'path' => __DIR__ . '/flags/ws.png'],
|
||||
'ye' => ['name' => 'Yemen', 'path' => __DIR__ . '/flags/ye.png'],
|
||||
'za' => ['name' => 'South Africa', 'path' => __DIR__ . '/flags/za.png'],
|
||||
'zm' => ['name' => 'Zambia', 'path' => __DIR__ . '/flags/zm.png'],
|
||||
'zw' => ['name' => 'Zimbabwe', 'path' => __DIR__ . '/flags/zw.png'],
|
||||
'af' => ['name' => 'Afghanistan', 'path' => __DIR__.'/flags/af.png'],
|
||||
'ao' => ['name' => 'Angola', 'path' => __DIR__.'/flags/ao.png'],
|
||||
'al' => ['name' => 'Albania', 'path' => __DIR__.'/flags/al.png'],
|
||||
'ad' => ['name' => 'Andorra', 'path' => __DIR__.'/flags/ad.png'],
|
||||
'ae' => ['name' => 'United Arab Emirates', 'path' => __DIR__.'/flags/ae.png'],
|
||||
'ar' => ['name' => 'Argentina', 'path' => __DIR__.'/flags/ar.png'],
|
||||
'am' => ['name' => 'Armenia', 'path' => __DIR__.'/flags/am.png'],
|
||||
'ag' => ['name' => 'Antigua and Barbuda', 'path' => __DIR__.'/flags/ag.png'],
|
||||
'au' => ['name' => 'Australia', 'path' => __DIR__.'/flags/au.png'],
|
||||
'at' => ['name' => 'Austria', 'path' => __DIR__.'/flags/at.png'],
|
||||
'az' => ['name' => 'Azerbaijan', 'path' => __DIR__.'/flags/az.png'],
|
||||
'bi' => ['name' => 'Burundi', 'path' => __DIR__.'/flags/bi.png'],
|
||||
'be' => ['name' => 'Belgium', 'path' => __DIR__.'/flags/be.png'],
|
||||
'bj' => ['name' => 'Benin', 'path' => __DIR__.'/flags/bj.png'],
|
||||
'bf' => ['name' => 'Burkina Faso', 'path' => __DIR__.'/flags/bf.png'],
|
||||
'bd' => ['name' => 'Bangladesh', 'path' => __DIR__.'/flags/bd.png'],
|
||||
'bg' => ['name' => 'Bulgaria', 'path' => __DIR__.'/flags/bg.png'],
|
||||
'bh' => ['name' => 'Bahrain', 'path' => __DIR__.'/flags/bh.png'],
|
||||
'bs' => ['name' => 'Bahamas', 'path' => __DIR__.'/flags/bs.png'],
|
||||
'ba' => ['name' => 'Bosnia and Herzegovina', 'path' => __DIR__.'/flags/ba.png'],
|
||||
'by' => ['name' => 'Belarus', 'path' => __DIR__.'/flags/by.png'],
|
||||
'bz' => ['name' => 'Belize', 'path' => __DIR__.'/flags/bz.png'],
|
||||
'bo' => ['name' => 'Bolivia', 'path' => __DIR__.'/flags/bo.png'],
|
||||
'br' => ['name' => 'Brazil', 'path' => __DIR__.'/flags/br.png'],
|
||||
'bb' => ['name' => 'Barbados', 'path' => __DIR__.'/flags/bb.png'],
|
||||
'bn' => ['name' => 'Brunei Darussalam', 'path' => __DIR__.'/flags/bn.png'],
|
||||
'bt' => ['name' => 'Bhutan', 'path' => __DIR__.'/flags/bt.png'],
|
||||
'bw' => ['name' => 'Botswana', 'path' => __DIR__.'/flags/bw.png'],
|
||||
'cf' => ['name' => 'Central African Republic', 'path' => __DIR__.'/flags/cf.png'],
|
||||
'ca' => ['name' => 'Canada', 'path' => __DIR__.'/flags/ca.png'],
|
||||
'ch' => ['name' => 'Switzerland', 'path' => __DIR__.'/flags/ch.png'],
|
||||
'cl' => ['name' => 'Chile', 'path' => __DIR__.'/flags/cl.png'],
|
||||
'cn' => ['name' => 'China', 'path' => __DIR__.'/flags/cn.png'],
|
||||
'ci' => ['name' => 'Côte d\'Ivoire', 'path' => __DIR__.'/flags/ci.png'],
|
||||
'cm' => ['name' => 'Cameroon', 'path' => __DIR__.'/flags/cm.png'],
|
||||
'cd' => ['name' => 'Democratic Republic of the Congo', 'path' => __DIR__.'/flags/cd.png'],
|
||||
'cg' => ['name' => 'Republic of the Congo', 'path' => __DIR__.'/flags/cg.png'],
|
||||
'co' => ['name' => 'Colombia', 'path' => __DIR__.'/flags/co.png'],
|
||||
'km' => ['name' => 'Comoros', 'path' => __DIR__.'/flags/km.png'],
|
||||
'cv' => ['name' => 'Cape Verde', 'path' => __DIR__.'/flags/cv.png'],
|
||||
'cr' => ['name' => 'Costa Rica', 'path' => __DIR__.'/flags/cr.png'],
|
||||
'cu' => ['name' => 'Cuba', 'path' => __DIR__.'/flags/cu.png'],
|
||||
'cy' => ['name' => 'Cyprus', 'path' => __DIR__.'/flags/cy.png'],
|
||||
'cz' => ['name' => 'Czech Republic', 'path' => __DIR__.'/flags/cz.png'],
|
||||
'de' => ['name' => 'Germany', 'path' => __DIR__.'/flags/de.png'],
|
||||
'dj' => ['name' => 'Djibouti', 'path' => __DIR__.'/flags/dj.png'],
|
||||
'dm' => ['name' => 'Dominica', 'path' => __DIR__.'/flags/dm.png'],
|
||||
'dk' => ['name' => 'Denmark', 'path' => __DIR__.'/flags/dk.png'],
|
||||
'do' => ['name' => 'Dominican Republic', 'path' => __DIR__.'/flags/do.png'],
|
||||
'dz' => ['name' => 'Algeria', 'path' => __DIR__.'/flags/dz.png'],
|
||||
'ec' => ['name' => 'Ecuador', 'path' => __DIR__.'/flags/ec.png'],
|
||||
'eg' => ['name' => 'Egypt', 'path' => __DIR__.'/flags/eg.png'],
|
||||
'er' => ['name' => 'Eritrea', 'path' => __DIR__.'/flags/er.png'],
|
||||
'es' => ['name' => 'Spain', 'path' => __DIR__.'/flags/es.png'],
|
||||
'ee' => ['name' => 'Estonia', 'path' => __DIR__.'/flags/ee.png'],
|
||||
'et' => ['name' => 'Ethiopia', 'path' => __DIR__.'/flags/et.png'],
|
||||
'fi' => ['name' => 'Finland', 'path' => __DIR__.'/flags/fi.png'],
|
||||
'fj' => ['name' => 'Fiji', 'path' => __DIR__.'/flags/fj.png'],
|
||||
'fr' => ['name' => 'France', 'path' => __DIR__.'/flags/fr.png'],
|
||||
'fm' => ['name' => 'Micronesia (Federated States of)', 'path' => __DIR__.'/flags/fm.png'],
|
||||
'ga' => ['name' => 'Gabon', 'path' => __DIR__.'/flags/ga.png'],
|
||||
'gb' => ['name' => 'United Kingdom', 'path' => __DIR__.'/flags/gb.png'],
|
||||
'ge' => ['name' => 'Georgia', 'path' => __DIR__.'/flags/ge.png'],
|
||||
'gh' => ['name' => 'Ghana', 'path' => __DIR__.'/flags/gh.png'],
|
||||
'gn' => ['name' => 'Guinea', 'path' => __DIR__.'/flags/gn.png'],
|
||||
'gm' => ['name' => 'Gambia', 'path' => __DIR__.'/flags/gm.png'],
|
||||
'gw' => ['name' => 'Guinea-Bissau', 'path' => __DIR__.'/flags/gw.png'],
|
||||
'gq' => ['name' => 'Equatorial Guinea', 'path' => __DIR__.'/flags/gq.png'],
|
||||
'gr' => ['name' => 'Greece', 'path' => __DIR__.'/flags/gr.png'],
|
||||
'gd' => ['name' => 'Grenada', 'path' => __DIR__.'/flags/gd.png'],
|
||||
'gt' => ['name' => 'Guatemala', 'path' => __DIR__.'/flags/gt.png'],
|
||||
'gy' => ['name' => 'Guyana', 'path' => __DIR__.'/flags/gy.png'],
|
||||
'hn' => ['name' => 'Honduras', 'path' => __DIR__.'/flags/hn.png'],
|
||||
'hr' => ['name' => 'Croatia', 'path' => __DIR__.'/flags/hr.png'],
|
||||
'ht' => ['name' => 'Haiti', 'path' => __DIR__.'/flags/ht.png'],
|
||||
'hu' => ['name' => 'Hungary', 'path' => __DIR__.'/flags/hu.png'],
|
||||
'id' => ['name' => 'Indonesia', 'path' => __DIR__.'/flags/id.png'],
|
||||
'in' => ['name' => 'India', 'path' => __DIR__.'/flags/in.png'],
|
||||
'ie' => ['name' => 'Ireland', 'path' => __DIR__.'/flags/ie.png'],
|
||||
'ir' => ['name' => 'Iran (Islamic Republic of)', 'path' => __DIR__.'/flags/ir.png'],
|
||||
'iq' => ['name' => 'Iraq', 'path' => __DIR__.'/flags/iq.png'],
|
||||
'is' => ['name' => 'Iceland', 'path' => __DIR__.'/flags/is.png'],
|
||||
'il' => ['name' => 'Israel', 'path' => __DIR__.'/flags/il.png'],
|
||||
'it' => ['name' => 'Italy', 'path' => __DIR__.'/flags/it.png'],
|
||||
'jm' => ['name' => 'Jamaica', 'path' => __DIR__.'/flags/jm.png'],
|
||||
'jo' => ['name' => 'Jordan', 'path' => __DIR__.'/flags/jo.png'],
|
||||
'jp' => ['name' => 'Japan', 'path' => __DIR__.'/flags/jp.png'],
|
||||
'kz' => ['name' => 'Kazakhstan', 'path' => __DIR__.'/flags/kz.png'],
|
||||
'ke' => ['name' => 'Kenya', 'path' => __DIR__.'/flags/ke.png'],
|
||||
'kg' => ['name' => 'Kyrgyzstan', 'path' => __DIR__.'/flags/kg.png'],
|
||||
'kh' => ['name' => 'Cambodia', 'path' => __DIR__.'/flags/kh.png'],
|
||||
'ki' => ['name' => 'Kiribati', 'path' => __DIR__.'/flags/ki.png'],
|
||||
'kn' => ['name' => 'Saint Kitts and Nevis', 'path' => __DIR__.'/flags/kn.png'],
|
||||
'kr' => ['name' => 'South Korea', 'path' => __DIR__.'/flags/kr.png'],
|
||||
'kw' => ['name' => 'Kuwait', 'path' => __DIR__.'/flags/kw.png'],
|
||||
'la' => ['name' => 'Lao People\'s Democratic Republic', 'path' => __DIR__.'/flags/la.png'],
|
||||
'lb' => ['name' => 'Lebanon', 'path' => __DIR__.'/flags/lb.png'],
|
||||
'lr' => ['name' => 'Liberia', 'path' => __DIR__.'/flags/lr.png'],
|
||||
'ly' => ['name' => 'Libya', 'path' => __DIR__.'/flags/ly.png'],
|
||||
'lc' => ['name' => 'Saint Lucia', 'path' => __DIR__.'/flags/lc.png'],
|
||||
'li' => ['name' => 'Liechtenstein', 'path' => __DIR__.'/flags/li.png'],
|
||||
'lk' => ['name' => 'Sri Lanka', 'path' => __DIR__.'/flags/lk.png'],
|
||||
'ls' => ['name' => 'Lesotho', 'path' => __DIR__.'/flags/ls.png'],
|
||||
'lt' => ['name' => 'Lithuania', 'path' => __DIR__.'/flags/lt.png'],
|
||||
'lu' => ['name' => 'Luxembourg', 'path' => __DIR__.'/flags/lu.png'],
|
||||
'lv' => ['name' => 'Latvia', 'path' => __DIR__.'/flags/lv.png'],
|
||||
'ma' => ['name' => 'Morocco', 'path' => __DIR__.'/flags/ma.png'],
|
||||
'mc' => ['name' => 'Monaco', 'path' => __DIR__.'/flags/mc.png'],
|
||||
'md' => ['name' => 'Moldova', 'path' => __DIR__.'/flags/md.png'],
|
||||
'mg' => ['name' => 'Madagascar', 'path' => __DIR__.'/flags/mg.png'],
|
||||
'mv' => ['name' => 'Maldives', 'path' => __DIR__.'/flags/mv.png'],
|
||||
'mx' => ['name' => 'Mexico', 'path' => __DIR__.'/flags/mx.png'],
|
||||
'mh' => ['name' => 'Marshall Islands', 'path' => __DIR__.'/flags/mh.png'],
|
||||
'mk' => ['name' => 'North Macedonia', 'path' => __DIR__.'/flags/mk.png'],
|
||||
'ml' => ['name' => 'Mali', 'path' => __DIR__.'/flags/ml.png'],
|
||||
'mt' => ['name' => 'Malta', 'path' => __DIR__.'/flags/mt.png'],
|
||||
'mm' => ['name' => 'Myanmar', 'path' => __DIR__.'/flags/mm.png'],
|
||||
'me' => ['name' => 'Montenegro', 'path' => __DIR__.'/flags/me.png'],
|
||||
'mn' => ['name' => 'Mongolia', 'path' => __DIR__.'/flags/mn.png'],
|
||||
'mz' => ['name' => 'Mozambique', 'path' => __DIR__.'/flags/mz.png'],
|
||||
'mr' => ['name' => 'Mauritania', 'path' => __DIR__.'/flags/mr.png'],
|
||||
'mu' => ['name' => 'Mauritius', 'path' => __DIR__.'/flags/mu.png'],
|
||||
'mw' => ['name' => 'Malawi', 'path' => __DIR__.'/flags/mw.png'],
|
||||
'my' => ['name' => 'Malaysia', 'path' => __DIR__.'/flags/my.png'],
|
||||
'na' => ['name' => 'Namibia', 'path' => __DIR__.'/flags/na.png'],
|
||||
'ne' => ['name' => 'Niger', 'path' => __DIR__.'/flags/ne.png'],
|
||||
'ng' => ['name' => 'Nigeria', 'path' => __DIR__.'/flags/ng.png'],
|
||||
'ni' => ['name' => 'Nicaragua', 'path' => __DIR__.'/flags/ni.png'],
|
||||
'nl' => ['name' => 'Netherlands', 'path' => __DIR__.'/flags/nl.png'],
|
||||
'no' => ['name' => 'Norway', 'path' => __DIR__.'/flags/no.png'],
|
||||
'np' => ['name' => 'Nepal', 'path' => __DIR__.'/flags/np.png'],
|
||||
'nr' => ['name' => 'Nauru', 'path' => __DIR__.'/flags/nr.png'],
|
||||
'nz' => ['name' => 'New Zealand', 'path' => __DIR__.'/flags/nz.png'],
|
||||
'om' => ['name' => 'Oman', 'path' => __DIR__.'/flags/om.png'],
|
||||
'pk' => ['name' => 'Pakistan', 'path' => __DIR__.'/flags/pk.png'],
|
||||
'pa' => ['name' => 'Panama', 'path' => __DIR__.'/flags/pa.png'],
|
||||
'pe' => ['name' => 'Peru', 'path' => __DIR__.'/flags/pe.png'],
|
||||
'ph' => ['name' => 'Philippines', 'path' => __DIR__.'/flags/ph.png'],
|
||||
'pw' => ['name' => 'Palau', 'path' => __DIR__.'/flags/pw.png'],
|
||||
'pg' => ['name' => 'Papua New Guinea', 'path' => __DIR__.'/flags/pg.png'],
|
||||
'pl' => ['name' => 'Poland', 'path' => __DIR__.'/flags/pl.png'],
|
||||
'kp' => ['name' => 'North Korea', 'path' => __DIR__.'/flags/kp.png'],
|
||||
'pt' => ['name' => 'Portugal', 'path' => __DIR__.'/flags/pt.png'],
|
||||
'py' => ['name' => 'Paraguay', 'path' => __DIR__.'/flags/py.png'],
|
||||
'qa' => ['name' => 'Qatar', 'path' => __DIR__.'/flags/qa.png'],
|
||||
'ro' => ['name' => 'Romania', 'path' => __DIR__.'/flags/ro.png'],
|
||||
'ru' => ['name' => 'Russia', 'path' => __DIR__.'/flags/ru.png'],
|
||||
'rw' => ['name' => 'Rwanda', 'path' => __DIR__.'/flags/rw.png'],
|
||||
'sa' => ['name' => 'Saudi Arabia', 'path' => __DIR__.'/flags/sa.png'],
|
||||
'sd' => ['name' => 'Sudan', 'path' => __DIR__.'/flags/sd.png'],
|
||||
'sn' => ['name' => 'Senegal', 'path' => __DIR__.'/flags/sn.png'],
|
||||
'sg' => ['name' => 'Singapore', 'path' => __DIR__.'/flags/sg.png'],
|
||||
'sb' => ['name' => 'Solomon Islands', 'path' => __DIR__.'/flags/sb.png'],
|
||||
'sl' => ['name' => 'Sierra Leone', 'path' => __DIR__.'/flags/sl.png'],
|
||||
'sv' => ['name' => 'El Salvador', 'path' => __DIR__.'/flags/sv.png'],
|
||||
'sm' => ['name' => 'San Marino', 'path' => __DIR__.'/flags/sm.png'],
|
||||
'so' => ['name' => 'Somalia', 'path' => __DIR__.'/flags/so.png'],
|
||||
'rs' => ['name' => 'Serbia', 'path' => __DIR__.'/flags/rs.png'],
|
||||
'ss' => ['name' => 'South Sudan', 'path' => __DIR__.'/flags/ss.png'],
|
||||
'st' => ['name' => 'Sao Tome and Principe', 'path' => __DIR__.'/flags/st.png'],
|
||||
'sr' => ['name' => 'Suriname', 'path' => __DIR__.'/flags/sr.png'],
|
||||
'sk' => ['name' => 'Slovakia', 'path' => __DIR__.'/flags/sk.png'],
|
||||
'si' => ['name' => 'Slovenia', 'path' => __DIR__.'/flags/si.png'],
|
||||
'se' => ['name' => 'Sweden', 'path' => __DIR__.'/flags/se.png'],
|
||||
'sz' => ['name' => 'Eswatini', 'path' => __DIR__.'/flags/sz.png'],
|
||||
'sc' => ['name' => 'Seychelles', 'path' => __DIR__.'/flags/sc.png'],
|
||||
'sy' => ['name' => 'Syria', 'path' => __DIR__.'/flags/sy.png'],
|
||||
'td' => ['name' => 'Chad', 'path' => __DIR__.'/flags/td.png'],
|
||||
'tg' => ['name' => 'Togo', 'path' => __DIR__.'/flags/tg.png'],
|
||||
'th' => ['name' => 'Thailand', 'path' => __DIR__.'/flags/th.png'],
|
||||
'tj' => ['name' => 'Tajikistan', 'path' => __DIR__.'/flags/tj.png'],
|
||||
'tm' => ['name' => 'Turkmenistan', 'path' => __DIR__.'/flags/tm.png'],
|
||||
'tl' => ['name' => 'Timor-Leste', 'path' => __DIR__.'/flags/tl.png'],
|
||||
'to' => ['name' => 'Tonga', 'path' => __DIR__.'/flags/to.png'],
|
||||
'tt' => ['name' => 'Trinidad and Tobago', 'path' => __DIR__.'/flags/tt.png'],
|
||||
'tn' => ['name' => 'Tunisia', 'path' => __DIR__.'/flags/tn.png'],
|
||||
'tr' => ['name' => 'Turkey', 'path' => __DIR__.'/flags/tr.png'],
|
||||
'tv' => ['name' => 'Tuvalu', 'path' => __DIR__.'/flags/tv.png'],
|
||||
'tz' => ['name' => 'Tanzania', 'path' => __DIR__.'/flags/tz.png'],
|
||||
'ug' => ['name' => 'Uganda', 'path' => __DIR__.'/flags/ug.png'],
|
||||
'ua' => ['name' => 'Ukraine', 'path' => __DIR__.'/flags/ua.png'],
|
||||
'uy' => ['name' => 'Uruguay', 'path' => __DIR__.'/flags/uy.png'],
|
||||
'us' => ['name' => 'United States', 'path' => __DIR__.'/flags/us.png'],
|
||||
'uz' => ['name' => 'Uzbekistan', 'path' => __DIR__.'/flags/uz.png'],
|
||||
'va' => ['name' => 'Vatican City', 'path' => __DIR__.'/flags/va.png'],
|
||||
'vc' => ['name' => 'Saint Vincent and the Grenadines', 'path' => __DIR__.'/flags/vc.png'],
|
||||
've' => ['name' => 'Venezuela', 'path' => __DIR__.'/flags/ve.png'],
|
||||
'vn' => ['name' => 'Vietnam', 'path' => __DIR__.'/flags/vn.png'],
|
||||
'vu' => ['name' => 'Vanuatu', 'path' => __DIR__.'/flags/vu.png'],
|
||||
'ws' => ['name' => 'Samoa', 'path' => __DIR__.'/flags/ws.png'],
|
||||
'ye' => ['name' => 'Yemen', 'path' => __DIR__.'/flags/ye.png'],
|
||||
'za' => ['name' => 'South Africa', 'path' => __DIR__.'/flags/za.png'],
|
||||
'zm' => ['name' => 'Zambia', 'path' => __DIR__.'/flags/zm.png'],
|
||||
'zw' => ['name' => 'Zimbabwe', 'path' => __DIR__.'/flags/zw.png'],
|
||||
];
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
return [
|
||||
// Codes based on: https://github.com/matomo-org/device-detector/blob/master/Parser/Client/Browser.php
|
||||
'AND' => __DIR__ . '/os/android.png',
|
||||
'ATV' => __DIR__ . '/os/apple-tv.png',
|
||||
'COS' => __DIR__ . '/os/chrome-os.png',
|
||||
'AND' => __DIR__.'/os/android.png',
|
||||
'ATV' => __DIR__.'/os/apple-tv.png',
|
||||
'COS' => __DIR__.'/os/chrome-os.png',
|
||||
|
||||
/*
|
||||
'AIX' => 'AIX',
|
||||
|
||||
+23
-25
@@ -16,7 +16,6 @@ $auth = Config::getParam('auth', []);
|
||||
* attributes => list of attributes
|
||||
* indexes => list of indexes
|
||||
*/
|
||||
|
||||
$commonCollections = [
|
||||
'users' => [
|
||||
'$collection' => ID::custom(Database::METADATA),
|
||||
@@ -253,7 +252,7 @@ $commonCollections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['datetime'],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -410,7 +409,7 @@ $commonCollections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -1278,7 +1277,7 @@ $commonCollections = [
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
'stats' => [
|
||||
@@ -1454,7 +1453,7 @@ $commonCollections = [
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['json', 'encrypt'],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -1470,7 +1469,7 @@ $commonCollections = [
|
||||
'attributes' => ['name'],
|
||||
'lengths' => [128],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -1811,7 +1810,7 @@ $commonCollections = [
|
||||
'attributes' => ['topicInternalId'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -1924,7 +1923,7 @@ $commonCollections = [
|
||||
'orders' => [],
|
||||
],
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
$projectCollections = array_merge([
|
||||
@@ -2667,7 +2666,7 @@ $projectCollections = array_merge([
|
||||
'default' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -2858,7 +2857,7 @@ $projectCollections = array_merge([
|
||||
'default' => '',
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -2867,7 +2866,7 @@ $projectCollections = array_merge([
|
||||
'attributes' => ['deploymentId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -3102,7 +3101,7 @@ $projectCollections = array_merge([
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [ 'encrypt' ]
|
||||
'filters' => ['encrypt'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('search'),
|
||||
@@ -3186,7 +3185,7 @@ $projectCollections = array_merge([
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => '_key_accessedAt',
|
||||
@@ -3308,7 +3307,7 @@ $projectCollections = array_merge([
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -3338,7 +3337,7 @@ $projectCollections = array_merge([
|
||||
'attributes' => ['search'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
], $commonCollections);
|
||||
@@ -3748,7 +3747,7 @@ $consoleCollections = array_merge([
|
||||
[
|
||||
'$id' => ID::custom('_key_region_resourceType_resourceUpdatedAt'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['region', 'resourceType','resourceUpdatedAt'],
|
||||
'attributes' => ['region', 'resourceType', 'resourceUpdatedAt'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
@@ -3843,7 +3842,7 @@ $consoleCollections = array_merge([
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -4185,7 +4184,7 @@ $consoleCollections = array_merge([
|
||||
'attributes' => ['projectInternalId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -4312,7 +4311,7 @@ $consoleCollections = array_merge([
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [], //TODO: use json filter
|
||||
]
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
@@ -4322,7 +4321,7 @@ $consoleCollections = array_merge([
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_DESC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
], $commonCollections);
|
||||
|
||||
@@ -4588,7 +4587,7 @@ $bucketCollections = [
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -4711,15 +4710,14 @@ $dbCollections = [
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
$collections = [
|
||||
'projects' => $projectCollections,
|
||||
'console' => $consoleCollections,
|
||||
'console' => $consoleCollections,
|
||||
'buckets' => $bucketCollections,
|
||||
'databases' => $dbCollections
|
||||
'databases' => $dbCollections,
|
||||
];
|
||||
|
||||
return $collections;
|
||||
|
||||
@@ -299,7 +299,7 @@ return [
|
||||
Exception::AVATAR_SET_NOT_FOUND => [
|
||||
'name' => Exception::AVATAR_SET_NOT_FOUND,
|
||||
'description' => 'The requested avatar set could not be found.',
|
||||
'code' => 404
|
||||
'code' => 404,
|
||||
],
|
||||
Exception::AVATAR_NOT_FOUND => [
|
||||
'name' => Exception::AVATAR_NOT_FOUND,
|
||||
@@ -426,13 +426,13 @@ return [
|
||||
Exception::DATABASE_NOT_FOUND => [
|
||||
'name' => Exception::DATABASE_NOT_FOUND,
|
||||
'description' => 'Database not found',
|
||||
'code' => 404
|
||||
'code' => 404,
|
||||
],
|
||||
|
||||
Exception::DATABASE_ALREADY_EXISTS => [
|
||||
'name' => Exception::DATABASE_ALREADY_EXISTS,
|
||||
'description' => 'Database already exists',
|
||||
'code' => 409
|
||||
'code' => 409,
|
||||
],
|
||||
|
||||
/** Collections */
|
||||
@@ -702,5 +702,5 @@ return [
|
||||
'name' => Exception::PROVIDER_INCORRECT_TYPE,
|
||||
'description' => 'Provider with the request ID is of incorrect type: ',
|
||||
'code' => 400,
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
+33
-33
@@ -19,7 +19,7 @@ return [
|
||||
'$description' => 'This event triggers when a session for a user is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a session for a user is deleted.'
|
||||
'$description' => 'This event triggers when a session for a user is deleted.',
|
||||
],
|
||||
],
|
||||
'recovery' => [
|
||||
@@ -30,7 +30,7 @@ return [
|
||||
'$description' => 'This event triggers when a recovery token for a user is created.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a recovery token for a user is validated.'
|
||||
'$description' => 'This event triggers when a recovery token for a user is validated.',
|
||||
],
|
||||
],
|
||||
'verification' => [
|
||||
@@ -41,7 +41,7 @@ return [
|
||||
'$description' => 'This event triggers when a verification token for a user is created.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a verification token for a user is validated.'
|
||||
'$description' => 'This event triggers when a verification token for a user is validated.',
|
||||
],
|
||||
],
|
||||
'targets' => [
|
||||
@@ -59,7 +59,7 @@ return [
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a user is created.'
|
||||
'$description' => 'This event triggers when a user is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a user is deleted.',
|
||||
@@ -81,7 +81,7 @@ return [
|
||||
'prefs' => [
|
||||
'$description' => 'This event triggers when a user\'s preferences is updated.',
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
'databases' => [
|
||||
'$model' => Response::MODEL_DATABASE,
|
||||
@@ -99,10 +99,10 @@ return [
|
||||
'$description' => 'This event triggers when a document is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a document is deleted.'
|
||||
'$description' => 'This event triggers when a document is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a document is updated.'
|
||||
'$description' => 'This event triggers when a document is updated.',
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
@@ -113,8 +113,8 @@ return [
|
||||
'$description' => 'This event triggers when an index is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when an index is deleted.'
|
||||
]
|
||||
'$description' => 'This event triggers when an index is deleted.',
|
||||
],
|
||||
],
|
||||
'attributes' => [
|
||||
'$model' => Response::MODEL_ATTRIBUTE,
|
||||
@@ -124,28 +124,28 @@ return [
|
||||
'$description' => 'This event triggers when an attribute is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when an attribute is deleted.'
|
||||
]
|
||||
'$description' => 'This event triggers when an attribute is deleted.',
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a collection is created.'
|
||||
'$description' => 'This event triggers when a collection is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a collection is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a collection is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a database is created.'
|
||||
'$description' => 'This event triggers when a database is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a database is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a database is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'buckets' => [
|
||||
'$model' => Response::MODEL_BUCKET,
|
||||
@@ -159,21 +159,21 @@ return [
|
||||
'$description' => 'This event triggers when a file is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a file is deleted.'
|
||||
'$description' => 'This event triggers when a file is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a file is updated.'
|
||||
'$description' => 'This event triggers when a file is updated.',
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a bucket is created.'
|
||||
'$description' => 'This event triggers when a bucket is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a bucket is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a bucket is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'teams' => [
|
||||
'$model' => Response::MODEL_TEAM,
|
||||
@@ -187,17 +187,17 @@ return [
|
||||
'$description' => 'This event triggers when a membership is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a membership is deleted.'
|
||||
'$description' => 'This event triggers when a membership is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a membership is updated.',
|
||||
'status' => [
|
||||
'$description' => 'This event triggers when a team memberships status is updated.'
|
||||
]
|
||||
'$description' => 'This event triggers when a team memberships status is updated.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a team is created.'
|
||||
'$description' => 'This event triggers when a team is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a team is deleted.',
|
||||
@@ -207,7 +207,7 @@ return [
|
||||
'prefs' => [
|
||||
'$description' => 'This event triggers when a team\'s preferences are updated.',
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
'functions' => [
|
||||
'$model' => Response::MODEL_FUNCTION,
|
||||
@@ -221,10 +221,10 @@ return [
|
||||
'$description' => 'This event triggers when a deployment is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a deployment is deleted.'
|
||||
'$description' => 'This event triggers when a deployment is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a deployment is updated.'
|
||||
'$description' => 'This event triggers when a deployment is updated.',
|
||||
],
|
||||
],
|
||||
'executions' => [
|
||||
@@ -235,21 +235,21 @@ return [
|
||||
'$description' => 'This event triggers when an execution is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when an execution is deleted.'
|
||||
'$description' => 'This event triggers when an execution is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when an execution is updated.'
|
||||
'$description' => 'This event triggers when an execution is updated.',
|
||||
],
|
||||
],
|
||||
'create' => [
|
||||
'$description' => 'This event triggers when a function is created.'
|
||||
'$description' => 'This event triggers when a function is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a function is deleted.',
|
||||
],
|
||||
'update' => [
|
||||
'$description' => 'This event triggers when a function is updated.',
|
||||
]
|
||||
],
|
||||
],
|
||||
'messages' => [
|
||||
'$model' => Response::MODEL_MESSAGE,
|
||||
@@ -269,7 +269,7 @@ return [
|
||||
'$description' => 'This event triggers when a provider is updated.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a provider is deleted.'
|
||||
'$description' => 'This event triggers when a provider is deleted.',
|
||||
],
|
||||
],
|
||||
'topics' => [
|
||||
@@ -280,7 +280,7 @@ return [
|
||||
'$description' => 'This event triggers when a provider is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a provider is deleted.'
|
||||
'$description' => 'This event triggers when a provider is deleted.',
|
||||
],
|
||||
'subscribers' => [
|
||||
'$model' => Response::MODEL_SUBSCRIBER,
|
||||
@@ -290,7 +290,7 @@ return [
|
||||
'$description' => 'This event triggers when a subscriber is created.',
|
||||
],
|
||||
'delete' => [
|
||||
'$description' => 'This event triggers when a subscriber is deleted.'
|
||||
'$description' => 'This event triggers when a subscriber is deleted.',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
+262
-263
@@ -6,532 +6,531 @@
|
||||
*
|
||||
* Source:
|
||||
* https://www.andiamo.co.uk/resources/iso-language-codes/
|
||||
*
|
||||
*/
|
||||
|
||||
return [
|
||||
[
|
||||
"code" => "af",
|
||||
"name" => "Afrikaans",
|
||||
'code' => 'af',
|
||||
'name' => 'Afrikaans',
|
||||
],
|
||||
[
|
||||
"code" => "ar-ae",
|
||||
"name" => "Arabic (U.A.E.)",
|
||||
'code' => 'ar-ae',
|
||||
'name' => 'Arabic (U.A.E.)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-bh",
|
||||
"name" => "Arabic (Bahrain)",
|
||||
'code' => 'ar-bh',
|
||||
'name' => 'Arabic (Bahrain)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-dz",
|
||||
"name" => "Arabic (Algeria)",
|
||||
'code' => 'ar-dz',
|
||||
'name' => 'Arabic (Algeria)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-eg",
|
||||
"name" => "Arabic (Egypt)",
|
||||
'code' => 'ar-eg',
|
||||
'name' => 'Arabic (Egypt)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-iq",
|
||||
"name" => "Arabic (Iraq)",
|
||||
'code' => 'ar-iq',
|
||||
'name' => 'Arabic (Iraq)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-jo",
|
||||
"name" => "Arabic (Jordan)",
|
||||
'code' => 'ar-jo',
|
||||
'name' => 'Arabic (Jordan)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-kw",
|
||||
"name" => "Arabic (Kuwait)",
|
||||
'code' => 'ar-kw',
|
||||
'name' => 'Arabic (Kuwait)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-lb",
|
||||
"name" => "Arabic (Lebanon)",
|
||||
'code' => 'ar-lb',
|
||||
'name' => 'Arabic (Lebanon)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-ly",
|
||||
"name" => "Arabic (Libya)",
|
||||
'code' => 'ar-ly',
|
||||
'name' => 'Arabic (Libya)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-ma",
|
||||
"name" => "Arabic (Morocco)",
|
||||
'code' => 'ar-ma',
|
||||
'name' => 'Arabic (Morocco)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-om",
|
||||
"name" => "Arabic (Oman)",
|
||||
'code' => 'ar-om',
|
||||
'name' => 'Arabic (Oman)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-qa",
|
||||
"name" => "Arabic (Qatar)",
|
||||
'code' => 'ar-qa',
|
||||
'name' => 'Arabic (Qatar)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-sa",
|
||||
"name" => "Arabic (Saudi Arabia)",
|
||||
'code' => 'ar-sa',
|
||||
'name' => 'Arabic (Saudi Arabia)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-sy",
|
||||
"name" => "Arabic (Syria)",
|
||||
'code' => 'ar-sy',
|
||||
'name' => 'Arabic (Syria)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-tn",
|
||||
"name" => "Arabic (Tunisia)",
|
||||
'code' => 'ar-tn',
|
||||
'name' => 'Arabic (Tunisia)',
|
||||
],
|
||||
[
|
||||
"code" => "ar-ye",
|
||||
"name" => "Arabic (Yemen)",
|
||||
'code' => 'ar-ye',
|
||||
'name' => 'Arabic (Yemen)',
|
||||
],
|
||||
[
|
||||
"code" => "as",
|
||||
"name" => "Assamese",
|
||||
'code' => 'as',
|
||||
'name' => 'Assamese',
|
||||
],
|
||||
[
|
||||
"code" => "az",
|
||||
"name" => "Azerbaijani",
|
||||
'code' => 'az',
|
||||
'name' => 'Azerbaijani',
|
||||
],
|
||||
[
|
||||
"code" => "be",
|
||||
"name" => "Belarusian",
|
||||
'code' => 'be',
|
||||
'name' => 'Belarusian',
|
||||
],
|
||||
[
|
||||
"code" => "bg",
|
||||
"name" => "Bulgarian",
|
||||
'code' => 'bg',
|
||||
'name' => 'Bulgarian',
|
||||
],
|
||||
[
|
||||
"code" => "bh",
|
||||
"name" => "Bihari",
|
||||
'code' => 'bh',
|
||||
'name' => 'Bihari',
|
||||
],
|
||||
[
|
||||
"code" => "bn",
|
||||
"name" => "Bengali",
|
||||
'code' => 'bn',
|
||||
'name' => 'Bengali',
|
||||
],
|
||||
[
|
||||
"code" => "bs",
|
||||
"name" => "Bosnian",
|
||||
'code' => 'bs',
|
||||
'name' => 'Bosnian',
|
||||
],
|
||||
[
|
||||
"code" => "ca",
|
||||
"name" => "Catalan",
|
||||
'code' => 'ca',
|
||||
'name' => 'Catalan',
|
||||
],
|
||||
[
|
||||
"code" => "cs",
|
||||
"name" => "Czech",
|
||||
'code' => 'cs',
|
||||
'name' => 'Czech',
|
||||
],
|
||||
[
|
||||
"code" => "cy",
|
||||
"name" => "Welsh",
|
||||
'code' => 'cy',
|
||||
'name' => 'Welsh',
|
||||
],
|
||||
[
|
||||
"code" => "da",
|
||||
"name" => "Danish",
|
||||
'code' => 'da',
|
||||
'name' => 'Danish',
|
||||
],
|
||||
[
|
||||
"code" => "de",
|
||||
"name" => "German (Standard)",
|
||||
'code' => 'de',
|
||||
'name' => 'German (Standard)',
|
||||
],
|
||||
[
|
||||
"code" => "de-at",
|
||||
"name" => "German (Austria)",
|
||||
'code' => 'de-at',
|
||||
'name' => 'German (Austria)',
|
||||
],
|
||||
[
|
||||
"code" => "de-ch",
|
||||
"name" => "German (Switzerland)",
|
||||
'code' => 'de-ch',
|
||||
'name' => 'German (Switzerland)',
|
||||
],
|
||||
[
|
||||
"code" => "de-li",
|
||||
"name" => "German (Liechtenstein)",
|
||||
'code' => 'de-li',
|
||||
'name' => 'German (Liechtenstein)',
|
||||
],
|
||||
[
|
||||
"code" => "de-lu",
|
||||
"name" => "German (Luxembourg)",
|
||||
'code' => 'de-lu',
|
||||
'name' => 'German (Luxembourg)',
|
||||
],
|
||||
[
|
||||
"code" => "el",
|
||||
"name" => "Greek",
|
||||
'code' => 'el',
|
||||
'name' => 'Greek',
|
||||
],
|
||||
[
|
||||
"code" => "en",
|
||||
"name" => "English",
|
||||
'code' => 'en',
|
||||
'name' => 'English',
|
||||
],
|
||||
[
|
||||
"code" => "en-au",
|
||||
"name" => "English (Australia)",
|
||||
'code' => 'en-au',
|
||||
'name' => 'English (Australia)',
|
||||
],
|
||||
[
|
||||
"code" => "en-bz",
|
||||
"name" => "English (Belize)",
|
||||
'code' => 'en-bz',
|
||||
'name' => 'English (Belize)',
|
||||
],
|
||||
[
|
||||
"code" => "en-ca",
|
||||
"name" => "English (Canada)",
|
||||
'code' => 'en-ca',
|
||||
'name' => 'English (Canada)',
|
||||
],
|
||||
[
|
||||
"code" => "en-gb",
|
||||
"name" => "English (United Kingdom)",
|
||||
'code' => 'en-gb',
|
||||
'name' => 'English (United Kingdom)',
|
||||
],
|
||||
[
|
||||
"code" => "en-ie",
|
||||
"name" => "English (Ireland)",
|
||||
'code' => 'en-ie',
|
||||
'name' => 'English (Ireland)',
|
||||
],
|
||||
[
|
||||
"code" => "en-jm",
|
||||
"name" => "English (Jamaica)",
|
||||
'code' => 'en-jm',
|
||||
'name' => 'English (Jamaica)',
|
||||
],
|
||||
[
|
||||
"code" => "en-nz",
|
||||
"name" => "English (New Zealand)",
|
||||
'code' => 'en-nz',
|
||||
'name' => 'English (New Zealand)',
|
||||
],
|
||||
[
|
||||
"code" => "en-tt",
|
||||
"name" => "English (Trinidad)",
|
||||
'code' => 'en-tt',
|
||||
'name' => 'English (Trinidad)',
|
||||
],
|
||||
[
|
||||
"code" => "en-us",
|
||||
"name" => "English (United States)",
|
||||
'code' => 'en-us',
|
||||
'name' => 'English (United States)',
|
||||
],
|
||||
[
|
||||
"code" => "en-za",
|
||||
"name" => "English (South Africa)",
|
||||
'code' => 'en-za',
|
||||
'name' => 'English (South Africa)',
|
||||
],
|
||||
[
|
||||
"code" => "eo",
|
||||
"name" => "Esperanto",
|
||||
'code' => 'eo',
|
||||
'name' => 'Esperanto',
|
||||
],
|
||||
[
|
||||
"code" => "es",
|
||||
"name" => "Spanish (Spain)",
|
||||
'code' => 'es',
|
||||
'name' => 'Spanish (Spain)',
|
||||
],
|
||||
[
|
||||
"code" => "es-ar",
|
||||
"name" => "Spanish (Argentina)",
|
||||
'code' => 'es-ar',
|
||||
'name' => 'Spanish (Argentina)',
|
||||
],
|
||||
[
|
||||
"code" => "es-bo",
|
||||
"name" => "Spanish (Bolivia)",
|
||||
'code' => 'es-bo',
|
||||
'name' => 'Spanish (Bolivia)',
|
||||
],
|
||||
[
|
||||
"code" => "es-cl",
|
||||
"name" => "Spanish (Chile)",
|
||||
'code' => 'es-cl',
|
||||
'name' => 'Spanish (Chile)',
|
||||
],
|
||||
[
|
||||
"code" => "es-co",
|
||||
"name" => "Spanish (Colombia)",
|
||||
'code' => 'es-co',
|
||||
'name' => 'Spanish (Colombia)',
|
||||
],
|
||||
[
|
||||
"code" => "es-cr",
|
||||
"name" => "Spanish (Costa Rica)",
|
||||
'code' => 'es-cr',
|
||||
'name' => 'Spanish (Costa Rica)',
|
||||
],
|
||||
[
|
||||
"code" => "es-do",
|
||||
"name" => "Spanish (Dominican Republic)",
|
||||
'code' => 'es-do',
|
||||
'name' => 'Spanish (Dominican Republic)',
|
||||
],
|
||||
[
|
||||
"code" => "es-ec",
|
||||
"name" => "Spanish (Ecuador)",
|
||||
'code' => 'es-ec',
|
||||
'name' => 'Spanish (Ecuador)',
|
||||
],
|
||||
[
|
||||
"code" => "es-gt",
|
||||
"name" => "Spanish (Guatemala)",
|
||||
'code' => 'es-gt',
|
||||
'name' => 'Spanish (Guatemala)',
|
||||
],
|
||||
[
|
||||
"code" => "es-hn",
|
||||
"name" => "Spanish (Honduras)",
|
||||
'code' => 'es-hn',
|
||||
'name' => 'Spanish (Honduras)',
|
||||
],
|
||||
[
|
||||
"code" => "es-mx",
|
||||
"name" => "Spanish (Mexico)",
|
||||
'code' => 'es-mx',
|
||||
'name' => 'Spanish (Mexico)',
|
||||
],
|
||||
[
|
||||
"code" => "es-ni",
|
||||
"name" => "Spanish (Nicaragua)",
|
||||
'code' => 'es-ni',
|
||||
'name' => 'Spanish (Nicaragua)',
|
||||
],
|
||||
[
|
||||
"code" => "es-pa",
|
||||
"name" => "Spanish (Panama)",
|
||||
'code' => 'es-pa',
|
||||
'name' => 'Spanish (Panama)',
|
||||
],
|
||||
[
|
||||
"code" => "es-pe",
|
||||
"name" => "Spanish (Peru)",
|
||||
'code' => 'es-pe',
|
||||
'name' => 'Spanish (Peru)',
|
||||
],
|
||||
[
|
||||
"code" => "es-pr",
|
||||
"name" => "Spanish (Puerto Rico)",
|
||||
'code' => 'es-pr',
|
||||
'name' => 'Spanish (Puerto Rico)',
|
||||
],
|
||||
[
|
||||
"code" => "es-py",
|
||||
"name" => "Spanish (Paraguay)",
|
||||
'code' => 'es-py',
|
||||
'name' => 'Spanish (Paraguay)',
|
||||
],
|
||||
[
|
||||
"code" => "es-sv",
|
||||
"name" => "Spanish (El Salvador)",
|
||||
'code' => 'es-sv',
|
||||
'name' => 'Spanish (El Salvador)',
|
||||
],
|
||||
[
|
||||
"code" => "es-uy",
|
||||
"name" => "Spanish (Uruguay)",
|
||||
'code' => 'es-uy',
|
||||
'name' => 'Spanish (Uruguay)',
|
||||
],
|
||||
[
|
||||
"code" => "es-ve",
|
||||
"name" => "Spanish (Venezuela)",
|
||||
'code' => 'es-ve',
|
||||
'name' => 'Spanish (Venezuela)',
|
||||
],
|
||||
[
|
||||
"code" => "et",
|
||||
"name" => "Estonian",
|
||||
'code' => 'et',
|
||||
'name' => 'Estonian',
|
||||
],
|
||||
[
|
||||
"code" => "eu",
|
||||
"name" => "Basque",
|
||||
'code' => 'eu',
|
||||
'name' => 'Basque',
|
||||
],
|
||||
[
|
||||
"code" => "fa",
|
||||
"name" => "Farsi",
|
||||
'code' => 'fa',
|
||||
'name' => 'Farsi',
|
||||
],
|
||||
[
|
||||
"code" => "fi",
|
||||
"name" => "Finnish",
|
||||
'code' => 'fi',
|
||||
'name' => 'Finnish',
|
||||
],
|
||||
[
|
||||
"code" => "fo",
|
||||
"name" => "Faeroese",
|
||||
'code' => 'fo',
|
||||
'name' => 'Faeroese',
|
||||
],
|
||||
[
|
||||
"code" => "fr",
|
||||
"name" => "French (Standard)",
|
||||
'code' => 'fr',
|
||||
'name' => 'French (Standard)',
|
||||
],
|
||||
[
|
||||
"code" => "fr-be",
|
||||
"name" => "French (Belgium)",
|
||||
'code' => 'fr-be',
|
||||
'name' => 'French (Belgium)',
|
||||
],
|
||||
[
|
||||
"code" => "fr-ca",
|
||||
"name" => "French (Canada)",
|
||||
'code' => 'fr-ca',
|
||||
'name' => 'French (Canada)',
|
||||
],
|
||||
[
|
||||
"code" => "fr-ch",
|
||||
"name" => "French (Switzerland)",
|
||||
'code' => 'fr-ch',
|
||||
'name' => 'French (Switzerland)',
|
||||
],
|
||||
[
|
||||
"code" => "fr-lu",
|
||||
"name" => "French (Luxembourg)",
|
||||
'code' => 'fr-lu',
|
||||
'name' => 'French (Luxembourg)',
|
||||
],
|
||||
[
|
||||
"code" => "ga",
|
||||
"name" => "Irish",
|
||||
'code' => 'ga',
|
||||
'name' => 'Irish',
|
||||
],
|
||||
[
|
||||
"code" => "gd",
|
||||
"name" => "Gaelic (Scotland)",
|
||||
'code' => 'gd',
|
||||
'name' => 'Gaelic (Scotland)',
|
||||
],
|
||||
[
|
||||
"code" => "he",
|
||||
"name" => "Hebrew",
|
||||
'code' => 'he',
|
||||
'name' => 'Hebrew',
|
||||
],
|
||||
[
|
||||
"code" => "hi",
|
||||
"name" => "Hindi",
|
||||
'code' => 'hi',
|
||||
'name' => 'Hindi',
|
||||
],
|
||||
[
|
||||
"code" => "hr",
|
||||
"name" => "Croatian",
|
||||
'code' => 'hr',
|
||||
'name' => 'Croatian',
|
||||
],
|
||||
[
|
||||
"code" => "hu",
|
||||
"name" => "Hungarian",
|
||||
'code' => 'hu',
|
||||
'name' => 'Hungarian',
|
||||
],
|
||||
[
|
||||
"code" => "id",
|
||||
"name" => "Indonesian",
|
||||
'code' => 'id',
|
||||
'name' => 'Indonesian',
|
||||
],
|
||||
[
|
||||
"code" => "is",
|
||||
"name" => "Icelandic",
|
||||
'code' => 'is',
|
||||
'name' => 'Icelandic',
|
||||
],
|
||||
[
|
||||
"code" => "it",
|
||||
"name" => "Italian (Standard)",
|
||||
'code' => 'it',
|
||||
'name' => 'Italian (Standard)',
|
||||
],
|
||||
[
|
||||
"code" => "it-ch",
|
||||
"name" => "Italian (Switzerland)",
|
||||
'code' => 'it-ch',
|
||||
'name' => 'Italian (Switzerland)',
|
||||
],
|
||||
[
|
||||
"code" => "ja",
|
||||
"name" => "Japanese",
|
||||
'code' => 'ja',
|
||||
'name' => 'Japanese',
|
||||
],
|
||||
[
|
||||
"code" => "ji",
|
||||
"name" => "Yiddish",
|
||||
'code' => 'ji',
|
||||
'name' => 'Yiddish',
|
||||
],
|
||||
[
|
||||
"code" => "ko",
|
||||
"name" => "Korean",
|
||||
'code' => 'ko',
|
||||
'name' => 'Korean',
|
||||
],
|
||||
[
|
||||
"code" => "ku",
|
||||
"name" => "Kurdish",
|
||||
'code' => 'ku',
|
||||
'name' => 'Kurdish',
|
||||
],
|
||||
[
|
||||
"code" => "lt",
|
||||
"name" => "Lithuanian",
|
||||
'code' => 'lt',
|
||||
'name' => 'Lithuanian',
|
||||
],
|
||||
[
|
||||
"code" => "lv",
|
||||
"name" => "Latvian",
|
||||
'code' => 'lv',
|
||||
'name' => 'Latvian',
|
||||
],
|
||||
[
|
||||
"code" => "mk",
|
||||
"name" => "Macedonian (FYROM)",
|
||||
'code' => 'mk',
|
||||
'name' => 'Macedonian (FYROM)',
|
||||
],
|
||||
[
|
||||
"code" => "ml",
|
||||
"name" => "Malayalam",
|
||||
'code' => 'ml',
|
||||
'name' => 'Malayalam',
|
||||
],
|
||||
[
|
||||
"code" => "ms",
|
||||
"name" => "Malaysian",
|
||||
'code' => 'ms',
|
||||
'name' => 'Malaysian',
|
||||
],
|
||||
[
|
||||
"code" => "mt",
|
||||
"name" => "Maltese",
|
||||
'code' => 'mt',
|
||||
'name' => 'Maltese',
|
||||
],
|
||||
[
|
||||
"code" => "nb",
|
||||
"name" => "Norwegian (Bokmål)",
|
||||
'code' => 'nb',
|
||||
'name' => 'Norwegian (Bokmål)',
|
||||
],
|
||||
[
|
||||
"code" => "ne",
|
||||
"name" => "Nepali",
|
||||
'code' => 'ne',
|
||||
'name' => 'Nepali',
|
||||
],
|
||||
[
|
||||
"code" => "nl",
|
||||
"name" => "Dutch (Standard)",
|
||||
'code' => 'nl',
|
||||
'name' => 'Dutch (Standard)',
|
||||
],
|
||||
[
|
||||
"code" => "nl-be",
|
||||
"name" => "Dutch (Belgium)",
|
||||
'code' => 'nl-be',
|
||||
'name' => 'Dutch (Belgium)',
|
||||
],
|
||||
[
|
||||
"code" => "nn",
|
||||
"name" => "Norwegian (Nynorsk)",
|
||||
'code' => 'nn',
|
||||
'name' => 'Norwegian (Nynorsk)',
|
||||
],
|
||||
[
|
||||
"code" => "no",
|
||||
"name" => "Norwegian",
|
||||
'code' => 'no',
|
||||
'name' => 'Norwegian',
|
||||
],
|
||||
[
|
||||
"code" => "pa",
|
||||
"name" => "Punjabi",
|
||||
'code' => 'pa',
|
||||
'name' => 'Punjabi',
|
||||
],
|
||||
[
|
||||
"code" => "pl",
|
||||
"name" => "Polish",
|
||||
'code' => 'pl',
|
||||
'name' => 'Polish',
|
||||
],
|
||||
[
|
||||
"code" => "pt",
|
||||
"name" => "Portuguese (Portugal)",
|
||||
'code' => 'pt',
|
||||
'name' => 'Portuguese (Portugal)',
|
||||
],
|
||||
[
|
||||
"code" => "pt-br",
|
||||
"name" => "Portuguese (Brazil)",
|
||||
'code' => 'pt-br',
|
||||
'name' => 'Portuguese (Brazil)',
|
||||
],
|
||||
[
|
||||
"code" => "rm",
|
||||
"name" => "Rhaeto-Romanic",
|
||||
'code' => 'rm',
|
||||
'name' => 'Rhaeto-Romanic',
|
||||
],
|
||||
[
|
||||
"code" => "ro",
|
||||
"name" => "Romanian",
|
||||
'code' => 'ro',
|
||||
'name' => 'Romanian',
|
||||
],
|
||||
[
|
||||
"code" => "ro-md",
|
||||
"name" => "Romanian (Republic of Moldova)",
|
||||
'code' => 'ro-md',
|
||||
'name' => 'Romanian (Republic of Moldova)',
|
||||
],
|
||||
[
|
||||
"code" => "ru",
|
||||
"name" => "Russian",
|
||||
'code' => 'ru',
|
||||
'name' => 'Russian',
|
||||
],
|
||||
[
|
||||
"code" => "ru-md",
|
||||
"name" => "Russian (Republic of Moldova)",
|
||||
'code' => 'ru-md',
|
||||
'name' => 'Russian (Republic of Moldova)',
|
||||
],
|
||||
[
|
||||
"code" => "sb",
|
||||
"name" => "Sorbian",
|
||||
'code' => 'sb',
|
||||
'name' => 'Sorbian',
|
||||
],
|
||||
[
|
||||
"code" => "sk",
|
||||
"name" => "Slovak",
|
||||
'code' => 'sk',
|
||||
'name' => 'Slovak',
|
||||
],
|
||||
[
|
||||
"code" => "sl",
|
||||
"name" => "Slovenian",
|
||||
'code' => 'sl',
|
||||
'name' => 'Slovenian',
|
||||
],
|
||||
[
|
||||
"code" => "sq",
|
||||
"name" => "Albanian",
|
||||
'code' => 'sq',
|
||||
'name' => 'Albanian',
|
||||
],
|
||||
[
|
||||
"code" => "sr",
|
||||
"name" => "Serbian",
|
||||
'code' => 'sr',
|
||||
'name' => 'Serbian',
|
||||
],
|
||||
[
|
||||
"code" => "sv",
|
||||
"name" => "Swedish",
|
||||
'code' => 'sv',
|
||||
'name' => 'Swedish',
|
||||
],
|
||||
[
|
||||
"code" => "sv-fi",
|
||||
"name" => "Swedish (Finland)",
|
||||
'code' => 'sv-fi',
|
||||
'name' => 'Swedish (Finland)',
|
||||
],
|
||||
[
|
||||
"code" => "th",
|
||||
"name" => "Thai",
|
||||
'code' => 'th',
|
||||
'name' => 'Thai',
|
||||
],
|
||||
[
|
||||
"code" => "tn",
|
||||
"name" => "Tswana",
|
||||
'code' => 'tn',
|
||||
'name' => 'Tswana',
|
||||
],
|
||||
[
|
||||
"code" => "tr",
|
||||
"name" => "Turkish",
|
||||
'code' => 'tr',
|
||||
'name' => 'Turkish',
|
||||
],
|
||||
[
|
||||
"code" => "ts",
|
||||
"name" => "Tsonga",
|
||||
'code' => 'ts',
|
||||
'name' => 'Tsonga',
|
||||
],
|
||||
[
|
||||
"code" => "ua",
|
||||
"name" => "Ukrainian",
|
||||
'code' => 'ua',
|
||||
'name' => 'Ukrainian',
|
||||
],
|
||||
[
|
||||
"code" => "ur",
|
||||
"name" => "Urdu",
|
||||
'code' => 'ur',
|
||||
'name' => 'Urdu',
|
||||
],
|
||||
[
|
||||
"code" => "ve",
|
||||
"name" => "Venda",
|
||||
'code' => 've',
|
||||
'name' => 'Venda',
|
||||
],
|
||||
[
|
||||
"code" => "vi",
|
||||
"name" => "Vietnamese",
|
||||
'code' => 'vi',
|
||||
'name' => 'Vietnamese',
|
||||
],
|
||||
[
|
||||
"code" => "xh",
|
||||
"name" => "Xhosa",
|
||||
'code' => 'xh',
|
||||
'name' => 'Xhosa',
|
||||
],
|
||||
[
|
||||
"code" => "zh-cn",
|
||||
"name" => "Chinese (PRC)",
|
||||
'code' => 'zh-cn',
|
||||
'name' => 'Chinese (PRC)',
|
||||
],
|
||||
[
|
||||
"code" => "zh-hk",
|
||||
"name" => "Chinese (Hong Kong)",
|
||||
'code' => 'zh-hk',
|
||||
'name' => 'Chinese (Hong Kong)',
|
||||
],
|
||||
[
|
||||
"code" => "zh-sg",
|
||||
"name" => "Chinese (Singapore)",
|
||||
'code' => 'zh-sg',
|
||||
'name' => 'Chinese (Singapore)',
|
||||
],
|
||||
[
|
||||
"code" => "zh-tw",
|
||||
"name" => "Chinese (Taiwan)",
|
||||
'code' => 'zh-tw',
|
||||
'name' => 'Chinese (Taiwan)',
|
||||
],
|
||||
[
|
||||
"code" => "zu",
|
||||
"name" => "Zulu",
|
||||
'code' => 'zu',
|
||||
'name' => 'Zulu',
|
||||
],
|
||||
];
|
||||
|
||||
+553
-553
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,6 @@ return [
|
||||
'sms' => [
|
||||
'verification',
|
||||
'login',
|
||||
'invitation'
|
||||
]
|
||||
'invitation',
|
||||
],
|
||||
];
|
||||
|
||||
+293
-293
@@ -1,300 +1,300 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => [
|
||||
'mailchimp' => [
|
||||
'name' => 'Mailchimp',
|
||||
'developers' => 'https://mailchimp.com/developer/marketing/api/',
|
||||
'icon' => 'icon-mailchimp',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'email' => [
|
||||
'mailchimp' => [
|
||||
'name' => 'Mailchimp',
|
||||
'developers' => 'https://mailchimp.com/developer/marketing/api/',
|
||||
'icon' => 'icon-mailchimp',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'mailgun' => [
|
||||
'name' => 'Mailgun',
|
||||
'developers' => 'https://documentation.mailgun.com/',
|
||||
'icon' => 'icon-mailgun',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'mailjet' => [
|
||||
'name' => 'Mailjet',
|
||||
'developers' => 'https://dev.mailjet.com/',
|
||||
'icon' => 'icon-mailjet',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'postmark' => [
|
||||
'name' => 'Postmark',
|
||||
'developers' => 'https://postmarkapp.com/developer',
|
||||
'icon' => 'icon-postmark',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sendgrid' => [
|
||||
'name' => 'Sendgrid',
|
||||
'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/',
|
||||
'icon' => 'icon-sendgrid',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sendinblue' => [
|
||||
'name' => 'SendinBlue',
|
||||
'developers' => 'https://developers.sendinblue.com/',
|
||||
'icon' => 'icon-sendinblue',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'mailslurp' => [
|
||||
'name' => 'MailSlurp',
|
||||
'developers' => 'https://www.mailslurp.com/docs/',
|
||||
'icon' => 'icon-mailslurp',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'elasticemail' => [
|
||||
'name' => 'ElasticEmail',
|
||||
'developers' => 'https://api.elasticemail.com/public/help',
|
||||
'icon' => 'icon-elasticemail',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'ses' => [
|
||||
'name' => 'SES',
|
||||
'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/',
|
||||
'icon' => 'icon-ses',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
],
|
||||
'mailgun' => [
|
||||
'name' => 'Mailgun',
|
||||
'developers' => 'https://documentation.mailgun.com/',
|
||||
'icon' => 'icon-mailgun',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'sms' => [
|
||||
'africastalking' => [
|
||||
'name' => 'Africa\'s Talking',
|
||||
'developers' => 'https://developers.africastalking.com/',
|
||||
'icon' => 'icon-africastalking',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'clickatell' => [
|
||||
'name' => 'Clickatell',
|
||||
'developers' => 'https://www.clickatell.com/developers/api-docs/',
|
||||
'icon' => 'icon-clickatell',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'infobip' => [
|
||||
'name' => 'Infobip',
|
||||
'developers' => 'https://www.infobip.com/docs/',
|
||||
'icon' => 'icon-infobip',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'msg91' => [
|
||||
'name' => 'Msg91',
|
||||
'developers' => 'https://docs.msg91.com/reference/overview',
|
||||
'icon' => 'icon-msg91',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'plivo' => [
|
||||
'name' => 'Plivo',
|
||||
'developers' => 'https://developers.plivo.com/',
|
||||
'icon' => 'icon-plivo',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sinch' => [
|
||||
'name' => 'Sinch',
|
||||
'developers' => 'https://developers.sinch.com/',
|
||||
'icon' => 'icon-sinch',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sms77' => [
|
||||
'name' => 'Sms77',
|
||||
'developers' => 'https://sms77.io/docs/gateway/',
|
||||
'icon' => 'icon-sms77',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'telesign' => [
|
||||
'name' => 'Telesign',
|
||||
'developers' => 'https://developer.telesign.com/enterprise/docs',
|
||||
'icon' => 'icon-telesign',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'textmagic' => [
|
||||
'name' => 'TextMagic',
|
||||
'developers' => 'https://www.textmagic.com/docs/api/',
|
||||
'icon' => 'icon-twilio',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'twilio' => [
|
||||
'name' => 'Twilio',
|
||||
'developers' => 'https://www.twilio.com/docs/sms',
|
||||
'icon' => 'icon-twilio',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'twilio-notify' => [
|
||||
'name' => 'Twilio Notify',
|
||||
'developers' => 'https://www.twilio.com/docs/notify',
|
||||
'icon' => 'icon-twilio',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'vonage' => [
|
||||
'name' => 'Vonage',
|
||||
'developers' => 'https://developer.nexmo.com/',
|
||||
'icon' => 'icon-vonage',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
],
|
||||
'mailjet' => [
|
||||
'name' => 'Mailjet',
|
||||
'developers' => 'https://dev.mailjet.com/',
|
||||
'icon' => 'icon-mailjet',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
'push' => [
|
||||
'apns' => [
|
||||
'name' => 'APNS',
|
||||
'developers' => 'https://developer.apple.com/documentation/usernotifications',
|
||||
'icon' => 'icon-apns',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'fcm' => [
|
||||
'name' => 'FCM',
|
||||
'developers' => 'https://firebase.google.com/docs/cloud-messaging',
|
||||
'icon' => 'icon-fcm',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'one_signal' => [
|
||||
'name' => 'OneSignal',
|
||||
'developers' => 'https://documentation.onesignal.com/docs',
|
||||
'icon' => 'icon-onesignal',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'pushbullet' => [
|
||||
'name' => 'PushBullet',
|
||||
'developers' => 'https://docs.pushbullet.com/',
|
||||
'icon' => 'icon-pushbullet',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'pusher' => [
|
||||
'name' => 'Pusher',
|
||||
'developers' => 'https://pusher.com/docs',
|
||||
'icon' => 'icon-pusher',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'pushwoosh' => [
|
||||
'name' => 'Pushwoosh',
|
||||
'developers' => 'https://www.pushwoosh.com/docs/',
|
||||
'icon' => 'icon-pushwoosh',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'urban_airship' => [
|
||||
'name' => 'Urban Airship',
|
||||
'developers' => 'https://docs.airship.com/api/',
|
||||
'icon' => 'icon-urbanairship',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'web_push' => [
|
||||
'name' => 'WebPush',
|
||||
'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API',
|
||||
'icon' => 'icon-webpush',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
],
|
||||
'postmark' => [
|
||||
'name' => 'Postmark',
|
||||
'developers' => 'https://postmarkapp.com/developer',
|
||||
'icon' => 'icon-postmark',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sendgrid' => [
|
||||
'name' => 'Sendgrid',
|
||||
'developers' => 'https://docs.sendgrid.com/api-reference/how-to-use-the-sendgrid-v3-api/',
|
||||
'icon' => 'icon-sendgrid',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sendinblue' => [
|
||||
'name' => 'SendinBlue',
|
||||
'developers' => 'https://developers.sendinblue.com/',
|
||||
'icon' => 'icon-sendinblue',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'mailslurp' => [
|
||||
'name' => 'MailSlurp',
|
||||
'developers' => 'https://www.mailslurp.com/docs/',
|
||||
'icon' => 'icon-mailslurp',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'elasticemail' => [
|
||||
'name' => 'ElasticEmail',
|
||||
'developers' => 'https://api.elasticemail.com/public/help',
|
||||
'icon' => 'icon-elasticemail',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'ses' => [
|
||||
'name' => 'SES',
|
||||
'developers' => 'https://docs.aws.amazon.com/ses/latest/APIReference/',
|
||||
'icon' => 'icon-ses',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
],
|
||||
'sms' => [
|
||||
'africastalking' => [
|
||||
'name' => 'Africa\'s Talking',
|
||||
'developers' => 'https://developers.africastalking.com/',
|
||||
'icon' => 'icon-africastalking',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'clickatell' => [
|
||||
'name' => 'Clickatell',
|
||||
'developers' => 'https://www.clickatell.com/developers/api-docs/',
|
||||
'icon' => 'icon-clickatell',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'infobip' => [
|
||||
'name' => 'Infobip',
|
||||
'developers' => 'https://www.infobip.com/docs/',
|
||||
'icon' => 'icon-infobip',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'msg91' => [
|
||||
'name' => 'Msg91',
|
||||
'developers' => 'https://docs.msg91.com/reference/overview',
|
||||
'icon' => 'icon-msg91',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'plivo' => [
|
||||
'name' => 'Plivo',
|
||||
'developers' => 'https://developers.plivo.com/',
|
||||
'icon' => 'icon-plivo',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sinch' => [
|
||||
'name' => 'Sinch',
|
||||
'developers' => 'https://developers.sinch.com/',
|
||||
'icon' => 'icon-sinch',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'sms77' => [
|
||||
'name' => 'Sms77',
|
||||
'developers' => 'https://sms77.io/docs/gateway/',
|
||||
'icon' => 'icon-sms77',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'telesign' => [
|
||||
'name' => 'Telesign',
|
||||
'developers' => 'https://developer.telesign.com/enterprise/docs',
|
||||
'icon' => 'icon-telesign',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'textmagic' => [
|
||||
'name' => 'TextMagic',
|
||||
'developers' => 'https://www.textmagic.com/docs/api/',
|
||||
'icon' => 'icon-twilio',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'twilio' => [
|
||||
'name' => 'Twilio',
|
||||
'developers' => 'https://www.twilio.com/docs/sms',
|
||||
'icon' => 'icon-twilio',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'twilio-notify' => [
|
||||
'name' => 'Twilio Notify',
|
||||
'developers' => 'https://www.twilio.com/docs/notify',
|
||||
'icon' => 'icon-twilio',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'vonage' => [
|
||||
'name' => 'Vonage',
|
||||
'developers' => 'https://developer.nexmo.com/',
|
||||
'icon' => 'icon-vonage',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
],
|
||||
'push' => [
|
||||
'apns' => [
|
||||
'name' => 'APNS',
|
||||
'developers' => 'https://developer.apple.com/documentation/usernotifications',
|
||||
'icon' => 'icon-apns',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'fcm' => [
|
||||
'name' => 'FCM',
|
||||
'developers' => 'https://firebase.google.com/docs/cloud-messaging',
|
||||
'icon' => 'icon-fcm',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'one_signal' => [
|
||||
'name' => 'OneSignal',
|
||||
'developers' => 'https://documentation.onesignal.com/docs',
|
||||
'icon' => 'icon-onesignal',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'pushbullet' => [
|
||||
'name' => 'PushBullet',
|
||||
'developers' => 'https://docs.pushbullet.com/',
|
||||
'icon' => 'icon-pushbullet',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'pusher' => [
|
||||
'name' => 'Pusher',
|
||||
'developers' => 'https://pusher.com/docs',
|
||||
'icon' => 'icon-pusher',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'pushwoosh' => [
|
||||
'name' => 'Pushwoosh',
|
||||
'developers' => 'https://www.pushwoosh.com/docs/',
|
||||
'icon' => 'icon-pushwoosh',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'urban_airship' => [
|
||||
'name' => 'Urban Airship',
|
||||
'developers' => 'https://docs.airship.com/api/',
|
||||
'icon' => 'icon-urbanairship',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'web_push' => [
|
||||
'name' => 'WebPush',
|
||||
'developers' => 'https://developer.mozilla.org/en-US/docs/Web/API/Push_API',
|
||||
'icon' => 'icon-webpush',
|
||||
'enabled' => false,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
+22
-22
@@ -24,7 +24,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'javascript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-web'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-web'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-web.git',
|
||||
'gitRepoName' => 'sdk-for-web',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -58,7 +58,7 @@ return [
|
||||
'source' => 'https://github.com/appwrite/todo-with-svelte',
|
||||
'url' => 'https://appwrite-todo-with-svelte.vercel.app/',
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'flutter',
|
||||
@@ -72,7 +72,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'dart',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-flutter'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-flutter'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-flutter.git',
|
||||
'gitRepoName' => 'sdk-for-flutter',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -90,7 +90,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'swift',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-apple'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-apple'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-apple.git',
|
||||
'gitRepoName' => 'sdk-for-apple',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -125,7 +125,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'kotlin',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-android'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-android'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git',
|
||||
'gitRepoName' => 'sdk-for-android',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -147,7 +147,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'graphql',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-graphql'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-graphql'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
@@ -166,7 +166,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_CLIENT,
|
||||
'prism' => 'http',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/client-rest'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/client-rest'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
@@ -194,7 +194,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_CONSOLE,
|
||||
'prism' => 'javascript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/console-web'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/console-web'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-console.git',
|
||||
'gitBranch' => 'dev',
|
||||
'gitRepoName' => 'sdk-for-console',
|
||||
@@ -212,7 +212,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_CONSOLE,
|
||||
'prism' => 'bash',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/console-cli'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/console-cli'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-cli.git',
|
||||
'gitRepoName' => 'sdk-for-cli',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -240,7 +240,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'javascript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-nodejs'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-nodejs'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-node.git',
|
||||
'gitRepoName' => 'sdk-for-node',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -258,7 +258,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'typescript',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-deno'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-deno'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-deno.git',
|
||||
'gitRepoName' => 'sdk-for-deno',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -276,7 +276,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'php',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-php'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-php'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-php.git',
|
||||
'gitRepoName' => 'sdk-for-php',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -294,7 +294,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'python',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-python'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-python'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-python.git',
|
||||
'gitRepoName' => 'sdk-for-python',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -312,7 +312,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'ruby',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-ruby'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-ruby'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-ruby.git',
|
||||
'gitRepoName' => 'sdk-for-ruby',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -330,7 +330,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'go',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-go'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-go'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-go.git',
|
||||
'gitRepoName' => 'sdk-for-go',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -348,7 +348,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'java',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-java'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-java'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-java.git',
|
||||
'gitRepoName' => 'sdk-for-java',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -366,7 +366,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'csharp',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-dotnet'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-dotnet'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-dotnet.git',
|
||||
'gitRepoName' => 'sdk-for-dotnet',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -384,7 +384,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'dart',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-dart'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-dart'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-dart.git',
|
||||
'gitRepoName' => 'sdk-for-dart',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -402,7 +402,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'kotlin',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-kotlin'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-kotlin'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git',
|
||||
'gitRepoName' => 'sdk-for-kotlin',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -424,7 +424,7 @@ return [
|
||||
'hidden' => false,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'swift',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-swift'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-swift'),
|
||||
'gitUrl' => 'git@github.com:appwrite/sdk-for-swift.git',
|
||||
'gitRepoName' => 'sdk-for-swift',
|
||||
'gitUserName' => 'appwrite',
|
||||
@@ -442,7 +442,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'graphql',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-graphql'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-graphql'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
@@ -461,7 +461,7 @@ return [
|
||||
'hidden' => true,
|
||||
'family' => APP_PLATFORM_SERVER,
|
||||
'prism' => 'http',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/server-rest'),
|
||||
'source' => \realpath(__DIR__.'/../sdks/server-rest'),
|
||||
'gitUrl' => '',
|
||||
'gitRepoName' => '',
|
||||
'gitUserName' => '',
|
||||
|
||||
@@ -5,5 +5,5 @@ return [
|
||||
'name' => 'Default',
|
||||
'default' => true,
|
||||
'disabled' => false,
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
@@ -25,7 +25,7 @@ $member = [
|
||||
'providers.write',
|
||||
'providers.read',
|
||||
'messages.write',
|
||||
'messages.read'
|
||||
'messages.read',
|
||||
];
|
||||
|
||||
$admins = [
|
||||
@@ -64,7 +64,7 @@ $admins = [
|
||||
'providers.write',
|
||||
'providers.read',
|
||||
'messages.write',
|
||||
'messages.read'
|
||||
'messages.read',
|
||||
];
|
||||
|
||||
return [
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* List of Appwrite Cloud Functions supported runtimes
|
||||
*/
|
||||
|
||||
use Utopia\App;
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
use Utopia\App;
|
||||
|
||||
$runtimes = new Runtimes('v2');
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ return [ // List of publicly visible scopes
|
||||
'indexes.write' => [
|
||||
'description' => 'Access to create, update, and delete your project\'s database collection\'s indexes',
|
||||
],
|
||||
'documents.read' => [
|
||||
'documents.read' => [
|
||||
'description' => 'Access to read your project\'s database documents',
|
||||
],
|
||||
'documents.write' => [
|
||||
@@ -111,5 +111,5 @@ return [ // List of publicly visible scopes
|
||||
],
|
||||
'targets.write' => [
|
||||
'description' => 'Access to create, update, and delete your project\'s targets',
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
@@ -66,8 +66,8 @@ return [
|
||||
'optional' => true,
|
||||
'icon' => '/images/services/databases.png',
|
||||
'globalAttributes' => [
|
||||
'databaseId'
|
||||
]
|
||||
'databaseId',
|
||||
],
|
||||
],
|
||||
'locale' => [
|
||||
'key' => 'locale',
|
||||
@@ -237,5 +237,5 @@ return [
|
||||
'tests' => false,
|
||||
'optional' => true,
|
||||
'icon' => '/images/services/messaging.png',
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
+20
-20
@@ -1,24 +1,24 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'24h' => [
|
||||
'period' => '1h',
|
||||
'limit' => 24,
|
||||
'factor' => 3600,
|
||||
],
|
||||
'7d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 7,
|
||||
'factor' => 86400,
|
||||
],
|
||||
'30d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 30,
|
||||
'factor' => 86400,
|
||||
],
|
||||
'90d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 90,
|
||||
'factor' => 86400,
|
||||
],
|
||||
'24h' => [
|
||||
'period' => '1h',
|
||||
'limit' => 24,
|
||||
'factor' => 3600,
|
||||
],
|
||||
'7d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 7,
|
||||
'factor' => 86400,
|
||||
],
|
||||
'30d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 30,
|
||||
'factor' => 86400,
|
||||
],
|
||||
'90d' => [
|
||||
'period' => '1d',
|
||||
'limit' => 90,
|
||||
'factor' => 86400,
|
||||
],
|
||||
];
|
||||
|
||||
+98
-98
@@ -14,7 +14,7 @@ return [
|
||||
'default' => 'production',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_LOCALE',
|
||||
@@ -23,7 +23,7 @@ return [
|
||||
'default' => 'en',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_OPTIONS_ABUSE',
|
||||
@@ -32,7 +32,7 @@ return [
|
||||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_OPTIONS_FORCE_HTTPS',
|
||||
@@ -41,7 +41,7 @@ return [
|
||||
'default' => 'disabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_OPENSSL_KEY_V1',
|
||||
@@ -50,7 +50,7 @@ return [
|
||||
'default' => 'your-secret-key',
|
||||
'required' => true,
|
||||
'question' => 'Choose a secret API key, make sure to make a backup of your key in a secure location',
|
||||
'filter' => 'token'
|
||||
'filter' => 'token',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOMAIN',
|
||||
@@ -59,7 +59,7 @@ return [
|
||||
'default' => 'localhost',
|
||||
'required' => true,
|
||||
'question' => 'Enter your Appwrite hostname',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOMAIN_TARGET',
|
||||
@@ -67,8 +67,8 @@ return [
|
||||
'introduction' => '',
|
||||
'default' => 'localhost',
|
||||
'required' => true,
|
||||
'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.' . PHP_EOL . 'You can use the same value as used for the Appwrite hostname.',
|
||||
'filter' => 'domainTarget'
|
||||
'question' => 'Enter a DNS A record hostname to serve as a CNAME for your custom domains.'.PHP_EOL.'You can use the same value as used for the Appwrite hostname.',
|
||||
'filter' => 'domainTarget',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONSOLE_WHITELIST_ROOT',
|
||||
@@ -77,7 +77,7 @@ return [
|
||||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONSOLE_WHITELIST_EMAILS',
|
||||
@@ -86,7 +86,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
// [
|
||||
// 'name' => '_APP_CONSOLE_WHITELIST_DOMAINS',
|
||||
@@ -103,7 +103,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONSOLE_ROOT_SESSION',
|
||||
@@ -112,7 +112,7 @@ return [
|
||||
'default' => 'disabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_EMAIL_NAME',
|
||||
@@ -121,7 +121,7 @@ return [
|
||||
'default' => 'Appwrite',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_EMAIL_ADDRESS',
|
||||
@@ -130,7 +130,7 @@ return [
|
||||
'default' => 'team@appwrite.io',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_RESPONSE_FORMAT',
|
||||
@@ -139,7 +139,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SYSTEM_SECURITY_EMAIL_ADDRESS',
|
||||
@@ -148,7 +148,7 @@ return [
|
||||
'default' => 'certs@appwrite.io',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_STATS',
|
||||
@@ -157,7 +157,7 @@ return [
|
||||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_LOGGING_PROVIDER',
|
||||
@@ -166,7 +166,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_LOGGING_CONFIG',
|
||||
@@ -175,7 +175,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_AGGREGATION_INTERVAL',
|
||||
@@ -184,7 +184,7 @@ return [
|
||||
'default' => '30',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_TIMESERIES_INTERVAL',
|
||||
@@ -193,7 +193,7 @@ return [
|
||||
'default' => '30',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_USAGE_DATABASE_INTERVAL',
|
||||
@@ -202,7 +202,7 @@ return [
|
||||
'default' => '900',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_WORKER_PER_CORE',
|
||||
@@ -211,7 +211,7 @@ return [
|
||||
'default' => 6,
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONSOLE_INVITES',
|
||||
@@ -220,7 +220,7 @@ return [
|
||||
'default' => 'enabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -235,7 +235,7 @@ return [
|
||||
'default' => 'redis',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_REDIS_PORT',
|
||||
@@ -244,7 +244,7 @@ return [
|
||||
'default' => '6379',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_REDIS_USER',
|
||||
@@ -253,7 +253,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_REDIS_PASS',
|
||||
@@ -262,7 +262,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -277,7 +277,7 @@ return [
|
||||
'default' => 'mariadb',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_PORT',
|
||||
@@ -286,7 +286,7 @@ return [
|
||||
'default' => '3306',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_SCHEMA',
|
||||
@@ -295,7 +295,7 @@ return [
|
||||
'default' => 'appwrite',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_USER',
|
||||
@@ -304,7 +304,7 @@ return [
|
||||
'default' => 'user',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_PASS',
|
||||
@@ -313,7 +313,7 @@ return [
|
||||
'default' => 'password',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => 'password'
|
||||
'filter' => 'password',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_ROOT_PASS',
|
||||
@@ -322,7 +322,7 @@ return [
|
||||
'default' => 'rootsecretpassword',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => 'password'
|
||||
'filter' => 'password',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONNECTIONS_MAX',
|
||||
@@ -331,26 +331,26 @@ return [
|
||||
'default' => 251,
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
// [
|
||||
// 'name' => '_APP_CONNECTIONS_DB_PROJECT',
|
||||
// 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.',
|
||||
// 'introduction' => 'TBD',
|
||||
// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite',
|
||||
// 'required' => true,
|
||||
// 'question' => '',
|
||||
// 'filter' => ''
|
||||
// ],
|
||||
// [
|
||||
// 'name' => '_APP_CONNECTIONS_DB_CONSOLE',
|
||||
// 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.',
|
||||
// 'introduction' => 'TBD',
|
||||
// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite',
|
||||
// 'required' => true,
|
||||
// 'question' => '',
|
||||
// 'filter' => ''
|
||||
// ]
|
||||
// [
|
||||
// 'name' => '_APP_CONNECTIONS_DB_PROJECT',
|
||||
// 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.',
|
||||
// 'introduction' => 'TBD',
|
||||
// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite',
|
||||
// 'required' => true,
|
||||
// 'question' => '',
|
||||
// 'filter' => ''
|
||||
// ],
|
||||
// [
|
||||
// 'name' => '_APP_CONNECTIONS_DB_CONSOLE',
|
||||
// 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.',
|
||||
// 'introduction' => 'TBD',
|
||||
// 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite',
|
||||
// 'required' => true,
|
||||
// 'question' => '',
|
||||
// 'filter' => ''
|
||||
// ]
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -364,7 +364,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_PORT',
|
||||
@@ -373,7 +373,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_SECURE',
|
||||
@@ -382,7 +382,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_USERNAME',
|
||||
@@ -391,7 +391,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMTP_PASSWORD',
|
||||
@@ -400,7 +400,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -415,7 +415,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_SMS_FROM',
|
||||
@@ -424,7 +424,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -439,7 +439,7 @@ return [
|
||||
'default' => '30000000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_PREVIEW_LIMIT',
|
||||
@@ -448,7 +448,7 @@ return [
|
||||
'default' => '20000000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_ANTIVIRUS',
|
||||
@@ -457,7 +457,7 @@ return [
|
||||
'default' => 'disabled',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_ANTIVIRUS_HOST',
|
||||
@@ -466,7 +466,7 @@ return [
|
||||
'default' => 'clamav',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_STORAGE_ANTIVIRUS_PORT',
|
||||
@@ -475,7 +475,7 @@ return [
|
||||
'default' => '3310',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_CONNECTIONS_STORAGE',
|
||||
@@ -666,7 +666,7 @@ return [
|
||||
'default' => '30000000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_TIMEOUT',
|
||||
@@ -675,7 +675,7 @@ return [
|
||||
'default' => '900',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_BUILD_TIMEOUT',
|
||||
@@ -684,7 +684,7 @@ return [
|
||||
'default' => '900',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_CONTAINERS',
|
||||
@@ -693,7 +693,7 @@ return [
|
||||
'default' => '10',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_CPUS',
|
||||
@@ -702,7 +702,7 @@ return [
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY',
|
||||
@@ -711,7 +711,7 @@ return [
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MEMORY_SWAP',
|
||||
@@ -720,16 +720,16 @@ return [
|
||||
'default' => '0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_RUNTIMES',
|
||||
'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: " . \implode(', ', \array_keys(Config::getParam('runtimes'))),
|
||||
'description' => "This option allows you to enable or disable runtime environments for cloud functions. Disable unused runtimes to save disk space.\n\nTo enable cloud function runtimes, pass a list of enabled environments separated by a comma.\n\nCurrently, supported environments are: ".\implode(', ', \array_keys(Config::getParam('runtimes'))),
|
||||
'introduction' => '0.8.0',
|
||||
'default' => 'node-16.0,php-8.0,python-3.9,ruby-3.0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_SECRET',
|
||||
@@ -738,7 +738,7 @@ return [
|
||||
'default' => 'your-secret-key',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_HOST',
|
||||
@@ -747,7 +747,7 @@ return [
|
||||
'default' => 'http://appwrite-executor/v1',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_EXECUTOR_RUNTIME_NETWORK',
|
||||
@@ -756,7 +756,7 @@ return [
|
||||
'default' => 'appwrite_runtimes',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_ENVS',
|
||||
@@ -765,7 +765,7 @@ return [
|
||||
'default' => 'node-16.0,php-7.4,python-3.9,ruby-3.0',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD',
|
||||
@@ -774,7 +774,7 @@ return [
|
||||
'default' => '60',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'DOCKERHUB_PULL_USERNAME',
|
||||
@@ -783,7 +783,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'DOCKERHUB_PULL_PASSWORD',
|
||||
@@ -792,7 +792,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'DOCKERHUB_PULL_EMAIL',
|
||||
@@ -801,7 +801,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'OPEN_RUNTIMES_NETWORK',
|
||||
@@ -810,7 +810,7 @@ return [
|
||||
'default' => 'appwrite_runtimes',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_RUNTIMES_NETWORK',
|
||||
@@ -819,7 +819,7 @@ return [
|
||||
'default' => 'runtimes',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOCKER_HUB_USERNAME',
|
||||
@@ -828,7 +828,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOCKER_HUB_PASSWORD',
|
||||
@@ -837,7 +837,7 @@ return [
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_FUNCTIONS_MAINTENANCE_INTERVAL',
|
||||
@@ -846,7 +846,7 @@ return [
|
||||
'default' => '60',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
@@ -861,7 +861,7 @@ return [
|
||||
'default' => '86400',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_CACHE',
|
||||
@@ -870,7 +870,7 @@ return [
|
||||
'default' => '2592000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_EXECUTION',
|
||||
@@ -879,7 +879,7 @@ return [
|
||||
'default' => '1209600',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_AUDIT',
|
||||
@@ -888,7 +888,7 @@ return [
|
||||
'default' => '1209600',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_ABUSE',
|
||||
@@ -897,7 +897,7 @@ return [
|
||||
'default' => '86400',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_USAGE_HOURLY',
|
||||
@@ -906,7 +906,7 @@ return [
|
||||
'default' => '8640000',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_MAINTENANCE_RETENTION_SCHEDULES',
|
||||
@@ -915,8 +915,8 @@ return [
|
||||
'default' => '86400',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
]
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -930,7 +930,7 @@ return [
|
||||
'default' => '10',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_GRAPHQL_MAX_COMPLEXITY',
|
||||
@@ -939,7 +939,7 @@ return [
|
||||
'default' => '250',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
[
|
||||
'name' => '_APP_GRAPHQL_MAX_DEPTH',
|
||||
@@ -948,7 +948,7 @@ return [
|
||||
'default' => '3',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
'filter' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
+227
-300
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Validator\URL;
|
||||
use Appwrite\URL\URL as URLParse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
@@ -21,23 +20,23 @@ use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\HexColor;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
$avatarCallback = function (string $type, string $code, int $width, int $height, int $quality, Response $response) {
|
||||
|
||||
$code = \strtolower($code);
|
||||
$type = \strtolower($type);
|
||||
$set = Config::getParam('avatar-' . $type, []);
|
||||
$set = Config::getParam('avatar-'.$type, []);
|
||||
|
||||
if (empty($set)) {
|
||||
throw new Exception(Exception::AVATAR_SET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\array_key_exists($code, $set)) {
|
||||
if (! \array_key_exists($code, $set)) {
|
||||
throw new Exception(Exception::AVATAR_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
@@ -45,8 +44,8 @@ $avatarCallback = function (string $type, string $code, int $width, int $height,
|
||||
$path = $set[$code]['path'];
|
||||
$type = 'png';
|
||||
|
||||
if (!\is_readable($path)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'File not readable in ' . $path);
|
||||
if (! \is_readable($path)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'File not readable in '.$path);
|
||||
}
|
||||
|
||||
$image = new Image(\file_get_contents($path));
|
||||
@@ -54,7 +53,7 @@ $avatarCallback = function (string $type, string $code, int $width, int $height,
|
||||
$output = (empty($output)) ? $type : $output;
|
||||
$data = $image->output($output, $quality);
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/png')
|
||||
->file($data);
|
||||
unset($image);
|
||||
@@ -83,12 +82,12 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
||||
$accessTokenExpiry = $gitHubSession->getAttribute('providerAccessTokenExpiry');
|
||||
$refreshToken = $gitHubSession->getAttribute('providerRefreshToken');
|
||||
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider . 'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}';
|
||||
$appId = $project->getAttribute('authProviders', [])[$provider.'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('authProviders', [])[$provider.'Secret'] ?? '{}';
|
||||
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\'.\ucfirst($provider);
|
||||
|
||||
if (!\class_exists($className)) {
|
||||
if (! \class_exists($className)) {
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
||||
@@ -105,13 +104,13 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
||||
$verificationId = $oauth2->getUserID($accessToken);
|
||||
|
||||
if (empty($verificationId)) {
|
||||
throw new \Exception("Locked tokens."); // Race codition, handeled in catch
|
||||
throw new \Exception('Locked tokens.'); // Race codition, handeled in catch
|
||||
}
|
||||
|
||||
$gitHubSession
|
||||
->setAttribute('providerAccessToken', $accessToken)
|
||||
->setAttribute('providerRefreshToken', $refreshToken)
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$oauth2->getAccessTokenExpiry('')));
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $oauth2->getAccessTokenExpiry('')));
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('sessions', $gitHubSession->getId(), $gitHubSession));
|
||||
|
||||
@@ -150,7 +149,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
||||
|
||||
return [
|
||||
'name' => $githubUser,
|
||||
'id' => $githubId
|
||||
'id' => $githubId,
|
||||
];
|
||||
} catch (Exception $error) {
|
||||
if ($logger) {
|
||||
@@ -177,7 +176,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('GitHub error log pushed with status code: ' . $responseCode);
|
||||
Console::info('GitHub error log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::warning("Failed: {$error->getMessage()}");
|
||||
@@ -202,12 +201,12 @@ App::get('/v1/avatars/credit-cards/:code')
|
||||
->label('sdk.description', '/docs/references/avatars/get-credit-card.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
|
||||
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.')
|
||||
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.')
|
||||
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
|
||||
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
|
||||
->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
|
||||
->inject('response')
|
||||
->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response));
|
||||
->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response));
|
||||
|
||||
App::get('/v1/avatars/browsers/:code')
|
||||
->desc('Get Browser Icon')
|
||||
@@ -267,18 +266,17 @@ App::get('/v1/avatars/image')
|
||||
->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.', true)
|
||||
->inject('response')
|
||||
->action(function (string $url, int $width, int $height, Response $response) {
|
||||
|
||||
$quality = 80;
|
||||
$output = 'png';
|
||||
$type = 'png';
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
$fetch = @\file_get_contents($url, false);
|
||||
|
||||
if (!$fetch) {
|
||||
if (! $fetch) {
|
||||
throw new Exception(Exception::AVATAR_IMAGE_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -293,7 +291,7 @@ App::get('/v1/avatars/image')
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/png')
|
||||
->file($data);
|
||||
unset($image);
|
||||
@@ -315,14 +313,13 @@ App::get('/v1/avatars/favicon')
|
||||
->param('url', '', new URL(['http', 'https']), 'Website URL which you want to fetch the favicon from.')
|
||||
->inject('response')
|
||||
->action(function (string $url, Response $response) {
|
||||
|
||||
$width = 56;
|
||||
$height = 56;
|
||||
$quality = 80;
|
||||
$output = 'png';
|
||||
$type = 'png';
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
@@ -344,7 +341,7 @@ App::get('/v1/avatars/favicon')
|
||||
|
||||
\curl_close($curl);
|
||||
|
||||
if (!$html) {
|
||||
if (! $html) {
|
||||
throw new Exception(Exception::AVATAR_REMOTE_URL_FAILED);
|
||||
}
|
||||
|
||||
@@ -395,7 +392,7 @@ App::get('/v1/avatars/favicon')
|
||||
if (empty($outputHref) || empty($outputExt)) {
|
||||
$default = \parse_url($url);
|
||||
|
||||
$outputHref = $default['scheme'] . '://' . $default['host'] . '/favicon.ico';
|
||||
$outputHref = $default['scheme'].'://'.$default['host'].'/favicon.ico';
|
||||
$outputExt = 'ico';
|
||||
}
|
||||
|
||||
@@ -406,14 +403,14 @@ App::get('/v1/avatars/favicon')
|
||||
throw new Exception(Exception::AVATAR_ICON_NOT_FOUND, 'Favicon not found');
|
||||
}
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/x-icon')
|
||||
->file($data);
|
||||
}
|
||||
|
||||
$fetch = @\file_get_contents($outputHref, false);
|
||||
|
||||
if (!$fetch) {
|
||||
if (! $fetch) {
|
||||
throw new Exception(Exception::AVATAR_ICON_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -423,7 +420,7 @@ App::get('/v1/avatars/favicon')
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType('image/png')
|
||||
->file($data);
|
||||
unset($image);
|
||||
@@ -446,7 +443,6 @@ App::get('/v1/avatars/qr')
|
||||
->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true)
|
||||
->inject('response')
|
||||
->action(function (string $text, int $size, int $margin, bool $download, Response $response) {
|
||||
|
||||
$download = ($download === '1' || $download === 'true' || $download === 1 || $download === true);
|
||||
$options = new QROptions([
|
||||
'addQuietzone' => true,
|
||||
@@ -464,7 +460,7 @@ App::get('/v1/avatars/qr')
|
||||
$image->crop((int) $size, (int) $size);
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->setContentType('image/png')
|
||||
->send($image->output('png', 9));
|
||||
});
|
||||
@@ -488,17 +484,16 @@ App::get('/v1/avatars/initials')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->action(function (string $name, int $width, int $height, string $background, Response $response, Document $user) {
|
||||
|
||||
$themes = [
|
||||
['background' => '#FFA1CE'], // Default (Pink)
|
||||
['background' => '#FDC584'], // Orange
|
||||
['background' => '#94DBD1'], // Green
|
||||
['background' => '#A1C4FF'], // Blue
|
||||
['background' => '#FFA1CE'], // Pink
|
||||
['background' => '#CBB1FC'] // Purple
|
||||
['background' => '#CBB1FC'], // Purple
|
||||
];
|
||||
|
||||
$name = (!empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', ''));
|
||||
$name = (! empty($name)) ? $name : $user->getAttribute('name', $user->getAttribute('email', ''));
|
||||
$words = \explode(' ', \strtoupper($name));
|
||||
// if there is no space, try to split by `_` underscore
|
||||
$words = (count($words) == 1) ? \explode('_', \strtoupper($name)) : $words;
|
||||
@@ -520,7 +515,7 @@ App::get('/v1/avatars/initials')
|
||||
// Wrap rand value to avoid out of range
|
||||
$rand = ($rand > \count($themes) - 1) ? $rand % \count($themes) : $rand;
|
||||
|
||||
$background = (!empty($background)) ? '#' . $background : $themes[$rand]['background'];
|
||||
$background = (! empty($background)) ? '#'.$background : $themes[$rand]['background'];
|
||||
|
||||
$image = new \Imagick();
|
||||
$punch = new \Imagick();
|
||||
@@ -529,8 +524,8 @@ App::get('/v1/avatars/initials')
|
||||
|
||||
$punch->newImage($width, $height, 'transparent');
|
||||
|
||||
$draw->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf");
|
||||
$image->setFont(__DIR__ . "/../../assets/fonts/poppins-v9-latin-500.ttf");
|
||||
$draw->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf');
|
||||
$image->setFont(__DIR__.'/../../assets/fonts/poppins-v9-latin-500.ttf');
|
||||
|
||||
$draw->setFillColor(new ImagickPixel('black'));
|
||||
$draw->setFontSize($fontSize);
|
||||
@@ -542,13 +537,13 @@ App::get('/v1/avatars/initials')
|
||||
$punch->negateImage(true, Imagick::CHANNEL_ALPHA);
|
||||
|
||||
$image->newImage($width, $height, $background);
|
||||
$image->setImageFormat("png");
|
||||
$image->setImageFormat('png');
|
||||
$image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
|
||||
|
||||
//$image->setImageCompressionQuality(9 - round(($quality / 100) * 9));
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->setContentType('image/png')
|
||||
->file($image->getImageBlob());
|
||||
});
|
||||
@@ -582,7 +577,7 @@ App::get('/v1/cards/cloud')
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$mock) {
|
||||
if (! $mock) {
|
||||
$name = $user->getAttribute('name', 'Anonymous');
|
||||
$email = $user->getAttribute('email', '');
|
||||
$createdAt = new \DateTime($user->getCreatedAt());
|
||||
@@ -602,9 +597,9 @@ App::get('/v1/cards/cloud')
|
||||
$createdAt = new \DateTime($employees[$email]['memberSince'] ?? '');
|
||||
}
|
||||
|
||||
if (!$isEmployee && !empty($githubName)) {
|
||||
if (! $isEmployee && ! empty($githubName)) {
|
||||
$employeeGitHub = \array_search(\strtolower($githubName), \array_map(fn ($employee) => \strtolower($employee['gitHub']) ?? '', $employees));
|
||||
if (!empty($employeeGitHub)) {
|
||||
if (! empty($employeeGitHub)) {
|
||||
$isEmployee = true;
|
||||
$employeeNumber = $isEmployee ? $employees[$employeeGitHub]['spot'] : '';
|
||||
$createdAt = new \DateTime($employees[$employeeGitHub]['memberSince'] ?? '');
|
||||
@@ -645,20 +640,20 @@ App::get('/v1/cards/cloud')
|
||||
|
||||
$isGolden = $isEmployee || $isHero || $isContributor;
|
||||
$isPlatinum = $isGolden ? false : $isPlatinum;
|
||||
$memberSince = \strtoupper('Member since ' . $createdAt->format('M') . ' ' . $createdAt->format('d') . ', ' . $createdAt->format('o'));
|
||||
$memberSince = \strtoupper('Member since '.$createdAt->format('M').' '.$createdAt->format('d').', '.$createdAt->format('o'));
|
||||
|
||||
$imagePath = $isGolden ? 'front-golden.png' : ($isPlatinum ? 'front-platinum.png' : 'front.png');
|
||||
|
||||
$baseImage = new \Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $imagePath);
|
||||
$baseImage = new \Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$imagePath);
|
||||
|
||||
if ($isEmployee) {
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/employee.png');
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/employee.png');
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
$baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 35);
|
||||
|
||||
$text = new \ImagickDraw();
|
||||
$text->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$text->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf');
|
||||
$text->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf');
|
||||
$text->setFillColor(new \ImagickPixel('#FFFADF'));
|
||||
$text->setFontSize(\strlen($employeeNumber) <= 2 ? 54 : 48);
|
||||
$text->setFontWeight(700);
|
||||
@@ -666,7 +661,7 @@ App::get('/v1/cards/cloud')
|
||||
|
||||
$hashtag = new \ImagickDraw();
|
||||
$hashtag->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$hashtag->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf');
|
||||
$hashtag->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf');
|
||||
$hashtag->setFillColor(new \ImagickPixel('#FFFADF'));
|
||||
$hashtag->setFontSize(28);
|
||||
$hashtag->setFontWeight(700);
|
||||
@@ -689,25 +684,25 @@ App::get('/v1/cards/cloud')
|
||||
}
|
||||
|
||||
if ($isContributor) {
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/contributor.png');
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/contributor.png');
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
$baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 34);
|
||||
}
|
||||
|
||||
if ($isHero) {
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/hero.png');
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/hero.png');
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
$baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 793, 34);
|
||||
}
|
||||
|
||||
setlocale(LC_ALL, "en_US.utf8");
|
||||
setlocale(LC_ALL, 'en_US.utf8');
|
||||
// $name = \iconv("utf-8", "ascii//TRANSLIT", $name);
|
||||
// $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince);
|
||||
// $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName);
|
||||
|
||||
$text = new \ImagickDraw();
|
||||
$text->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$text->setFont(__DIR__ . '/../../../public/fonts/Poppins-Bold.ttf');
|
||||
$text->setFont(__DIR__.'/../../../public/fonts/Poppins-Bold.ttf');
|
||||
$text->setFillColor(new \ImagickPixel('#FFFFFF'));
|
||||
|
||||
if (\strlen($name) > 32) {
|
||||
@@ -726,17 +721,17 @@ App::get('/v1/cards/cloud')
|
||||
|
||||
$text = new \ImagickDraw();
|
||||
$text->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$text->setFont(__DIR__ . '/../../../public/fonts/Inter-SemiBold.ttf');
|
||||
$text->setFont(__DIR__.'/../../../public/fonts/Inter-SemiBold.ttf');
|
||||
$text->setFillColor(new \ImagickPixel($isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC'));
|
||||
$text->setFontSize(27);
|
||||
$text->setFontWeight(600);
|
||||
$text->setTextKerning(1.08);
|
||||
$baseImage->annotateImage($text, 512, 541, 0, \strtoupper($memberSince));
|
||||
|
||||
if (!empty($githubName)) {
|
||||
if (! empty($githubName)) {
|
||||
$text = new \ImagickDraw();
|
||||
$text->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$text->setFont(__DIR__ . '/../../../public/fonts/Inter-Regular.ttf');
|
||||
$text->setFont(__DIR__.'/../../../public/fonts/Inter-Regular.ttf');
|
||||
$text->setFillColor(new \ImagickPixel('#FFFFFF'));
|
||||
$text->setFontSize($scalingDown ? 28 : 32);
|
||||
$text->setFontWeight(400);
|
||||
@@ -744,18 +739,18 @@ App::get('/v1/cards/cloud')
|
||||
|
||||
$baseImage->annotateImage($text, 512 + 20 + 4, 373 + ($scalingDown ? 2 : 0), 0, $githubName);
|
||||
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png');
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png');
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
$precisionFix = 5;
|
||||
$baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 512 - ($metrics['textWidth'] / 2) - 20 - 4, 373 - ($metrics['textHeight'] - $precisionFix));
|
||||
}
|
||||
|
||||
if (!empty($width) || !empty($height)) {
|
||||
if (! empty($width) || ! empty($height)) {
|
||||
$baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->setContentType('image/png')
|
||||
->file($baseImage->getImageBlob());
|
||||
});
|
||||
@@ -789,7 +784,7 @@ App::get('/v1/cards/cloud-back')
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$mock) {
|
||||
if (! $mock) {
|
||||
$userId = $user->getId();
|
||||
$email = $user->getAttribute('email', '');
|
||||
|
||||
@@ -809,31 +804,31 @@ App::get('/v1/cards/cloud-back')
|
||||
$isPlatinum = $mock === 'platinum';
|
||||
}
|
||||
|
||||
$userId = 'UID ' . $userId;
|
||||
$userId = 'UID '.$userId;
|
||||
|
||||
$isPlatinum = $isGolden ? false : $isPlatinum;
|
||||
|
||||
$imagePath = $isGolden ? 'back-golden.png' : ($isPlatinum ? 'back-platinum.png' : 'back.png');
|
||||
|
||||
$baseImage = new \Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $imagePath);
|
||||
$baseImage = new \Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$imagePath);
|
||||
|
||||
setlocale(LC_ALL, "en_US.utf8");
|
||||
setlocale(LC_ALL, 'en_US.utf8');
|
||||
// $userId = \iconv("utf-8", "ascii//TRANSLIT", $userId);
|
||||
|
||||
$text = new \ImagickDraw();
|
||||
$text->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$text->setFont(__DIR__ . '/../../../public/fonts/SourceCodePro-Regular.ttf');
|
||||
$text->setFont(__DIR__.'/../../../public/fonts/SourceCodePro-Regular.ttf');
|
||||
$text->setFillColor(new \ImagickPixel($isGolden ? '#664A1E' : ($isPlatinum ? '#555555' : '#E8E9F0')));
|
||||
$text->setFontSize(28);
|
||||
$text->setFontWeight(400);
|
||||
$baseImage->annotateImage($text, 512, 596, 0, $userId);
|
||||
|
||||
if (!empty($width) || !empty($height)) {
|
||||
if (! empty($width) || ! empty($height)) {
|
||||
$baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->setContentType('image/png')
|
||||
->file($baseImage->getImageBlob());
|
||||
});
|
||||
@@ -867,7 +862,7 @@ App::get('/v1/cards/cloud-og')
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$mock) {
|
||||
if (! $mock) {
|
||||
$internalId = $user->getInternalId();
|
||||
$bgVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3');
|
||||
$cardVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3');
|
||||
@@ -891,9 +886,9 @@ App::get('/v1/cards/cloud-og')
|
||||
$createdAt = new \DateTime($employees[$email]['memberSince'] ?? '');
|
||||
}
|
||||
|
||||
if (!$isEmployee && !empty($githubName)) {
|
||||
if (! $isEmployee && ! empty($githubName)) {
|
||||
$employeeGitHub = \array_search(\strtolower($githubName), \array_map(fn ($employee) => \strtolower($employee['gitHub']) ?? '', $employees));
|
||||
if (!empty($employeeGitHub)) {
|
||||
if (! empty($employeeGitHub)) {
|
||||
$isEmployee = true;
|
||||
$employeeNumber = $isEmployee ? $employees[$employeeGitHub]['spot'] : '';
|
||||
$createdAt = new \DateTime($employees[$employeeGitHub]['memberSince'] ?? '');
|
||||
@@ -940,17 +935,17 @@ App::get('/v1/cards/cloud-og')
|
||||
|
||||
$isGolden = $isEmployee || $isHero || $isContributor;
|
||||
$isPlatinum = $isGolden ? false : $isPlatinum;
|
||||
$memberSince = \strtoupper('Member since ' . $createdAt->format('M') . ' ' . $createdAt->format('d') . ', ' . $createdAt->format('o'));
|
||||
$memberSince = \strtoupper('Member since '.$createdAt->format('M').' '.$createdAt->format('d').', '.$createdAt->format('o'));
|
||||
|
||||
$baseImage = new \Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-background{$bgVariation}.png");
|
||||
$baseImage = new \Imagick(__DIR__."/../../../public/images/cards/cloud/og-background{$bgVariation}.png");
|
||||
|
||||
$cardType = $isGolden ? '-golden' : ($isPlatinum ? '-platinum' : '');
|
||||
|
||||
$image = new Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-card{$cardType}{$cardVariation}.png");
|
||||
$image = new Imagick(__DIR__."/../../../public/images/cards/cloud/og-card{$cardType}{$cardVariation}.png");
|
||||
$baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 1008 / 2 - $image->getImageWidth() / 2, 1008 / 2 - $image->getImageHeight() / 2);
|
||||
|
||||
$imageLogo = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/og-background-logo.png');
|
||||
$imageShadow = new Imagick(__DIR__ . "/../../../public/images/cards/cloud/og-shadow{$cardType}.png");
|
||||
$imageLogo = new Imagick(__DIR__.'/../../../public/images/cards/cloud/og-background-logo.png');
|
||||
$imageShadow = new Imagick(__DIR__."/../../../public/images/cards/cloud/og-shadow{$cardType}.png");
|
||||
if ($cardVariation === '1') {
|
||||
$baseImage->compositeImage($imageLogo, Imagick::COMPOSITE_OVER, 32, 1008 - $imageLogo->getImageHeight() - 32);
|
||||
$baseImage->compositeImage($imageShadow, Imagick::COMPOSITE_OVER, -450, 700);
|
||||
@@ -964,19 +959,19 @@ App::get('/v1/cards/cloud-og')
|
||||
|
||||
if ($isEmployee) {
|
||||
$file = $cardVariation === '3' ? 'employee-skew.png' : 'employee.png';
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file);
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file);
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
|
||||
$hashtag = new \ImagickDraw();
|
||||
$hashtag->setTextAlignment(Imagick::ALIGN_LEFT);
|
||||
$hashtag->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf');
|
||||
$hashtag->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf');
|
||||
$hashtag->setFillColor(new \ImagickPixel('#FFFADF'));
|
||||
$hashtag->setFontSize(20);
|
||||
$hashtag->setFontWeight(700);
|
||||
|
||||
$text = new \ImagickDraw();
|
||||
$text->setTextAlignment(Imagick::ALIGN_LEFT);
|
||||
$text->setFont(__DIR__ . '/../../../public/fonts/Inter-Bold.ttf');
|
||||
$text->setFont(__DIR__.'/../../../public/fonts/Inter-Bold.ttf');
|
||||
$text->setFillColor(new \ImagickPixel('#FFFADF'));
|
||||
$text->setFontSize(\strlen($employeeNumber) <= 1 ? 36 : 28);
|
||||
$text->setFontWeight(700);
|
||||
@@ -1050,7 +1045,7 @@ App::get('/v1/cards/cloud-og')
|
||||
|
||||
if ($isContributor) {
|
||||
$file = $cardVariation === '3' ? 'contributor-skew.png' : 'contributor.png';
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file);
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file);
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
|
||||
if ($cardVariation === '1') {
|
||||
@@ -1068,7 +1063,7 @@ App::get('/v1/cards/cloud-og')
|
||||
|
||||
if ($isHero) {
|
||||
$file = $cardVariation === '3' ? 'hero-skew.png' : 'hero.png';
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/' . $file);
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/'.$file);
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
|
||||
if ($cardVariation === '1') {
|
||||
@@ -1084,14 +1079,14 @@ App::get('/v1/cards/cloud-og')
|
||||
}
|
||||
}
|
||||
|
||||
setlocale(LC_ALL, "en_US.utf8");
|
||||
setlocale(LC_ALL, 'en_US.utf8');
|
||||
// $name = \iconv("utf-8", "ascii//TRANSLIT", $name);
|
||||
// $memberSince = \iconv("utf-8", "ascii//TRANSLIT", $memberSince);
|
||||
// $githubName = \iconv("utf-8", "ascii//TRANSLIT", $githubName);
|
||||
|
||||
$textName = new \ImagickDraw();
|
||||
$textName->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$textName->setFont(__DIR__ . '/../../../public/fonts/Poppins-Bold.ttf');
|
||||
$textName->setFont(__DIR__.'/../../../public/fonts/Poppins-Bold.ttf');
|
||||
$textName->setFillColor(new \ImagickPixel('#FFFFFF'));
|
||||
|
||||
if (\strlen($name) > 32) {
|
||||
@@ -1128,7 +1123,7 @@ App::get('/v1/cards/cloud-og')
|
||||
|
||||
$textMember = new \ImagickDraw();
|
||||
$textMember->setTextAlignment(Imagick::ALIGN_CENTER);
|
||||
$textMember->setFont(__DIR__ . '/../../../public/fonts/Inter-Medium.ttf');
|
||||
$textMember->setFont(__DIR__.'/../../../public/fonts/Inter-Medium.ttf');
|
||||
$textMember->setFillColor(new \ImagickPixel($isGolden || $isPlatinum ? '#FFFFFF' : '#FFB9CC'));
|
||||
$textMember->setFontWeight(500);
|
||||
$textMember->setTextKerning(1.12);
|
||||
@@ -1158,10 +1153,10 @@ App::get('/v1/cards/cloud-og')
|
||||
$baseImage->drawImage($textMember);
|
||||
}
|
||||
|
||||
if (!empty($githubName)) {
|
||||
if (! empty($githubName)) {
|
||||
$text = new \ImagickDraw();
|
||||
$text->setTextAlignment(Imagick::ALIGN_LEFT);
|
||||
$text->setFont(__DIR__ . '/../../../public/fonts/Inter-Regular.ttf');
|
||||
$text->setFont(__DIR__.'/../../../public/fonts/Inter-Regular.ttf');
|
||||
$text->setFillColor(new \ImagickPixel('#FFFFFF'));
|
||||
$text->setFontSize($scalingDown ? 16 : 20);
|
||||
$text->setFontWeight(400);
|
||||
@@ -1172,7 +1167,7 @@ App::get('/v1/cards/cloud-og')
|
||||
$group = new Imagick();
|
||||
$groupWidth = $metrics['textWidth'] + 32 + 4;
|
||||
$group->newImage($groupWidth, $metrics['textHeight'] + 10, '#00000000');
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png');
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png');
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
$image->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1);
|
||||
$precisionFix = -1;
|
||||
@@ -1190,7 +1185,7 @@ App::get('/v1/cards/cloud-og')
|
||||
$group = new Imagick();
|
||||
$groupWidth = $metrics['textWidth'] + 32 + 4;
|
||||
$group->newImage($groupWidth, $metrics['textHeight'] + 10, '#00000000');
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github.png');
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github.png');
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
$image->resizeImage(32, 32, Imagick::FILTER_LANCZOS, 1);
|
||||
$precisionFix = -1;
|
||||
@@ -1210,7 +1205,7 @@ App::get('/v1/cards/cloud-og')
|
||||
$text->annotation(320 + 15 + 2, 640, $githubName);
|
||||
$metrics = $baseImage->queryFontMetrics($text, $githubName);
|
||||
|
||||
$image = new Imagick(__DIR__ . '/../../../public/images/cards/cloud/github-skew.png');
|
||||
$image = new Imagick(__DIR__.'/../../../public/images/cards/cloud/github-skew.png');
|
||||
$image->setGravity(Imagick::GRAVITY_CENTER);
|
||||
$baseImage->compositeImage($image, Imagick::COMPOSITE_OVER, 512 - ($metrics['textWidth'] / 2), 518 + \strlen($githubName) * 1.3);
|
||||
|
||||
@@ -1218,12 +1213,12 @@ App::get('/v1/cards/cloud-og')
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($width) || !empty($height)) {
|
||||
if (! empty($width) || ! empty($height)) {
|
||||
$baseImage->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->setContentType('image/png')
|
||||
->file($baseImage->getImageBlob());
|
||||
});
|
||||
|
||||
@@ -15,7 +15,6 @@ App::init()
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
App::get('/v1/console/variables')
|
||||
->desc('Get Variables')
|
||||
->groups(['api', 'projects'])
|
||||
@@ -29,7 +28,6 @@ App::get('/v1/console/variables')
|
||||
->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$variables = new Document([
|
||||
'_APP_DOMAIN_TARGET' => App::getEnv('_APP_DOMAIN_TARGET'),
|
||||
'_APP_STORAGE_LIMIT' => +App::getEnv('_APP_STORAGE_LIMIT'),
|
||||
@@ -40,7 +38,6 @@ App::get('/v1/console/variables')
|
||||
$response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES);
|
||||
});
|
||||
|
||||
|
||||
App::post('/v1/console/assistant')
|
||||
->desc('Ask Query')
|
||||
->groups(['api', 'assistant'])
|
||||
|
||||
+300
-342
File diff suppressed because it is too large
Load Diff
@@ -9,40 +9,40 @@ use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Event\Validator\Event as ValidatorEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Task\Validator\Cron;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Executions;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Functions;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Executor\Executor;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Validator\File;
|
||||
use Utopia\Storage\Validator\FileExt;
|
||||
use Utopia\Storage\Validator\FileSize;
|
||||
use Utopia\Storage\Validator\Upload;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Swoole\Request;
|
||||
use Appwrite\Task\Validator\Cron;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Executions;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Functions;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Config\Config;
|
||||
use Executor\Executor;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
include_once __DIR__ . '/../shared/api.php';
|
||||
include_once __DIR__.'/../shared/api.php';
|
||||
|
||||
App::post('/v1/functions')
|
||||
->groups(['api', 'functions'])
|
||||
@@ -60,9 +60,9 @@ App::post('/v1/functions')
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION)
|
||||
->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.', true)
|
||||
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true)
|
||||
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
|
||||
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.', true)
|
||||
->param('enabled', true, new Boolean(), 'Is function enabled?', true)
|
||||
@@ -73,7 +73,6 @@ App::post('/v1/functions')
|
||||
->inject('events')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $functionId, string $name, array $execute, string $runtime, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) {
|
||||
|
||||
$functionId = ($functionId == 'unique()') ? ID::unique() : $functionId;
|
||||
$function = $dbForProject->createDocument('functions', new Document([
|
||||
'$id' => $functionId,
|
||||
@@ -87,18 +86,18 @@ App::post('/v1/functions')
|
||||
'schedule' => $schedule,
|
||||
'scheduleInternalId' => '',
|
||||
'timeout' => $timeout,
|
||||
'search' => implode(' ', [$functionId, $name, $runtime])
|
||||
'search' => implode(' ', [$functionId, $name, $runtime]),
|
||||
]));
|
||||
|
||||
$schedule = Authorization::skip(
|
||||
fn() => $dbForConsole->createDocument('schedules', new Document([
|
||||
fn () => $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'), // Todo replace with projects region
|
||||
'resourceType' => 'function',
|
||||
'resourceId' => $function->getId(),
|
||||
'resourceInternalId' => $function->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
'projectId' => $project->getId(),
|
||||
'schedule' => $function->getAttribute('schedule'),
|
||||
'schedule' => $function->getAttribute('schedule'),
|
||||
'active' => false,
|
||||
]))
|
||||
);
|
||||
@@ -125,15 +124,14 @@ App::get('/v1/functions')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION_LIST)
|
||||
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -173,17 +171,17 @@ App::get('/v1/functions/runtimes')
|
||||
->label('sdk.response.model', Response::MODEL_RUNTIME_LIST)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$runtimes = Config::getParam('runtimes');
|
||||
|
||||
$runtimes = array_map(function ($key) use ($runtimes) {
|
||||
$runtimes[$key]['$id'] = $key;
|
||||
|
||||
return $runtimes[$key];
|
||||
}, array_keys($runtimes));
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => count($runtimes),
|
||||
'runtimes' => $runtimes
|
||||
'runtimes' => $runtimes,
|
||||
]), Response::MODEL_RUNTIME_LIST);
|
||||
});
|
||||
|
||||
@@ -226,7 +224,6 @@ App::get('/v1/functions/:functionId/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -270,18 +267,18 @@ App::get('/v1/functions/:functionId/usage')
|
||||
'1d' => 'Y-m-d\T00:00:00.000P',
|
||||
};
|
||||
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'range' => $range,
|
||||
@@ -309,7 +306,6 @@ App::get('/v1/functions/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$periods = Config::getParam('usage', []);
|
||||
$stats = $usage = [];
|
||||
$days = $periods[$range];
|
||||
@@ -348,18 +344,18 @@ App::get('/v1/functions/usage')
|
||||
'1d' => 'Y-m-d\T00:00:00.000P',
|
||||
};
|
||||
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
$response->dynamic(new Document([
|
||||
'range' => $range,
|
||||
'functionsTotal' => $usage[$metrics[0]],
|
||||
@@ -389,8 +385,8 @@ App::put('/v1/functions/:functionId')
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
|
||||
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 64 characters long.', true)
|
||||
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.', true)
|
||||
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
|
||||
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true)
|
||||
->param('enabled', true, new Boolean(), 'Is function enabled?', true)
|
||||
@@ -401,7 +397,6 @@ App::put('/v1/functions/:functionId')
|
||||
->inject('events')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $functionId, string $name, array $execute, array $events, string $schedule, int $timeout, bool $enabled, Response $response, Database $dbForProject, Document $project, Document $user, Event $eventsInstance, Database $dbForConsole) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -424,7 +419,7 @@ App::put('/v1/functions/:functionId')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$eventsInstance->setParam('functionId', $function->getId());
|
||||
@@ -454,7 +449,6 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
->inject('events')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Document $project, Event $events, Database $dbForConsole) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''));
|
||||
@@ -484,7 +478,7 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$events
|
||||
@@ -515,14 +509,13 @@ App::delete('/v1/functions/:functionId')
|
||||
->inject('project')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $functionId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Document $project, Database $dbForConsole) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('functions', $function->getId())) {
|
||||
if (! $dbForProject->deleteDocument('functions', $function->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove function from DB');
|
||||
}
|
||||
|
||||
@@ -570,7 +563,6 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
->inject('deviceLocal')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $functionId, string $entrypoint, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $events, Document $project, Device $deviceFunctions, Device $deviceLocal, Database $dbForConsole) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -597,7 +589,7 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
$fileTmpName = (\is_array($file['tmp_name']) && isset($file['tmp_name'][0])) ? $file['tmp_name'][0] : $file['tmp_name'];
|
||||
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||
|
||||
if (!$fileExt->isValid($file['name'])) { // Check if file type is allowed
|
||||
if (! $fileExt->isValid($file['name'])) { // Check if file type is allowed
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
@@ -606,7 +598,7 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
$chunk = 1;
|
||||
$chunks = 1;
|
||||
|
||||
if (!empty($contentRange)) {
|
||||
if (! empty($contentRange)) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$fileSize = $request->getContentRangeSize();
|
||||
@@ -627,21 +619,21 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit
|
||||
if (! $fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE);
|
||||
}
|
||||
|
||||
if (!$upload->isValid($fileTmpName)) {
|
||||
if (! $upload->isValid($fileTmpName)) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE);
|
||||
}
|
||||
|
||||
// Save to storage
|
||||
$fileSize ??= $deviceLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceFunctions->getPath($deploymentId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = $deviceFunctions->getPath($deploymentId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
$metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)];
|
||||
if (!$deployment->isEmpty()) {
|
||||
if (! $deployment->isEmpty()) {
|
||||
$chunks = $deployment->getAttribute('chunksTotal', 1);
|
||||
$metadata = $deployment->getAttribute('metadata', []);
|
||||
if ($chunk === -1) {
|
||||
@@ -663,7 +655,7 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
$activeDeployments = $dbForProject->find('deployments', [
|
||||
Query::equal('activate', [true]),
|
||||
Query::equal('resourceId', [$functionId]),
|
||||
Query::equal('resourceType', ['functions'])
|
||||
Query::equal('resourceType', ['functions']),
|
||||
]);
|
||||
|
||||
foreach ($activeDeployments as $activeDeployment) {
|
||||
@@ -755,12 +747,11 @@ App::get('/v1/functions/:functionId/deployments')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -769,7 +760,7 @@ App::get('/v1/functions/:functionId/deployments')
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -827,7 +818,6 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -873,7 +863,6 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
->inject('events')
|
||||
->inject('deviceFunctions')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $deletes, Event $events, Device $deviceFunctions) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
@@ -889,7 +878,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
||||
}
|
||||
|
||||
if ($deviceFunctions->delete($deployment->getAttribute('path', ''))) {
|
||||
if (!$dbForProject->deleteDocument('deployments', $deployment->getId())) {
|
||||
if (! $dbForProject->deleteDocument('deployments', $deployment->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from DB');
|
||||
}
|
||||
}
|
||||
@@ -933,7 +922,6 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
||||
->inject('project')
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Response $response, Database $dbForProject, Document $project, Event $events) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
@@ -998,11 +986,10 @@ App::post('/v1/functions/:functionId/executions')
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForUsage')
|
||||
->action(function (string $functionId, string $data, bool $async, Response $response, Document $project, Database $dbForProject, Document $user, Event $events, string $mode, Func $queueForFunctions, Usage $queueForUsage) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
if ($function->isEmpty() || ! $function->getAttribute('enabled')) {
|
||||
if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
@@ -1012,7 +999,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
|
||||
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "'.$function->getAttribute('runtime', '').'" is not supported');
|
||||
}
|
||||
|
||||
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
|
||||
@@ -1037,7 +1024,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
|
||||
$validator = new Authorization('execute');
|
||||
|
||||
if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function
|
||||
if (! $validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, $validator->getDescription());
|
||||
}
|
||||
|
||||
@@ -1046,7 +1033,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
/** @var Document $execution */
|
||||
$execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', new Document([
|
||||
'$id' => $executionId,
|
||||
'$permissions' => !$user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [],
|
||||
'$permissions' => ! $user->isEmpty() ? [Permission::read(Role::user($user->getId()))] : [],
|
||||
'functionInternalId' => $function->getInternalId(),
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentInternalId' => $deployment->getInternalId(),
|
||||
@@ -1061,7 +1048,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
])));
|
||||
|
||||
$jwt = ''; // initialize
|
||||
if (!$user->isEmpty()) { // If userId exists, generate a JWT for function
|
||||
if (! $user->isEmpty()) { // If userId exists, generate a JWT for function
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$current = new Document();
|
||||
|
||||
@@ -1072,7 +1059,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
}
|
||||
}
|
||||
|
||||
if (!$current->isEmpty()) {
|
||||
if (! $current->isEmpty()) {
|
||||
$jwtObj = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
$jwt = $jwtObj->encode([
|
||||
'userId' => $user->getId(),
|
||||
@@ -1104,6 +1091,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
|
||||
$vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? '';
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
@@ -1145,13 +1133,13 @@ App::post('/v1/functions/:functionId/executions')
|
||||
* Sync execution compute usage from
|
||||
*/
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($executionResponse['duration'] * 1000))// per project
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($executionResponse['duration'] * 1000))// per function
|
||||
;
|
||||
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int) ($executionResponse['duration'] * 1000))// per project
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int) ($executionResponse['duration'] * 1000))// per function
|
||||
;
|
||||
} catch (\Throwable $th) {
|
||||
$interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt()));
|
||||
$execution
|
||||
->setAttribute('duration', (float)$interval->format('%s.%f'))
|
||||
->setAttribute('duration', (float) $interval->format('%s.%f'))
|
||||
->setAttribute('status', 'failed')
|
||||
->setAttribute('statusCode', $th->getCode())
|
||||
->setAttribute('stderr', $th->getMessage());
|
||||
@@ -1164,7 +1152,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
|
||||
if (!$isPrivilegedUser && !$isAppUser) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) {
|
||||
$execution->setAttribute('stdout', '');
|
||||
$execution->setAttribute('stderr', '');
|
||||
}
|
||||
@@ -1186,24 +1174,23 @@ App::get('/v1/functions/:functionId/executions')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_EXECUTION_LIST)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $functionId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
if ($function->isEmpty() || ! $function->getAttribute('enabled')) {
|
||||
if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -1233,10 +1220,11 @@ App::get('/v1/functions/:functionId/executions')
|
||||
$roles = Authorization::getRoles();
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
if (!$isPrivilegedUser && !$isAppUser) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) {
|
||||
$results = array_map(function ($execution) {
|
||||
$execution->setAttribute('stdout', '');
|
||||
$execution->setAttribute('stderr', '');
|
||||
|
||||
return $execution;
|
||||
}, $results);
|
||||
}
|
||||
@@ -1264,11 +1252,10 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $functionId, string $executionId, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||
|
||||
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
if ($function->isEmpty() || ! $function->getAttribute('enabled')) {
|
||||
if (! ($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
@@ -1286,7 +1273,7 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
||||
$roles = Authorization::getRoles();
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
|
||||
$isAppUser = Auth::isAppUser($roles);
|
||||
if (!$isPrivilegedUser && !$isAppUser) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) {
|
||||
$execution->setAttribute('stdout', '');
|
||||
$execution->setAttribute('stderr', '');
|
||||
}
|
||||
@@ -1310,7 +1297,7 @@ App::post('/v1/functions/:functionId/variables')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VARIABLE)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.', false)
|
||||
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
|
||||
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: '.Database::LENGTH_KEY.' chars.', false)
|
||||
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1348,7 +1335,7 @@ App::post('/v1/functions/:functionId/variables')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$dbForProject->deleteCachedDocument('functions', $function->getId());
|
||||
@@ -1357,7 +1344,7 @@ App::post('/v1/functions/:functionId/variables')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$response
|
||||
@@ -1447,7 +1434,6 @@ App::put('/v1/functions/:functionId/variables/:variableId')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject, Database $dbForConsole) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
@@ -1466,8 +1452,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
|
||||
$variable
|
||||
->setAttribute('key', $key)
|
||||
->setAttribute('value', $value ?? $variable->getAttribute('value'))
|
||||
->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key]))
|
||||
;
|
||||
->setAttribute('search', implode(' ', [$variableId, $function->getId(), $key]));
|
||||
|
||||
try {
|
||||
$dbForProject->updateDocument('variables', $variable->getId(), $variable);
|
||||
@@ -1479,7 +1464,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$dbForProject->deleteCachedDocument('functions', $function->getId());
|
||||
@@ -1488,7 +1473,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$response->dynamic($variable, Response::MODEL_VARIABLE);
|
||||
@@ -1533,7 +1518,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$dbForProject->deleteCachedDocument('functions', $function->getId());
|
||||
@@ -1542,7 +1527,7 @@ App::delete('/v1/functions/:functionId/variables/:variableId')
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
|
||||
$response->noContent();
|
||||
|
||||
@@ -42,11 +42,11 @@ App::get('/v1/graphql')
|
||||
'query' => $query,
|
||||
];
|
||||
|
||||
if (!empty($operationName)) {
|
||||
if (! empty($operationName)) {
|
||||
$query['operationName'] = $operationName;
|
||||
}
|
||||
|
||||
if (!empty($variables)) {
|
||||
if (! empty($variables)) {
|
||||
$query['variables'] = \json_decode($variables, true);
|
||||
}
|
||||
|
||||
@@ -150,10 +150,11 @@ App::post('/v1/graphql')
|
||||
/**
|
||||
* Execute a GraphQL request
|
||||
*
|
||||
* @param GQLSchema $schema
|
||||
* @param Adapter $promiseAdapter
|
||||
* @param array $query
|
||||
* @param GQLSchema $schema
|
||||
* @param Adapter $promiseAdapter
|
||||
* @param array $query
|
||||
* @return array
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
function execute(
|
||||
@@ -165,7 +166,7 @@ function execute(
|
||||
$maxComplexity = App::getEnv('_APP_GRAPHQL_MAX_COMPLEXITY', 250);
|
||||
$maxDepth = App::getEnv('_APP_GRAPHQL_MAX_DEPTH', 3);
|
||||
|
||||
if (!empty($query) && !isset($query[0])) {
|
||||
if (! empty($query) && ! isset($query[0])) {
|
||||
$query = [$query];
|
||||
}
|
||||
if (empty($query)) {
|
||||
@@ -224,7 +225,7 @@ function execute(
|
||||
/**
|
||||
* Parse an "application/graphql" type request
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
function parseGraphql(Request $request): array
|
||||
@@ -235,8 +236,8 @@ function parseGraphql(Request $request): array
|
||||
/**
|
||||
* Parse an "multipart/form-data" type request
|
||||
*
|
||||
* @param array $query
|
||||
* @param Request $request
|
||||
* @param array $query
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
function parseMultipart(array $query, Request $request): array
|
||||
@@ -248,7 +249,7 @@ function parseMultipart(array $query, Request $request): array
|
||||
foreach ($locations as $location) {
|
||||
$items = &$operations;
|
||||
foreach (\explode('.', $location) as $key) {
|
||||
if (!isset($items[$key]) || !\is_array($items[$key])) {
|
||||
if (! isset($items[$key]) || ! \is_array($items[$key])) {
|
||||
$items[$key] = [];
|
||||
}
|
||||
$items = &$items[$key];
|
||||
@@ -276,7 +277,7 @@ function parseMultipart(array $query, Request $request): array
|
||||
function processResult($result, $debugFlags): array
|
||||
{
|
||||
// Only one query, return the result
|
||||
if (!isset($result[1])) {
|
||||
if (! isset($result[1])) {
|
||||
return $result[0]->toArray($debugFlags);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,11 +28,10 @@ App::get('/v1/health')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_STATUS)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$output = [
|
||||
'name' => 'http',
|
||||
'status' => 'pass',
|
||||
'ping' => 0
|
||||
'ping' => 0,
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -47,7 +46,7 @@ App::get('/v1/health/version')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_VERSION)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$response->dynamic(new Document([ 'version' => APP_VERSION_STABLE ]), Response::MODEL_HEALTH_VERSION);
|
||||
$response->dynamic(new Document(['version' => APP_VERSION_STABLE]), Response::MODEL_HEALTH_VERSION);
|
||||
});
|
||||
|
||||
App::get('/v1/health/db')
|
||||
@@ -64,7 +63,6 @@ App::get('/v1/health/db')
|
||||
->inject('response')
|
||||
->inject('pools')
|
||||
->action(function (Response $response, Group $pools) {
|
||||
|
||||
$output = [];
|
||||
|
||||
$configs = [
|
||||
@@ -81,22 +79,22 @@ App::get('/v1/health/db')
|
||||
|
||||
if ($adapter->ping()) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
} else {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -122,7 +120,6 @@ App::get('/v1/health/cache')
|
||||
->inject('response')
|
||||
->inject('pools')
|
||||
->action(function (Response $response, Group $pools) {
|
||||
|
||||
$output = [];
|
||||
|
||||
$configs = [
|
||||
@@ -138,22 +135,22 @@ App::get('/v1/health/cache')
|
||||
|
||||
if ($adapter->ping()) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
} else {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -179,7 +176,6 @@ App::get('/v1/health/queue')
|
||||
->inject('response')
|
||||
->inject('pools')
|
||||
->action(function (Response $response, Group $pools) {
|
||||
|
||||
$output = [];
|
||||
|
||||
$configs = [
|
||||
@@ -195,22 +191,22 @@ App::get('/v1/health/queue')
|
||||
|
||||
if ($adapter->ping()) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
} else {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -236,7 +232,6 @@ App::get('/v1/health/pubsub')
|
||||
->inject('response')
|
||||
->inject('pools')
|
||||
->action(function (Response $response, Group $pools) {
|
||||
|
||||
$output = [];
|
||||
|
||||
$configs = [
|
||||
@@ -252,22 +247,22 @@ App::get('/v1/health/pubsub')
|
||||
|
||||
if ($adapter->ping()) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
} else {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$output[] = new Document([
|
||||
'name' => $key . " ($database)",
|
||||
'name' => $key." ($database)",
|
||||
'status' => 'fail',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -292,7 +287,6 @@ App::get('/v1/health/time')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_TIME)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
/*
|
||||
* Code from: @see https://www.beliefmedia.com.au/query-ntp-time-server
|
||||
*/
|
||||
@@ -305,7 +299,7 @@ App::get('/v1/health/time')
|
||||
\socket_connect($sock, $host, 123);
|
||||
|
||||
/* Send request */
|
||||
$msg = "\010" . \str_repeat("\0", 47);
|
||||
$msg = "\010".\str_repeat("\0", 47);
|
||||
|
||||
\socket_send($sock, $msg, \strlen($msg), 0);
|
||||
|
||||
@@ -330,7 +324,7 @@ App::get('/v1/health/time')
|
||||
$output = [
|
||||
'remoteTime' => $timestamp,
|
||||
'localTime' => \time(),
|
||||
'diff' => $diff
|
||||
'diff' => $diff,
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_TIME);
|
||||
@@ -349,8 +343,7 @@ App::get('/v1/health/queue/webhooks')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::WEBHOOK_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => Resque::size(Event::WEBHOOK_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/logs')
|
||||
@@ -366,8 +359,7 @@ App::get('/v1/health/queue/logs')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => Resque::size(Event::AUDITS_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/certificates')
|
||||
@@ -383,8 +375,7 @@ App::get('/v1/health/queue/certificates')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => Resque::size(Event::CERTIFICATES_QUEUE_NAME)]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/queue/functions')
|
||||
@@ -402,7 +393,7 @@ App::get('/v1/health/queue/functions')
|
||||
->inject('response')
|
||||
->action(function (Connection $queue, Response $response) {
|
||||
$client = new Client(Event::FUNCTIONS_QUEUE_NAME, $queue);
|
||||
$response->dynamic(new Document([ 'size' => $client->sumProcessingJobs() ]), Response::MODEL_HEALTH_QUEUE);
|
||||
$response->dynamic(new Document(['size' => $client->sumProcessingJobs()]), Response::MODEL_HEALTH_QUEUE);
|
||||
}, ['response']);
|
||||
|
||||
App::get('/v1/health/storage/local')
|
||||
@@ -418,31 +409,30 @@ App::get('/v1/health/storage/local')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_STATUS)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$checkStart = \microtime(true);
|
||||
|
||||
foreach (
|
||||
[
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES
|
||||
'Uploads' => APP_STORAGE_UPLOADS,
|
||||
'Cache' => APP_STORAGE_CACHE,
|
||||
'Config' => APP_STORAGE_CONFIG,
|
||||
'Certs' => APP_STORAGE_CERTIFICATES,
|
||||
] as $key => $volume
|
||||
) {
|
||||
$device = new Local($volume);
|
||||
|
||||
if (!\is_readable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not readable');
|
||||
if (! \is_readable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not readable');
|
||||
}
|
||||
|
||||
if (!\is_writable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device ' . $key . ' dir is not writable');
|
||||
if (! \is_writable($device->getRoot())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Device '.$key.' dir is not writable');
|
||||
}
|
||||
}
|
||||
|
||||
$output = [
|
||||
'status' => 'pass',
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000)
|
||||
'ping' => \round((\microtime(true) - $checkStart) / 1000),
|
||||
];
|
||||
|
||||
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
|
||||
@@ -461,10 +451,9 @@ App::get('/v1/health/anti-virus')
|
||||
->label('sdk.response.model', Response::MODEL_HEALTH_ANTIVIRUS)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$output = [
|
||||
'status' => '',
|
||||
'version' => ''
|
||||
'version' => '',
|
||||
];
|
||||
|
||||
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'disabled') { // Check if scans are enabled
|
||||
@@ -499,7 +488,6 @@ App::get('/v1/health/stats') // Currently only used internally
|
||||
->inject('register')
|
||||
->inject('deviceFiles')
|
||||
->action(function (Response $response, Registry $register, Device $deviceFiles) {
|
||||
|
||||
$cache = $register->get('cache');
|
||||
|
||||
$cacheStats = $cache->info();
|
||||
@@ -507,7 +495,7 @@ App::get('/v1/health/stats') // Currently only used internally
|
||||
$response
|
||||
->json([
|
||||
'storage' => [
|
||||
'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot() . '/')),
|
||||
'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot().'/')),
|
||||
'partitionTotal' => Storage::human($deviceFiles->getPartitionTotalSpace()),
|
||||
'partitionFree' => Storage::human($deviceFiles->getPartitionFreeSpace()),
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
@@ -40,8 +40,8 @@ App::get('/v1/locale')
|
||||
|
||||
if ($record) {
|
||||
$output['countryCode'] = $record['country']['iso_code'];
|
||||
$output['country'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output['continent'] = $locale->getText('continents.' . strtolower($record['continent']['code']), $locale->getText('locale.country.unknown'));
|
||||
$output['country'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output['continent'] = $locale->getText('continents.'.strtolower($record['continent']['code']), $locale->getText('locale.country.unknown'));
|
||||
$output['continentCode'] = $record['continent']['code'];
|
||||
$output['eu'] = (\in_array($record['country']['iso_code'], $eu)) ? true : false;
|
||||
|
||||
@@ -62,9 +62,9 @@ App::get('/v1/locale')
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', 'public, max-age=' . $time)
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache
|
||||
;
|
||||
->addHeader('Cache-Control', 'public, max-age='.$time)
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time).' GMT') // 45 days cache
|
||||
;
|
||||
$response->dynamic(new Document($output), Response::MODEL_LOCALE);
|
||||
});
|
||||
|
||||
@@ -111,7 +111,7 @@ App::get('/v1/locale/countries')
|
||||
|
||||
foreach ($list as $value) {
|
||||
$output[] = new Document([
|
||||
'name' => $locale->getText('countries.' . strtolower($value)),
|
||||
'name' => $locale->getText('countries.'.strtolower($value)),
|
||||
'code' => $value,
|
||||
]);
|
||||
}
|
||||
@@ -143,9 +143,9 @@ App::get('/v1/locale/countries/eu')
|
||||
$output = [];
|
||||
|
||||
foreach ($eu as $code) {
|
||||
if ($locale->getText('countries.' . strtolower($code), false) !== false) {
|
||||
if ($locale->getText('countries.'.strtolower($code), false) !== false) {
|
||||
$output[] = new Document([
|
||||
'name' => $locale->getText('countries.' . strtolower($code)),
|
||||
'name' => $locale->getText('countries.'.strtolower($code)),
|
||||
'code' => $code,
|
||||
]);
|
||||
}
|
||||
@@ -180,11 +180,11 @@ App::get('/v1/locale/countries/phones')
|
||||
\asort($list);
|
||||
|
||||
foreach ($list as $code => $name) {
|
||||
if ($locale->getText('countries.' . strtolower($code), false) !== false) {
|
||||
if ($locale->getText('countries.'.strtolower($code), false) !== false) {
|
||||
$output[] = new Document([
|
||||
'code' => '+' . $list[$code],
|
||||
'code' => '+'.$list[$code],
|
||||
'countryCode' => $code,
|
||||
'countryName' => $locale->getText('countries.' . strtolower($code)),
|
||||
'countryName' => $locale->getText('countries.'.strtolower($code)),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ App::get('/v1/locale/continents')
|
||||
|
||||
foreach ($list as $value) {
|
||||
$output[] = new Document([
|
||||
'name' => $locale->getText('continents.' . strtolower($value)),
|
||||
'name' => $locale->getText('continents.'.strtolower($value)),
|
||||
'code' => $value,
|
||||
]);
|
||||
}
|
||||
@@ -246,7 +246,6 @@ App::get('/v1/locale/currencies')
|
||||
$response->dynamic(new Document(['currencies' => $list, 'total' => \count($list)]), Response::MODEL_CURRENCY_LIST);
|
||||
});
|
||||
|
||||
|
||||
App::get('/v1/locale/languages')
|
||||
->desc('List Languages')
|
||||
->groups(['api', 'locale'])
|
||||
|
||||
+394
-394
@@ -25,35 +25,35 @@ App::get('/v1/messaging/providers')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROVIDER_LIST)
|
||||
->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Providers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Providers::ALLOWED_ATTRIBUTES), true)
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (array $queries, Database $dbForProject, Response $response) {
|
||||
$queries = Query::parseQueries($queries);
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
// Get cursor document if there was a cursor query
|
||||
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
|
||||
$cursor = reset($cursor);
|
||||
// Get cursor document if there was a cursor query
|
||||
$cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]);
|
||||
$cursor = reset($cursor);
|
||||
|
||||
if ($cursor) {
|
||||
$providerId = $cursor->getValue();
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [
|
||||
Query::equal('$id', [$providerId]),
|
||||
Query::limit(1),
|
||||
]));
|
||||
if ($cursor) {
|
||||
$providerId = $cursor->getValue();
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->find('providers', [
|
||||
Query::equal('$id', [$providerId]),
|
||||
Query::limit(1),
|
||||
]));
|
||||
|
||||
if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found.");
|
||||
}
|
||||
if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Provider '{$providerId}' for the 'cursor' value not found.");
|
||||
}
|
||||
|
||||
$cursor->setValue($cursorDocument[0]);
|
||||
}
|
||||
$cursor->setValue($cursorDocument[0]);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
$response->dynamic(new Document([
|
||||
'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT),
|
||||
'indexes' => $dbForProject->find('providers', $queries),
|
||||
]), Response::MODEL_PROVIDER_LIST);
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
$response->dynamic(new Document([
|
||||
'total' => $dbForProject->count('providers', $filterQueries, APP_LIMIT_COUNT),
|
||||
'indexes' => $dbForProject->find('providers', $queries),
|
||||
]), Response::MODEL_PROVIDER_LIST);
|
||||
});
|
||||
|
||||
App::get('/v1/messaging/providers/:id')
|
||||
@@ -71,13 +71,13 @@ App::get('/v1/messaging/providers/:id')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -101,18 +101,18 @@ App::post('/v1/messaging/providers/mailgun')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'mailgun',
|
||||
'type' => 'email',
|
||||
'credentials' => [
|
||||
'apiKey' => $apiKey,
|
||||
'domain' => $domain,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'mailgun',
|
||||
'type' => 'email',
|
||||
'credentials' => [
|
||||
'apiKey' => $apiKey,
|
||||
'domain' => $domain,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/mailgun')
|
||||
@@ -134,39 +134,39 @@ App::patch('/v1/messaging/providers/:id/mailgun')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $apiKey, string $domain, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'mailgun') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'mailgun') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($apiKey || $domain) {
|
||||
// Check if all five variables are present
|
||||
if ($apiKey && $domain) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey,
|
||||
'domain' => $domain
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
if ($apiKey || $domain) {
|
||||
// Check if all five variables are present
|
||||
if ($apiKey && $domain) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey,
|
||||
'domain' => $domain,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/sendgrid')
|
||||
@@ -186,17 +186,17 @@ App::post('/v1/messaging/providers/sendgrid')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $apiKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'sendgrid',
|
||||
'type' => 'email',
|
||||
'credentials' => [
|
||||
'apiKey' => $apiKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'sendgrid',
|
||||
'type' => 'email',
|
||||
'credentials' => [
|
||||
'apiKey' => $apiKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/sendgrid')
|
||||
@@ -217,32 +217,32 @@ App::patch('/v1/messaging/providers/:id/sendgrid')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $apiKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'sendgrid') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'sendgrid') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($apiKey) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey
|
||||
]);
|
||||
}
|
||||
if ($apiKey) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey,
|
||||
]);
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -266,18 +266,18 @@ App::post('/v1/messaging/providers/msg91')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'msg91',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'senderId' => $senderId,
|
||||
'authKey' => $authKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'msg91',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'senderId' => $senderId,
|
||||
'authKey' => $authKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/msg91')
|
||||
@@ -299,39 +299,39 @@ App::patch('/v1/messaging/providers/:id/msg91')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $senderId, string $authKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'msg91') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'msg91') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($senderId || $authKey) {
|
||||
// Check if all five variables are present
|
||||
if ($senderId && $authKey) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'senderId' => $senderId,
|
||||
'authKey' => $authKey
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
if ($senderId || $authKey) {
|
||||
// Check if all five variables are present
|
||||
if ($senderId && $authKey) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'senderId' => $senderId,
|
||||
'authKey' => $authKey,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/telesign')
|
||||
@@ -352,18 +352,18 @@ App::post('/v1/messaging/providers/telesign')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $username, string $password, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'telesign',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'telesign',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/telesign')
|
||||
@@ -385,39 +385,39 @@ App::patch('/v1/messaging/providers/:id/telesign')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $username, string $password, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'telesign') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'telesign') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($username || $password) {
|
||||
// Check if all five variables are present
|
||||
if ($username && $password) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'username' => $username,
|
||||
'password' => $password
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
if ($username || $password) {
|
||||
// Check if all five variables are present
|
||||
if ($username && $password) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/textmagic')
|
||||
@@ -438,18 +438,18 @@ App::post('/v1/messaging/providers/textmagic')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $username, string $apiKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'text-magic',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'username' => $username,
|
||||
'apiKey' => $apiKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'text-magic',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'username' => $username,
|
||||
'apiKey' => $apiKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/textmagic')
|
||||
@@ -471,39 +471,39 @@ App::patch('/v1/messaging/providers/:id/textmagic')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $username, string $apiKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'text-magic') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'text-magic') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($username || $apiKey) {
|
||||
// Check if all five variables are present
|
||||
if ($username && $apiKey) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'username' => $username,
|
||||
'apiKey' => $apiKey
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
if ($username || $apiKey) {
|
||||
// Check if all five variables are present
|
||||
if ($username && $apiKey) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'username' => $username,
|
||||
'apiKey' => $apiKey,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/twilio')
|
||||
@@ -524,18 +524,18 @@ App::post('/v1/messaging/providers/twilio')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'twilio',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'accountSid' => $accountSid,
|
||||
'authToken' => $authToken,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'twilio',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'accountSid' => $accountSid,
|
||||
'authToken' => $authToken,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/twilio')
|
||||
@@ -557,39 +557,39 @@ App::patch('/v1/messaging/providers/:id/twilio')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $accountSid, string $authToken, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'twilio') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'twilio') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($accountSid || $authToken) {
|
||||
// Check if all five variables are present
|
||||
if ($accountSid && $authToken) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'accountSid' => $accountSid,
|
||||
'authToken' => $authToken,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
if ($accountSid || $authToken) {
|
||||
// Check if all five variables are present
|
||||
if ($accountSid && $authToken) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'accountSid' => $accountSid,
|
||||
'authToken' => $authToken,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/vonage')
|
||||
@@ -610,18 +610,18 @@ App::post('/v1/messaging/providers/vonage')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'vonage',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'apiKey' => $apiKey,
|
||||
'apiSecret' => $apiSecret,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'vonage',
|
||||
'type' => 'sms',
|
||||
'credentials' => [
|
||||
'apiKey' => $apiKey,
|
||||
'apiSecret' => $apiSecret,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/vonage')
|
||||
@@ -643,39 +643,39 @@ App::patch('/v1/messaging/providers/:id/vonage')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $apiKey, string $apiSecret, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'vonage') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'vonage') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($apiKey || $apiSecret) {
|
||||
// Check if all five variables are present
|
||||
if ($apiKey && $apiSecret) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey,
|
||||
'apiSecret' => $apiSecret,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
if ($apiKey || $apiSecret) {
|
||||
// Check if all five variables are present
|
||||
if ($apiKey && $apiSecret) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey,
|
||||
'apiSecret' => $apiSecret,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -698,17 +698,17 @@ App::post('/v1/messaging/providers/fcm')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $serverKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'fcm',
|
||||
'type' => 'push',
|
||||
'credentials' => [
|
||||
'serverKey' => $serverKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'fcm',
|
||||
'type' => 'push',
|
||||
'credentials' => [
|
||||
'serverKey' => $serverKey,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/fcm')
|
||||
@@ -729,30 +729,30 @@ App::patch('/v1/messaging/providers/:id/fcm')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $serverKey, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'fcm') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'fcm') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($serverKey) {
|
||||
$provider->setAttribute('credentials', ['serverKey' => $serverKey]);
|
||||
}
|
||||
if ($serverKey) {
|
||||
$provider->setAttribute('credentials', ['serverKey' => $serverKey]);
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/providers/apns')
|
||||
@@ -776,21 +776,21 @@ App::post('/v1/messaging/providers/apns')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'apns',
|
||||
'type' => 'push',
|
||||
'credentials' => [
|
||||
'authKey' => $authKey,
|
||||
'authKeyId' => $authKeyId,
|
||||
'teamId' => $teamId,
|
||||
'bundleId' => $bundleId,
|
||||
'endpoint' => $endpoint,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$provider = $dbForProject->createDocument('providers', new Document([
|
||||
'name' => $name,
|
||||
'provider' => 'apns',
|
||||
'type' => 'push',
|
||||
'credentials' => [
|
||||
'authKey' => $authKey,
|
||||
'authKeyId' => $authKeyId,
|
||||
'teamId' => $teamId,
|
||||
'bundleId' => $bundleId,
|
||||
'endpoint' => $endpoint,
|
||||
],
|
||||
]));
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::patch('/v1/messaging/providers/:id/apns')
|
||||
@@ -815,42 +815,42 @@ App::patch('/v1/messaging/providers/:id/apns')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, string $name, string $authKey, string $authKeyId, string $teamId, string $bundleId, string $endpoint, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
$providerAttr = $provider->getAttribute('provider');
|
||||
|
||||
if ($providerAttr !== 'apns') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE . $providerAttr);
|
||||
}
|
||||
if ($providerAttr !== 'apns') {
|
||||
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE.$providerAttr);
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
if ($name) {
|
||||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) {
|
||||
// Check if all five variables are present
|
||||
if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'authKey' => $authKey,
|
||||
'authKeyId' => $authKeyId,
|
||||
'teamId' => $teamId,
|
||||
'bundleId' => $bundleId,
|
||||
'endpoint' => $endpoint,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
if ($authKey || $authKeyId || $teamId || $bundleId || $endpoint) {
|
||||
// Check if all five variables are present
|
||||
if ($authKey && $authKeyId && $teamId && $bundleId && $endpoint) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'authKey' => $authKey,
|
||||
'authKeyId' => $authKeyId,
|
||||
'teamId' => $teamId,
|
||||
'bundleId' => $bundleId,
|
||||
'endpoint' => $endpoint,
|
||||
]);
|
||||
} else {
|
||||
// Not all credential params are present
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
$response
|
||||
->dynamic($provider, Response::MODEL_PROVIDER);
|
||||
});
|
||||
|
||||
App::delete('/v1/messaging/providers/:id')
|
||||
@@ -869,16 +869,16 @@ App::delete('/v1/messaging/providers/:id')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $id, Database $dbForProject, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
$provider = $dbForProject->getDocument('providers', $id);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$dbForProject->deleteDocument('providers', $provider->getId());
|
||||
$dbForProject->deleteCachedDocument('providers', $provider->getId());
|
||||
$dbForProject->deleteDocument('providers', $provider->getId());
|
||||
|
||||
$response->noContent();
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
App::post('/v1/messaging/messages/email')
|
||||
@@ -904,30 +904,30 @@ App::post('/v1/messaging/messages/email')
|
||||
->inject('events')
|
||||
->inject('response')
|
||||
->action(function (string $providerId, string $to, string $subject, string $content, string $from, string $html, DateTime $deliveryTime, Database $dbForProject, Event $eventsInstance, Response $response) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$message = $dbForProject->createDocument('messages', new Document([
|
||||
'providerId' => $provider->getId(),
|
||||
'providerInternalId' => $provider->getInternalId(),
|
||||
'to' => $to,
|
||||
'data' => [
|
||||
'subject' => $subject,
|
||||
'content' => $content,
|
||||
],
|
||||
'deliveryTime' => $deliveryTime,
|
||||
'deliveryError' => null,
|
||||
'deliveredTo' => null,
|
||||
'delivered' => false,
|
||||
'search' => null,
|
||||
]));
|
||||
$message = $dbForProject->createDocument('messages', new Document([
|
||||
'providerId' => $provider->getId(),
|
||||
'providerInternalId' => $provider->getInternalId(),
|
||||
'to' => $to,
|
||||
'data' => [
|
||||
'subject' => $subject,
|
||||
'content' => $content,
|
||||
],
|
||||
'deliveryTime' => $deliveryTime,
|
||||
'deliveryError' => null,
|
||||
'deliveredTo' => null,
|
||||
'delivered' => false,
|
||||
'search' => null,
|
||||
]));
|
||||
|
||||
$eventsInstance->setParam('messageId', $message->getId());
|
||||
$eventsInstance->setParam('messageId', $message->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_MESSAGE);
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($provider, Response::MODEL_MESSAGE);
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
include_once __DIR__ . '/../shared/api.php';
|
||||
include_once __DIR__.'/../shared/api.php';
|
||||
|
||||
App::post('/v1/migrations/appwrite')
|
||||
->groups(['api', 'migrations'])
|
||||
@@ -110,7 +110,7 @@ App::post('/v1/migrations/firebase/oauth')
|
||||
$firebase = new OAuth2Firebase(
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''),
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''),
|
||||
$request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect'
|
||||
$request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect'
|
||||
);
|
||||
|
||||
$identity = $dbForConsole->findOne('identities', [
|
||||
@@ -141,7 +141,7 @@ App::post('/v1/migrations/firebase/oauth')
|
||||
$identity = $identity
|
||||
->setAttribute('providerAccessToken', $accessToken)
|
||||
->setAttribute('providerRefreshToken', $refreshToken)
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry('')));
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry('')));
|
||||
|
||||
$dbForConsole->updateDocument('identities', $identity->getId(), $identity);
|
||||
}
|
||||
@@ -167,7 +167,7 @@ App::post('/v1/migrations/firebase/oauth')
|
||||
'resources' => $resources,
|
||||
'statusCounters' => '{}',
|
||||
'resourceData' => '{}',
|
||||
'errors' => []
|
||||
'errors' => [],
|
||||
]));
|
||||
|
||||
$events->setParam('migrationId', $migration->getId());
|
||||
@@ -368,14 +368,14 @@ App::get('/v1/migrations')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_MIGRATION_LIST)
|
||||
->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Migrations::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Migrations(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Migrations::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -505,7 +505,7 @@ App::get('/v1/migrations/firebase/report/oauth')
|
||||
$firebase = new OAuth2Firebase(
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''),
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''),
|
||||
$request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect'
|
||||
$request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect'
|
||||
);
|
||||
|
||||
$identity = $dbForConsole->findOne('identities', [
|
||||
@@ -536,7 +536,7 @@ App::get('/v1/migrations/firebase/report/oauth')
|
||||
$identity = $identity
|
||||
->setAttribute('providerAccessToken', $accessToken)
|
||||
->setAttribute('providerRefreshToken', $refreshToken)
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry('')));
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry('')));
|
||||
|
||||
$dbForConsole->updateDocument('identities', $identity->getId(), $identity);
|
||||
}
|
||||
@@ -597,7 +597,7 @@ App::get('/v1/migrations/firebase/connect')
|
||||
$oauth2 = new OAuth2Firebase(
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''),
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''),
|
||||
$request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect'
|
||||
$request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect'
|
||||
);
|
||||
$url = $oauth2->getLoginURL();
|
||||
|
||||
@@ -611,7 +611,7 @@ App::get('/v1/migrations/firebase/redirect')
|
||||
->desc('Capture and receive data on Firebase authorization')
|
||||
->groups(['api', 'migrations'])
|
||||
->label('scope', 'public')
|
||||
->label('error', __DIR__ . '/../../views/general/error.phtml')
|
||||
->label('error', __DIR__.'/../../views/general/error.phtml')
|
||||
->param('code', '', new Text(2048), 'OAuth2 code.', true)
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
@@ -635,7 +635,7 @@ App::get('/v1/migrations/firebase/redirect')
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if (empty($redirect)) {
|
||||
$redirect = $request->getProtocol() . '://' . $request->getHostname() . '/console/project-$projectId/settings/migrations';
|
||||
$redirect = $request->getProtocol().'://'.$request->getHostname().'/console/project-$projectId/settings/migrations';
|
||||
}
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -648,11 +648,11 @@ App::get('/v1/migrations/firebase/redirect')
|
||||
}
|
||||
|
||||
// OAuth Authroization
|
||||
if (!empty($code)) {
|
||||
if (! empty($code)) {
|
||||
$oauth2 = new OAuth2Firebase(
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''),
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''),
|
||||
$request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect'
|
||||
$request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect'
|
||||
);
|
||||
|
||||
$accessToken = $oauth2->getAccessToken($code);
|
||||
@@ -678,17 +678,17 @@ App::get('/v1/migrations/firebase/redirect')
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
|
||||
if ($identity !== false && !$identity->isEmpty()) {
|
||||
if ($identity !== false && ! $identity->isEmpty()) {
|
||||
if ($identity->getAttribute('userInternalId', '') !== $user->getInternalId()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
if ($identity !== false && !$identity->isEmpty()) {
|
||||
if ($identity !== false && ! $identity->isEmpty()) {
|
||||
$identity = $identity
|
||||
->setAttribute('providerAccessToken', $accessToken)
|
||||
->setAttribute('providerRefreshToken', $refreshToken)
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry));
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry));
|
||||
|
||||
$dbForConsole->updateDocument('identities', $identity->getId(), $identity);
|
||||
} else {
|
||||
@@ -706,7 +706,7 @@ App::get('/v1/migrations/firebase/redirect')
|
||||
'providerEmail' => $email,
|
||||
'providerAccessToken' => $accessToken,
|
||||
'providerRefreshToken' => $refreshToken,
|
||||
'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int)$accessTokenExpiry),
|
||||
'providerAccessTokenExpiry' => DateTime::addSeconds(new \DateTime(), (int) $accessTokenExpiry),
|
||||
]));
|
||||
}
|
||||
} else {
|
||||
@@ -738,7 +738,7 @@ App::get('/v1/migrations/firebase/projects')
|
||||
$firebase = new OAuth2Firebase(
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_ID', ''),
|
||||
App::getEnv('_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET', ''),
|
||||
$request->getProtocol() . '://' . $request->getHostname() . '/v1/migrations/firebase/redirect'
|
||||
$request->getProtocol().'://'.$request->getHostname().'/v1/migrations/firebase/redirect'
|
||||
);
|
||||
|
||||
$identity = $dbForConsole->findOne('identities', [
|
||||
@@ -781,7 +781,7 @@ App::get('/v1/migrations/firebase/projects')
|
||||
$identity = $identity
|
||||
->setAttribute('providerAccessToken', $accessToken)
|
||||
->setAttribute('providerRefreshToken', $refreshToken)
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int)$firebase->getAccessTokenExpiry('')));
|
||||
->setAttribute('providerAccessTokenExpiry', DateTime::addSeconds(new \DateTime(), (int) $firebase->getAccessTokenExpiry('')));
|
||||
|
||||
$dbForConsole->updateDocument('identities', $identity->getId(), $identity);
|
||||
}
|
||||
@@ -964,7 +964,7 @@ App::delete('/v1/migrations/:migrationId')
|
||||
throw new Exception(Exception::MIGRATION_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('migrations', $migration->getId())) {
|
||||
if (! $dbForProject->deleteDocument('migrations', $migration->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove migration from DB', 500);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
@@ -24,7 +23,6 @@ App::get('/v1/project/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$periods = Config::getParam('usage', []);
|
||||
$stats = $usage = [];
|
||||
$days = $periods[$range];
|
||||
@@ -37,7 +35,7 @@ App::get('/v1/project/usage')
|
||||
METRIC_DATABASES,
|
||||
METRIC_USERS,
|
||||
METRIC_BUCKETS,
|
||||
METRIC_FILES_STORAGE
|
||||
METRIC_FILES_STORAGE,
|
||||
];
|
||||
|
||||
Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) {
|
||||
@@ -60,25 +58,23 @@ App::get('/v1/project/usage')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$format = match ($days['period']) {
|
||||
'1h' => 'Y-m-d\TH:00:00.000P',
|
||||
'1d' => 'Y-m-d\T00:00:00.000P',
|
||||
};
|
||||
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'range' => $range,
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Validator\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\CNAME;
|
||||
use Utopia\Validator\Domain as DomainValidator;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Utopia\Validator\URL;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Database\Validator\ProjectId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Appwrite\Utopia\Response;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
@@ -21,26 +24,22 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Domains\Domain;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Domain as DomainValidator;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Appwrite\Template\Template;
|
||||
use Utopia\Locale\Locale;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
|
||||
App::init()
|
||||
->groups(['projects'])
|
||||
@@ -64,7 +63,7 @@ App::post('/v1/projects')
|
||||
->param('projectId', '', new ProjectId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn($config) => !$config['disabled']))), 'Project Region.', true)
|
||||
->param('region', App::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn ($config) => ! $config['disabled']))), 'Project Region.', true)
|
||||
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
->param('logo', '', new Text(1024), 'Project logo.', true)
|
||||
->param('url', '', new URL(), 'Project URL.', true)
|
||||
@@ -79,8 +78,6 @@ App::post('/v1/projects')
|
||||
->inject('cache')
|
||||
->inject('pools')
|
||||
->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) {
|
||||
|
||||
|
||||
$team = $dbForConsole->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -164,7 +161,7 @@ App::post('/v1/projects')
|
||||
'domains' => null,
|
||||
'auths' => $auths,
|
||||
'search' => implode(' ', [$projectId, $name]),
|
||||
'database' => $database
|
||||
'database' => $database,
|
||||
]));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::PROJECT_ALREADY_EXISTS);
|
||||
@@ -201,7 +198,7 @@ App::post('/v1/projects')
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -232,15 +229,14 @@ App::get('/v1/projects')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT_LIST)
|
||||
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForConsole) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -281,7 +277,6 @@ App::get('/v1/projects/:projectId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -315,7 +310,6 @@ App::patch('/v1/projects/:projectId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $name, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -353,7 +347,6 @@ App::patch('/v1/projects/:projectId/team')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $teamId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
$team = $dbForConsole->getDocument('teams', $teamId);
|
||||
|
||||
@@ -389,12 +382,11 @@ App::patch('/v1/projects/:projectId/service')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('status', null, new Boolean(), 'Service status.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $service, bool $status, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -424,14 +416,13 @@ App::patch('/v1/projects/:projectId/service/all')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, bool $status, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$allServices = array_keys(array_filter(Config::getParam('services'), fn($element) => $element['optional']));
|
||||
$allServices = array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional']));
|
||||
|
||||
$services = [];
|
||||
foreach ($allServices as $service) {
|
||||
@@ -461,7 +452,6 @@ App::patch('/v1/projects/:projectId/oauth2')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $provider, ?string $appId, ?string $secret, ?bool $enabled, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -471,15 +461,15 @@ App::patch('/v1/projects/:projectId/oauth2')
|
||||
$providers = $project->getAttribute('authProviders', []);
|
||||
|
||||
if ($appId !== null) {
|
||||
$providers[$provider . 'Appid'] = $appId;
|
||||
$providers[$provider.'Appid'] = $appId;
|
||||
}
|
||||
|
||||
if ($secret !== null) {
|
||||
$providers[$provider . 'Secret'] = $secret;
|
||||
$providers[$provider.'Secret'] = $secret;
|
||||
}
|
||||
|
||||
if ($enabled !== null) {
|
||||
$providers[$provider . 'Enabled'] = $enabled;
|
||||
$providers[$provider.'Enabled'] = $enabled;
|
||||
}
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers));
|
||||
@@ -502,7 +492,6 @@ App::patch('/v1/projects/:projectId/auth/limit')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -533,7 +522,6 @@ App::patch('/v1/projects/:projectId/auth/duration')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $duration, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -560,12 +548,11 @@ App::patch('/v1/projects/:projectId/auth/:method')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: ' . implode(',', \array_keys(Config::getParam('auth'))), false)
|
||||
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: '.implode(',', \array_keys(Config::getParam('auth'))), false)
|
||||
->param('status', false, new Boolean(true), 'Set the status of this auth method.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $method, bool $status, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
$auth = Config::getParam('auth')[$method] ?? [];
|
||||
$authKey = $auth['key'] ?? '';
|
||||
@@ -594,11 +581,10 @@ App::patch('/v1/projects/:projectId/auth/password-history')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0')
|
||||
->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is'.APP_LIMIT_USER_PASSWORD_HISTORY.'. Default value is 0')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -629,7 +615,6 @@ App::patch('/v1/projects/:projectId/auth/password-dictionary')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -660,7 +645,6 @@ App::patch('/v1/projects/:projectId/auth/personal-data')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -687,11 +671,10 @@ App::patch('/v1/projects/:projectId/auth/max-sessions')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-' . APP_LIMIT_USER_SESSIONS_MAX . '. Default is ' . APP_LIMIT_USER_SESSIONS_DEFAULT)
|
||||
->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-'.APP_LIMIT_USER_SESSIONS_MAX.'. Default is '.APP_LIMIT_USER_SESSIONS_DEFAULT)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -730,10 +713,9 @@ App::delete('/v1/projects/:projectId')
|
||||
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_DOCUMENT)
|
||||
->setDocument($project)
|
||||
;
|
||||
->setDocument($project);
|
||||
|
||||
if (!$dbForConsole->deleteDocument('projects', $projectId)) {
|
||||
if (! $dbForConsole->deleteDocument('projects', $projectId)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB');
|
||||
}
|
||||
|
||||
@@ -754,7 +736,7 @@ App::post('/v1/projects/:projectId/webhooks')
|
||||
->label('sdk.response.model', Response::MODEL_WEBHOOK)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.')
|
||||
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
|
||||
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
|
||||
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
|
||||
@@ -762,7 +744,6 @@ App::post('/v1/projects/:projectId/webhooks')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -812,7 +793,6 @@ App::get('/v1/projects/:projectId/webhooks')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -845,7 +825,6 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -877,7 +856,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.')
|
||||
->param('url', null, new URL(['http', 'https']), 'Webhook URL.')
|
||||
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
|
||||
->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true)
|
||||
@@ -885,7 +864,6 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -909,8 +887,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->setAttribute('url', $url)
|
||||
->setAttribute('security', $security)
|
||||
->setAttribute('httpUser', $httpUser)
|
||||
->setAttribute('httpPass', $httpPass)
|
||||
;
|
||||
->setAttribute('httpPass', $httpPass);
|
||||
|
||||
$dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook);
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
@@ -933,7 +910,6 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -971,7 +947,6 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1008,12 +983,11 @@ App::post('/v1/projects/:projectId/keys')
|
||||
->label('sdk.response.model', Response::MODEL_KEY)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' scopes are allowed.')
|
||||
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1060,7 +1034,6 @@ App::get('/v1/projects/:projectId/keys')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1093,7 +1066,6 @@ App::get('/v1/projects/:projectId/keys/:keyId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1125,12 +1097,11 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' events are allowed.')
|
||||
->param('expire', null, new DatetimeValidator(), 'Expiration time in ISO 8601 format. Use null for unlimited expiration.', true)
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, string $name, array $scopes, ?string $expire, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1149,8 +1120,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
||||
$key
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('scopes', $scopes)
|
||||
->setAttribute('expire', $expire)
|
||||
;
|
||||
->setAttribute('expire', $expire);
|
||||
|
||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||
|
||||
@@ -1173,7 +1143,6 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1236,7 +1205,7 @@ App::post('/v1/projects/:projectId/platforms')
|
||||
'name' => $name,
|
||||
'key' => $key,
|
||||
'store' => $store,
|
||||
'hostname' => $hostname
|
||||
'hostname' => $hostname,
|
||||
]);
|
||||
|
||||
$platform = $dbForConsole->createDocument('platforms', $platform);
|
||||
@@ -1262,7 +1231,6 @@ App::get('/v1/projects/:projectId/platforms')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1295,7 +1263,6 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1352,8 +1319,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('key', $key)
|
||||
->setAttribute('store', $store)
|
||||
->setAttribute('hostname', $hostname)
|
||||
;
|
||||
->setAttribute('hostname', $hostname);
|
||||
|
||||
$dbForConsole->updateDocument('platforms', $platform->getId(), $platform);
|
||||
|
||||
@@ -1376,7 +1342,6 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1416,7 +1381,6 @@ App::post('/v1/projects/:projectId/domains')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domain, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1428,17 +1392,17 @@ App::post('/v1/projects/:projectId/domains')
|
||||
}
|
||||
|
||||
$document = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain])
|
||||
Query::equal('domain', [$domain]),
|
||||
]);
|
||||
|
||||
if ($document && !$document->isEmpty()) {
|
||||
if ($document && ! $document->isEmpty()) {
|
||||
throw new Exception(Exception::DOMAIN_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if (!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.');
|
||||
if (! $target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target ('.$target->get().'). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.');
|
||||
}
|
||||
|
||||
$domain = new Domain($domain);
|
||||
@@ -1483,7 +1447,6 @@ App::get('/v1/projects/:projectId/domains')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1516,7 +1479,6 @@ App::get('/v1/projects/:projectId/domains/:domainId')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1550,7 +1512,6 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1568,8 +1529,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
||||
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if (!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
|
||||
if (! $target->isKnown() || $target->isTest()) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.');
|
||||
}
|
||||
|
||||
if ($domain->getAttribute('verification') === true) {
|
||||
@@ -1578,11 +1539,10 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
||||
|
||||
$validator = new CNAME($target->get()); // Verify Domain with DNS records
|
||||
|
||||
if (!$validator->isValid($domain->getAttribute('domain', ''))) {
|
||||
if (! $validator->isValid($domain->getAttribute('domain', ''))) {
|
||||
throw new Exception(Exception::DOMAIN_VERIFICATION_FAILED);
|
||||
}
|
||||
|
||||
|
||||
$dbForConsole->updateDocument('domains', $domain->getId(), $domain->setAttribute('verification', true));
|
||||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
@@ -1610,7 +1570,6 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
|
||||
->inject('dbForConsole')
|
||||
->inject('deletes')
|
||||
->action(function (string $projectId, string $domainId, Response $response, Database $dbForConsole, Delete $deletes) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1663,7 +1622,6 @@ App::patch('/v1/projects/:projectId/smtp')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, bool $enabled, string $sender, string $host, int $port, string $username, string $password, string $secure, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1681,7 +1639,7 @@ App::patch('/v1/projects/:projectId/smtp')
|
||||
$mail->SMTPAutoTLS = false;
|
||||
$valid = $mail->SmtpConnect();
|
||||
|
||||
if (!$valid) {
|
||||
if (! $valid) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED);
|
||||
}
|
||||
|
||||
@@ -1712,11 +1670,10 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1724,11 +1681,11 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
}
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$template = $templates['sms.' . $type . '-' . $locale] ?? null;
|
||||
$template = $templates['sms.'.$type.'-'.$locale] ?? null;
|
||||
|
||||
if (is_null($template)) {
|
||||
$template = [
|
||||
'message' => Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl')->render(),
|
||||
'message' => Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl')->render(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1750,11 +1707,10 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1762,11 +1718,11 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
}
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$template = $templates['email.' . $type . '-' . $locale] ?? null;
|
||||
$template = $templates['email.'.$type.'-'.$locale] ?? null;
|
||||
|
||||
$localeObj = new Locale($locale);
|
||||
if (is_null($template)) {
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
|
||||
$message = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl');
|
||||
$message = $message
|
||||
->setParam('{{hello}}', $localeObj->getText("emails.{$type}.hello"))
|
||||
->setParam('{{name}}', '')
|
||||
@@ -1781,12 +1737,12 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
->render();
|
||||
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($localeObj->getText('emails.sender'), $project->getAttribute('name'));
|
||||
$from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from;
|
||||
$from = empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) : $from;
|
||||
$template = [
|
||||
'message' => $message,
|
||||
'subject' => $localeObj->getText('emails.' . $type . '.subject'),
|
||||
'subject' => $localeObj->getText('emails.'.$type.'.subject'),
|
||||
'senderEmail' => App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', ''),
|
||||
'senderName' => $from
|
||||
'senderName' => $from,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1808,12 +1764,11 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('message', '', new Text(0), 'Template message')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, string $message, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1821,8 +1776,8 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
}
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$templates['sms.' . $type . '-' . $locale] = [
|
||||
'message' => $message
|
||||
$templates['sms.'.$type.'-'.$locale] = [
|
||||
'message' => $message,
|
||||
];
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates));
|
||||
@@ -1846,7 +1801,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('senderName', '', new Text(255), 'Name of the email sender')
|
||||
->param('senderEmail', '', new Email(), 'Email of the sender')
|
||||
->param('subject', '', new Text(255), 'Email Subject')
|
||||
@@ -1855,7 +1810,6 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, string $senderName, string $senderEmail, string $subject, string $message, string $replyTo, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1863,12 +1817,12 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
}
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$templates['email.' . $type . '-' . $locale] = [
|
||||
$templates['email.'.$type.'-'.$locale] = [
|
||||
'senderName' => $senderName,
|
||||
'senderEmail' => $senderEmail,
|
||||
'subject' => $subject,
|
||||
'replyTo' => $replyTo,
|
||||
'message' => $message
|
||||
'message' => $message,
|
||||
];
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates));
|
||||
@@ -1880,7 +1834,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
'senderEmail' => $senderEmail,
|
||||
'subject' => $subject,
|
||||
'replyTo' => $replyTo,
|
||||
'message' => $message
|
||||
'message' => $message,
|
||||
]), Response::MODEL_EMAIL_TEMPLATE);
|
||||
});
|
||||
|
||||
@@ -1896,11 +1850,10 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
->label('sdk.response.model', Response::MODEL_SMS_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1908,20 +1861,20 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
}
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$template = $templates['sms.' . $type . '-' . $locale] ?? null;
|
||||
$template = $templates['sms.'.$type.'-'.$locale] ?? null;
|
||||
|
||||
if (is_null($template)) {
|
||||
throw new Exception(Exception::PROJECT_TEMPLATE_DEFAULT_DELETION);
|
||||
}
|
||||
|
||||
unset($template['sms.' . $type . '-' . $locale]);
|
||||
unset($template['sms.'.$type.'-'.$locale]);
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates));
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'type' => $type,
|
||||
'locale' => $locale,
|
||||
'message' => $template['message']
|
||||
'message' => $template['message'],
|
||||
]), Response::MODEL_SMS_TEMPLATE);
|
||||
});
|
||||
|
||||
@@ -1937,11 +1890,10 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
->label('sdk.response.model', Response::MODEL_EMAIL_TEMPLATE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $locale, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
@@ -1949,13 +1901,13 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
}
|
||||
|
||||
$templates = $project->getAttribute('templates', []);
|
||||
$template = $templates['email.' . $type . '-' . $locale] ?? null;
|
||||
$template = $templates['email.'.$type.'-'.$locale] ?? null;
|
||||
|
||||
if (is_null($template)) {
|
||||
throw new Exception(Exception::PROJECT_TEMPLATE_DEFAULT_DELETION);
|
||||
}
|
||||
|
||||
unset($templates['email.' . $type . '-' . $locale]);
|
||||
unset($templates['email.'.$type.'-'.$locale]);
|
||||
|
||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('templates', $templates));
|
||||
|
||||
@@ -1966,6 +1918,6 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
'senderEmail' => $template['senderEmail'],
|
||||
'subject' => $template['subject'],
|
||||
'replyTo' => $template['replyTo'],
|
||||
'message' => $template['message']
|
||||
'message' => $template['message'],
|
||||
]), Response::MODEL_EMAIL_TEMPLATE);
|
||||
});
|
||||
|
||||
+140
-166
@@ -4,28 +4,27 @@ use Appwrite\Auth\Auth;
|
||||
use Appwrite\ClamAV\Network;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Buckets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Files;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Exception\Authorization as AuthorizationException;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Buckets;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Files;
|
||||
use Utopia\Image\Image;
|
||||
use Utopia\Storage\Compression\Algorithms\GZIP;
|
||||
use Utopia\Storage\Compression\Algorithms\Zstd;
|
||||
@@ -35,14 +34,13 @@ use Utopia\Storage\Validator\File;
|
||||
use Utopia\Storage\Validator\FileExt;
|
||||
use Utopia\Storage\Validator\FileSize;
|
||||
use Utopia\Storage\Validator\Upload;
|
||||
use Utopia\Swoole\Request;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\HexColor;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Swoole\Request;
|
||||
|
||||
App::post('/v1/storage/buckets')
|
||||
->desc('Create bucket')
|
||||
@@ -63,16 +61,15 @@ App::post('/v1/storage/buckets')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
|
||||
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$bucketId = $bucketId === 'unique()' ? ID::unique() : $bucketId;
|
||||
|
||||
// Map aggregate permissions into the multiple permissions they represent.
|
||||
@@ -97,7 +94,7 @@ App::post('/v1/storage/buckets')
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -128,14 +125,13 @@ App::post('/v1/storage/buckets')
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity);
|
||||
$dbForProject->createCollection('bucket_'.$bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity);
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
;
|
||||
->setParam('bucketId', $bucket->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -153,15 +149,14 @@ App::get('/v1/storage/buckets')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_BUCKET_LIST)
|
||||
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -203,7 +198,6 @@ App::get('/v1/storage/buckets/:bucketId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $bucketId, Response $response, Database $dbForProject) {
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
if ($bucket->isEmpty()) {
|
||||
@@ -232,11 +226,11 @@ App::put('/v1/storage/buckets/:bucketId')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
|
||||
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is '.Storage::human((int) App::getEnv('_APP_STORAGE_LIMIT', 0), 0).'. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' extensions are allowed, each 64 characters long.', true)
|
||||
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of '.COMPRESSION_TYPE_NONE.', ['.COMPRESSION_TYPE_GZIP.'](https://en.wikipedia.org/wiki/Gzip), or ['.COMPRESSION_TYPE_ZSTD.'](https://en.wikipedia.org/wiki/Zstd), For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' compression is skipped even if it\'s enabled', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above '.Storage::human(APP_STORAGE_READ_BUFFER, 0).' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above '.Storage::human(APP_LIMIT_ANTIVIRUS, 0).' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
@@ -271,11 +265,10 @@ App::put('/v1/storage/buckets/:bucketId')
|
||||
->setAttribute('encryption', $encryption)
|
||||
->setAttribute('compression', $compression)
|
||||
->setAttribute('antivirus', $antivirus));
|
||||
$dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity);
|
||||
$dbForProject->updateCollection('bucket_'.$bucket->getInternalId(), $permissions, $fileSecurity);
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
;
|
||||
->setParam('bucketId', $bucket->getId());
|
||||
|
||||
$response->dynamic($bucket, Response::MODEL_BUCKET);
|
||||
});
|
||||
@@ -305,7 +298,7 @@ App::delete('/v1/storage/buckets/:bucketId')
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('buckets', $bucketId)) {
|
||||
if (! $dbForProject->deleteDocument('buckets', $bucketId)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove bucket from DB');
|
||||
}
|
||||
|
||||
@@ -315,8 +308,7 @@ App::delete('/v1/storage/buckets/:bucketId')
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setPayload($response->output($bucket, Response::MODEL_BUCKET))
|
||||
;
|
||||
->setPayload($response->output($bucket, Response::MODEL_BUCKET));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -354,15 +346,14 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
->inject('deviceFiles')
|
||||
->inject('deviceLocal')
|
||||
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$validator = new Authorization(Database::PERMISSION_CREATE);
|
||||
if (!$validator->isValid($bucket->getCreate())) {
|
||||
if (! $validator->isValid($bucket->getCreate())) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -378,7 +369,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
// Add permissions for current the user if none were provided.
|
||||
if (\is_null($permissions)) {
|
||||
$permissions = [];
|
||||
if (!empty($user->getId())) {
|
||||
if (! empty($user->getId())) {
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
}
|
||||
@@ -387,7 +378,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = Authorization::getRoles();
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) {
|
||||
if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
@@ -399,8 +390,8 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')');
|
||||
if (! Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -411,7 +402,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Maximum bucket file size is larger than _APP_STORAGE_LIMIT');
|
||||
}
|
||||
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
// GraphQL multipart spec adds files with index keys
|
||||
@@ -433,7 +423,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$chunk = 1;
|
||||
$chunks = 1;
|
||||
|
||||
if (!empty($contentRange)) {
|
||||
if (! empty($contentRange)) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$fileSize = $request->getContentRangeSize();
|
||||
@@ -444,7 +434,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
}
|
||||
|
||||
$idValidator = new UID();
|
||||
if (!$idValidator->isValid($request->getHeader('x-appwrite-id'))) {
|
||||
if (! $idValidator->isValid($request->getHeader('x-appwrite-id'))) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_APPWRITE_ID);
|
||||
}
|
||||
|
||||
@@ -465,30 +455,30 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
// Check if file type is allowed
|
||||
$allowedFileExtensions = $bucket->getAttribute('allowedFileExtensions', []);
|
||||
$fileExt = new FileExt($allowedFileExtensions);
|
||||
if (!empty($allowedFileExtensions) && !$fileExt->isValid($fileName)) {
|
||||
if (! empty($allowedFileExtensions) && ! $fileExt->isValid($fileName)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED, 'File extension not allowed');
|
||||
}
|
||||
|
||||
// Check if file size is exceeding allowed limit
|
||||
$fileSizeValidator = new FileSize($maximumFileSize);
|
||||
if (!$fileSizeValidator->isValid($fileSize)) {
|
||||
if (! $fileSizeValidator->isValid($fileSize)) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE, 'File size not allowed');
|
||||
}
|
||||
|
||||
$upload = new Upload();
|
||||
if (!$upload->isValid($fileTmpName)) {
|
||||
if (! $upload->isValid($fileTmpName)) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE);
|
||||
}
|
||||
|
||||
// Save to storage
|
||||
$fileSize ??= $deviceLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceFiles->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root
|
||||
$path = $deviceFiles->getPath($fileId.'.'.\pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot().DIRECTORY_SEPARATOR.$bucket->getId(), $path); // Add bucket id to path after root
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
|
||||
$metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)];
|
||||
if (!$file->isEmpty()) {
|
||||
if (! $file->isEmpty()) {
|
||||
$chunks = $file->getAttribute('chunksTotal', 1);
|
||||
$metadata = $file->getAttribute('metadata', []);
|
||||
if ($chunk === -1) {
|
||||
@@ -508,7 +498,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310)
|
||||
);
|
||||
|
||||
if (!$antivirus->fileScan($path)) {
|
||||
if (! $antivirus->fileScan($path)) {
|
||||
$deviceFiles->delete($path);
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE);
|
||||
}
|
||||
@@ -542,8 +532,8 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
if (!$deviceFiles->write($path, $data, $mimeType)) {
|
||||
if (! empty($data)) {
|
||||
if (! $deviceFiles->write($path, $data, $mimeType)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to save file');
|
||||
}
|
||||
}
|
||||
@@ -587,7 +577,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
'metadata' => $metadata,
|
||||
]);
|
||||
|
||||
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
|
||||
$file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc);
|
||||
} else {
|
||||
$file = $file
|
||||
->setAttribute('$permissions', $permissions)
|
||||
@@ -602,7 +592,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
->setAttribute('metadata', $metadata)
|
||||
->setAttribute('chunksUploaded', $chunksUploaded);
|
||||
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
$file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file);
|
||||
}
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
@@ -633,13 +623,13 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
'metadata' => $metadata,
|
||||
]);
|
||||
|
||||
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
|
||||
$file = $dbForProject->createDocument('bucket_'.$bucket->getInternalId(), $doc);
|
||||
} else {
|
||||
$file = $file
|
||||
->setAttribute('chunksUploaded', $chunksUploaded)
|
||||
->setAttribute('metadata', $metadata);
|
||||
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
$file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file);
|
||||
}
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
@@ -653,8 +643,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setParam('fileId', $file->getId())
|
||||
->setContext('bucket', $bucket)
|
||||
;
|
||||
->setContext('bucket', $bucket);
|
||||
|
||||
$metadata = null; // was causing leaks as it was passed by reference
|
||||
|
||||
@@ -676,29 +665,28 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE_LIST)
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Files::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $bucketId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -709,10 +697,10 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
/** @var Query $cursor */
|
||||
$fileId = $cursor->getValue();
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$cursorDocument = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$cursorDocument = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($cursorDocument->isEmpty()) {
|
||||
@@ -724,12 +712,12 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$files = $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries);
|
||||
$total = $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$files = $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries);
|
||||
$total = $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
|
||||
} else {
|
||||
$files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries));
|
||||
$total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT));
|
||||
$files = Authorization::skip(fn () => $dbForProject->find('bucket_'.$bucket->getInternalId(), $queries));
|
||||
$total = Authorization::skip(fn () => $dbForProject->count('bucket_'.$bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT));
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
@@ -756,24 +744,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -802,7 +789,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
->param('fileId', '', new UID(), 'File ID')
|
||||
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
|
||||
->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true)
|
||||
->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of ' . implode(",", Image::getGravityTypes()), true)
|
||||
->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of '.implode(',', Image::getGravityTypes()), true)
|
||||
->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true)
|
||||
->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true)
|
||||
->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true)
|
||||
@@ -819,21 +806,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
->inject('deviceFiles')
|
||||
->inject('deviceLocal')
|
||||
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceFiles, Device $deviceLocal) {
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
if (! \extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -845,10 +831,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$outputs = Config::getParam('storage-outputs');
|
||||
$fileLogos = Config::getParam('storage-logos');
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -860,8 +846,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$algorithm = $file->getAttribute('algorithm', 'none');
|
||||
$cipher = $file->getAttribute('openSSLCipher');
|
||||
$mime = $file->getAttribute('mimeType');
|
||||
if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) {
|
||||
if (!\in_array($mime, $inputs)) {
|
||||
if (! \in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) App::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) {
|
||||
if (! \in_array($mime, $inputs)) {
|
||||
$path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default'];
|
||||
} else {
|
||||
// it was an image but the file size exceeded the limit
|
||||
@@ -875,7 +861,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$deviceFiles = $deviceLocal;
|
||||
}
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
if (! $deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -885,14 +871,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type;
|
||||
}
|
||||
|
||||
|
||||
$source = $deviceFiles->read($path);
|
||||
|
||||
if (!empty($cipher)) { // Decrypt
|
||||
if (! empty($cipher)) { // Decrypt
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -914,23 +899,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
|
||||
$image->crop((int) $width, (int) $height, $gravity);
|
||||
|
||||
if (!empty($opacity) || $opacity === 0) {
|
||||
if (! empty($opacity) || $opacity === 0) {
|
||||
$image->setOpacity($opacity);
|
||||
}
|
||||
|
||||
if (!empty($background)) {
|
||||
$image->setBackground('#' . $background);
|
||||
if (! empty($background)) {
|
||||
$image->setBackground('#'.$background);
|
||||
}
|
||||
|
||||
if (!empty($borderWidth)) {
|
||||
$image->setBorder($borderWidth, '#' . $borderColor);
|
||||
if (! empty($borderWidth)) {
|
||||
$image->setBorder($borderWidth, '#'.$borderColor);
|
||||
}
|
||||
|
||||
if (!empty($borderRadius)) {
|
||||
if (! empty($borderRadius)) {
|
||||
$image->setBorderRadius($borderRadius);
|
||||
}
|
||||
|
||||
if (!empty($rotation)) {
|
||||
if (! empty($rotation)) {
|
||||
$image->setRotation(($rotation + 360) % 360);
|
||||
}
|
||||
|
||||
@@ -939,10 +924,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'];
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30).' GMT')
|
||||
->setContentType($contentType)
|
||||
->file($data)
|
||||
;
|
||||
->file($data);
|
||||
|
||||
unset($image);
|
||||
});
|
||||
@@ -967,24 +951,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Device $deviceFiles) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -993,21 +976,20 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
if (! $deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path);
|
||||
}
|
||||
|
||||
$response
|
||||
->setContentType($file->getAttribute('mimeType'))
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->addHeader('X-Peak', \memory_get_peak_usage())
|
||||
->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"')
|
||||
;
|
||||
->addHeader('Content-Disposition', 'attachment; filename="'.$file->getAttribute('name', '').'"');
|
||||
|
||||
$size = $file->getAttribute('sizeOriginal', 0);
|
||||
|
||||
$rangeHeader = $request->getHeader('range');
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$start = $request->getRangeStart();
|
||||
$end = $request->getRangeEnd();
|
||||
$unit = $request->getRangeUnit();
|
||||
@@ -1022,18 +1004,18 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
|
||||
$response
|
||||
->addHeader('Accept-Ranges', 'bytes')
|
||||
->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size)
|
||||
->addHeader('Content-Range', 'bytes '.$start.'-'.$end.'/'.$size)
|
||||
->addHeader('Content-Length', $end - $start + 1)
|
||||
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
|
||||
}
|
||||
|
||||
$source = '';
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -1057,14 +1039,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($source)) {
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($source)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send(substr($source, $start, ($end - $start + 1)));
|
||||
}
|
||||
$response->send($source);
|
||||
}
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send($deviceFiles->read($path, $start, ($end - $start + 1)));
|
||||
}
|
||||
|
||||
@@ -1105,24 +1087,23 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceFiles) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -1133,8 +1114,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
if (! $deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in '.$path);
|
||||
}
|
||||
|
||||
$contentType = 'text/plain';
|
||||
@@ -1147,15 +1128,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
->setContentType($contentType)
|
||||
->addHeader('Content-Security-Policy', 'script-src none;')
|
||||
->addHeader('X-Content-Type-Options', 'nosniff')
|
||||
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('X-Peak', \memory_get_peak_usage())
|
||||
;
|
||||
->addHeader('Content-Disposition', 'inline; filename="'.$file->getAttribute('name', '').'"')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->addHeader('X-Peak', \memory_get_peak_usage());
|
||||
|
||||
$size = $file->getAttribute('sizeOriginal', 0);
|
||||
|
||||
$rangeHeader = $request->getHeader('range');
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$start = $request->getRangeStart();
|
||||
$end = $request->getRangeEnd();
|
||||
$unit = $request->getRangeUnit();
|
||||
@@ -1176,12 +1156,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
}
|
||||
|
||||
$source = '';
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
if (! empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
@@ -1205,14 +1185,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($source)) {
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($source)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send(substr($source, $start, ($end - $start + 1)));
|
||||
}
|
||||
$response->send($source);
|
||||
}
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
if (! empty($rangeHeader)) {
|
||||
$response->send($deviceFiles->read($path, $start, ($end - $start + 1)));
|
||||
}
|
||||
|
||||
@@ -1262,22 +1242,21 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->inject('mode')
|
||||
->inject('events')
|
||||
->action(function (string $bucketId, string $fileId, ?string $name, ?array $permissions, Response $response, Database $dbForProject, Document $user, string $mode, Event $events) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttributes('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_UPDATE);
|
||||
$valid = $validator->isValid($bucket->getUpdate());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// Read permission should not be required for update
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
@@ -1292,7 +1271,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = Authorization::getRoles();
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles) && !\is_null($permissions)) {
|
||||
if (! Auth::isAppUser($roles) && ! Auth::isPrivilegedUser($roles) && ! \is_null($permissions)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
@@ -1304,8 +1283,8 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')');
|
||||
if (! Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: ('.\implode(', ', $roles).')');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1317,25 +1296,24 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
|
||||
$file->setAttribute('$permissions', $permissions);
|
||||
|
||||
if (!is_null($name)) {
|
||||
if (! is_null($name)) {
|
||||
$file->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
if ($fileSecurity && ! $valid) {
|
||||
try {
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
$file = $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file);
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
|
||||
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_'.$bucket->getInternalId(), $fileId, $file));
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setParam('fileId', $file->getId())
|
||||
->setContext('bucket', $bucket)
|
||||
;
|
||||
->setContext('bucket', $bucket);
|
||||
|
||||
$response->dynamic($file, Response::MODEL_FILE);
|
||||
});
|
||||
@@ -1368,26 +1346,26 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $events, string $mode, Device $deviceFiles, Delete $deletes) {
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttributes('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_DELETE);
|
||||
$valid = $validator->isValid($bucket->getDelete());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
// Read permission should not be required for delete
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Make sure we don't delete the file before the document permission check occurs
|
||||
if ($fileSecurity && !$valid && !$validator->isValid($file->getDelete())) {
|
||||
if ($fileSecurity && ! $valid && ! $validator->isValid($file->getDelete())) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@@ -1404,20 +1382,19 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
if ($deviceDeleted) {
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_CACHE_BY_RESOURCE)
|
||||
->setResource('file/' . $fileId)
|
||||
;
|
||||
->setResource('file/'.$fileId);
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
if ($fileSecurity && ! $valid) {
|
||||
try {
|
||||
$deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
$deleted = $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} catch (AuthorizationException) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
} else {
|
||||
$deleted = Authorization::skip(fn() => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if (!$deleted) {
|
||||
if (! $deleted) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove file from DB');
|
||||
}
|
||||
} else {
|
||||
@@ -1428,8 +1405,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
->setParam('bucketId', $bucket->getId())
|
||||
->setParam('fileId', $file->getId())
|
||||
->setContext('bucket', $bucket)
|
||||
->setPayload($response->output($file, Response::MODEL_FILE))
|
||||
;
|
||||
->setPayload($response->output($file, Response::MODEL_FILE));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -1448,7 +1424,6 @@ App::get('/v1/storage/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$periods = Config::getParam('usage', []);
|
||||
$stats = $usage = [];
|
||||
$days = $periods[$range];
|
||||
@@ -1518,7 +1493,6 @@ App::get('/v1/storage/:bucketId/usage')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $bucketId, string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
if ($bucket->isEmpty()) {
|
||||
|
||||
@@ -9,14 +9,10 @@ use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Phone as EventPhone;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Utopia\Validator\Host;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Teams;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use MaxMind\Db\Reader;
|
||||
@@ -24,20 +20,24 @@ use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Authorization as AuthorizationException;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Host;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
App::post('/v1/teams')
|
||||
@@ -56,20 +56,19 @@ App::post('/v1/teams')
|
||||
->label('sdk.response.model', Response::MODEL_TEAM)
|
||||
->param('teamId', '', new CustomId(), 'Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
|
||||
->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', true)
|
||||
->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.', true)
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Event $events) {
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||
|
||||
$teamId = $teamId == 'unique()' ? ID::unique() : $teamId;
|
||||
|
||||
try {
|
||||
$team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([
|
||||
$team = Authorization::skip(fn () => $dbForProject->createDocument('teams', new Document([
|
||||
'$id' => $teamId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::team($teamId)),
|
||||
@@ -85,8 +84,8 @@ App::post('/v1/teams')
|
||||
throw new Exception(Exception::TEAM_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode
|
||||
if (!\in_array('owner', $roles)) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser) { // Don't add user on server mode
|
||||
if (! \in_array('owner', $roles)) {
|
||||
$roles[] = 'owner';
|
||||
}
|
||||
|
||||
@@ -110,7 +109,7 @@ App::post('/v1/teams')
|
||||
'joined' => DateTime::now(),
|
||||
'confirm' => true,
|
||||
'secret' => '',
|
||||
'search' => implode(' ', [$membershipId, $user->getId()])
|
||||
'search' => implode(' ', [$membershipId, $user->getId()]),
|
||||
]);
|
||||
|
||||
$membership = $dbForProject->createDocument('memberships', $membership);
|
||||
@@ -119,7 +118,7 @@ App::post('/v1/teams')
|
||||
|
||||
$events->setParam('teamId', $team->getId());
|
||||
|
||||
if (!empty($user->getId())) {
|
||||
if (! empty($user->getId())) {
|
||||
$events->setParam('userId', $user->getId());
|
||||
}
|
||||
|
||||
@@ -140,15 +139,14 @@ App::get('/v1/teams')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TEAM_LIST)
|
||||
->label('sdk.offline.model', '/teams')
|
||||
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -195,7 +193,6 @@ App::get('/v1/teams/:teamId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -221,7 +218,6 @@ App::get('/v1/teams/:teamId/prefs')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -256,7 +252,6 @@ App::put('/v1/teams/:teamId')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -298,7 +293,6 @@ App::put('/v1/teams/:teamId/prefs')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -331,14 +325,13 @@ App::delete('/v1/teams/:teamId')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('teams', $teamId)) {
|
||||
if (! $dbForProject->deleteDocument('teams', $teamId)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB');
|
||||
}
|
||||
|
||||
@@ -348,8 +341,7 @@ App::delete('/v1/teams/:teamId')
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setPayload($response->output($team, Response::MODEL_TEAM))
|
||||
;
|
||||
->setPayload($response->output($team, Response::MODEL_TEAM));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -375,8 +367,8 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->param('email', '', new Email(), 'Email of the new team member.', true)
|
||||
->param('userId', '', new UID(), 'ID of the user to be added to a team.', true)
|
||||
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
|
||||
->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.')
|
||||
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
|
||||
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
@@ -387,14 +379,13 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->inject('messaging')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, EventPhone $messaging, Event $events) {
|
||||
|
||||
if (empty($userId) && empty($email) && empty($phone)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'At least one of userId, email, or phone is required');
|
||||
}
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||
|
||||
if (!$isPrivilegedUser && !$isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
if (! $isPrivilegedUser && ! $isAppUser && empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
throw new Exception(Exception::GENERAL_SMTP_DISABLED);
|
||||
}
|
||||
|
||||
@@ -405,28 +396,28 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
}
|
||||
if (!empty($userId)) {
|
||||
if (! empty($userId)) {
|
||||
$invitee = $dbForProject->getDocument('users', $userId);
|
||||
if ($invitee->isEmpty()) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND, 'User with given userId doesn\'t exist.', 404);
|
||||
}
|
||||
if (!empty($email) && $invitee->getAttribute('email', '') !== $email) {
|
||||
if (! empty($email) && $invitee->getAttribute('email', '') !== $email) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and email doesn\'t match', 409);
|
||||
}
|
||||
if (!empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
|
||||
if (! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and phone doesn\'t match', 409);
|
||||
}
|
||||
$email = $invitee->getAttribute('email', '');
|
||||
$phone = $invitee->getAttribute('phone', '');
|
||||
$name = empty($name) ? $invitee->getAttribute('name', '') : $name;
|
||||
} elseif (!empty($email)) {
|
||||
} elseif (! empty($email)) {
|
||||
$invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address
|
||||
if (!empty($invitee) && !empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
|
||||
if (! empty($invitee) && ! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given email and phone doesn\'t match', 409);
|
||||
}
|
||||
} elseif (!empty($phone)) {
|
||||
} elseif (! empty($phone)) {
|
||||
$invitee = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]);
|
||||
if (!empty($invitee) && !empty($email) && $invitee->getAttribute('email', '') !== $email) {
|
||||
if (! empty($invitee) && ! empty($email) && $invitee->getAttribute('email', '') !== $email) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given phone and email doesn\'t match', 409);
|
||||
}
|
||||
}
|
||||
@@ -446,13 +437,13 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) {
|
||||
if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
try {
|
||||
$userId = ID::unique();
|
||||
$invitee = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([
|
||||
$invitee = Authorization::skip(fn () => $dbForProject->createDocument('users', new Document([
|
||||
'$id' => $userId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
@@ -480,16 +471,16 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name])
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
])));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');
|
||||
$isOwner = Authorization::isRole('team:'.$team->getId().'/owner');
|
||||
|
||||
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
|
||||
if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team');
|
||||
}
|
||||
|
||||
@@ -514,17 +505,17 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
'joined' => ($isPrivilegedUser || $isAppUser) ? DateTime::now() : null,
|
||||
'confirm' => ($isPrivilegedUser || $isAppUser),
|
||||
'secret' => Auth::hash($secret),
|
||||
'search' => implode(' ', [$membershipId, $invitee->getId()])
|
||||
'search' => implode(' ', [$membershipId, $invitee->getId()]),
|
||||
]);
|
||||
|
||||
if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership
|
||||
try {
|
||||
$membership = Authorization::skip(fn() => $dbForProject->createDocument('memberships', $membership));
|
||||
$membership = Authorization::skip(fn () => $dbForProject->createDocument('memberships', $membership));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::TEAM_INVITE_ALREADY_EXISTS);
|
||||
}
|
||||
$team->setAttribute('total', $team->getAttribute('total', 0) + 1);
|
||||
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
$team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $invitee->getId());
|
||||
} else {
|
||||
@@ -537,16 +528,16 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
$url = Template::parseURL($url);
|
||||
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]);
|
||||
$url = Template::unParseURL($url);
|
||||
if (!empty($email)) {
|
||||
if (! empty($email)) {
|
||||
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
|
||||
|
||||
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
|
||||
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
|
||||
$subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName);
|
||||
$body = Template::fromFile(__DIR__.'/../../config/locale/templates/email-base.tpl');
|
||||
$subject = \sprintf($locale->getText('emails.invitation.subject'), $team->getAttribute('name'), $projectName);
|
||||
|
||||
$smtpEnabled = $project->getAttribute('smtp', [])['enabled'] ?? false;
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? [];
|
||||
if ($smtpEnabled && !empty($customTemplate)) {
|
||||
$customTemplate = $project->getAttribute('templates', [])['email.invitation-'.$locale->default] ?? [];
|
||||
if ($smtpEnabled && ! empty($customTemplate)) {
|
||||
$body = $customTemplate['message'];
|
||||
$subject = $customTemplate['subject'];
|
||||
$from = $customTemplate['senderName'];
|
||||
@@ -557,13 +548,13 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
|
||||
$body
|
||||
->setParam('{{subject}}', $subject)
|
||||
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
|
||||
->setParam('{{hello}}', $locale->getText('emails.invitation.hello'))
|
||||
->setParam('{{name}}', $user->getAttribute('name'))
|
||||
->setParam('{{body}}', $locale->getText("emails.invitation.body"))
|
||||
->setParam('{{body}}', $locale->getText('emails.invitation.body'))
|
||||
->setParam('{{redirect}}', $url)
|
||||
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
|
||||
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
|
||||
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"))
|
||||
->setParam('{{footer}}', $locale->getText('emails.invitation.footer'))
|
||||
->setParam('{{thanks}}', $locale->getText('emails.invitation.thanks'))
|
||||
->setParam('{{signature}}', $locale->getText('emails.invitation.signature'))
|
||||
->setParam('{{project}}', $projectName)
|
||||
->setParam('{{direction}}', $locale->getText('settings.direction'))
|
||||
->setParam('{{bg-body}}', '#f7f7f7')
|
||||
@@ -578,13 +569,12 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
->setFrom($from)
|
||||
->setRecipient($invitee->getAttribute('email'))
|
||||
->setName($invitee->getAttribute('name'))
|
||||
->trigger()
|
||||
;
|
||||
} elseif (!empty($phone)) {
|
||||
$message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl');
|
||||
->trigger();
|
||||
} elseif (! empty($phone)) {
|
||||
$message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl');
|
||||
|
||||
$customTemplate = $project->getAttribute('templates', [])['sms.invitation-' . $locale->default] ?? [];
|
||||
if (!empty($customTemplate)) {
|
||||
$customTemplate = $project->getAttribute('templates', [])['sms.invitation-'.$locale->default] ?? [];
|
||||
if (! empty($customTemplate)) {
|
||||
$message = $customTemplate['message'];
|
||||
}
|
||||
|
||||
@@ -600,8 +590,7 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setParam('membershipId', $membership->getId())
|
||||
;
|
||||
->setParam('membershipId', $membership->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -627,12 +616,11 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST)
|
||||
->label('sdk.offline.model', '/teams/{teamId}/memberships')
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -641,7 +629,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -676,7 +664,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
max: APP_LIMIT_COUNT
|
||||
);
|
||||
|
||||
$memberships = array_filter($memberships, fn(Document $membership) => !empty($membership->getAttribute('userId')));
|
||||
$memberships = array_filter($memberships, fn (Document $membership) => ! empty($membership->getAttribute('userId')));
|
||||
|
||||
$memberships = array_map(function ($membership) use ($dbForProject, $team) {
|
||||
$user = $dbForProject->getDocument('users', $membership->getAttribute('userId'));
|
||||
@@ -684,8 +672,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
$membership
|
||||
->setAttribute('teamName', $team->getAttribute('name'))
|
||||
->setAttribute('userName', $user->getAttribute('name'))
|
||||
->setAttribute('userEmail', $user->getAttribute('email'))
|
||||
;
|
||||
->setAttribute('userEmail', $user->getAttribute('email'));
|
||||
|
||||
return $membership;
|
||||
}, $memberships);
|
||||
@@ -714,7 +701,6 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -732,8 +718,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
||||
$membership
|
||||
->setAttribute('teamName', $team->getAttribute('name'))
|
||||
->setAttribute('userName', $user->getAttribute('name'))
|
||||
->setAttribute('userEmail', $user->getAttribute('email'))
|
||||
;
|
||||
->setAttribute('userEmail', $user->getAttribute('email'));
|
||||
|
||||
$response->dynamic($membership, Response::MODEL_MEMBERSHIP);
|
||||
});
|
||||
@@ -754,14 +739,13 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
|
||||
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
@@ -779,9 +763,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||
$isOwner = Authorization::isRole('team:' . $team->getId() . '/owner');
|
||||
$isOwner = Authorization::isRole('team:'.$team->getId().'/owner');
|
||||
|
||||
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
|
||||
if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to modify roles');
|
||||
}
|
||||
|
||||
@@ -848,7 +832,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH);
|
||||
}
|
||||
|
||||
$team = Authorization::skip(fn() => $dbForProject->getDocument('teams', $teamId));
|
||||
$team = Authorization::skip(fn () => $dbForProject->getDocument('teams', $teamId));
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
@@ -859,7 +843,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
}
|
||||
|
||||
if ($userId !== $membership->getAttribute('userId')) {
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')');
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')');
|
||||
}
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -867,7 +851,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
}
|
||||
|
||||
if ($membership->getAttribute('userId') !== $user->getId()) {
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')');
|
||||
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')');
|
||||
}
|
||||
|
||||
if ($membership->getAttribute('confirm') === true) {
|
||||
@@ -876,10 +860,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
|
||||
$membership // Attach user to team
|
||||
->setAttribute('joined', DateTime::now())
|
||||
->setAttribute('confirm', true)
|
||||
;
|
||||
->setAttribute('confirm', true);
|
||||
|
||||
Authorization::skip(fn() => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true)));
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true)));
|
||||
|
||||
// Log user in
|
||||
|
||||
@@ -917,23 +900,20 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
|
||||
$team = Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setParam('membershipId', $membership->getId())
|
||||
;
|
||||
->setParam('membershipId', $membership->getId());
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
if (! Config::getParam('domainVerification')) {
|
||||
$response
|
||||
->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]))
|
||||
;
|
||||
->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)]));
|
||||
}
|
||||
|
||||
$response
|
||||
->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
;
|
||||
->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'));
|
||||
|
||||
$response->dynamic(
|
||||
$membership
|
||||
@@ -963,7 +943,6 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$membership = $dbForProject->getDocument('memberships', $membershipId);
|
||||
|
||||
if ($membership->isEmpty()) {
|
||||
@@ -998,14 +977,13 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
|
||||
if ($membership->getAttribute('confirm')) { // Count only confirmed members
|
||||
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0));
|
||||
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
Authorization::skip(fn () => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
}
|
||||
|
||||
$events
|
||||
->setParam('teamId', $team->getId())
|
||||
->setParam('membershipId', $membership->getId())
|
||||
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP))
|
||||
;
|
||||
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
@@ -1028,7 +1006,6 @@ App::get('/v1/teams/:teamId/logs')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $teamId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -1041,13 +1018,13 @@ App::get('/v1/teams/:teamId/logs')
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
|
||||
$audit = new Audit($dbForProject);
|
||||
$resource = 'team/' . $team->getId();
|
||||
$resource = 'team/'.$team->getId();
|
||||
$logs = $audit->getLogsByResource($resource, $limit, $offset);
|
||||
|
||||
$output = [];
|
||||
|
||||
foreach ($logs as $i => &$log) {
|
||||
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
$log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
|
||||
$detector = new Detector($log['userAgent']);
|
||||
$detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
|
||||
@@ -1075,14 +1052,14 @@ App::get('/v1/teams/:teamId/logs')
|
||||
'clientEngineVersion' => $client['clientEngineVersion'],
|
||||
'deviceName' => $device['deviceName'],
|
||||
'deviceBrand' => $device['deviceBrand'],
|
||||
'deviceModel' => $device['deviceModel']
|
||||
'deviceModel' => $device['deviceModel'],
|
||||
]);
|
||||
|
||||
$record = $geodb->get($log['ip']);
|
||||
|
||||
if ($record) {
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
} else {
|
||||
$output[$i]['countryCode'] = '--';
|
||||
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||
|
||||
@@ -2,43 +2,43 @@
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Auth\Validator\PasswordDictionary;
|
||||
use Appwrite\Auth\Validator\PasswordHistory;
|
||||
use Appwrite\Auth\Validator\PersonalData;
|
||||
use Appwrite\Auth\Validator\Phone;
|
||||
use Appwrite\Detector\Detector;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Identities;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Users;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Appwrite\Utopia\Response;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Locale\Locale;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Boolean;
|
||||
use MaxMind\Db\Reader;
|
||||
use Utopia\Validator\Integer;
|
||||
use Appwrite\Auth\Validator\PasswordHistory;
|
||||
use Appwrite\Auth\Validator\PasswordDictionary;
|
||||
use Appwrite\Auth\Validator\PersonalData;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
/** TODO: Remove function when we move to using utopia/platform */
|
||||
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $events): Document
|
||||
@@ -46,14 +46,14 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
$hashOptionsObject = (\is_string($hashOptions)) ? \json_decode($hashOptions, true) : $hashOptions; // Cast to JSON array
|
||||
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
|
||||
|
||||
if (!empty($email)) {
|
||||
if (! empty($email)) {
|
||||
$email = \strtolower($email);
|
||||
|
||||
// Makes sure this email is not already used in another identity
|
||||
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) {
|
||||
if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
@@ -65,12 +65,12 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
|
||||
if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) {
|
||||
$personalDataValidator = new PersonalData($userId, $email, $name, $phone);
|
||||
if (!$personalDataValidator->isValid($password)) {
|
||||
if (! $personalDataValidator->isValid($password)) {
|
||||
throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
$password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null;
|
||||
$password = (! empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null;
|
||||
$user = $dbForProject->createDocument('users', new Document([
|
||||
'$id' => $userId,
|
||||
'$permissions' => [
|
||||
@@ -86,7 +86,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
'labels' => [],
|
||||
'password' => $password,
|
||||
'passwordHistory' => is_null($password) && $passwordHistory === 0 ? [] : [$password],
|
||||
'passwordUpdate' => (!empty($password)) ? DateTime::now() : null,
|
||||
'passwordUpdate' => (! empty($password)) ? DateTime::now() : null,
|
||||
'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash,
|
||||
'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash],
|
||||
'registration' => DateTime::now(),
|
||||
@@ -96,7 +96,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $phone, $name])
|
||||
'search' => implode(' ', [$userId, $email, $phone, $name]),
|
||||
]));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
@@ -131,7 +131,6 @@ App::post('/v1/users')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $events);
|
||||
|
||||
$response
|
||||
@@ -255,8 +254,8 @@ App::post('/v1/users/sha')
|
||||
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
|
||||
$options = '{}';
|
||||
|
||||
if (!empty($passwordVersion)) {
|
||||
$options = '{"version":"' . $passwordVersion . '"}';
|
||||
if (! empty($passwordVersion)) {
|
||||
$options = '{"version":"'.$passwordVersion.'"}';
|
||||
}
|
||||
|
||||
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $project, $dbForProject, $events);
|
||||
@@ -329,7 +328,7 @@ App::post('/v1/users/scrypt')
|
||||
'costCpu' => $passwordCpu,
|
||||
'costMemory' => $passwordMemory,
|
||||
'costParallel' => $passwordParallel,
|
||||
'length' => $passwordLength
|
||||
'length' => $passwordLength,
|
||||
];
|
||||
|
||||
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $project, $dbForProject, $events);
|
||||
@@ -365,7 +364,7 @@ App::post('/v1/users/scrypt-modified')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
|
||||
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
|
||||
$user = createUser('scryptMod', '{"signerKey":"'.$passwordSignerKey.'","saltSeparator":"'.$passwordSaltSeparator.'","salt":"'.$passwordSalt.'"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -406,7 +405,7 @@ App::post('/v1/users/:userId/targets')
|
||||
|
||||
$target = $dbForProject->getDocument('targets', $targetId);
|
||||
|
||||
if (!$target->isEmpty()) {
|
||||
if (! $target->isEmpty()) {
|
||||
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
@@ -414,7 +413,7 @@ App::post('/v1/users/:userId/targets')
|
||||
'$id' => $targetId,
|
||||
// TO DO: what permissions should be given when created a target.
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any())
|
||||
Permission::read(Role::any()),
|
||||
],
|
||||
'providerId' => $providerId,
|
||||
'providerInternalId' => $provider->getInternalId(),
|
||||
@@ -442,15 +441,14 @@ App::get('/v1/users')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER_LIST)
|
||||
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Users::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -492,7 +490,6 @@ App::get('/v1/users/:userId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -517,7 +514,6 @@ App::get('/v1/users/:userId/prefs')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -545,7 +541,6 @@ App::get('/v1/users/:userId/targets/:targetId')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, string $targetId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -577,7 +572,6 @@ App::get('/v1/users/:userId/sessions')
|
||||
->inject('dbForProject')
|
||||
->inject('locale')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Locale $locale) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -588,8 +582,7 @@ App::get('/v1/users/:userId/sessions')
|
||||
|
||||
foreach ($sessions as $key => $session) {
|
||||
/** @var Document $session */
|
||||
|
||||
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||
$session->setAttribute('countryName', $countryName);
|
||||
$session->setAttribute('current', false);
|
||||
|
||||
@@ -617,7 +610,6 @@ App::get('/v1/users/:userId/memberships')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -659,7 +651,6 @@ App::get('/v1/users/:userId/logs')
|
||||
->inject('locale')
|
||||
->inject('geodb')
|
||||
->action(function (string $userId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -678,7 +669,7 @@ App::get('/v1/users/:userId/logs')
|
||||
$output = [];
|
||||
|
||||
foreach ($logs as $i => &$log) {
|
||||
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
$log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||
|
||||
$detector = new Detector($log['userAgent']);
|
||||
$detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
|
||||
@@ -702,14 +693,14 @@ App::get('/v1/users/:userId/logs')
|
||||
'clientEngineVersion' => $client['clientEngineVersion'],
|
||||
'deviceName' => $device['deviceName'],
|
||||
'deviceBrand' => $device['deviceBrand'],
|
||||
'deviceModel' => $device['deviceModel']
|
||||
'deviceModel' => $device['deviceModel'],
|
||||
]);
|
||||
|
||||
$record = $geodb->get($log['ip']);
|
||||
|
||||
if ($record) {
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||
} else {
|
||||
$output[$i]['countryCode'] = '--';
|
||||
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||
@@ -737,7 +728,6 @@ App::get('/v1/users/:userId/targets')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -763,15 +753,14 @@ App::get('/v1/users/identities')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_IDENTITY_LIST)
|
||||
->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Identities::ALLOWED_ATTRIBUTES), true)
|
||||
->param('queries', [], new Identities(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Identities::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
|
||||
$queries = Query::parseQueries($queries);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (! empty($search)) {
|
||||
$queries[] = Query::search('search', $search);
|
||||
}
|
||||
|
||||
@@ -819,7 +808,6 @@ App::patch('/v1/users/:userId/status')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $status, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -856,7 +844,6 @@ App::put('/v1/users/:userId/labels')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, array $labels, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -893,7 +880,6 @@ App::patch('/v1/users/:userId/verification')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -928,7 +914,6 @@ App::patch('/v1/users/:userId/verification/phone')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $phoneVerification, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -964,7 +949,6 @@ App::patch('/v1/users/:userId/name')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $name, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1002,7 +986,6 @@ App::patch('/v1/users/:userId/password')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1011,7 +994,7 @@ App::patch('/v1/users/:userId/password')
|
||||
|
||||
if ($project->getAttribute('auths', [])['personalDataCheck'] ?? false) {
|
||||
$personalDataValidator = new PersonalData($userId, $user->getAttribute('email'), $user->getAttribute('name'), $user->getAttribute('phone'));
|
||||
if (!$personalDataValidator->isValid($password)) {
|
||||
if (! $personalDataValidator->isValid($password)) {
|
||||
throw new Exception(Exception::USER_PASSWORD_PERSONAL_DATA);
|
||||
}
|
||||
}
|
||||
@@ -1022,7 +1005,7 @@ App::patch('/v1/users/:userId/password')
|
||||
$history = $user->getAttribute('passwordHistory', []);
|
||||
if ($historyLimit > 0) {
|
||||
$validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions'));
|
||||
if (!$validator->isValid($password)) {
|
||||
if (! $validator->isValid($password)) {
|
||||
throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED);
|
||||
}
|
||||
|
||||
@@ -1065,7 +1048,6 @@ App::patch('/v1/users/:userId/email')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $email, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1079,15 +1061,13 @@ App::patch('/v1/users/:userId/email')
|
||||
Query::equal('providerEmail', [$email]),
|
||||
Query::notEqual('userId', $user->getId()),
|
||||
]);
|
||||
if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) {
|
||||
if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) {
|
||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$user
|
||||
->setAttribute('email', $email)
|
||||
->setAttribute('emailVerification', false)
|
||||
;
|
||||
|
||||
->setAttribute('emailVerification', false);
|
||||
|
||||
try {
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
@@ -1120,7 +1100,6 @@ App::patch('/v1/users/:userId/phone')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $number, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1129,8 +1108,7 @@ App::patch('/v1/users/:userId/phone')
|
||||
|
||||
$user
|
||||
->setAttribute('phone', $number)
|
||||
->setAttribute('phoneVerification', false)
|
||||
;
|
||||
->setAttribute('phoneVerification', false);
|
||||
|
||||
try {
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
@@ -1164,7 +1142,6 @@ App::patch('/v1/users/:userId/verification')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, bool $emailVerification, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1196,7 +1173,6 @@ App::patch('/v1/users/:userId/prefs')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, array $prefs, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1230,7 +1206,6 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $targetId, string $userId, string $identifier, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1276,7 +1251,6 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, string $sessionId, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1318,7 +1292,6 @@ App::delete('/v1/users/:userId/sessions')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1361,7 +1334,6 @@ App::delete('/v1/users/:userId')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1402,7 +1374,6 @@ App::delete('/v1/users/:userId/targets/:targetId')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $targetId, string $userId, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
@@ -1449,7 +1420,6 @@ App::delete('/v1/users/identities/:identityId')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->action(function (string $identityId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
|
||||
|
||||
$identity = $dbForProject->getDocument('identities', $identityId);
|
||||
|
||||
if ($identity->isEmpty()) {
|
||||
@@ -1476,7 +1446,6 @@ App::get('/v1/users/usage')
|
||||
->inject('dbForProject')
|
||||
->inject('register')
|
||||
->action(function (string $range, Response $response, Database $dbForProject) {
|
||||
|
||||
$periods = Config::getParam('usage', []);
|
||||
$stats = $usage = [];
|
||||
$days = $periods[$range];
|
||||
@@ -1509,22 +1478,22 @@ App::get('/v1/users/usage')
|
||||
'1d' => 'Y-m-d\T00:00:00.000P',
|
||||
};
|
||||
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
foreach ($metrics as $metric) {
|
||||
$usage[$metric] = [];
|
||||
$leap = time() - ($days['limit'] * $days['factor']);
|
||||
while ($leap < time()) {
|
||||
$leap += $days['factor'];
|
||||
$formatDate = date($format, $leap);
|
||||
$usage[$metric][] = [
|
||||
'value' => $stats[$metric][$formatDate]['value'] ?? 0,
|
||||
'date' => $formatDate,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'range' => $range,
|
||||
'usersTotal' => $usage[$metrics[0]],
|
||||
'usersTotal' => $usage[$metrics[0]],
|
||||
'sessionsTotal' => $usage[$metrics[1]],
|
||||
]), Response::MODEL_USAGE_USERS);
|
||||
});
|
||||
|
||||
+76
-81
@@ -1,38 +1,38 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\View;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Domains\Domain;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Request\Filters\V12 as RequestV12;
|
||||
use Appwrite\Utopia\Request\Filters\V13 as RequestV13;
|
||||
use Appwrite\Utopia\Request\Filters\V14 as RequestV14;
|
||||
use Appwrite\Utopia\Request\Filters\V15 as RequestV15;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
||||
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
|
||||
use Appwrite\Utopia\Response\Filters\V13 as ResponseV13;
|
||||
use Appwrite\Utopia\Response\Filters\V14 as ResponseV14;
|
||||
use Appwrite\Utopia\Response\Filters\V15 as ResponseV15;
|
||||
use Appwrite\Utopia\View;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Appwrite\Utopia\Request\Filters\V12 as RequestV12;
|
||||
use Appwrite\Utopia\Request\Filters\V13 as RequestV13;
|
||||
use Appwrite\Utopia\Request\Filters\V14 as RequestV14;
|
||||
use Appwrite\Utopia\Request\Filters\V15 as RequestV15;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -84,12 +84,12 @@ App::init()
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$domains = Config::getParam('domains', []);
|
||||
if (!array_key_exists($domain, $domains)) {
|
||||
$domain = new Domain(!empty($domain) ? $domain : '');
|
||||
if (! array_key_exists($domain, $domains)) {
|
||||
$domain = new Domain(! empty($domain) ? $domain : '');
|
||||
|
||||
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
|
||||
if (empty($domain->get()) || ! $domain->isKnown() || $domain->isTest()) {
|
||||
$domains[$domain->get()] = false;
|
||||
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||
Console::warning($domain->get().' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||
} elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
||||
Console::warning('Skipping SSL certificates generation on ACME challenge.');
|
||||
} else {
|
||||
@@ -97,7 +97,7 @@ App::init()
|
||||
|
||||
$envDomain = App::getEnv('_APP_DOMAIN', '');
|
||||
$mainDomain = null;
|
||||
if (!empty($envDomain) && $envDomain !== 'localhost') {
|
||||
if (! empty($envDomain) && $envDomain !== 'localhost') {
|
||||
$mainDomain = $envDomain;
|
||||
} else {
|
||||
$domainDocument = $dbForConsole->findOne('domains', [Query::orderAsc('_id')]);
|
||||
@@ -105,13 +105,13 @@ App::init()
|
||||
}
|
||||
|
||||
if ($mainDomain !== $domain->get()) {
|
||||
Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.');
|
||||
Console::warning($domain->get().' is not a main domain. Skipping SSL certificate generation.');
|
||||
} else {
|
||||
$domainDocument = $dbForConsole->findOne('domains', [
|
||||
Query::equal('domain', [$domain->get()])
|
||||
Query::equal('domain', [$domain->get()]),
|
||||
]);
|
||||
|
||||
if (!$domainDocument) {
|
||||
if (! $domainDocument) {
|
||||
$domainDocument = new Document([
|
||||
'domain' => $domain->get(),
|
||||
'tld' => $domain->getSuffix(),
|
||||
@@ -122,7 +122,7 @@ App::init()
|
||||
|
||||
$domainDocument = $dbForConsole->createDocument('domains', $domainDocument);
|
||||
|
||||
Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...');
|
||||
Console::info('Issuing a TLS certificate for the main domain ('.$domain->get().') in a few seconds...');
|
||||
|
||||
(new Certificate())
|
||||
->setDomain($domainDocument)
|
||||
@@ -145,7 +145,7 @@ App::init()
|
||||
throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) {
|
||||
if (! empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) {
|
||||
throw new AppwriteException(AppwriteException::PROJECT_UNKNOWN);
|
||||
}
|
||||
|
||||
@@ -160,14 +160,14 @@ App::init()
|
||||
$refDomainOrigin = $origin;
|
||||
}
|
||||
|
||||
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : '');
|
||||
$refDomain = (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$refDomainOrigin.(! empty($port) ? ':'.$port : '');
|
||||
|
||||
$refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible
|
||||
$refDomain = (! $route->getLabel('origin', false)) // This route is publicly accessible
|
||||
? $refDomain
|
||||
: (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
|
||||
: (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$origin.(! empty($port) ? ':'.$port : '');
|
||||
|
||||
$selfDomain = new Domain($request->getHostname());
|
||||
$endDomain = new Domain((string)$origin);
|
||||
$endDomain = new Domain((string) $origin);
|
||||
|
||||
Config::setParam(
|
||||
'domainVerification',
|
||||
@@ -175,7 +175,7 @@ App::init()
|
||||
$endDomain->getRegisterable() !== ''
|
||||
);
|
||||
|
||||
$isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:' . $request->getPort();
|
||||
$isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:'.$request->getPort();
|
||||
$isIpAddress = filter_var($request->getHostname(), FILTER_VALIDATE_IP) !== false;
|
||||
|
||||
$isConsoleProject = $project->getAttribute('$id', '') === 'console';
|
||||
@@ -186,8 +186,8 @@ App::init()
|
||||
$isLocalHost || $isIpAddress
|
||||
? null
|
||||
: ($isConsoleProject && $isConsoleRootSession
|
||||
? '.' . $selfDomain->getRegisterable()
|
||||
: '.' . $request->getHostname()
|
||||
? '.'.$selfDomain->getRegisterable()
|
||||
: '.'.$request->getHostname()
|
||||
)
|
||||
);
|
||||
|
||||
@@ -231,12 +231,12 @@ App::init()
|
||||
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP.');
|
||||
}
|
||||
|
||||
return $response->redirect('https://' . $request->getHostname() . $request->getURI());
|
||||
return $response->redirect('https://'.$request->getHostname().$request->getURI());
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->getProtocol() === 'https') {
|
||||
$response->addHeader('Strict-Transport-Security', 'max-age=' . (60 * 60 * 24 * 126)); // 126 days
|
||||
$response->addHeader('Strict-Transport-Security', 'max-age='.(60 * 60 * 24 * 126)); // 126 days
|
||||
}
|
||||
|
||||
$response
|
||||
@@ -246,8 +246,7 @@ App::init()
|
||||
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma')
|
||||
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
|
||||
->addHeader('Access-Control-Allow-Origin', $refDomain)
|
||||
->addHeader('Access-Control-Allow-Credentials', 'true')
|
||||
;
|
||||
->addHeader('Access-Control-Allow-Credentials', 'true');
|
||||
|
||||
/*
|
||||
* Validate Client Domain - Check to avoid CSRF attack
|
||||
@@ -258,7 +257,7 @@ App::init()
|
||||
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||
|
||||
if (
|
||||
!$originValidator->isValid($origin)
|
||||
! $originValidator->isValid($origin)
|
||||
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
|
||||
&& $route->getLabel('origin', false) !== '*'
|
||||
&& empty($request->getHeader('x-appwrite-key', ''))
|
||||
@@ -298,7 +297,7 @@ App::init()
|
||||
|
||||
$authKey = $request->getHeader('x-appwrite-key', '');
|
||||
|
||||
if (!empty($authKey)) { // API Key authentication
|
||||
if (! empty($authKey)) { // API Key authentication
|
||||
// Check if given key match project API keys
|
||||
$key = $project->find('secret', $authKey, 'keys');
|
||||
|
||||
@@ -310,7 +309,7 @@ App::init()
|
||||
$user = new Document([
|
||||
'$id' => '',
|
||||
'status' => true,
|
||||
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
|
||||
'email' => 'app.'.$project->getId().'@service.'.$request->getHostname(),
|
||||
'password' => '',
|
||||
'name' => $project->getAttribute('name', 'Untitled'),
|
||||
]);
|
||||
@@ -319,8 +318,8 @@ App::init()
|
||||
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
|
||||
|
||||
$expire = $key->getAttribute('expire');
|
||||
if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
|
||||
throw new AppwriteException(AppwriteException:: PROJECT_KEY_EXPIRED);
|
||||
if (! empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
|
||||
throw new AppwriteException(AppwriteException::PROJECT_KEY_EXPIRED);
|
||||
}
|
||||
|
||||
Authorization::setRole(Auth::USER_ROLE_APPS);
|
||||
@@ -337,7 +336,7 @@ App::init()
|
||||
$sdk = $request->getHeader('x-sdk-name', 'UNKNOWN');
|
||||
if ($sdkValidator->isValid($sdk)) {
|
||||
$sdks = $key->getAttribute('sdks', []);
|
||||
if (!in_array($sdk, $sdks)) {
|
||||
if (! in_array($sdk, $sdks)) {
|
||||
array_push($sdks, $sdk);
|
||||
$key->setAttribute('sdks', $sdks);
|
||||
|
||||
@@ -357,22 +356,22 @@ App::init()
|
||||
}
|
||||
|
||||
$service = $route->getLabel('sdk.namespace', '');
|
||||
if (!empty($service)) {
|
||||
if (! empty($service)) {
|
||||
if (
|
||||
array_key_exists($service, $project->getAttribute('services', []))
|
||||
&& !$project->getAttribute('services', [])[$service]
|
||||
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
|
||||
&& ! $project->getAttribute('services', [])[$service]
|
||||
&& ! (Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
|
||||
) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (!\in_array($scope, $scopes)) {
|
||||
if (! \in_array($scope, $scopes)) {
|
||||
if ($project->isEmpty()) { // Check if permission is denied because project is missing
|
||||
throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')');
|
||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User').' (role: '.\strtolower($roles[$role]['label']).') missing scope ('.$scope.')');
|
||||
}
|
||||
|
||||
if (false === $user->getAttribute('status')) { // Account is blocked
|
||||
@@ -388,7 +387,6 @@ App::options()
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (Request $request, Response $response) {
|
||||
|
||||
$origin = $request->getOrigin();
|
||||
|
||||
$response
|
||||
@@ -410,7 +408,6 @@ App::error()
|
||||
->inject('logger')
|
||||
->inject('loggerBreadcrumbs')
|
||||
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, array $loggerBreadcrumbs) {
|
||||
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
$route = $utopia->match($request);
|
||||
|
||||
@@ -425,11 +422,11 @@ App::error()
|
||||
|
||||
$log = new Utopia\Logger\Log();
|
||||
|
||||
if (isset($user) && !$user->isEmpty()) {
|
||||
if (isset($user) && ! $user->isEmpty()) {
|
||||
$log->setUser(new User($user->getId()));
|
||||
}
|
||||
|
||||
$log->setNamespace("http");
|
||||
$log->setNamespace('http');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -442,7 +439,7 @@ App::error()
|
||||
$log->addTag('code', $error->getCode());
|
||||
$log->addTag('projectId', $project->getId());
|
||||
$log->addTag('hostname', $request->getHostname());
|
||||
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
$log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
|
||||
$log->addExtra('file', $error->getFile());
|
||||
$log->addExtra('line', $error->getLine());
|
||||
@@ -450,7 +447,7 @@ App::error()
|
||||
$log->addExtra('detailedTrace', $error->getTrace());
|
||||
$log->addExtra('roles', Authorization::getRoles());
|
||||
|
||||
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
|
||||
$action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD');
|
||||
$log->setAction($action);
|
||||
|
||||
$isProduction = App::getEnv('_APP_ENV', 'development') === 'production';
|
||||
@@ -461,7 +458,7 @@ App::error()
|
||||
}
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Log pushed with status code: ' . $responseCode);
|
||||
Console::info('Log pushed with status code: '.$responseCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,17 +469,17 @@ App::error()
|
||||
$trace = $error->getTrace();
|
||||
|
||||
if (php_sapi_name() === 'cli') {
|
||||
Console::error('[Error] Timestamp: ' . date('c', time()));
|
||||
Console::error('[Error] Timestamp: '.date('c', time()));
|
||||
|
||||
if ($route) {
|
||||
Console::error('[Error] Method: ' . $route->getMethod());
|
||||
Console::error('[Error] URL: ' . $route->getPath());
|
||||
Console::error('[Error] Method: '.$route->getMethod());
|
||||
Console::error('[Error] URL: '.$route->getPath());
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: ' . get_class($error));
|
||||
Console::error('[Error] Message: ' . $message);
|
||||
Console::error('[Error] File: ' . $file);
|
||||
Console::error('[Error] Line: ' . $line);
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
Console::error('[Error] Message: '.$message);
|
||||
Console::error('[Error] File: '.$file);
|
||||
Console::error('[Error] Line: '.$line);
|
||||
}
|
||||
|
||||
/** Handle Utopia Errors */
|
||||
@@ -503,7 +500,7 @@ App::error()
|
||||
}
|
||||
|
||||
/** Wrap all exceptions inside Appwrite\Extend\Exception */
|
||||
if (!($error instanceof AppwriteException)) {
|
||||
if (! ($error instanceof AppwriteException)) {
|
||||
$error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error);
|
||||
}
|
||||
|
||||
@@ -548,8 +545,7 @@ App::error()
|
||||
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
|
||||
->addHeader('Expires', '0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->setStatusCode($code)
|
||||
;
|
||||
->setStatusCode($code);
|
||||
|
||||
$template = ($route) ? $route->getLabel('error', null) : null;
|
||||
|
||||
@@ -557,15 +553,14 @@ App::error()
|
||||
$layout = new View($template);
|
||||
|
||||
$layout
|
||||
->setParam('title', $project->getAttribute('name') . ' - Error')
|
||||
->setParam('title', $project->getAttribute('name').' - Error')
|
||||
->setParam('development', App::isDevelopment())
|
||||
->setParam('projectName', $project->getAttribute('name'))
|
||||
->setParam('projectURL', $project->getAttribute('url'))
|
||||
->setParam('message', $error->getMessage())
|
||||
->setParam('type', $type)
|
||||
->setParam('code', $code)
|
||||
->setParam('trace', $trace)
|
||||
;
|
||||
->setParam('trace', $trace);
|
||||
|
||||
$response->html($layout->render());
|
||||
}
|
||||
@@ -582,7 +577,7 @@ App::get('/robots.txt')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$template = new View(__DIR__ . '/../views/general/robots.phtml');
|
||||
$template = new View(__DIR__.'/../views/general/robots.phtml');
|
||||
$response->text($template->render(false));
|
||||
});
|
||||
|
||||
@@ -592,7 +587,7 @@ App::get('/humans.txt')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
$template = new View(__DIR__ . '/../views/general/humans.phtml');
|
||||
$template = new View(__DIR__.'/../views/general/humans.phtml');
|
||||
$response->text($template->render(false));
|
||||
});
|
||||
|
||||
@@ -611,43 +606,43 @@ App::get('/.well-known/acme-challenge/*')
|
||||
...Text::ALPHABET_LOWER,
|
||||
...Text::ALPHABET_UPPER,
|
||||
'-',
|
||||
'_'
|
||||
'_',
|
||||
]);
|
||||
|
||||
if (!$validator->isValid($token) || \count($uriChunks) !== 4) {
|
||||
if (! $validator->isValid($token) || \count($uriChunks) !== 4) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, 'Invalid challenge token.');
|
||||
}
|
||||
|
||||
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
||||
$absolute = \realpath($base . '/.well-known/acme-challenge/' . $token);
|
||||
$absolute = \realpath($base.'/.well-known/acme-challenge/'.$token);
|
||||
|
||||
if (!$base) {
|
||||
if (! $base) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Storage error');
|
||||
}
|
||||
|
||||
if (!$absolute) {
|
||||
if (! $absolute) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
||||
}
|
||||
|
||||
if (!\substr($absolute, 0, \strlen($base)) === $base) {
|
||||
if (! \substr($absolute, 0, \strlen($base)) === $base) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, 'Invalid path');
|
||||
}
|
||||
|
||||
if (!\file_exists($absolute)) {
|
||||
if (! \file_exists($absolute)) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
||||
}
|
||||
|
||||
$content = @\file_get_contents($absolute);
|
||||
|
||||
if (!$content) {
|
||||
if (! $content) {
|
||||
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Failed to get contents');
|
||||
}
|
||||
|
||||
$response->text($content);
|
||||
});
|
||||
|
||||
include_once __DIR__ . '/shared/api.php';
|
||||
include_once __DIR__ . '/shared/api/auth.php';
|
||||
include_once __DIR__.'/shared/api.php';
|
||||
include_once __DIR__.'/shared/api/auth.php';
|
||||
|
||||
foreach (Config::getParam('services', []) as $service) {
|
||||
include_once $service['controller'];
|
||||
|
||||
+27
-42
@@ -3,18 +3,18 @@
|
||||
global $utopia, $request, $response;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Validator\Host;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Storage\Validator\File;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Storage\Validator\File;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Host;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
App::get('/v1/mock/tests/foo')
|
||||
->desc('Get Foo')
|
||||
@@ -220,9 +220,9 @@ App::get('/v1/mock/tests/general/headers')
|
||||
'x-sdk-version' => $request->getHeader('x-sdk-version'),
|
||||
];
|
||||
$res = array_map(function ($key, $value) {
|
||||
return $key . ': ' . $value;
|
||||
return $key.': '.$value;
|
||||
}, array_keys($res), $res);
|
||||
$res = implode("; ", $res);
|
||||
$res = implode('; ', $res);
|
||||
|
||||
$response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK);
|
||||
});
|
||||
@@ -241,14 +241,12 @@ App::get('/v1/mock/tests/general/download')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setContentType('text/plain')
|
||||
->addHeader('Content-Disposition', 'attachment; filename="test.txt"')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT') // 45 days cache
|
||||
->addHeader('X-Peak', \memory_get_peak_usage())
|
||||
->send("GET:/v1/mock/tests/general/download:passed")
|
||||
;
|
||||
->send('GET:/v1/mock/tests/general/download:passed');
|
||||
});
|
||||
|
||||
App::post('/v1/mock/tests/general/upload')
|
||||
@@ -271,14 +269,13 @@ App::post('/v1/mock/tests/general/upload')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (string $x, int $y, array $z, mixed $file, Request $request, Response $response) {
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
$contentRange = $request->getHeader('content-range');
|
||||
|
||||
$chunkSize = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
if (!empty($contentRange)) {
|
||||
if (! empty($contentRange)) {
|
||||
$start = $request->getContentRangeStart();
|
||||
$end = $request->getContentRangeEnd();
|
||||
$size = $request->getContentRangeSize();
|
||||
@@ -293,7 +290,7 @@ App::post('/v1/mock/tests/general/upload')
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Invalid content-range header');
|
||||
}
|
||||
|
||||
if ($start === 0 && !empty($id)) {
|
||||
if ($start === 0 && ! empty($id)) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'First chunked request cannot have id header');
|
||||
}
|
||||
|
||||
@@ -317,7 +314,7 @@ App::post('/v1/mock/tests/general/upload')
|
||||
$response->json([
|
||||
'$id' => ID::custom('newfileid'),
|
||||
'chunksTotal' => (int) ceil($size / ($end + 1 - $start)),
|
||||
'chunksUploaded' => ceil($start / $chunkSize) + 1
|
||||
'chunksUploaded' => ceil($start / $chunkSize) + 1,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
@@ -330,7 +327,7 @@ App::post('/v1/mock/tests/general/upload')
|
||||
}
|
||||
|
||||
if ($file['size'] !== 38756) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size');
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Wrong file size');
|
||||
}
|
||||
|
||||
if (\md5(\file_get_contents($file['tmp_name'])) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
|
||||
@@ -353,7 +350,6 @@ App::get('/v1/mock/tests/general/redirect')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->redirect('/v1/mock/tests/general/redirect/done');
|
||||
});
|
||||
|
||||
@@ -387,7 +383,6 @@ App::get('/v1/mock/tests/general/set-cookie')
|
||||
->inject('response')
|
||||
->inject('request')
|
||||
->action(function (Response $response, Request $request) {
|
||||
|
||||
$response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', $request->getHostname(), true, true);
|
||||
});
|
||||
|
||||
@@ -405,7 +400,6 @@ App::get('/v1/mock/tests/general/get-cookie')
|
||||
->label('sdk.mock', true)
|
||||
->inject('request')
|
||||
->action(function (Request $request) {
|
||||
|
||||
if ($request->getCookie('cookieName', '') !== 'cookieValue') {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Missing cookie value');
|
||||
}
|
||||
@@ -424,7 +418,6 @@ App::get('/v1/mock/tests/general/empty')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
@@ -465,9 +458,9 @@ App::get('/v1/mock/tests/general/headers')
|
||||
'x-sdk-version' => $request->getHeader('x-sdk-version'),
|
||||
];
|
||||
$res = array_map(function ($key, $value) {
|
||||
return $key . ': ' . $value;
|
||||
return $key.': '.$value;
|
||||
}, array_keys($res), $res);
|
||||
$res = implode("; ", $res);
|
||||
$res = implode('; ', $res);
|
||||
|
||||
$response->dynamic(new Document(['result' => $res]), Response::MODEL_MOCK);
|
||||
});
|
||||
@@ -518,11 +511,9 @@ App::get('/v1/mock/tests/general/502-error')
|
||||
->label('sdk.mock', true)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setStatusCode(502)
|
||||
->text('This is a text error')
|
||||
;
|
||||
->text('This is a text error');
|
||||
});
|
||||
|
||||
App::get('/v1/mock/tests/general/oauth2')
|
||||
@@ -537,8 +528,7 @@ App::get('/v1/mock/tests/general/oauth2')
|
||||
->param('state', '', new Text(1024), 'OAuth2 state.')
|
||||
->inject('response')
|
||||
->action(function (string $client_id, string $redirectURI, string $scope, string $state, Response $response) {
|
||||
|
||||
$response->redirect($redirectURI . '?' . \http_build_query(['code' => 'abcdef', 'state' => $state]));
|
||||
$response->redirect($redirectURI.'?'.\http_build_query(['code' => 'abcdef', 'state' => $state]));
|
||||
});
|
||||
|
||||
App::get('/v1/mock/tests/general/oauth2/token')
|
||||
@@ -555,7 +545,6 @@ App::get('/v1/mock/tests/general/oauth2/token')
|
||||
->param('refresh_token', '', new Text(100), 'OAuth2 refresh token.', true)
|
||||
->inject('response')
|
||||
->action(function (string $client_id, string $client_secret, string $grantType, string $redirectURI, string $code, string $refreshToken, Response $response) {
|
||||
|
||||
if ($client_id != '1') {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Invalid client ID');
|
||||
}
|
||||
@@ -567,7 +556,7 @@ App::get('/v1/mock/tests/general/oauth2/token')
|
||||
$responseJson = [
|
||||
'access_token' => '123456',
|
||||
'refresh_token' => 'tuvwxyz',
|
||||
'expires_in' => 14400
|
||||
'expires_in' => 14400,
|
||||
];
|
||||
|
||||
if ($grantType === 'authorization_code') {
|
||||
@@ -595,7 +584,6 @@ App::get('/v1/mock/tests/general/oauth2/user')
|
||||
->param('token', '', new Text(100), 'OAuth2 Access Token.')
|
||||
->inject('response')
|
||||
->action(function (string $token, Response $response) {
|
||||
|
||||
if ($token != '123456') {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Invalid token');
|
||||
}
|
||||
@@ -614,7 +602,6 @@ App::get('/v1/mock/tests/general/oauth2/success')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response->json([
|
||||
'result' => 'success',
|
||||
]);
|
||||
@@ -627,7 +614,6 @@ App::get('/v1/mock/tests/general/oauth2/failure')
|
||||
->label('docs', false)
|
||||
->inject('response')
|
||||
->action(function (Response $response) {
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_BAD_REQUEST)
|
||||
->json([
|
||||
@@ -641,23 +627,22 @@ App::shutdown()
|
||||
->inject('response')
|
||||
->inject('request')
|
||||
->action(function (App $utopia, Response $response, Request $request) {
|
||||
|
||||
$result = [];
|
||||
$route = $utopia->match($request);
|
||||
$path = APP_STORAGE_CACHE . '/tests.json';
|
||||
$tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : [];
|
||||
$route = $utopia->match($request);
|
||||
$path = APP_STORAGE_CACHE.'/tests.json';
|
||||
$tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : [];
|
||||
|
||||
if (!\is_array($tests)) {
|
||||
if (! \is_array($tests)) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Failed to read results', 500);
|
||||
}
|
||||
|
||||
$result[$route->getMethod() . ':' . $route->getPath()] = true;
|
||||
$result[$route->getMethod().':'.$route->getPath()] = true;
|
||||
|
||||
$tests = \array_merge($tests, $result);
|
||||
|
||||
if (!\file_put_contents($path, \json_encode($tests), LOCK_EX)) {
|
||||
if (! \file_put_contents($path, \json_encode($tests), LOCK_EX)) {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Failed to save results', 500);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK);
|
||||
$response->dynamic(new Document(['result' => $route->getMethod().':'.$route->getPath().':passed']), Response::MODEL_MOCK);
|
||||
});
|
||||
|
||||
@@ -7,14 +7,14 @@ use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\App;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Database\Database;
|
||||
@@ -36,7 +36,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
|
||||
$replace = $parts[1] ?? '';
|
||||
|
||||
$params = match ($namespace) {
|
||||
'user' => (array)$user,
|
||||
'user' => (array) $user,
|
||||
'request' => $requestParams,
|
||||
default => $responsePayload,
|
||||
};
|
||||
@@ -45,11 +45,11 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
|
||||
$label = \str_replace($find, $params[$replace], $label);
|
||||
}
|
||||
}
|
||||
|
||||
return $label;
|
||||
};
|
||||
|
||||
$databaseListener = function (string $event, Document $document, Document $project, Usage $queueForUsage, Database $dbForProject) {
|
||||
|
||||
$value = 1;
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$value = -1;
|
||||
@@ -81,13 +81,13 @@ $databaseListener = function (string $event, Document $document, Document $proje
|
||||
->addReduce($document);
|
||||
}
|
||||
break;
|
||||
case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections
|
||||
case str_starts_with($document->getCollection(), 'database_') && ! str_contains($document->getCollection(), 'collection'): //collections
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_COLLECTIONS, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value) // per database
|
||||
;
|
||||
;
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$queueForUsage
|
||||
@@ -96,7 +96,7 @@ $databaseListener = function (string $event, Document $document, Document $proje
|
||||
break;
|
||||
case str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_'): //documents
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_DOCUMENTS, $value) // per project
|
||||
@@ -132,13 +132,13 @@ $databaseListener = function (string $event, Document $document, Document $proje
|
||||
->addMetric(METRIC_DEPLOYMENTS, $value) // per project
|
||||
->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project
|
||||
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value)// per function
|
||||
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);// per function
|
||||
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value); // per function
|
||||
|
||||
break;
|
||||
case $document->getCollection() === 'executions':
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_EXECUTIONS, $value) // per project
|
||||
->addMetric(str_replace('{functionInternalId}', $document->getAttribute('functionInternalId'), METRIC_FUNCTION_ID_EXECUTIONS), $value);// per function
|
||||
->addMetric(str_replace('{functionInternalId}', $document->getAttribute('functionInternalId'), METRIC_FUNCTION_ID_EXECUTIONS), $value); // per function
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -161,7 +161,6 @@ App::init()
|
||||
->inject('mode')
|
||||
->inject('mails')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Usage $queueForUsage, string $mode, Mail $mails) use ($databaseListener) {
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
if ($project->isEmpty() && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope
|
||||
@@ -174,7 +173,7 @@ App::init()
|
||||
$abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}');
|
||||
$timeLimitArray = [];
|
||||
|
||||
$abuseKeyLabel = (!is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel;
|
||||
$abuseKeyLabel = (! is_array($abuseKeyLabel)) ? [$abuseKeyLabel] : $abuseKeyLabel;
|
||||
|
||||
foreach ($abuseKeyLabel as $abuseKey) {
|
||||
$timeLimit = new TimeLimit($abuseKey, $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForProject);
|
||||
@@ -182,7 +181,7 @@ App::init()
|
||||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
->setParam('{ip}', $request->getIP())
|
||||
->setParam('{url}', $request->getHostname() . $route->getPath())
|
||||
->setParam('{url}', $request->getHostname().$route->getPath())
|
||||
->setParam('{method}', $request->getMethod());
|
||||
$timeLimitArray[] = $timeLimit;
|
||||
}
|
||||
@@ -195,8 +194,8 @@ App::init()
|
||||
|
||||
foreach ($timeLimitArray as $timeLimit) {
|
||||
foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys
|
||||
if (!empty($value)) {
|
||||
$timeLimit->setParam('{param-' . $key . '}', (\is_array($value)) ? \json_encode($value) : $value);
|
||||
if (! empty($value)) {
|
||||
$timeLimit->setParam('{param-'.$key.'}', (\is_array($value)) ? \json_encode($value) : $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,16 +209,15 @@ App::init()
|
||||
$response
|
||||
->addHeader('X-RateLimit-Limit', $limit)
|
||||
->addHeader('X-RateLimit-Remaining', $remaining)
|
||||
->addHeader('X-RateLimit-Reset', $time)
|
||||
;
|
||||
->addHeader('X-RateLimit-Reset', $time);
|
||||
}
|
||||
|
||||
$enabled = App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled';
|
||||
|
||||
if (
|
||||
$enabled // Abuse is enabled
|
||||
&& !$isAppUser // User is not API key
|
||||
&& !$isPrivilegedUser // User is not an admin
|
||||
&& ! $isAppUser // User is not API key
|
||||
&& ! $isPrivilegedUser // User is not an admin
|
||||
&& $abuse->check() // Route is rate-limited
|
||||
) {
|
||||
throw new Exception(Exception::GENERAL_RATE_LIMIT_EXCEEDED);
|
||||
@@ -243,7 +241,7 @@ App::init()
|
||||
->setUser($user);
|
||||
|
||||
$smtp = $project->getAttribute('smtp', []);
|
||||
if (!empty($smtp) && ($smtp['enabled'] ?? false)) {
|
||||
if (! empty($smtp) && ($smtp['enabled'] ?? false)) {
|
||||
$mails
|
||||
->setSmtpHost($smtp['host'] ?? '')
|
||||
->setSmtpPort($smtp['port'] ?? 25)
|
||||
@@ -265,14 +263,14 @@ App::init()
|
||||
$useCache = $route->getLabel('cache', false);
|
||||
|
||||
if ($useCache) {
|
||||
$key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER;
|
||||
$key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER;
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
|
||||
new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId())
|
||||
);
|
||||
$timestamp = 60 * 60 * 24 * 30;
|
||||
$data = $cache->load($key, $timestamp);
|
||||
|
||||
if (!empty($data)) {
|
||||
if (! empty($data)) {
|
||||
$data = json_decode($data, true);
|
||||
$parts = explode('/', $data['resourceType']);
|
||||
$type = $parts[0] ?? null;
|
||||
@@ -282,24 +280,24 @@ App::init()
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
if ($bucket->isEmpty() || (! $bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
if (! $fileSecurity && ! $valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$parts = explode('/', $data['resource']);
|
||||
$fileId = $parts[1] ?? null;
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($fileSecurity && ! $valid) {
|
||||
$file = $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_'.$bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
@@ -308,11 +306,10 @@ App::init()
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT')
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp).' GMT')
|
||||
->addHeader('X-Appwrite-Cache', 'hit')
|
||||
->setContentType($data['contentType'])
|
||||
->send(base64_decode($data['payload']))
|
||||
;
|
||||
->send(base64_decode($data['payload']));
|
||||
|
||||
$route->setIsActive(false);
|
||||
} else {
|
||||
@@ -327,7 +324,6 @@ App::init()
|
||||
->inject('request')
|
||||
->inject('project')
|
||||
->action(function (App $utopia, Request $request, Document $project) {
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
@@ -431,10 +427,9 @@ App::shutdown()
|
||||
->inject('mode')
|
||||
->inject('dbForConsole')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $events, Audit $audits, Delete $deletes, EventDatabase $database, Database $dbForProject, Func $queueForFunctions, Usage $queueForUsage, string $mode, Database $dbForConsole) use ($parseLabel) {
|
||||
|
||||
$responsePayload = $response->getPayload();
|
||||
|
||||
if (!empty($events->getEvent())) {
|
||||
if (! empty($events->getEvent())) {
|
||||
if (empty($events->getPayload())) {
|
||||
$events->setPayload($responsePayload);
|
||||
}
|
||||
@@ -483,7 +478,7 @@ App::shutdown()
|
||||
roles: $target['roles'],
|
||||
options: [
|
||||
'permissionsChanged' => $target['permissionsChanged'],
|
||||
'userId' => $events->getParam('userId')
|
||||
'userId' => $events->getParam('userId'),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -496,24 +491,24 @@ App::shutdown()
|
||||
* Audit labels
|
||||
*/
|
||||
$pattern = $route->getLabel('audits.resource', null);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$resource = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
if (!empty($resource) && $resource !== $pattern) {
|
||||
if (! empty($resource) && $resource !== $pattern) {
|
||||
$audits->setResource($resource);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$user->isEmpty()) {
|
||||
if (! $user->isEmpty()) {
|
||||
$audits->setUser($user);
|
||||
}
|
||||
|
||||
if (!empty($audits->getResource()) && !empty($audits->getUser()->getId())) {
|
||||
if (! empty($audits->getResource()) && ! empty($audits->getUser()->getId())) {
|
||||
/**
|
||||
* audits.payload is switched to default true
|
||||
* in order to auto audit payload for all endpoints
|
||||
*/
|
||||
$pattern = $route->getLabel('audits.payload', true);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$audits->setPayload($responsePayload);
|
||||
}
|
||||
|
||||
@@ -523,11 +518,11 @@ App::shutdown()
|
||||
$audits->trigger();
|
||||
}
|
||||
|
||||
if (!empty($deletes->getType())) {
|
||||
if (! empty($deletes->getType())) {
|
||||
$deletes->trigger();
|
||||
}
|
||||
|
||||
if (!empty($database->getType())) {
|
||||
if (! empty($database->getType())) {
|
||||
$database->trigger();
|
||||
}
|
||||
|
||||
@@ -539,35 +534,35 @@ App::shutdown()
|
||||
$resource = $resourceType = null;
|
||||
$data = $response->getPayload();
|
||||
|
||||
if (!empty($data['payload'])) {
|
||||
if (! empty($data['payload'])) {
|
||||
$pattern = $route->getLabel('cache.resource', null);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$resource = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
}
|
||||
|
||||
$pattern = $route->getLabel('cache.resourceType', null);
|
||||
if (!empty($pattern)) {
|
||||
if (! empty($pattern)) {
|
||||
$resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
}
|
||||
|
||||
$key = md5($request->getURI() . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER;
|
||||
$key = md5($request->getURI().implode('*', $request->getParams())).'*'.APP_CACHE_BUSTER;
|
||||
$data = json_encode([
|
||||
'resourceType' => $resourceType,
|
||||
'resource' => $resource,
|
||||
'contentType' => $response->getContentType(),
|
||||
'payload' => base64_encode($data['payload']),
|
||||
]) ;
|
||||
]);
|
||||
|
||||
$signature = md5($data);
|
||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$accessedAt = $cacheLog->getAttribute('accessedAt', '');
|
||||
$now = DateTime::now();
|
||||
if ($cacheLog->isEmpty()) {
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
|
||||
'$id' => $key,
|
||||
'resource' => $resource,
|
||||
'accessedAt' => $now,
|
||||
'signature' => $signature,
|
||||
'$id' => $key,
|
||||
'resource' => $resource,
|
||||
'accessedAt' => $now,
|
||||
'signature' => $signature,
|
||||
])));
|
||||
} elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
|
||||
$cacheLog->setAttribute('accessedAt', $now);
|
||||
@@ -576,20 +571,18 @@ App::shutdown()
|
||||
|
||||
if ($signature !== $cacheLog->getAttribute('signature')) {
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
|
||||
new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$project->getId())
|
||||
);
|
||||
$cache->save($key, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($project->getId() !== 'console') {
|
||||
if ($mode !== APP_MODE_ADMIN) {
|
||||
$fileSize = 0;
|
||||
$file = $request->getFiles('file');
|
||||
if (!empty($file)) {
|
||||
if (! empty($file)) {
|
||||
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||
}
|
||||
|
||||
@@ -607,7 +600,7 @@ App::shutdown()
|
||||
/**
|
||||
* Update user last activity
|
||||
*/
|
||||
if (!$user->isEmpty()) {
|
||||
if (! $user->isEmpty()) {
|
||||
$accessedAt = $user->getAttribute('accessedAt', '');
|
||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCCESS)) > $accessedAt) {
|
||||
$user->setAttribute('accessedAt', DateTime::now());
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\App;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
@@ -13,7 +13,6 @@ App::init()
|
||||
->inject('request')
|
||||
->inject('project')
|
||||
->action(function (App $utopia, Request $request, Document $project) {
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
|
||||
@@ -11,9 +11,9 @@ App::init()
|
||||
->action(function (Request $request, Response $response) {
|
||||
$response
|
||||
->addHeader('X-Frame-Options', 'SAMEORIGIN') // Avoid console and homepage from showing in iframes
|
||||
->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url=' . \urlencode($request->getURI()))
|
||||
->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url='.\urlencode($request->getURI()))
|
||||
->addHeader('X-UA-Compatible', 'IE=Edge') // Deny IE browsers from going into quirks mode
|
||||
;
|
||||
;
|
||||
});
|
||||
|
||||
App::get('/console/*')
|
||||
@@ -30,41 +30,41 @@ App::get('/console/*')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (Request $request, Response $response) {
|
||||
$fallback = file_get_contents(__DIR__ . '/../../../console/index.html');
|
||||
$fallback = file_get_contents(__DIR__.'/../../../console/index.html');
|
||||
|
||||
// Card SSR
|
||||
if (\str_starts_with($request->getURI(), '/card')) {
|
||||
$urlCunks = \explode('/', $request->getURI());
|
||||
$userId = $urlCunks[\count($urlCunks) - 1] ?? '';
|
||||
|
||||
$domain = $request->getProtocol() . '://' . $request->getHostname();
|
||||
$domain = $request->getProtocol().'://'.$request->getHostname();
|
||||
|
||||
if (!empty($userId)) {
|
||||
$ogImageUrl = $domain . '/v1/cards/cloud-og?userId=' . $userId;
|
||||
if (! empty($userId)) {
|
||||
$ogImageUrl = $domain.'/v1/cards/cloud-og?userId='.$userId;
|
||||
} else {
|
||||
$ogImageUrl = $domain . '/v1/cards/cloud-og?mock=normal';
|
||||
$ogImageUrl = $domain.'/v1/cards/cloud-og?mock=normal';
|
||||
}
|
||||
|
||||
$ogTags = [
|
||||
'<title>Appwrite Cloud Card</title>',
|
||||
'<meta name="description" content="Appwrite Cloud is now LIVE! Share your Cloud card for a chance to win an exclusive Cloud hoodie!">',
|
||||
'<meta property="og:url" content="' . $domain . $request->getURI() . '">',
|
||||
'<meta property="og:url" content="'.$domain.$request->getURI().'">',
|
||||
'<meta name="og:image:type" content="image/png">',
|
||||
'<meta name="og:image:width" content="1008">',
|
||||
'<meta name="og:image:height" content="1008">',
|
||||
'<meta property="og:type" content="website">',
|
||||
'<meta property="og:title" content="Appwrite Cloud Card">',
|
||||
'<meta property="og:description" content="Appwrite Cloud is now LIVE! Share your Cloud card for a chance to win an exclusive Cloud hoodie!">',
|
||||
'<meta property="og:image" content="' . $ogImageUrl . '">',
|
||||
'<meta property="og:image" content="'.$ogImageUrl.'">',
|
||||
'<meta name="twitter:card" content="summary_large_image">',
|
||||
'<meta property="twitter:domain" content="' . $request->getHostname() . '">',
|
||||
'<meta property="twitter:url" content="' . $domain . $request->getURI() . '">',
|
||||
'<meta property="twitter:domain" content="'.$request->getHostname().'">',
|
||||
'<meta property="twitter:url" content="'.$domain.$request->getURI().'">',
|
||||
'<meta name="twitter:title" content="Appwrite Cloud Card">',
|
||||
'<meta name="twitter:image:type" content="image/png">',
|
||||
'<meta name="twitter:image:width" content="1008">',
|
||||
'<meta name="twitter:image:height" content="1008">',
|
||||
'<meta name="twitter:description" content="Appwrite Cloud is now LIVE! Share your Cloud card for a chance to win an exclusive Cloud hoodie!">',
|
||||
'<meta name="twitter:image" content="' . $ogImageUrl . '">',
|
||||
'<meta name="twitter:image" content="'.$ogImageUrl.'">',
|
||||
];
|
||||
|
||||
$fallback = \str_replace('<!-- {{CLOUD_OG}} -->', \implode('', $ogTags), $fallback);
|
||||
|
||||
@@ -24,14 +24,14 @@ App::get('/versions')
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($language['enabled']) && !$language['enabled']) {
|
||||
if (isset($language['enabled']) && ! $language['enabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$platformKey = $platform['key'] ?? '';
|
||||
$languageKey = $language['key'] ?? '';
|
||||
$version = $language['version'] ?? '';
|
||||
$versions[$platformKey . '-' . $languageKey] = $version;
|
||||
$versions[$platformKey.'-'.$languageKey] = $version;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+38
-38
@@ -1,30 +1,30 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Process;
|
||||
use Swoole\Http\Server;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
use Swoole\Http\Response as SwooleResponse;
|
||||
use Swoole\Http\Server;
|
||||
use Swoole\Process;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Swoole\Files;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Swoole\Files;
|
||||
|
||||
$http = new Server("0.0.0.0", App::getEnv('PORT', 80));
|
||||
$http = new Server('0.0.0.0', App::getEnv('PORT', 80));
|
||||
|
||||
$payloadSize = 6 * (1024 * 1024); // 6MB
|
||||
$workerNumber = swoole_cpu_num() * intval(App::getEnv('_APP_WORKER_PER_CORE', 6));
|
||||
@@ -42,7 +42,7 @@ $http
|
||||
]);
|
||||
|
||||
$http->on('WorkerStart', function ($server, $workerId) {
|
||||
Console::success('Worker ' . ++$workerId . ' started successfully');
|
||||
Console::success('Worker '.++$workerId.' started successfully');
|
||||
});
|
||||
|
||||
$http->on('BeforeReload', function ($server, $workerId) {
|
||||
@@ -53,16 +53,16 @@ $http->on('AfterReload', function ($server, $workerId) {
|
||||
Console::success('Reload completed...');
|
||||
});
|
||||
|
||||
Files::load(__DIR__ . '/../console');
|
||||
Files::load(__DIR__.'/../console');
|
||||
|
||||
include __DIR__ . '/controllers/general.php';
|
||||
include __DIR__.'/controllers/general.php';
|
||||
|
||||
$http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
$app = new App('UTC');
|
||||
|
||||
go(function () use ($register, $app) {
|
||||
$pools = $register->get('pools'); /** @var Group $pools */
|
||||
App::setResource('pools', fn() => $pools);
|
||||
App::setResource('pools', fn () => $pools);
|
||||
|
||||
// wait for database to be ready
|
||||
$attempts = 0;
|
||||
@@ -77,7 +77,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
} catch (\Exception $e) {
|
||||
Console::warning("Database not ready. Retrying connection ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception('Failed to connect to database: ' . $e->getMessage());
|
||||
throw new \Exception('Failed to connect to database: '.$e->getMessage());
|
||||
}
|
||||
sleep($sleep);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
}
|
||||
|
||||
if ($dbForConsole->getCollection(TimeLimit::COLLECTION)->isEmpty()) {
|
||||
$adapter = new TimeLimit("", 0, 1, $dbForConsole);
|
||||
$adapter = new TimeLimit('', 0, 1, $dbForConsole);
|
||||
$adapter->setup();
|
||||
}
|
||||
|
||||
@@ -109,11 +109,11 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
if (($collection['$collection'] ?? '') !== Database::METADATA) {
|
||||
continue;
|
||||
}
|
||||
if (!$dbForConsole->getCollection($key)->isEmpty()) {
|
||||
if (! $dbForConsole->getCollection($key)->isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
|
||||
Console::success('[Setup] - Creating collection: '.$collection['$id'].'...');
|
||||
|
||||
$attributes = [];
|
||||
$indexes = [];
|
||||
@@ -128,7 +128,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
$dbForConsole->createCollection($key, $attributes, $indexes);
|
||||
}
|
||||
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && !$dbForConsole->exists($dbForConsole->getDefaultDatabase(), 'bucket_1')) {
|
||||
if ($dbForConsole->getDocument('buckets', 'default')->isEmpty() && ! $dbForConsole->exists($dbForConsole->getDefaultDatabase(), 'bucket_1')) {
|
||||
Console::success('[Setup] - Creating default bucket...');
|
||||
$dbForConsole->createDocument('buckets', new Document([
|
||||
'$id' => ID::custom('default'),
|
||||
@@ -188,7 +188,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
'array' => $attribute['array'],
|
||||
'filters' => $attribute['filters'],
|
||||
'default' => $attribute['default'] ?? null,
|
||||
'format' => $attribute['format'] ?? ''
|
||||
'format' => $attribute['format'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
]);
|
||||
}
|
||||
|
||||
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
||||
$dbForConsole->createCollection('bucket_'.$bucket->getInternalId(), $attributes, $indexes);
|
||||
}
|
||||
|
||||
$pools->reclaim();
|
||||
@@ -210,7 +210,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
Console::success('[Setup] - Server database init completed...');
|
||||
});
|
||||
|
||||
Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)');
|
||||
Console::success('Server started successfully (max payload is '.number_format($payloadSize).' bytes)');
|
||||
Console::info("Master pid {$http->master_pid}, manager pid {$http->manager_pid}");
|
||||
|
||||
// listen ctrl + c
|
||||
@@ -229,8 +229,8 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
|
||||
$response
|
||||
->setContentType(Files::getFileMimeType($request->getURI()))
|
||||
->addHeader('Cache-Control', 'public, max-age=' . $time)
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache
|
||||
->addHeader('Cache-Control', 'public, max-age='.$time)
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time).' GMT') // 45 days cache
|
||||
->send(Files::getFileContents($request->getURI()));
|
||||
|
||||
return;
|
||||
@@ -239,7 +239,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
$app = new App('UTC');
|
||||
|
||||
$pools = $register->get('pools');
|
||||
App::setResource('pools', fn() => $pools);
|
||||
App::setResource('pools', fn () => $pools);
|
||||
|
||||
try {
|
||||
Authorization::cleanRoles();
|
||||
@@ -249,7 +249,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
} catch (\Throwable $th) {
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
$logger = $app->getResource("logger");
|
||||
$logger = $app->getResource('logger');
|
||||
if ($logger) {
|
||||
try {
|
||||
/** @var Utopia\Database\Document $user */
|
||||
@@ -258,16 +258,16 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
// All good, user is optional information for logger
|
||||
}
|
||||
|
||||
$loggerBreadcrumbs = $app->getResource("loggerBreadcrumbs");
|
||||
$loggerBreadcrumbs = $app->getResource('loggerBreadcrumbs');
|
||||
$route = $app->match($request);
|
||||
|
||||
$log = new Utopia\Logger\Log();
|
||||
|
||||
if (isset($user) && !$user->isEmpty()) {
|
||||
if (isset($user) && ! $user->isEmpty()) {
|
||||
$log->setUser(new User($user->getId()));
|
||||
}
|
||||
|
||||
$log->setNamespace("http");
|
||||
$log->setNamespace('http');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -279,7 +279,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
$log->addTag('code', $th->getCode());
|
||||
// $log->addTag('projectId', $project->getId()); // TODO: Figure out how to get ProjectID, if it becomes relevant
|
||||
$log->addTag('hostname', $request->getHostname());
|
||||
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
$log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||
|
||||
$log->addExtra('file', $th->getFile());
|
||||
$log->addExtra('line', $th->getLine());
|
||||
@@ -287,7 +287,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
$log->addExtra('detailedTrace', $th->getTrace());
|
||||
$log->addExtra('roles', Authorization::getRoles());
|
||||
|
||||
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
|
||||
$action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD');
|
||||
$log->setAction($action);
|
||||
|
||||
$isProduction = App::getEnv('_APP_ENV', 'development') === 'production';
|
||||
@@ -298,18 +298,18 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
}
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Log pushed with status code: ' . $responseCode);
|
||||
Console::info('Log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: ' . get_class($th));
|
||||
Console::error('[Error] Message: ' . $th->getMessage());
|
||||
Console::error('[Error] File: ' . $th->getFile());
|
||||
Console::error('[Error] Line: ' . $th->getLine());
|
||||
Console::error('[Error] Type: '.get_class($th));
|
||||
Console::error('[Error] Message: '.$th->getMessage());
|
||||
Console::error('[Error] File: '.$th->getFile());
|
||||
Console::error('[Error] Line: '.$th->getLine());
|
||||
|
||||
$swooleResponse->setStatusCode(500);
|
||||
|
||||
$output = ((App::isDevelopment())) ? [
|
||||
'message' => 'Error: ' . $th->getMessage(),
|
||||
'message' => 'Error: '.$th->getMessage(),
|
||||
'code' => 500,
|
||||
'file' => $th->getFile(),
|
||||
'line' => $th->getLine(),
|
||||
|
||||
+152
-151
@@ -5,11 +5,9 @@
|
||||
*
|
||||
* Initializes both Appwrite API entry point, queue workers, and CLI tasks.
|
||||
* Set configuration, framework resources & app constants
|
||||
*
|
||||
*/
|
||||
|
||||
if (\file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
if (\file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
}
|
||||
|
||||
ini_set('memory_limit', '512M');
|
||||
@@ -18,41 +16,54 @@ ini_set('display_startup_errors', 1);
|
||||
ini_set('default_socket_timeout', -1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Ahc\Jwt\JWT;
|
||||
use Ahc\Jwt\JWTException;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Phone;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\GraphQL\Promises\Adapter\Swoole;
|
||||
use Appwrite\GraphQL\Schema;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\URL\URL as AppwriteURL;
|
||||
use MaxMind\Db\Reader;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Swoole\Database\PDOProxy;
|
||||
use Utopia\App;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Adapter\Sharding;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Adapter\MySQL;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Structure;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Messaging\Adapters\SMS\Mock;
|
||||
use Appwrite\GraphQL\Promises\Adapter\Swoole;
|
||||
use Utopia\Messaging\Adapters\SMS\Msg91;
|
||||
use Utopia\Messaging\Adapters\SMS\Telesign;
|
||||
use Utopia\Messaging\Adapters\SMS\TextMagic;
|
||||
use Utopia\Messaging\Adapters\SMS\Twilio;
|
||||
use Utopia\Messaging\Adapters\SMS\Vonage;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Pools\Pool;
|
||||
use Utopia\Queue;
|
||||
use Utopia\Queue\Connection;
|
||||
use Utopia\Registry\Registry;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Device\Backblaze;
|
||||
@@ -61,22 +72,9 @@ use Utopia\Storage\Device\Linode;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Device\S3;
|
||||
use Utopia\Storage\Device\Wasabi;
|
||||
use Utopia\Cache\Adapter\Sharding;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Adapter\MySQL;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Pools\Pool;
|
||||
use Ahc\Jwt\JWT;
|
||||
use Ahc\Jwt\JWTException;
|
||||
use Appwrite\Event\Func;
|
||||
use MaxMind\Db\Reader;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Swoole\Database\PDOProxy;
|
||||
use Utopia\Queue;
|
||||
use Utopia\Queue\Connection;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\IP;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\URL;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -84,7 +82,7 @@ const APP_NAME = 'Appwrite';
|
||||
const APP_DOMAIN = 'appwrite.io';
|
||||
const APP_EMAIL_TEAM = 'team@localhost.test'; // Default email address
|
||||
const APP_EMAIL_SECURITY = ''; // Default security email address
|
||||
const APP_USERAGENT = APP_NAME . '-Server v%s. Please report abuse at %s';
|
||||
const APP_USERAGENT = APP_NAME.'-Server v%s. Please report abuse at %s';
|
||||
const APP_MODE_DEFAULT = 'default';
|
||||
const APP_MODE_ADMIN = 'admin';
|
||||
const APP_PAGING_LIMIT = 12;
|
||||
@@ -162,7 +160,7 @@ const DELETE_TYPE_REALTIME = 'realtime';
|
||||
const DELETE_TYPE_BUCKETS = 'buckets';
|
||||
const DELETE_TYPE_SESSIONS = 'sessions';
|
||||
const DELETE_TYPE_CACHE_BY_TIMESTAMP = 'cacheByTimeStamp';
|
||||
const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource';
|
||||
const DELETE_TYPE_CACHE_BY_RESOURCE = 'cacheByResource';
|
||||
const DELETE_TYPE_SCHEDULES = 'schedules';
|
||||
// Compression type
|
||||
const COMPRESSION_TYPE_NONE = 'none';
|
||||
@@ -184,7 +182,7 @@ const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB
|
||||
// Usage metrics
|
||||
const METRIC_TEAMS = 'teams';
|
||||
const METRIC_USERS = 'users';
|
||||
const METRIC_SESSIONS = 'sessions';
|
||||
const METRIC_SESSIONS = 'sessions';
|
||||
const METRIC_DATABASES = 'databases';
|
||||
const METRIC_COLLECTIONS = 'collections';
|
||||
const METRIC_DATABASE_ID_COLLECTIONS = '{databaseInternalId}.collections';
|
||||
@@ -192,28 +190,28 @@ const METRIC_DOCUMENTS = 'documents';
|
||||
const METRIC_DATABASE_ID_DOCUMENTS = '{databaseInternalId}.documents';
|
||||
const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS = '{databaseInternalId}.{collectionInternalId}.documents';
|
||||
const METRIC_BUCKETS = 'buckets';
|
||||
const METRIC_FILES = 'files';
|
||||
const METRIC_FILES_STORAGE = 'files.storage';
|
||||
const METRIC_FILES = 'files';
|
||||
const METRIC_FILES_STORAGE = 'files.storage';
|
||||
const METRIC_BUCKET_ID_FILES = '{bucketInternalId}.files';
|
||||
const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage';
|
||||
const METRIC_FUNCTIONS = 'functions';
|
||||
const METRIC_DEPLOYMENTS = 'deployments';
|
||||
const METRIC_DEPLOYMENTS_STORAGE = 'deployments.storage';
|
||||
const METRIC_BUILDS = 'builds';
|
||||
const METRIC_BUILDS_STORAGE = 'builds.storage';
|
||||
const METRIC_BUILDS_COMPUTE = 'builds.compute';
|
||||
const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds';
|
||||
const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage';
|
||||
const METRIC_FUNCTIONS = 'functions';
|
||||
const METRIC_DEPLOYMENTS = 'deployments';
|
||||
const METRIC_DEPLOYMENTS_STORAGE = 'deployments.storage';
|
||||
const METRIC_BUILDS = 'builds';
|
||||
const METRIC_BUILDS_STORAGE = 'builds.storage';
|
||||
const METRIC_BUILDS_COMPUTE = 'builds.compute';
|
||||
const METRIC_FUNCTION_ID_BUILDS = '{functionInternalId}.builds';
|
||||
const METRIC_FUNCTION_ID_BUILDS_STORAGE = '{functionInternalId}.builds.storage';
|
||||
const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute';
|
||||
const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
|
||||
const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage';
|
||||
const METRIC_EXECUTIONS = 'executions';
|
||||
const METRIC_EXECUTIONS_COMPUTE = 'executions.compute';
|
||||
const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions';
|
||||
const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute';
|
||||
const METRIC_NETWORK_REQUESTS = 'network.requests';
|
||||
const METRIC_NETWORK_INBOUND = 'network.inbound';
|
||||
const METRIC_NETWORK_OUTBOUND = 'network.outbound';
|
||||
const METRIC_FUNCTION_ID_BUILDS_COMPUTE = '{functionInternalId}.builds.compute';
|
||||
const METRIC_FUNCTION_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
|
||||
const METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage';
|
||||
const METRIC_EXECUTIONS = 'executions';
|
||||
const METRIC_EXECUTIONS_COMPUTE = 'executions.compute';
|
||||
const METRIC_FUNCTION_ID_EXECUTIONS = '{functionInternalId}.executions';
|
||||
const METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE = '{functionInternalId}.executions.compute';
|
||||
const METRIC_NETWORK_REQUESTS = 'network.requests';
|
||||
const METRIC_NETWORK_INBOUND = 'network.inbound';
|
||||
const METRIC_NETWORK_OUTBOUND = 'network.outbound';
|
||||
|
||||
$register = new Registry();
|
||||
|
||||
@@ -222,42 +220,42 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION));
|
||||
/*
|
||||
* ENV vars
|
||||
*/
|
||||
Config::load('events', __DIR__ . '/config/events.php');
|
||||
Config::load('auth', __DIR__ . '/config/auth.php');
|
||||
Config::load('errors', __DIR__ . '/config/errors.php');
|
||||
Config::load('authProviders', __DIR__ . '/config/authProviders.php');
|
||||
Config::load('platforms', __DIR__ . '/config/platforms.php');
|
||||
Config::load('collections', __DIR__ . '/config/collections.php');
|
||||
Config::load('runtimes', __DIR__ . '/config/runtimes.php');
|
||||
Config::load('usage', __DIR__ . '/config/usage.php');
|
||||
Config::load('roles', __DIR__ . '/config/roles.php'); // User roles and scopes
|
||||
Config::load('scopes', __DIR__ . '/config/scopes.php'); // User roles and scopes
|
||||
Config::load('services', __DIR__ . '/config/services.php'); // List of services
|
||||
Config::load('variables', __DIR__ . '/config/variables.php'); // List of env variables
|
||||
Config::load('regions', __DIR__ . '/config/regions.php'); // List of available regions
|
||||
Config::load('avatar-browsers', __DIR__ . '/config/avatars/browsers.php');
|
||||
Config::load('avatar-credit-cards', __DIR__ . '/config/avatars/credit-cards.php');
|
||||
Config::load('avatar-flags', __DIR__ . '/config/avatars/flags.php');
|
||||
Config::load('locale-codes', __DIR__ . '/config/locale/codes.php');
|
||||
Config::load('locale-currencies', __DIR__ . '/config/locale/currencies.php');
|
||||
Config::load('locale-eu', __DIR__ . '/config/locale/eu.php');
|
||||
Config::load('locale-languages', __DIR__ . '/config/locale/languages.php');
|
||||
Config::load('locale-phones', __DIR__ . '/config/locale/phones.php');
|
||||
Config::load('locale-countries', __DIR__ . '/config/locale/countries.php');
|
||||
Config::load('locale-continents', __DIR__ . '/config/locale/continents.php');
|
||||
Config::load('locale-templates', __DIR__ . '/config/locale/templates.php');
|
||||
Config::load('storage-logos', __DIR__ . '/config/storage/logos.php');
|
||||
Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php');
|
||||
Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php');
|
||||
Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php');
|
||||
Config::load('messagingProviders', __DIR__ . '/config/messagingProviders.php');
|
||||
Config::load('events', __DIR__.'/config/events.php');
|
||||
Config::load('auth', __DIR__.'/config/auth.php');
|
||||
Config::load('errors', __DIR__.'/config/errors.php');
|
||||
Config::load('authProviders', __DIR__.'/config/authProviders.php');
|
||||
Config::load('platforms', __DIR__.'/config/platforms.php');
|
||||
Config::load('collections', __DIR__.'/config/collections.php');
|
||||
Config::load('runtimes', __DIR__.'/config/runtimes.php');
|
||||
Config::load('usage', __DIR__.'/config/usage.php');
|
||||
Config::load('roles', __DIR__.'/config/roles.php'); // User roles and scopes
|
||||
Config::load('scopes', __DIR__.'/config/scopes.php'); // User roles and scopes
|
||||
Config::load('services', __DIR__.'/config/services.php'); // List of services
|
||||
Config::load('variables', __DIR__.'/config/variables.php'); // List of env variables
|
||||
Config::load('regions', __DIR__.'/config/regions.php'); // List of available regions
|
||||
Config::load('avatar-browsers', __DIR__.'/config/avatars/browsers.php');
|
||||
Config::load('avatar-credit-cards', __DIR__.'/config/avatars/credit-cards.php');
|
||||
Config::load('avatar-flags', __DIR__.'/config/avatars/flags.php');
|
||||
Config::load('locale-codes', __DIR__.'/config/locale/codes.php');
|
||||
Config::load('locale-currencies', __DIR__.'/config/locale/currencies.php');
|
||||
Config::load('locale-eu', __DIR__.'/config/locale/eu.php');
|
||||
Config::load('locale-languages', __DIR__.'/config/locale/languages.php');
|
||||
Config::load('locale-phones', __DIR__.'/config/locale/phones.php');
|
||||
Config::load('locale-countries', __DIR__.'/config/locale/countries.php');
|
||||
Config::load('locale-continents', __DIR__.'/config/locale/continents.php');
|
||||
Config::load('locale-templates', __DIR__.'/config/locale/templates.php');
|
||||
Config::load('storage-logos', __DIR__.'/config/storage/logos.php');
|
||||
Config::load('storage-mimes', __DIR__.'/config/storage/mimes.php');
|
||||
Config::load('storage-inputs', __DIR__.'/config/storage/inputs.php');
|
||||
Config::load('storage-outputs', __DIR__.'/config/storage/outputs.php');
|
||||
Config::load('messagingProviders', __DIR__.'/config/messagingProviders.php');
|
||||
|
||||
$user = App::getEnv('_APP_REDIS_USER', '');
|
||||
$pass = App::getEnv('_APP_REDIS_PASS', '');
|
||||
if (!empty($user) || !empty($pass)) {
|
||||
Resque::setBackend('redis://' . $user . ':' . $pass . '@' . App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', ''));
|
||||
if (! empty($user) || ! empty($pass)) {
|
||||
Resque::setBackend('redis://'.$user.':'.$pass.'@'.App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', ''));
|
||||
} else {
|
||||
Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '') . ':' . App::getEnv('_APP_REDIS_PORT', ''));
|
||||
Resque::setBackend(App::getEnv('_APP_REDIS_HOST', '').':'.App::getEnv('_APP_REDIS_PORT', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,8 +311,7 @@ Database::addFilter(
|
||||
if (isset($formatOptions['min']) || isset($formatOptions['max'])) {
|
||||
$attribute
|
||||
->setAttribute('min', $formatOptions['min'])
|
||||
->setAttribute('max', $formatOptions['max'])
|
||||
;
|
||||
->setAttribute('max', $formatOptions['max']);
|
||||
}
|
||||
|
||||
return $value;
|
||||
@@ -437,7 +434,7 @@ Database::addFilter(
|
||||
return null;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
return Authorization::skip(fn () => $database
|
||||
->find('tokens', [
|
||||
Query::equal('userInternalId', [$document->getInternalId()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -451,7 +448,7 @@ Database::addFilter(
|
||||
return null;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
return Authorization::skip(fn () => $database
|
||||
->find('memberships', [
|
||||
Query::equal('userInternalId', [$document->getInternalId()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -493,7 +490,7 @@ Database::addFilter(
|
||||
return null;
|
||||
}
|
||||
$value = json_decode($value, true);
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V' . $value['version']);
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$value['version']);
|
||||
|
||||
return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag']));
|
||||
}
|
||||
@@ -506,11 +503,11 @@ Database::addFilter(
|
||||
$user->getId(),
|
||||
$user->getAttribute('email', ''),
|
||||
$user->getAttribute('name', ''),
|
||||
$user->getAttribute('phone', '')
|
||||
$user->getAttribute('phone', ''),
|
||||
];
|
||||
|
||||
foreach ($user->getAttribute('labels', []) as $label) {
|
||||
$searchValues[] = 'label:' . $label;
|
||||
$searchValues[] = 'label:'.$label;
|
||||
}
|
||||
|
||||
$search = implode(' ', \array_filter($searchValues));
|
||||
@@ -528,7 +525,7 @@ Database::addFilter(
|
||||
return null;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
return Authorization::skip(fn() => $database
|
||||
return Authorization::skip(fn () => $database
|
||||
->find('targets', [
|
||||
Query::equal('userInternalId', [$document->getInternalId()]),
|
||||
Query::limit(APP_LIMIT_SUBQUERY),
|
||||
@@ -542,7 +539,7 @@ Database::addFilter(
|
||||
return null;
|
||||
},
|
||||
function (mixed $value, Document $document, Database $database) {
|
||||
$provider = Authorization::skip(fn() => $database
|
||||
$provider = Authorization::skip(fn () => $database
|
||||
->findOne('providers', [
|
||||
Query::equal('$id', [$document->getAttribute('providerId')]),
|
||||
Query::select(['type']),
|
||||
@@ -551,6 +548,7 @@ Database::addFilter(
|
||||
if ($provider) {
|
||||
return $provider->getAttribute('type');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
@@ -568,6 +566,7 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_DATETIME, function () {
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_ENUM, function ($attribute) {
|
||||
$elements = $attribute['formatOptions']['elements'];
|
||||
|
||||
return new WhiteList($elements, true);
|
||||
}, Database::VAR_STRING);
|
||||
|
||||
@@ -582,12 +581,14 @@ Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function () {
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function ($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
|
||||
return new Range($min, $max, Range::TYPE_INTEGER);
|
||||
}, Database::VAR_INTEGER);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function ($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
|
||||
return new Range($min, $max, Range::TYPE_FLOAT);
|
||||
}, Database::VAR_FLOAT);
|
||||
|
||||
@@ -603,12 +604,13 @@ $register->set('logger', function () {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Logger::hasProvider($providerName)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled");
|
||||
if (! Logger::hasProvider($providerName)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Logging provider not supported. Logging is disabled');
|
||||
}
|
||||
|
||||
$classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName);
|
||||
$classname = '\\Utopia\\Logger\\Adapter\\'.\ucfirst($providerName);
|
||||
$adapter = new $classname($providerConfig);
|
||||
|
||||
return new Logger($adapter);
|
||||
});
|
||||
$register->set('pools', function () {
|
||||
@@ -677,7 +679,7 @@ $register->set('pools', function () {
|
||||
throw new \Exception('Pool size is too small. Increase the number of allowed database connections or decrease the number of workers.', 500);
|
||||
}
|
||||
|
||||
$poolSize = (int)($instanceConnections / $workerCount);
|
||||
$poolSize = (int) ($instanceConnections / $workerCount);
|
||||
|
||||
foreach ($connections as $key => $connection) {
|
||||
$type = $connection['type'] ?? '';
|
||||
@@ -688,7 +690,7 @@ $register->set('pools', function () {
|
||||
$dsns = explode(',', $connection['dsns'] ?? '');
|
||||
foreach ($dsns as &$dsn) {
|
||||
$dsn = explode('=', $dsn);
|
||||
$name = ($multipe) ? $key . '_' . $dsn[0] : $key;
|
||||
$name = ($multipe) ? $key.'_'.$dsn[0] : $key;
|
||||
$dsn = $dsn[1] ?? '';
|
||||
$config[] = $name;
|
||||
if (empty($dsn)) {
|
||||
@@ -704,8 +706,8 @@ $register->set('pools', function () {
|
||||
$dsnScheme = $dsn->getScheme();
|
||||
$dsnDatabase = $dsn->getPath();
|
||||
|
||||
if (!in_array($dsnScheme, $schemes)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme");
|
||||
if (! in_array($dsnScheme, $schemes)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid console database scheme');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -720,21 +722,21 @@ $register->set('pools', function () {
|
||||
case 'mariadb':
|
||||
$resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
|
||||
return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
|
||||
return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array(
|
||||
return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, [
|
||||
PDO::ATTR_TIMEOUT => 3, // Seconds
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => true
|
||||
));
|
||||
PDO::ATTR_STRINGIFY_FETCHES => true,
|
||||
]);
|
||||
});
|
||||
};
|
||||
break;
|
||||
case 'redis':
|
||||
$resource = function () use ($dsnHost, $dsnPort, $dsnPass) {
|
||||
$redis = new Redis();
|
||||
@$redis->pconnect($dsnHost, (int)$dsnPort);
|
||||
@$redis->pconnect($dsnHost, (int) $dsnPort);
|
||||
if ($dsnPass) {
|
||||
$redis->auth($dsnPass);
|
||||
}
|
||||
@@ -745,7 +747,7 @@ $register->set('pools', function () {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme");
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid scheme');
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -779,7 +781,7 @@ $register->set('pools', function () {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation.");
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Server error: Missing adapter implementation.');
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -789,7 +791,7 @@ $register->set('pools', function () {
|
||||
$group->add($pool);
|
||||
}
|
||||
|
||||
Config::setParam('pools-' . $key, $config);
|
||||
Config::setParam('pools-'.$key, $config);
|
||||
}
|
||||
|
||||
return $group;
|
||||
@@ -806,14 +808,14 @@ $register->set('smtp', function () {
|
||||
$mail->XMailer = 'Appwrite Mailer';
|
||||
$mail->Host = App::getEnv('_APP_SMTP_HOST', 'smtp');
|
||||
$mail->Port = App::getEnv('_APP_SMTP_PORT', 25);
|
||||
$mail->SMTPAuth = (!empty($username) && !empty($password));
|
||||
$mail->SMTPAuth = (! empty($username) && ! empty($password));
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->SMTPSecure = App::getEnv('_APP_SMTP_SECURE', false);
|
||||
$mail->SMTPAutoTLS = false;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
|
||||
$from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'));
|
||||
$from = \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server'));
|
||||
$email = App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
|
||||
$mail->setFrom($email, $from);
|
||||
@@ -824,12 +826,13 @@ $register->set('smtp', function () {
|
||||
return $mail;
|
||||
});
|
||||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2023-01.mmdb');
|
||||
return new Reader(__DIR__.'/assets/dbip/dbip-country-lite-2023-01.mmdb');
|
||||
});
|
||||
$register->set('passwordsDictionary', function () {
|
||||
$content = \file_get_contents(__DIR__ . '/assets/security/10k-common-passwords');
|
||||
$content = \file_get_contents(__DIR__.'/assets/security/10k-common-passwords');
|
||||
$content = explode("\n", $content);
|
||||
$content = array_flip($content);
|
||||
|
||||
return $content;
|
||||
});
|
||||
$register->set('promiseAdapter', function () {
|
||||
@@ -845,12 +848,12 @@ $locales = Config::getParam('locale-codes', []);
|
||||
foreach ($locales as $locale) {
|
||||
$code = $locale['code'];
|
||||
|
||||
$path = __DIR__ . '/config/locale/translations/' . $code . '.json';
|
||||
$path = __DIR__.'/config/locale/translations/'.$code.'.json';
|
||||
|
||||
if (!\file_exists($path)) {
|
||||
$path = __DIR__ . '/config/locale/translations/' . \substr($code, 0, 2) . '.json'; // if `ar-ae` doesn't exist, look for `ar`
|
||||
if (!\file_exists($path)) {
|
||||
$path = __DIR__ . '/config/locale/translations/en.json'; // if none translation exists, use default from `en.json`
|
||||
if (! \file_exists($path)) {
|
||||
$path = __DIR__.'/config/locale/translations/'.\substr($code, 0, 2).'.json'; // if `ar-ae` doesn't exist, look for `ar`
|
||||
if (! \file_exists($path)) {
|
||||
$path = __DIR__.'/config/locale/translations/en.json'; // if none translation exists, use default from `en.json`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,20 +881,20 @@ App::setResource('loggerBreadcrumbs', function () {
|
||||
return [];
|
||||
});
|
||||
|
||||
App::setResource('register', fn() => $register);
|
||||
App::setResource('locale', fn() => new Locale(App::getEnv('_APP_LOCALE', 'en')));
|
||||
App::setResource('register', fn () => $register);
|
||||
App::setResource('locale', fn () => new Locale(App::getEnv('_APP_LOCALE', 'en')));
|
||||
|
||||
App::setResource('localeCodes', function () {
|
||||
return array_map(fn($locale) => $locale['code'], Config::getParam('locale-codes', []));
|
||||
return array_map(fn ($locale) => $locale['code'], Config::getParam('locale-codes', []));
|
||||
});
|
||||
|
||||
// Queues
|
||||
App::setResource('events', fn() => new Event('', ''));
|
||||
App::setResource('audits', fn() => new Audit());
|
||||
App::setResource('mails', fn() => new Mail());
|
||||
App::setResource('deletes', fn() => new Delete());
|
||||
App::setResource('database', fn() => new EventDatabase());
|
||||
App::setResource('messaging', fn() => new Phone());
|
||||
App::setResource('events', fn () => new Event('', ''));
|
||||
App::setResource('audits', fn () => new Audit());
|
||||
App::setResource('mails', fn () => new Mail());
|
||||
App::setResource('deletes', fn () => new Delete());
|
||||
App::setResource('database', fn () => new EventDatabase());
|
||||
App::setResource('messaging', fn () => new Phone());
|
||||
App::setResource('queue', function (Group $pools) {
|
||||
return $pools->get('queue')->pop()->getResource();
|
||||
}, ['pools']);
|
||||
@@ -917,7 +920,7 @@ App::setResource('clients', function ($request, $console, $project) {
|
||||
fn ($node) => $node['hostname'],
|
||||
\array_filter(
|
||||
$console->getAttribute('platforms', []),
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && !empty($node['hostname']))
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB) && isset($node['hostname']) && ! empty($node['hostname']))
|
||||
)
|
||||
);
|
||||
|
||||
@@ -928,7 +931,7 @@ App::setResource('clients', function ($request, $console, $project) {
|
||||
fn ($node) => $node['hostname'],
|
||||
\array_filter(
|
||||
$project->getAttribute('platforms', []),
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && !empty($node['hostname']))
|
||||
fn ($node) => (isset($node['type']) && ($node['type'] === Origin::CLIENT_TYPE_WEB || $node['type'] === Origin::CLIENT_TYPE_FLUTTER_WEB) && isset($node['hostname']) && ! empty($node['hostname']))
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -944,23 +947,22 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var string $mode */
|
||||
|
||||
Authorization::setDefaultStatus(true);
|
||||
|
||||
Auth::setCookieName('a_session_' . $project->getId());
|
||||
Auth::setCookieName('a_session_'.$project->getId());
|
||||
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
|
||||
if (APP_MODE_ADMIN === $mode) {
|
||||
Auth::setCookieName('a_session_' . $console->getId());
|
||||
Auth::setCookieName('a_session_'.$console->getId());
|
||||
$authDuration = Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||
}
|
||||
|
||||
$session = Auth::decodeSession(
|
||||
$request->getCookie(
|
||||
Auth::$cookieName, // Get sessions
|
||||
$request->getCookie(Auth::$cookieName . '_legacy', '')
|
||||
$request->getCookie(Auth::$cookieName.'_legacy', '')
|
||||
)
|
||||
);// Get fallback session from old clients (no SameSite support)
|
||||
); // Get fallback session from old clients (no SameSite support)
|
||||
|
||||
// Get fallback session from clients who block 3rd-party cookies
|
||||
if ($response) {
|
||||
@@ -991,7 +993,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
|
||||
if (
|
||||
$user->isEmpty() // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration)
|
||||
|| ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration)
|
||||
) { // Validate user has valid login token
|
||||
$user = new Document([]);
|
||||
}
|
||||
@@ -1006,13 +1008,13 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
|
||||
$authJWT = $request->getHeader('x-appwrite-jwt', '');
|
||||
|
||||
if (!empty($authJWT) && !$project->isEmpty()) { // JWT authentication
|
||||
if (! empty($authJWT) && ! $project->isEmpty()) { // JWT authentication
|
||||
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
|
||||
try {
|
||||
$payload = $jwt->decode($authJWT);
|
||||
} catch (JWTException $error) {
|
||||
throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. ' . $error->getMessage());
|
||||
throw new Exception(Exception::USER_JWT_INVALID, 'Failed to verify JWT. '.$error->getMessage());
|
||||
}
|
||||
|
||||
$jwtUserId = $payload['userId'] ?? '';
|
||||
@@ -1034,14 +1036,13 @@ App::setResource('project', function ($dbForConsole, $request, $console) {
|
||||
/** @var Appwrite\Utopia\Request $request */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Document $console */
|
||||
|
||||
$projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', ''));
|
||||
|
||||
if (empty($projectId) || $projectId === 'console') {
|
||||
return $console;
|
||||
}
|
||||
|
||||
$project = Authorization::skip(fn() => $dbForConsole->getDocument('projects', $projectId));
|
||||
$project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId));
|
||||
|
||||
return $project;
|
||||
}, ['dbForConsole', 'request', 'console']);
|
||||
@@ -1076,12 +1077,12 @@ App::setResource('console', function () {
|
||||
'limit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
||||
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds
|
||||
],
|
||||
'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
|
||||
'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
|
||||
'authWhitelistEmails' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
|
||||
'authWhitelistIPs' => (! empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
|
||||
'authProviders' => [
|
||||
'githubEnabled' => true,
|
||||
'githubSecret' => App::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''),
|
||||
'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '')
|
||||
'githubAppid' => App::getEnv('_APP_CONSOLE_GITHUB_APP_ID', ''),
|
||||
],
|
||||
]);
|
||||
}, []);
|
||||
@@ -1094,11 +1095,10 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole,
|
||||
$dbAdapter = $pools
|
||||
->get($project->getAttribute('database'))
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$database = new Database($dbAdapter, $cache);
|
||||
$database->setNamespace('_' . $project->getInternalId());
|
||||
$database->setNamespace('_'.$project->getInternalId());
|
||||
|
||||
return $database;
|
||||
}, ['pools', 'dbForConsole', 'cache', 'project']);
|
||||
@@ -1107,8 +1107,7 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) {
|
||||
$dbAdapter = $pools
|
||||
->get('console')
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$database = new Database($dbAdapter, $cache);
|
||||
|
||||
@@ -1125,8 +1124,7 @@ App::setResource('cache', function (Group $pools) {
|
||||
$adapters[] = $pools
|
||||
->get($value)
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
}
|
||||
|
||||
return new Cache(new Sharding($adapters));
|
||||
@@ -1137,15 +1135,15 @@ App::setResource('deviceLocal', function () {
|
||||
});
|
||||
|
||||
App::setResource('deviceFiles', function ($project) {
|
||||
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
return getDevice(APP_STORAGE_UPLOADS.'/app-'.$project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceFunctions', function ($project) {
|
||||
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
|
||||
return getDevice(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceBuilds', function ($project) {
|
||||
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
|
||||
return getDevice(APP_STORAGE_BUILDS.'/app-'.$project->getId());
|
||||
}, ['project']);
|
||||
|
||||
function getDevice($root): Device
|
||||
@@ -1167,7 +1165,7 @@ function getDevice($root): Device
|
||||
$bucket = $dsn->getPath();
|
||||
$region = $dsn->getParam('region');
|
||||
} catch (\Exception $e) {
|
||||
Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.');
|
||||
Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.');
|
||||
}
|
||||
|
||||
switch ($device) {
|
||||
@@ -1240,7 +1238,6 @@ App::setResource('promiseAdapter', function ($register) {
|
||||
}, ['register']);
|
||||
|
||||
App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
|
||||
$complexity = function (int $complexity, array $args) {
|
||||
$queries = Query::parseQueries($args['queries'] ?? []);
|
||||
$query = Query::getByType($queries, [Query::TYPE_LIMIT])[0] ?? null;
|
||||
@@ -1250,7 +1247,7 @@ App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
};
|
||||
|
||||
$attributes = function (int $limit, int $offset) use ($dbForProject) {
|
||||
$attrs = Authorization::skip(fn() => $dbForProject->find('attributes', [
|
||||
$attrs = Authorization::skip(fn () => $dbForProject->find('attributes', [
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
]));
|
||||
@@ -1280,7 +1277,7 @@ App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
|
||||
$params = [
|
||||
'list' => function (string $databaseId, string $collectionId, array $args) {
|
||||
return [ 'queries' => $args['queries']];
|
||||
return ['queries' => $args['queries']];
|
||||
},
|
||||
'create' => function (string $databaseId, string $collectionId, array $args) {
|
||||
$id = $args['id'] ?? 'unique()';
|
||||
@@ -1328,18 +1325,21 @@ App::setResource('schema', function ($utopia, $dbForProject) {
|
||||
App::setResource('contributors', function () {
|
||||
$path = 'app/config/cloud/contributors.json';
|
||||
$list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : [];
|
||||
|
||||
return $list;
|
||||
}, []);
|
||||
|
||||
App::setResource('employees', function () {
|
||||
$path = 'app/config/cloud/employees.json';
|
||||
$list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : [];
|
||||
|
||||
return $list;
|
||||
}, []);
|
||||
|
||||
App::setResource('heroes', function () {
|
||||
$path = 'app/config/cloud/heroes.json';
|
||||
$list = (file_exists($path)) ? json_decode(file_get_contents($path), true) : [];
|
||||
|
||||
return $list;
|
||||
}, []);
|
||||
|
||||
@@ -1347,12 +1347,13 @@ App::setResource('requestTimestamp', function ($request) {
|
||||
//TODO: Move this to the Request class itself
|
||||
$timestampHeader = $request->getHeader('x-appwrite-timestamp');
|
||||
$requestTimestamp = null;
|
||||
if (!empty($timestampHeader)) {
|
||||
if (! empty($timestampHeader)) {
|
||||
try {
|
||||
$requestTimestamp = new \DateTime($timestampHeader);
|
||||
} catch (\Throwable $e) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid X-Appwrite-Timestamp header value');
|
||||
}
|
||||
}
|
||||
|
||||
return $requestTimestamp;
|
||||
}, ['request']);
|
||||
|
||||
+19
-21
@@ -5,38 +5,36 @@
|
||||
*
|
||||
* Inializes both Appwrite API entry point, queue workers, and CLI tasks.
|
||||
* Set configuration, framework resources, app constants
|
||||
*
|
||||
*/
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
if (file_exists(__DIR__.'/../vendor/autoload.php')) {
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
}
|
||||
|
||||
use Utopia\Preloader\Preloader;
|
||||
|
||||
include __DIR__ . '/controllers/general.php';
|
||||
include __DIR__.'/controllers/general.php';
|
||||
|
||||
$preloader = new Preloader();
|
||||
|
||||
foreach (
|
||||
[
|
||||
realpath(__DIR__ . '/../vendor/composer'),
|
||||
realpath(__DIR__ . '/../vendor/amphp'),
|
||||
realpath(__DIR__ . '/../vendor/felixfbecker'),
|
||||
realpath(__DIR__ . '/../vendor/twig/twig'),
|
||||
realpath(__DIR__ . '/../vendor/guzzlehttp/guzzle'),
|
||||
realpath(__DIR__ . '/../vendor/slickdeals'),
|
||||
realpath(__DIR__ . '/../vendor/psr/log'),
|
||||
realpath(__DIR__ . '/../vendor/matomo'),
|
||||
realpath(__DIR__ . '/../vendor/symfony'),
|
||||
realpath(__DIR__ . '/../vendor/mongodb'),
|
||||
realpath(__DIR__ . '/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload
|
||||
realpath(__DIR__ . '/../vendor/utopia-php/cache'), // TODO: remove memcached autoload
|
||||
realpath(__DIR__ . '/../vendor/utopia-php/queue/src/Queue/Adapter/Workerman.php'), // TODO: remove workerman autoload
|
||||
realpath(__DIR__.'/../vendor/composer'),
|
||||
realpath(__DIR__.'/../vendor/amphp'),
|
||||
realpath(__DIR__.'/../vendor/felixfbecker'),
|
||||
realpath(__DIR__.'/../vendor/twig/twig'),
|
||||
realpath(__DIR__.'/../vendor/guzzlehttp/guzzle'),
|
||||
realpath(__DIR__.'/../vendor/slickdeals'),
|
||||
realpath(__DIR__.'/../vendor/psr/log'),
|
||||
realpath(__DIR__.'/../vendor/matomo'),
|
||||
realpath(__DIR__.'/../vendor/symfony'),
|
||||
realpath(__DIR__.'/../vendor/mongodb'),
|
||||
realpath(__DIR__.'/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload
|
||||
realpath(__DIR__.'/../vendor/utopia-php/cache'), // TODO: remove memcached autoload
|
||||
realpath(__DIR__.'/../vendor/utopia-php/queue/src/Queue/Adapter/Workerman.php'), // TODO: remove workerman autoload
|
||||
] as $key => $value
|
||||
) {
|
||||
if ($value !== false) {
|
||||
@@ -45,7 +43,7 @@ foreach (
|
||||
}
|
||||
|
||||
$preloader
|
||||
->paths(realpath(__DIR__ . '/../app/config'))
|
||||
->paths(realpath(__DIR__ . '/../app/controllers'))
|
||||
->paths(realpath(__DIR__ . '/../src'))
|
||||
->paths(realpath(__DIR__.'/../app/config'))
|
||||
->paths(realpath(__DIR__.'/../app/controllers'))
|
||||
->paths(realpath(__DIR__.'/../src'))
|
||||
->load();
|
||||
|
||||
+73
-76
@@ -3,6 +3,7 @@
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Http\Request as SwooleRequest;
|
||||
use Swoole\Http\Response as SwooleResponse;
|
||||
@@ -12,23 +13,22 @@ use Swoole\Timer;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Utopia\Cache\Adapter\Sharding;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\WebSocket\Server;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\WebSocket\Adapter;
|
||||
use Utopia\WebSocket\Server;
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
require_once __DIR__.'/init.php';
|
||||
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
||||
@@ -42,8 +42,7 @@ function getConsoleDB(): Database
|
||||
$dbAdapter = $pools
|
||||
->get('console')
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$database = new Database($dbAdapter, getCache());
|
||||
|
||||
@@ -66,11 +65,10 @@ function getProjectDB(Document $project): Database
|
||||
$dbAdapter = $pools
|
||||
->get($project->getAttribute('database'))
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$database = new Database($dbAdapter, getCache());
|
||||
$database->setNamespace('_' . $project->getInternalId());
|
||||
$database->setNamespace('_'.$project->getInternalId());
|
||||
|
||||
return $database;
|
||||
}
|
||||
@@ -80,7 +78,6 @@ function getCache(): Cache
|
||||
global $register;
|
||||
|
||||
$pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */
|
||||
|
||||
$list = Config::getParam('pools-cache', []);
|
||||
$adapters = [];
|
||||
|
||||
@@ -88,8 +85,7 @@ function getCache(): Cache
|
||||
$adapters[] = $pools
|
||||
->get($value)
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
}
|
||||
|
||||
return new Cache(new Sharding($adapters));
|
||||
@@ -126,7 +122,7 @@ $logError = function (Throwable $error, string $action) use ($register) {
|
||||
$version = App::getEnv('_APP_VERSION', 'UNKNOWN');
|
||||
|
||||
$log = new Log();
|
||||
$log->setNamespace("realtime");
|
||||
$log->setNamespace('realtime');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
@@ -146,13 +142,13 @@ $logError = function (Throwable $error, string $action) use ($register) {
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Realtime log pushed with status code: ' . $responseCode);
|
||||
Console::info('Realtime log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: ' . get_class($error));
|
||||
Console::error('[Error] Message: ' . $error->getMessage());
|
||||
Console::error('[Error] File: ' . $error->getFile());
|
||||
Console::error('[Error] Line: ' . $error->getLine());
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
Console::error('[Error] Message: '.$error->getMessage());
|
||||
Console::error('[Error] File: '.$error->getFile());
|
||||
Console::error('[Error] Line: '.$error->getLine());
|
||||
};
|
||||
|
||||
$server->error($logError);
|
||||
@@ -177,7 +173,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
'$permissions' => [],
|
||||
'container' => $containerId,
|
||||
'timestamp' => DateTime::now(),
|
||||
'value' => '{}'
|
||||
'value' => '{}',
|
||||
]);
|
||||
|
||||
$statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document));
|
||||
@@ -211,7 +207,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
|
||||
Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
|
||||
} catch (\Throwable $th) {
|
||||
call_user_func($logError, $th, "updateWorkerDocument");
|
||||
call_user_func($logError, $th, 'updateWorkerDocument');
|
||||
} finally {
|
||||
$register->get('pools')->reclaim();
|
||||
}
|
||||
@@ -219,12 +215,12 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||
});
|
||||
|
||||
$server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime, $logError) {
|
||||
Console::success('Worker ' . $workerId . ' started successfully');
|
||||
Console::success('Worker '.$workerId.' started successfully');
|
||||
|
||||
$attempts = 0;
|
||||
$start = time();
|
||||
|
||||
Timer::tick(5000, function () use ($server, $register, $realtime, $stats, $logError) {
|
||||
Timer::tick(5000, function () use ($server, $register, $realtime, $stats) {
|
||||
/**
|
||||
* Sending current connections to project channels on the console project every 5 seconds.
|
||||
*/
|
||||
@@ -243,34 +239,34 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
foreach ($list as $document) {
|
||||
foreach (json_decode($document->getAttribute('value')) as $projectId => $value) {
|
||||
if (array_key_exists($projectId, $payload)) {
|
||||
$payload[$projectId] += $value;
|
||||
$payload[$projectId] += $value;
|
||||
} else {
|
||||
$payload[$projectId] = $value;
|
||||
$payload[$projectId] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($stats as $projectId => $value) {
|
||||
if (!array_key_exists($projectId, $payload)) {
|
||||
if (! array_key_exists($projectId, $payload)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$event = [
|
||||
'project' => 'console',
|
||||
'roles' => ['team:' . $stats->get($projectId, 'teamId')],
|
||||
'roles' => ['team:'.$stats->get($projectId, 'teamId')],
|
||||
'data' => [
|
||||
'events' => ['stats.connections'],
|
||||
'channels' => ['project'],
|
||||
'timestamp' => DateTime::formatTz(DateTime::now()),
|
||||
'payload' => [
|
||||
$projectId => $payload[$projectId]
|
||||
]
|
||||
]
|
||||
$projectId => $payload[$projectId],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$server->send($realtime->getSubscribers($event), json_encode([
|
||||
'type' => 'event',
|
||||
'data' => $event['data']
|
||||
'data' => $event['data'],
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -289,13 +285,13 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
'events' => ['test.event'],
|
||||
'channels' => ['tests'],
|
||||
'timestamp' => DateTime::formatTz(DateTime::now()),
|
||||
'payload' => $payload
|
||||
]
|
||||
'payload' => $payload,
|
||||
],
|
||||
];
|
||||
|
||||
$server->send($realtime->getSubscribers($event), json_encode([
|
||||
'type' => 'event',
|
||||
'data' => $event['data']
|
||||
'data' => $event['data'],
|
||||
]));
|
||||
}
|
||||
});
|
||||
@@ -303,8 +299,8 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
while ($attempts < 300) {
|
||||
try {
|
||||
if ($attempts > 0) {
|
||||
Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . ').
|
||||
Attempting restart in 5 seconds (attempt #' . $attempts . ')');
|
||||
Console::error('Pub/sub connection lost (lasted '.(time() - $start).' seconds, worker: '.$workerId.').
|
||||
Attempting restart in 5 seconds (attempt #'.$attempts.')');
|
||||
sleep(5); // 5 sec delay between connection attempts
|
||||
}
|
||||
$start = time();
|
||||
@@ -314,9 +310,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
|
||||
if ($redis->ping(true)) {
|
||||
$attempts = 0;
|
||||
Console::success('Pub/sub connection established (worker: ' . $workerId . ')');
|
||||
Console::success('Pub/sub connection established (worker: '.$workerId.')');
|
||||
} else {
|
||||
Console::error('Pub/sub failed (worker: ' . $workerId . ')');
|
||||
Console::error('Pub/sub failed (worker: '.$workerId.')');
|
||||
}
|
||||
|
||||
$redis->subscribe(['realtime'], function (Redis $redis, string $channel, string $payload) use ($server, $workerId, $stats, $register, $realtime) {
|
||||
@@ -326,10 +322,10 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
$projectId = $event['project'];
|
||||
$userId = $event['userId'];
|
||||
|
||||
if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) {
|
||||
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId]));
|
||||
if ($realtime->hasSubscriber($projectId, 'user:'.$userId)) {
|
||||
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:'.$userId]));
|
||||
$consoleDatabase = getConsoleDB();
|
||||
$project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId));
|
||||
$project = Authorization::skip(fn () => $consoleDatabase->getDocument('projects', $projectId));
|
||||
$database = getProjectDB($project);
|
||||
|
||||
$user = $database->getDocument('users', $userId);
|
||||
@@ -344,17 +340,17 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
|
||||
$receivers = $realtime->getSubscribers($event);
|
||||
|
||||
if (App::isDevelopment() && !empty($receivers)) {
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Event: " . $payload);
|
||||
if (App::isDevelopment() && ! empty($receivers)) {
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers: ".count($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: ".json_encode($receivers));
|
||||
Console::log("[Debug][Worker {$workerId}] Event: ".$payload);
|
||||
}
|
||||
|
||||
$server->send(
|
||||
$receivers,
|
||||
json_encode([
|
||||
'type' => 'event',
|
||||
'data' => $event['data']
|
||||
'data' => $event['data'],
|
||||
])
|
||||
);
|
||||
|
||||
@@ -363,11 +359,12 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||
}
|
||||
});
|
||||
} catch (\Throwable $th) {
|
||||
call_user_func($logError, $th, "pubSubConnection");
|
||||
call_user_func($logError, $th, 'pubSubConnection');
|
||||
|
||||
Console::error('Pub/sub error: ' . $th->getMessage());
|
||||
Console::error('Pub/sub error: '.$th->getMessage());
|
||||
$attempts++;
|
||||
sleep(DATABASE_RECONNECT_SLEEP);
|
||||
|
||||
continue;
|
||||
} finally {
|
||||
$register->get('pools')->reclaim();
|
||||
@@ -384,9 +381,9 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
|
||||
Console::info("Connection open (user: {$connection})");
|
||||
|
||||
App::setResource('pools', fn() => $register->get('pools'));
|
||||
App::setResource('request', fn() => $request);
|
||||
App::setResource('response', fn() => $response);
|
||||
App::setResource('pools', fn () => $register->get('pools'));
|
||||
App::setResource('request', fn () => $request);
|
||||
App::setResource('response', fn () => $response);
|
||||
|
||||
try {
|
||||
/** @var \Utopia\Database\Document $project */
|
||||
@@ -427,7 +424,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
$origin = $request->getOrigin();
|
||||
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||
|
||||
if (!$originValidator->isValid($origin) && $project->getId() !== 'console') {
|
||||
if (! $originValidator->isValid($origin) && $project->getId() !== 'console') {
|
||||
throw new Exception($originValidator->getDescription(), 1008);
|
||||
}
|
||||
|
||||
@@ -450,25 +447,25 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
'type' => 'connected',
|
||||
'data' => [
|
||||
'channels' => array_keys($channels),
|
||||
'user' => $user
|
||||
]
|
||||
'user' => $user,
|
||||
],
|
||||
]));
|
||||
|
||||
$stats->set($project->getId(), [
|
||||
'projectId' => $project->getId(),
|
||||
'teamId' => $project->getAttribute('teamId')
|
||||
'teamId' => $project->getAttribute('teamId'),
|
||||
]);
|
||||
$stats->incr($project->getId(), 'connections');
|
||||
$stats->incr($project->getId(), 'connectionsTotal');
|
||||
} catch (\Throwable $th) {
|
||||
call_user_func($logError, $th, "initServer");
|
||||
call_user_func($logError, $th, 'initServer');
|
||||
|
||||
$response = [
|
||||
'type' => 'error',
|
||||
'data' => [
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage()
|
||||
]
|
||||
'message' => $th->getMessage(),
|
||||
],
|
||||
];
|
||||
|
||||
$server->send([$connection], json_encode($response));
|
||||
@@ -476,8 +473,8 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||
|
||||
if (App::isDevelopment()) {
|
||||
Console::error('[Error] Connection Error');
|
||||
Console::error('[Error] Code: ' . $response['data']['code']);
|
||||
Console::error('[Error] Message: ' . $response['data']['message']);
|
||||
Console::error('[Error] Code: '.$response['data']['code']);
|
||||
Console::error('[Error] Message: '.$response['data']['message']);
|
||||
}
|
||||
} finally {
|
||||
$register->get('pools')->reclaim();
|
||||
@@ -492,7 +489,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
$database = getConsoleDB();
|
||||
|
||||
if ($projectId !== 'console') {
|
||||
$project = Authorization::skip(fn() => $database->getDocument('projects', $projectId));
|
||||
$project = Authorization::skip(fn () => $database->getDocument('projects', $projectId));
|
||||
$database = getProjectDB($project);
|
||||
}
|
||||
|
||||
@@ -515,16 +512,16 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
|
||||
$message = json_decode($message, true);
|
||||
|
||||
if (is_null($message) || (!array_key_exists('type', $message) && !array_key_exists('data', $message))) {
|
||||
if (is_null($message) || (! array_key_exists('type', $message) && ! array_key_exists('data', $message))) {
|
||||
throw new Exception('Message format is not valid.', 1003);
|
||||
}
|
||||
|
||||
switch ($message['type']) {
|
||||
/**
|
||||
/**
|
||||
* This type is used to authenticate.
|
||||
*/
|
||||
case 'authentication':
|
||||
if (!array_key_exists('session', $message['data'])) {
|
||||
if (! array_key_exists('session', $message['data'])) {
|
||||
throw new Exception('Payload is not valid.', 1003);
|
||||
}
|
||||
|
||||
@@ -537,7 +534,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
|
||||
if (
|
||||
empty($user->getId()) // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token
|
||||
|| ! Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration) // Validate user has valid login token
|
||||
) {
|
||||
// cookie not valid
|
||||
throw new Exception('Session is not valid.', 1003);
|
||||
@@ -553,8 +550,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
'data' => [
|
||||
'to' => 'authentication',
|
||||
'success' => true,
|
||||
'user' => $user
|
||||
]
|
||||
'user' => $user,
|
||||
],
|
||||
]));
|
||||
|
||||
break;
|
||||
@@ -567,8 +564,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||
'type' => 'error',
|
||||
'data' => [
|
||||
'code' => $th->getCode(),
|
||||
'message' => $th->getMessage()
|
||||
]
|
||||
'message' => $th->getMessage(),
|
||||
],
|
||||
];
|
||||
|
||||
$server->send([$connection], json_encode($response));
|
||||
@@ -587,7 +584,7 @@ $server->onClose(function (int $connection) use ($realtime, $stats) {
|
||||
}
|
||||
$realtime->unsubscribe($connection);
|
||||
|
||||
Console::info('Connection close: ' . $connection);
|
||||
Console::info('Connection close: '.$connection);
|
||||
});
|
||||
|
||||
$server->start();
|
||||
|
||||
+20
-20
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
require_once __DIR__.'/init.php';
|
||||
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Usage;
|
||||
@@ -12,27 +12,26 @@ use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Queue\Adapter\Swoole;
|
||||
use Utopia\Queue\Message;
|
||||
use Utopia\Queue\Server;
|
||||
use Utopia\Registry\Registry;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Pools\Group;
|
||||
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
||||
global $register;
|
||||
|
||||
Server::setResource('register', fn() => $register);
|
||||
Server::setResource('register', fn () => $register);
|
||||
|
||||
Server::setResource('dbForConsole', function (Cache $cache, Registry $register) {
|
||||
$pools = $register->get('pools');
|
||||
$database = $pools
|
||||
->get('console')
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$adapter = new Database($database, $cache);
|
||||
$adapter->setNamespace('console');
|
||||
@@ -52,11 +51,11 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register,
|
||||
$database = $pools
|
||||
->get($project->getAttribute('database'))
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$adapter = new Database($database, $cache);
|
||||
$adapter->setNamespace('_' . $project->getInternalId());
|
||||
$adapter->setNamespace('_'.$project->getInternalId());
|
||||
|
||||
return $adapter;
|
||||
}, ['cache', 'register', 'message', 'dbForConsole']);
|
||||
|
||||
@@ -69,8 +68,7 @@ Server::setResource('cache', function (Registry $register) {
|
||||
$adapters[] = $pools
|
||||
->get($value)
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
}
|
||||
|
||||
return new Cache(new Sharding($adapters));
|
||||
@@ -78,6 +76,7 @@ Server::setResource('cache', function (Registry $register) {
|
||||
|
||||
Server::setResource('queueForFunctions', function (Registry $register) {
|
||||
$pools = $register->get('pools');
|
||||
|
||||
return new Func(
|
||||
$pools
|
||||
->get('queue')
|
||||
@@ -88,6 +87,7 @@ Server::setResource('queueForFunctions', function (Registry $register) {
|
||||
|
||||
Server::setResource('queueForUsage', function (Registry $register) {
|
||||
$pools = $register->get('pools');
|
||||
|
||||
return new Usage(
|
||||
$pools
|
||||
->get('queue')
|
||||
@@ -96,7 +96,7 @@ Server::setResource('queueForUsage', function (Registry $register) {
|
||||
);
|
||||
}, ['register']);
|
||||
|
||||
Server::setResource('log', fn() => new Log());
|
||||
Server::setResource('log', fn () => new Log());
|
||||
|
||||
Server::setResource('logger', function ($register) {
|
||||
return $register->get('logger');
|
||||
@@ -137,12 +137,12 @@ $server
|
||||
}
|
||||
|
||||
if ($logger && ($error->getCode() >= 500 || $error->getCode() === 0)) {
|
||||
$log->setNamespace("appwrite-worker");
|
||||
$log->setNamespace('appwrite-worker');
|
||||
$log->setServer(\gethostname());
|
||||
$log->setVersion($version);
|
||||
$log->setType(Log::TYPE_ERROR);
|
||||
$log->setMessage($error->getMessage());
|
||||
$log->setAction('appwrite-queue-' . App::getEnv('QUEUE'));
|
||||
$log->setAction('appwrite-queue-'.App::getEnv('QUEUE'));
|
||||
$log->addTag('verboseType', get_class($error));
|
||||
$log->addTag('code', $error->getCode());
|
||||
$log->addExtra('file', $error->getFile());
|
||||
@@ -155,11 +155,11 @@ $server
|
||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||
|
||||
$responseCode = $logger->addLog($log);
|
||||
Console::info('Usage stats log pushed with status code: ' . $responseCode);
|
||||
Console::info('Usage stats log pushed with status code: '.$responseCode);
|
||||
}
|
||||
|
||||
Console::error('[Error] Type: ' . get_class($error));
|
||||
Console::error('[Error] Message: ' . $error->getMessage());
|
||||
Console::error('[Error] File: ' . $error->getFile());
|
||||
Console::error('[Error] Line: ' . $error->getLine());
|
||||
Console::error('[Error] Type: '.get_class($error));
|
||||
Console::error('[Error] Message: '.$error->getMessage());
|
||||
Console::error('[Error] File: '.$error->getFile());
|
||||
Console::error('[Error] Line: '.$error->getLine());
|
||||
});
|
||||
|
||||
@@ -5,16 +5,16 @@ use Utopia\Audit\Audit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Audits V1 Worker');
|
||||
Console::success(APP_NAME . ' audits worker v1 has started');
|
||||
Console::success(APP_NAME.' audits worker v1 has started');
|
||||
|
||||
class AuditsV1 extends Worker
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return "audits";
|
||||
return 'audits';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
|
||||
+19
-20
@@ -6,20 +6,20 @@ use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Appwrite\Utopia\Response\Model\Deployment;
|
||||
use Executor\Executor;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Builds V1 Worker');
|
||||
Console::success(APP_NAME . ' build worker v1 has started');
|
||||
Console::success(APP_NAME.' build worker v1 has started');
|
||||
|
||||
// TODO: Executor should return appropriate response codes.
|
||||
class BuildsV1 extends Worker
|
||||
@@ -28,7 +28,7 @@ class BuildsV1 extends Worker
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "builds";
|
||||
return 'builds';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -46,7 +46,7 @@ class BuildsV1 extends Worker
|
||||
switch ($type) {
|
||||
case BUILD_TYPE_DEPLOYMENT:
|
||||
case BUILD_TYPE_RETRY:
|
||||
Console::info('Creating build for deployment: ' . $deployment->getId());
|
||||
Console::info('Creating build for deployment: '.$deployment->getId());
|
||||
$this->buildDeployment($project, $resource, $deployment);
|
||||
break;
|
||||
|
||||
@@ -81,7 +81,7 @@ class BuildsV1 extends Worker
|
||||
$key = $function->getAttribute('runtime');
|
||||
$runtime = isset($runtimes[$key]) ? $runtimes[$key] : null;
|
||||
if (\is_null($runtime)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported');
|
||||
}
|
||||
|
||||
$connection = App::getEnv('_APP_CONNECTIONS_STORAGE', ''); /** @TODO : move this to the registry or someplace else */
|
||||
@@ -90,7 +90,7 @@ class BuildsV1 extends Worker
|
||||
$dsn = new DSN($connection);
|
||||
$device = $dsn->getScheme();
|
||||
} catch (\Exception $e) {
|
||||
Console::error($e->getMessage() . 'Invalid DSN. Defaulting to Local device.');
|
||||
Console::error($e->getMessage().'Invalid DSN. Defaulting to Local device.');
|
||||
}
|
||||
|
||||
$buildId = $deployment->getAttribute('buildId', '');
|
||||
@@ -111,7 +111,7 @@ class BuildsV1 extends Worker
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'endTime' => null,
|
||||
'duration' => 0
|
||||
'duration' => 0,
|
||||
]));
|
||||
$deployment->setAttribute('buildId', $build->getId());
|
||||
$deployment->setAttribute('buildInternalId', $build->getInternalId());
|
||||
@@ -150,7 +150,7 @@ class BuildsV1 extends Worker
|
||||
/** Trigger Realtime */
|
||||
$allEvents = Event::generateEvents('functions.[functionId].deployments.[deploymentId].update', [
|
||||
'functionId' => $function->getId(),
|
||||
'deploymentId' => $deployment->getId()
|
||||
'deploymentId' => $deployment->getId(),
|
||||
]);
|
||||
$target = Realtime::fromPayload(
|
||||
// Pass first, most verbose event pattern
|
||||
@@ -171,6 +171,7 @@ class BuildsV1 extends Worker
|
||||
|
||||
$vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value');
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
@@ -183,12 +184,12 @@ class BuildsV1 extends Worker
|
||||
remove: true,
|
||||
entrypoint: $deployment->getAttribute('entrypoint'),
|
||||
workdir: '/usr/code',
|
||||
destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}",
|
||||
destination: APP_STORAGE_BUILDS."/app-{$project->getId()}",
|
||||
variables: $vars,
|
||||
commands: [
|
||||
'sh', '-c',
|
||||
'tar -zxf /tmp/code.tar.gz -C /usr/code && \
|
||||
cd /usr/local/src/ && ./build.sh'
|
||||
cd /usr/local/src/ && ./build.sh',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -222,8 +223,7 @@ class BuildsV1 extends Worker
|
||||
|
||||
$schedule
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
|
||||
->setAttribute('active', ! empty($function->getAttribute('schedule')) && ! empty($function->getAttribute('deployment')));
|
||||
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
} catch (\Throwable $th) {
|
||||
@@ -261,12 +261,11 @@ class BuildsV1 extends Worker
|
||||
->setProject($project)
|
||||
->addMetric(METRIC_BUILDS, 1) // per project
|
||||
->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0))
|
||||
->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000)
|
||||
->addMetric(METRIC_BUILDS_COMPUTE, (int) $build->getAttribute('duration', 0) * 1000)
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS), 1) // per function
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0))
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000)
|
||||
->trigger()
|
||||
;
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int) $build->getAttribute('duration', 0) * 1000)
|
||||
->trigger();
|
||||
}
|
||||
|
||||
public function shutdown(): void
|
||||
|
||||
@@ -7,17 +7,17 @@ use Appwrite\Template\Template;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Certificates V1 Worker');
|
||||
Console::success(APP_NAME . ' certificates worker v1 has started');
|
||||
Console::success(APP_NAME.' certificates worker v1 has started');
|
||||
|
||||
class CertificatesV1 extends Worker
|
||||
{
|
||||
@@ -30,7 +30,7 @@ class CertificatesV1 extends Worker
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "certificates";
|
||||
return 'certificates';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -68,7 +68,6 @@ class CertificatesV1 extends Worker
|
||||
*
|
||||
* Note: Renewals are checked and scheduled from maintenence worker
|
||||
*/
|
||||
|
||||
$this->dbForConsole = $this->getConsoleDB();
|
||||
|
||||
$skipCheck = $this->args['skipRenewCheck'] ?? false; // If true, we won't double-check expiry from cert file
|
||||
@@ -79,7 +78,7 @@ class CertificatesV1 extends Worker
|
||||
$certificate = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain->get()])]);
|
||||
|
||||
// If we don't have certificate for domain yet, let's create new document. At the end we save it
|
||||
if (!$certificate) {
|
||||
if (! $certificate) {
|
||||
$certificate = new Document();
|
||||
$certificate->setAttribute('domain', $domain->get());
|
||||
}
|
||||
@@ -92,14 +91,14 @@ class CertificatesV1 extends Worker
|
||||
}
|
||||
|
||||
// Validate domain and DNS records. Skip if job is forced
|
||||
if (!$skipCheck) {
|
||||
if (! $skipCheck) {
|
||||
$mainDomain = $this->getMainDomain();
|
||||
$isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain;
|
||||
$isMainDomain = ! isset($mainDomain) || $domain->get() === $mainDomain;
|
||||
$this->validateDomain($domain, $isMainDomain);
|
||||
}
|
||||
|
||||
// If certificate exists already, double-check expiry date. Skip if job is forced
|
||||
if (!$skipCheck && !$this->isRenewRequired($domain->get())) {
|
||||
if (! $skipCheck && ! $this->isRenewRequired($domain->get())) {
|
||||
throw new Exception('Renew isn\'t required.');
|
||||
}
|
||||
|
||||
@@ -152,16 +151,15 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* Save certificate data into database.
|
||||
*
|
||||
* @param string $domain Domain name that certificate is for
|
||||
* @param Document $certificate Certificate document that we need to save
|
||||
*
|
||||
* @param string $domain Domain name that certificate is for
|
||||
* @param Document $certificate Certificate document that we need to save
|
||||
* @return void
|
||||
*/
|
||||
private function saveCertificateDocument(string $domain, Document $certificate): void
|
||||
{
|
||||
// Check if update or insert required
|
||||
$certificateDocument = $this->dbForConsole->findOne('certificates', [Query::equal('domain', [$domain])]);
|
||||
if (!empty($certificateDocument) && !$certificateDocument->isEmpty()) {
|
||||
if (! empty($certificateDocument) && ! $certificateDocument->isEmpty()) {
|
||||
// Merge new data with current data
|
||||
$certificate = new Document(\array_merge($certificateDocument->getArrayCopy(), $certificate->getArrayCopy()));
|
||||
|
||||
@@ -182,7 +180,7 @@ class CertificatesV1 extends Worker
|
||||
private function getMainDomain(): ?string
|
||||
{
|
||||
$envDomain = App::getEnv('_APP_DOMAIN', '');
|
||||
if (!empty($envDomain) && $envDomain !== 'localhost') {
|
||||
if (! empty($envDomain) && $envDomain !== 'localhost') {
|
||||
return $envDomain;
|
||||
} else {
|
||||
$domainDocument = $this->dbForConsole->findOne('domains', [Query::orderAsc('_id')]);
|
||||
@@ -199,9 +197,8 @@ class CertificatesV1 extends Worker
|
||||
* - Domain needs to be public and valid (prevents NFT domains that are not supported by Let's Encrypt)
|
||||
* - Domain must have proper DNS record
|
||||
*
|
||||
* @param Domain $domain Domain which we validate
|
||||
* @param bool $isMainDomain In case of master domain, we look for different DNS configurations
|
||||
*
|
||||
* @param Domain $domain Domain which we validate
|
||||
* @param bool $isMainDomain In case of master domain, we look for different DNS configurations
|
||||
* @return void
|
||||
*/
|
||||
private function validateDomain(Domain $domain, bool $isMainDomain): void
|
||||
@@ -210,23 +207,23 @@ class CertificatesV1 extends Worker
|
||||
throw new Exception('Missing certificate domain.');
|
||||
}
|
||||
|
||||
if (!$domain->isKnown() || $domain->isTest()) {
|
||||
if (! $domain->isKnown() || $domain->isTest()) {
|
||||
throw new Exception('Unknown public suffix for domain.');
|
||||
}
|
||||
|
||||
if (!$isMainDomain) {
|
||||
if (! $isMainDomain) {
|
||||
// TODO: Would be awesome to also support A/AAAA records here. Maybe dry run?
|
||||
|
||||
// Validate if domain target is properly configured
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if (!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
|
||||
if (! $target->isKnown() || $target->isTest()) {
|
||||
throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.');
|
||||
}
|
||||
|
||||
// Verify domain with DNS records
|
||||
$validator = new CNAME($target->get());
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
if (! $validator->isValid($domain->get())) {
|
||||
throw new Exception('Failed to verify domain DNS records.');
|
||||
}
|
||||
} else {
|
||||
@@ -238,13 +235,12 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* Reads expiry date of certificate from file and decides if renewal is required or not.
|
||||
*
|
||||
* @param string $domain Domain for which we check certificate file
|
||||
*
|
||||
* @param string $domain Domain for which we check certificate file
|
||||
* @return bool True, if certificate needs to be renewed
|
||||
*/
|
||||
private function isRenewRequired(string $domain): bool
|
||||
{
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
$certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem';
|
||||
if (\file_exists($certPath)) {
|
||||
$validTo = null;
|
||||
|
||||
@@ -268,9 +264,8 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* LetsEncrypt communication to issue certificate (using certbot CLI)
|
||||
*
|
||||
* @param string $folder Folder into which certificates should be generated
|
||||
* @param string $domain Domain to generate certificate for
|
||||
*
|
||||
* @param string $folder Folder into which certificates should be generated
|
||||
* @param string $domain Domain to generate certificate for
|
||||
* @return array Named array with keys 'stdout' and 'stderr', both string
|
||||
*/
|
||||
private function issueCertificate(string $folder, string $domain, string $email): array
|
||||
@@ -280,83 +275,82 @@ class CertificatesV1 extends Worker
|
||||
|
||||
$staging = (App::isProduction()) ? '' : ' --dry-run';
|
||||
$exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}"
|
||||
. " --email " . $email
|
||||
. " --cert-name " . $folder
|
||||
. " -w " . APP_STORAGE_CERTIFICATES
|
||||
. " -d {$domain}", '', $stdout, $stderr);
|
||||
.' --email '.$email
|
||||
.' --cert-name '.$folder
|
||||
.' -w '.APP_STORAGE_CERTIFICATES
|
||||
." -d {$domain}", '', $stdout, $stderr);
|
||||
|
||||
// Unexpected error, usually 5XX, API limits, ...
|
||||
if ($exit !== 0) {
|
||||
throw new Exception('Failed to issue a certificate with message: ' . $stderr);
|
||||
throw new Exception('Failed to issue a certificate with message: '.$stderr);
|
||||
}
|
||||
|
||||
return [
|
||||
'stdout' => $stdout,
|
||||
'stderr' => $stderr
|
||||
'stderr' => $stderr,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read new renew date from certificate file generated by Let's Encrypt
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
* @return string
|
||||
*/
|
||||
private function getRenewDate(string $domain): string
|
||||
{
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
$certPath = APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem';
|
||||
$certData = openssl_x509_parse(file_get_contents($certPath));
|
||||
$validTo = $certData['validTo_time_t'] ?? null;
|
||||
$dt = (new \DateTime())->setTimestamp($validTo);
|
||||
|
||||
return DateTime::addSeconds($dt, -60 * 60 * 24 * 30); // -30 days
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to take files from Let's Encrypt, and put it into Traefik.
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
* @param string $folder Folder in which certificates were generated
|
||||
* @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
* @param string $folder Folder in which certificates were generated
|
||||
* @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error
|
||||
* @return void
|
||||
*/
|
||||
private function applyCertificateFiles(string $folder, string $domain, array $letsEncryptData): void
|
||||
{
|
||||
// Prepare folder in storage for domain
|
||||
$path = APP_STORAGE_CERTIFICATES . '/' . $domain;
|
||||
if (!\is_readable($path)) {
|
||||
if (!\mkdir($path, 0755, true)) {
|
||||
$path = APP_STORAGE_CERTIFICATES.'/'.$domain;
|
||||
if (! \is_readable($path)) {
|
||||
if (! \mkdir($path, 0755, true)) {
|
||||
throw new Exception('Failed to create path for certificate.');
|
||||
}
|
||||
}
|
||||
|
||||
// Move generated files
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/cert.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/chain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/fullchain.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $folder . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
if (! @\rename('/etc/letsencrypt/live/'.$folder.'/privkey.pem', APP_STORAGE_CERTIFICATES.'/'.$domain.'/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: '.$letsEncryptData['stderr'].' ; '.$letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
$config = \implode(PHP_EOL, [
|
||||
"tls:",
|
||||
" certificates:",
|
||||
'tls:',
|
||||
' certificates:',
|
||||
" - certFile: /storage/certificates/{$domain}/fullchain.pem",
|
||||
" keyFile: /storage/certificates/{$domain}/privkey.pem"
|
||||
" keyFile: /storage/certificates/{$domain}/privkey.pem",
|
||||
]);
|
||||
|
||||
// Save configuration into Traefik using our new cert files
|
||||
if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain . '.yml', $config)) {
|
||||
if (! \file_put_contents(APP_STORAGE_CONFIG.'/'.$domain.'.yml', $config)) {
|
||||
throw new Exception('Failed to save Traefik configuration.');
|
||||
}
|
||||
}
|
||||
@@ -364,39 +358,38 @@ class CertificatesV1 extends Worker
|
||||
/**
|
||||
* Method to make sure information about error is delivered to admnistrator.
|
||||
*
|
||||
* @param string $domain Domain that caused the error
|
||||
* @param string $errorMessage Verbose error message
|
||||
* @param int $attempt How many times it failed already
|
||||
*
|
||||
* @param string $domain Domain that caused the error
|
||||
* @param string $errorMessage Verbose error message
|
||||
* @param int $attempt How many times it failed already
|
||||
* @return void
|
||||
*/
|
||||
private function notifyError(string $domain, string $errorMessage, int $attempt): void
|
||||
{
|
||||
// Log error into console
|
||||
Console::warning('Cannot renew domain (' . $domain . ') on attempt no. ' . $attempt . ' certificate: ' . $errorMessage);
|
||||
Console::warning('Cannot renew domain ('.$domain.') on attempt no. '.$attempt.' certificate: '.$errorMessage);
|
||||
|
||||
// Send mail to administratore mail
|
||||
|
||||
$locale = new Locale(App::getEnv('_APP_LOCALE', 'en'));
|
||||
if (!$locale->getText('emails.sender') || !$locale->getText("emails.certificate.hello") || !$locale->getText("emails.certificate.subject") || !$locale->getText("emails.certificate.body") || !$locale->getText("emails.certificate.footer") || !$locale->getText("emails.certificate.thanks") || !$locale->getText("emails.certificate.signature")) {
|
||||
if (! $locale->getText('emails.sender') || ! $locale->getText('emails.certificate.hello') || ! $locale->getText('emails.certificate.subject') || ! $locale->getText('emails.certificate.body') || ! $locale->getText('emails.certificate.footer') || ! $locale->getText('emails.certificate.thanks') || ! $locale->getText('emails.certificate.signature')) {
|
||||
$locale->setDefault('en');
|
||||
}
|
||||
|
||||
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
|
||||
$body = Template::fromFile(__DIR__.'/../config/locale/templates/email-base.tpl');
|
||||
|
||||
$subject = \sprintf($locale->getText("emails.certificate.subject"), $domain);
|
||||
$body->setParam('{{domain}}', $domain);
|
||||
$body->setParam('{{error}}', $errorMessage);
|
||||
$body->setParam('{{attempt}}', $attempt);
|
||||
$subject = \sprintf($locale->getText('emails.certificate.subject'), $domain);
|
||||
$body->setParam('{{domain}}', $domain);
|
||||
$body->setParam('{{error}}', $errorMessage);
|
||||
$body->setParam('{{attempt}}', $attempt);
|
||||
|
||||
$body
|
||||
->setParam('{{subject}}', $subject)
|
||||
->setParam('{{hello}}', $locale->getText("emails.certificate.hello"))
|
||||
->setParam('{{body}}', $locale->getText("emails.certificate.body"))
|
||||
->setParam('{{redirect}}', 'https://' . $domain)
|
||||
->setParam('{{footer}}', $locale->getText("emails.certificate.footer"))
|
||||
->setParam('{{thanks}}', $locale->getText("emails.certificate.thanks"))
|
||||
->setParam('{{signature}}', $locale->getText("emails.certificate.signature"))
|
||||
->setParam('{{hello}}', $locale->getText('emails.certificate.hello'))
|
||||
->setParam('{{body}}', $locale->getText('emails.certificate.body'))
|
||||
->setParam('{{redirect}}', 'https://'.$domain)
|
||||
->setParam('{{footer}}', $locale->getText('emails.certificate.footer'))
|
||||
->setParam('{{thanks}}', $locale->getText('emails.certificate.thanks'))
|
||||
->setParam('{{signature}}', $locale->getText('emails.certificate.signature'))
|
||||
->setParam('{{project}}', 'Console')
|
||||
->setParam('{{direction}}', $locale->getText('settings.direction'))
|
||||
->setParam('{{bg-body}}', '#f7f7f7')
|
||||
@@ -418,9 +411,8 @@ class CertificatesV1 extends Worker
|
||||
* - when renew creates new document? It might?
|
||||
* - overall makes it more reliable
|
||||
*
|
||||
* @param string $certificateId ID of a new or updated certificate document
|
||||
* @param string $domain Domain that is affected by new certificate
|
||||
*
|
||||
* @param string $certificateId ID of a new or updated certificate document
|
||||
* @param string $domain Domain that is affected by new certificate
|
||||
* @return void
|
||||
*/
|
||||
private function updateDomainDocuments(string $certificateId, string $domain): void
|
||||
|
||||
+53
-51
@@ -9,10 +9,10 @@ use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception as DatabaseException;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Database V1 Worker');
|
||||
Console::success(APP_NAME . ' database worker v1 has started' . "\n");
|
||||
Console::success(APP_NAME.' database worker v1 has started'."\n");
|
||||
|
||||
class DatabaseV1 extends Worker
|
||||
{
|
||||
@@ -51,7 +51,7 @@ class DatabaseV1 extends Worker
|
||||
break;
|
||||
|
||||
default:
|
||||
Console::error('No database operation for type: ' . $type);
|
||||
Console::error('No database operation for type: '.$type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -61,10 +61,10 @@ class DatabaseV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param Document $project
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function createAttribute(Document $database, Document $collection, Document $attribute, Document $project): void
|
||||
{
|
||||
@@ -75,7 +75,7 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].update', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'attributeId' => $attribute->getId()
|
||||
'attributeId' => $attribute->getId(),
|
||||
]);
|
||||
/**
|
||||
* Fetch attribute from the database, since with Resque float values are loosing informations.
|
||||
@@ -99,15 +99,15 @@ class DatabaseV1 extends Worker
|
||||
try {
|
||||
switch ($type) {
|
||||
case Database::VAR_RELATIONSHIP:
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
|
||||
$relatedCollection = $dbForProject->getDocument('database_'.$database->getInternalId(), $options['relatedCollection']);
|
||||
if ($relatedCollection->isEmpty()) {
|
||||
throw new DatabaseException('Collection not found');
|
||||
}
|
||||
|
||||
if (
|
||||
!$dbForProject->createRelationship(
|
||||
collection: 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
relatedCollection: 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
|
||||
! $dbForProject->createRelationship(
|
||||
collection: 'database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(),
|
||||
relatedCollection: 'database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId(),
|
||||
type: $options['relationType'],
|
||||
twoWay: $options['twoWay'],
|
||||
id: $key,
|
||||
@@ -119,12 +119,12 @@ class DatabaseV1 extends Worker
|
||||
}
|
||||
|
||||
if ($options['twoWay']) {
|
||||
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
|
||||
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']);
|
||||
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'available'));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
||||
if (! $dbForProject->createAttribute('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
||||
throw new Exception('Failed to create Attribute');
|
||||
}
|
||||
}
|
||||
@@ -170,23 +170,24 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $relatedCollection->getId());
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param Document $project
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $attribute
|
||||
* @param Document $project
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
protected function deleteAttribute(Document $database, Document $collection, Document $attribute, Document $project): void
|
||||
@@ -198,7 +199,7 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'attributeId' => $attribute->getId()
|
||||
'attributeId' => $attribute->getId(),
|
||||
]);
|
||||
$collectionId = $collection->getId();
|
||||
$key = $attribute->getAttribute('key', '');
|
||||
@@ -219,25 +220,25 @@ class DatabaseV1 extends Worker
|
||||
if ($status !== 'failed') {
|
||||
if ($type === Database::VAR_RELATIONSHIP) {
|
||||
if ($options['twoWay']) {
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
|
||||
$relatedCollection = $dbForProject->getDocument('database_'.$database->getInternalId(), $options['relatedCollection']);
|
||||
if ($relatedCollection->isEmpty()) {
|
||||
throw new DatabaseException('Collection not found');
|
||||
}
|
||||
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
|
||||
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId().'_'.$relatedCollection->getInternalId().'_'.$options['twoWayKey']);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
||||
if (! $dbForProject->deleteRelationship('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) {
|
||||
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'stuck'));
|
||||
throw new DatabaseException('Failed to delete Relationship');
|
||||
}
|
||||
} elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
||||
} elseif (! $dbForProject->deleteAttribute('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) {
|
||||
throw new DatabaseException('Failed to delete Attribute');
|
||||
}
|
||||
}
|
||||
|
||||
$dbForProject->deleteDocument('attributes', $attribute->getId());
|
||||
|
||||
if (!$relatedAttribute->isEmpty()) {
|
||||
if (! $relatedAttribute->isEmpty()) {
|
||||
$dbForProject->deleteDocument('attributes', $relatedAttribute->getId());
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
@@ -245,7 +246,7 @@ class DatabaseV1 extends Worker
|
||||
|
||||
if ($e instanceof DatabaseException) {
|
||||
$attribute->setAttribute('error', $e->getMessage());
|
||||
if (!$relatedAttribute->isEmpty()) {
|
||||
if (! $relatedAttribute->isEmpty()) {
|
||||
$relatedAttribute->setAttribute('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -254,7 +255,7 @@ class DatabaseV1 extends Worker
|
||||
$attribute->getId(),
|
||||
$attribute->setAttribute('status', 'stuck')
|
||||
);
|
||||
if (!$relatedAttribute->isEmpty()) {
|
||||
if (! $relatedAttribute->isEmpty()) {
|
||||
$dbForProject->updateDocument(
|
||||
'attributes',
|
||||
$relatedAttribute->getId(),
|
||||
@@ -278,7 +279,7 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -334,20 +335,21 @@ class DatabaseV1 extends Worker
|
||||
}
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId());
|
||||
|
||||
if (!$relatedCollection->isEmpty() && !$relatedAttribute->isEmpty()) {
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
|
||||
if (! $relatedCollection->isEmpty() && ! $relatedAttribute->isEmpty()) {
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $relatedCollection->getId());
|
||||
$dbForProject->deleteCachedCollection('database_'.$database->getInternalId().'_collection_'.$relatedCollection->getInternalId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param Document $project
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param Document $project
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function createIndex(Document $database, Document $collection, Document $index, Document $project): void
|
||||
@@ -359,7 +361,7 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].update', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'indexId' => $index->getId()
|
||||
'indexId' => $index->getId(),
|
||||
]);
|
||||
$collectionId = $collection->getId();
|
||||
$key = $index->getAttribute('key', '');
|
||||
@@ -370,7 +372,7 @@ class DatabaseV1 extends Worker
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if (!$dbForProject->createIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) {
|
||||
if (! $dbForProject->createIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key, $type, $attributes, $lengths, $orders)) {
|
||||
throw new DatabaseException('Failed to create Index');
|
||||
}
|
||||
$dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available'));
|
||||
@@ -402,19 +404,19 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param Document $project
|
||||
* @param Document $database
|
||||
* @param Document $collection
|
||||
* @param Document $index
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteIndex(Document $database, Document $collection, Document $index, Document $project): void
|
||||
{
|
||||
@@ -425,14 +427,14 @@ class DatabaseV1 extends Worker
|
||||
$events = Event::generateEvents('databases.[databaseId].collections.[collectionId].indexes.[indexId].delete', [
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId(),
|
||||
'indexId' => $index->getId()
|
||||
'indexId' => $index->getId(),
|
||||
]);
|
||||
$key = $index->getAttribute('key');
|
||||
$status = $index->getAttribute('status', '');
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
try {
|
||||
if ($status !== 'failed' && !$dbForProject->deleteIndex('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
||||
if ($status !== 'failed' && ! $dbForProject->deleteIndex('database_'.$database->getInternalId().'_collection_'.$collection->getInternalId(), $key)) {
|
||||
throw new DatabaseException('Failed to delete index');
|
||||
}
|
||||
$dbForProject->deleteDocument('indexes', $index->getId());
|
||||
@@ -464,11 +466,11 @@ class DatabaseV1 extends Worker
|
||||
options: [
|
||||
'projectId' => $projectId,
|
||||
'databaseId' => $database->getId(),
|
||||
'collectionId' => $collection->getId()
|
||||
'collectionId' => $collection->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collection->getId());
|
||||
$dbForProject->deleteCachedDocument('database_'.$database->getInternalId(), $collection->getId());
|
||||
}
|
||||
}
|
||||
|
||||
+144
-131
@@ -1,29 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\Abuse\Abuse;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\App;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Cache\Adapter\Filesystem;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Deletes V1 Worker');
|
||||
Console::success(APP_NAME . ' deletes worker v1 has started' . "\n");
|
||||
Console::success(APP_NAME.' deletes worker v1 has started'."\n");
|
||||
|
||||
class DeletesV1 extends Worker
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return "deletes";
|
||||
return 'deletes';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -71,7 +71,7 @@ class DeletesV1 extends Worker
|
||||
$this->deleteCollection($document, $project);
|
||||
break;
|
||||
}
|
||||
Console::error('No lazy delete operation available for document of type: ' . $document->getCollection());
|
||||
Console::error('No lazy delete operation available for document of type: '.$document->getCollection());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -82,14 +82,14 @@ class DeletesV1 extends Worker
|
||||
|
||||
case DELETE_TYPE_AUDIT:
|
||||
$datetime = $this->args['datetime'] ?? null;
|
||||
if (!empty($datetime)) {
|
||||
if (! empty($datetime)) {
|
||||
$this->deleteAuditLogs($datetime);
|
||||
}
|
||||
|
||||
$document = new Document($this->args['document'] ?? []);
|
||||
|
||||
if (!$document->isEmpty()) {
|
||||
$this->deleteAuditLogsByResource('document/' . $document->getId(), $project);
|
||||
if (! $document->isEmpty()) {
|
||||
$this->deleteAuditLogsByResource('document/'.$document->getId(), $project);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -125,7 +125,7 @@ class DeletesV1 extends Worker
|
||||
$this->deleteSchedules($this->args['datetime']);
|
||||
break;
|
||||
default:
|
||||
Console::error('No delete operation for type: ' . $type);
|
||||
Console::error('No delete operation for type: '.$type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,8 @@ class DeletesV1 extends Worker
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
$this->getConsoleDB()->deleteDocument('schedules', $document->getId());
|
||||
Console::success('Deleted schedule for deleted project ' . $document->getAttribute('projectId'));
|
||||
Console::success('Deleted schedule for deleted project '.$document->getAttribute('projectId'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -161,15 +162,16 @@ class DeletesV1 extends Worker
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
$this->getConsoleDB()->deleteDocument('schedules', $document->getId());
|
||||
Console::success('Deleted schedule for function ' . $document->getAttribute('resourceId'));
|
||||
Console::success('Deleted schedule for function '.$document->getAttribute('resourceId'));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $project
|
||||
* @param string $resource
|
||||
* @param Document $project
|
||||
* @param string $resource
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteCacheByResource(Document $project, string $resource): void
|
||||
@@ -180,19 +182,19 @@ class DeletesV1 extends Worker
|
||||
|
||||
if ($document) {
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
|
||||
new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId)
|
||||
);
|
||||
|
||||
$this->deleteById(
|
||||
$document,
|
||||
$dbForProject,
|
||||
function ($document) use ($cache, $projectId) {
|
||||
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
|
||||
$path = APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId.DIRECTORY_SEPARATOR.$document->getId();
|
||||
|
||||
if ($cache->purge($document->getId())) {
|
||||
Console::success('Deleting cache file: ' . $path);
|
||||
Console::success('Deleting cache file: '.$path);
|
||||
} else {
|
||||
Console::error('Failed to delete cache file: ' . $path);
|
||||
Console::error('Failed to delete cache file: '.$path);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -200,7 +202,8 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteCacheByDate(string $datetime): void
|
||||
@@ -209,7 +212,7 @@ class DeletesV1 extends Worker
|
||||
$projectId = $project->getId();
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
|
||||
new Filesystem(APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId)
|
||||
);
|
||||
|
||||
$query = [
|
||||
@@ -221,22 +224,21 @@ class DeletesV1 extends Worker
|
||||
$query,
|
||||
$dbForProject,
|
||||
function (Document $document) use ($cache, $projectId) {
|
||||
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
|
||||
$path = APP_STORAGE_CACHE.DIRECTORY_SEPARATOR.'app-'.$projectId.DIRECTORY_SEPARATOR.$document->getId();
|
||||
|
||||
if ($cache->purge($document->getId())) {
|
||||
Console::success('Deleting cache file: ' . $path);
|
||||
Console::success('Deleting cache file: '.$path);
|
||||
} else {
|
||||
Console::error('Failed to delete cache file: ' . $path);
|
||||
Console::error('Failed to delete cache file: '.$path);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Document $document database document
|
||||
* @param Document $project
|
||||
* @param Document $document database document
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteDatabase(Document $document, Document $project): void
|
||||
{
|
||||
@@ -245,18 +247,18 @@ class DeletesV1 extends Worker
|
||||
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
|
||||
$this->deleteByGroup('database_' . $document->getInternalId(), [], $dbForProject, function ($document) use ($project) {
|
||||
$this->deleteByGroup('database_'.$document->getInternalId(), [], $dbForProject, function ($document) use ($project) {
|
||||
$this->deleteCollection($document, $project);
|
||||
});
|
||||
|
||||
$dbForProject->deleteCollection('database_' . $document->getInternalId());
|
||||
$dbForProject->deleteCollection('database_'.$document->getInternalId());
|
||||
|
||||
$this->deleteAuditLogsByResource('database/' . $databaseId, $project);
|
||||
$this->deleteAuditLogsByResource('database/'.$databaseId, $project);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document teams document
|
||||
* @param Document $project
|
||||
* @param Document $document teams document
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteCollection(Document $document, Document $project): void
|
||||
{
|
||||
@@ -273,32 +275,33 @@ class DeletesV1 extends Worker
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
if (!$relationship['twoWay']) {
|
||||
if (! $relationship['twoWay']) {
|
||||
continue;
|
||||
}
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $databaseInternalId, $relationship['relatedCollection']);
|
||||
$dbForProject->deleteDocument('attributes', $databaseInternalId . '_' . $relatedCollection->getInternalId() . '_' . $relationship['twoWayKey']);
|
||||
$dbForProject->deleteCachedDocument('database_' . $databaseInternalId, $relatedCollection->getId());
|
||||
$dbForProject->deleteCachedCollection('database_' . $databaseInternalId . '_collection_' . $relatedCollection->getInternalId());
|
||||
$relatedCollection = $dbForProject->getDocument('database_'.$databaseInternalId, $relationship['relatedCollection']);
|
||||
$dbForProject->deleteDocument('attributes', $databaseInternalId.'_'.$relatedCollection->getInternalId().'_'.$relationship['twoWayKey']);
|
||||
$dbForProject->deleteCachedDocument('database_'.$databaseInternalId, $relatedCollection->getId());
|
||||
$dbForProject->deleteCachedCollection('database_'.$databaseInternalId.'_collection_'.$relatedCollection->getInternalId());
|
||||
}
|
||||
|
||||
$dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId());
|
||||
$dbForProject->deleteCollection('database_'.$databaseInternalId.'_collection_'.$document->getInternalId());
|
||||
|
||||
$this->deleteByGroup('attributes', [
|
||||
Query::equal('databaseInternalId', [$databaseInternalId]),
|
||||
Query::equal('collectionInternalId', [$collectionInternalId])
|
||||
Query::equal('collectionInternalId', [$collectionInternalId]),
|
||||
], $dbForProject);
|
||||
|
||||
$this->deleteByGroup('indexes', [
|
||||
Query::equal('databaseInternalId', [$databaseInternalId]),
|
||||
Query::equal('collectionInternalId', [$collectionInternalId])
|
||||
Query::equal('collectionInternalId', [$collectionInternalId]),
|
||||
], $dbForProject);
|
||||
|
||||
$this->deleteAuditLogsByResource('database/' . $databaseId . '/collection/' . $collectionId, $project);
|
||||
$this->deleteAuditLogsByResource('database/'.$databaseId.'/collection/'.$collectionId, $project);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hourlyUsageRetentionDatetime
|
||||
* @param string $hourlyUsageRetentionDatetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteUsageStats(string $hourlyUsageRetentionDatetime)
|
||||
@@ -314,8 +317,8 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document teams document
|
||||
* @param Document $project
|
||||
* @param Document $document teams document
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteMemberships(Document $document, Document $project): void
|
||||
{
|
||||
@@ -326,7 +329,7 @@ class DeletesV1 extends Worker
|
||||
$this->deleteByGroup(
|
||||
'memberships',
|
||||
[
|
||||
Query::equal('teamInternalId', [$teamInternalId])
|
||||
Query::equal('teamInternalId', [$teamInternalId]),
|
||||
],
|
||||
$dbForProject,
|
||||
function (Document $membership) use ($dbForProject) {
|
||||
@@ -337,8 +340,9 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Utopia\Database\Document $document
|
||||
* @param \Utopia\Database\Document $document
|
||||
* @return void
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function deleteProjectsByTeam(Document $document): void
|
||||
@@ -346,7 +350,7 @@ class DeletesV1 extends Worker
|
||||
$dbForConsole = $this->getConsoleDB();
|
||||
|
||||
$projects = $dbForConsole->find('projects', [
|
||||
Query::equal('teamInternalId', [$document->getInternalId()])
|
||||
Query::equal('teamInternalId', [$document->getInternalId()]),
|
||||
]);
|
||||
|
||||
foreach ($projects as $project) {
|
||||
@@ -356,7 +360,8 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document project document
|
||||
* @param Document $document project document
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteProject(Document $document): void
|
||||
@@ -368,7 +373,7 @@ class DeletesV1 extends Worker
|
||||
$dbForConsole = $this->getConsoleDB();
|
||||
|
||||
$domains = $dbForConsole->find('domains', [
|
||||
Query::equal('projectInternalId', [$projectInternalId])
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
]);
|
||||
|
||||
foreach ($domains as $domain) {
|
||||
@@ -392,22 +397,22 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete Platforms
|
||||
$this->deleteByGroup('platforms', [
|
||||
Query::equal('projectInternalId', [$projectInternalId])
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
], $dbForConsole);
|
||||
|
||||
// Delete Domains
|
||||
$this->deleteByGroup('domains', [
|
||||
Query::equal('projectInternalId', [$projectInternalId])
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
], $dbForConsole);
|
||||
|
||||
// Delete Keys
|
||||
$this->deleteByGroup('keys', [
|
||||
Query::equal('projectInternalId', [$projectInternalId])
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
], $dbForConsole);
|
||||
|
||||
// Delete Webhooks
|
||||
$this->deleteByGroup('webhooks', [
|
||||
Query::equal('projectInternalId', [$projectInternalId])
|
||||
Query::equal('projectInternalId', [$projectInternalId]),
|
||||
], $dbForConsole);
|
||||
|
||||
// Delete metadata tables
|
||||
@@ -431,8 +436,8 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document user document
|
||||
* @param Document $project
|
||||
* @param Document $document user document
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteUser(Document $document, Document $project): void
|
||||
{
|
||||
@@ -443,19 +448,19 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
|
||||
$this->deleteByGroup('sessions', [
|
||||
Query::equal('userInternalId', [$userInternalId])
|
||||
Query::equal('userInternalId', [$userInternalId]),
|
||||
], $dbForProject);
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $userId);
|
||||
|
||||
// Delete Memberships and decrement team membership counts
|
||||
$this->deleteByGroup('memberships', [
|
||||
Query::equal('userInternalId', [$userInternalId])
|
||||
Query::equal('userInternalId', [$userInternalId]),
|
||||
], $dbForProject, function (Document $document) use ($dbForProject) {
|
||||
if ($document->getAttribute('confirm')) { // Count only confirmed members
|
||||
$teamId = $document->getAttribute('teamId');
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
if (!$team->isEmpty()) {
|
||||
if (! $team->isEmpty()) {
|
||||
$team = $dbForProject->updateDocument(
|
||||
'teams',
|
||||
$teamId,
|
||||
@@ -468,17 +473,18 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete tokens
|
||||
$this->deleteByGroup('tokens', [
|
||||
Query::equal('userInternalId', [$userInternalId])
|
||||
Query::equal('userInternalId', [$userInternalId]),
|
||||
], $dbForProject);
|
||||
|
||||
// Delete identities
|
||||
$this->deleteByGroup('identities', [
|
||||
Query::equal('userInternalId', [$userInternalId])
|
||||
Query::equal('userInternalId', [$userInternalId]),
|
||||
], $dbForProject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteExecutionLogs(string $datetime): void
|
||||
@@ -487,7 +493,7 @@ class DeletesV1 extends Worker
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
// Delete Executions
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::lessThan('$createdAt', $datetime)
|
||||
Query::lessThan('$createdAt', $datetime),
|
||||
], $dbForProject);
|
||||
});
|
||||
}
|
||||
@@ -505,13 +511,14 @@ class DeletesV1 extends Worker
|
||||
|
||||
// Delete Sessions
|
||||
$this->deleteByGroup('sessions', [
|
||||
Query::lessThan('$createdAt', $expired)
|
||||
Query::lessThan('$createdAt', $expired),
|
||||
], $dbForProject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteRealtimeUsage(string $datetime): void
|
||||
@@ -520,13 +527,14 @@ class DeletesV1 extends Worker
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
// Delete Dead Realtime Logs
|
||||
$this->deleteByGroup('realtime', [
|
||||
Query::lessThan('timestamp', $datetime)
|
||||
Query::lessThan('timestamp', $datetime),
|
||||
], $dbForProject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteAbuseLogs(string $datetime): void
|
||||
@@ -538,17 +546,18 @@ class DeletesV1 extends Worker
|
||||
$this->deleteForProjectIds(function (Document $project) use ($datetime) {
|
||||
$projectId = $project->getId();
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
$timeLimit = new TimeLimit("", 0, 1, $dbForProject);
|
||||
$timeLimit = new TimeLimit('', 0, 1, $dbForProject);
|
||||
$abuse = new Abuse($timeLimit);
|
||||
$status = $abuse->cleanup($datetime);
|
||||
if (!$status) {
|
||||
throw new Exception('Failed to delete Abuse logs for project ' . $projectId);
|
||||
if (! $status) {
|
||||
throw new Exception('Failed to delete Abuse logs for project '.$projectId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $datetime
|
||||
* @param string $datetime
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteAuditLogs(string $datetime): void
|
||||
@@ -562,28 +571,28 @@ class DeletesV1 extends Worker
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
$audit = new Audit($dbForProject);
|
||||
$status = $audit->cleanup($datetime);
|
||||
if (!$status) {
|
||||
throw new Exception('Failed to delete Audit logs for project' . $projectId);
|
||||
if (! $status) {
|
||||
throw new Exception('Failed to delete Audit logs for project'.$projectId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $resource
|
||||
* @param Document $project
|
||||
* @param string $resource
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteAuditLogsByResource(string $resource, Document $project): void
|
||||
{
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
|
||||
$this->deleteByGroup(Audit::COLLECTION, [
|
||||
Query::equal('resource', [$resource])
|
||||
Query::equal('resource', [$resource]),
|
||||
], $dbForProject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document function document
|
||||
* @param Document $project
|
||||
* @param Document $document function document
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteFunction(Document $document, Document $project): void
|
||||
{
|
||||
@@ -595,41 +604,41 @@ class DeletesV1 extends Worker
|
||||
/**
|
||||
* Delete Variables
|
||||
*/
|
||||
Console::info("Deleting variables for function " . $functionId);
|
||||
Console::info('Deleting variables for function '.$functionId);
|
||||
$this->deleteByGroup('variables', [
|
||||
Query::equal('functionInternalId', [$functionInternalId])
|
||||
Query::equal('functionInternalId', [$functionInternalId]),
|
||||
], $dbForProject);
|
||||
|
||||
/**
|
||||
* Delete Deployments
|
||||
*/
|
||||
Console::info("Deleting deployments for function " . $functionId);
|
||||
Console::info('Deleting deployments for function '.$functionId);
|
||||
$storageFunctions = $this->getFunctionsDevice($projectId);
|
||||
$deploymentIds = [];
|
||||
$this->deleteByGroup('deployments', [
|
||||
Query::equal('resourceId', [$functionId])
|
||||
Query::equal('resourceId', [$functionId]),
|
||||
], $dbForProject, function (Document $document) use ($storageFunctions, &$deploymentIds) {
|
||||
$deploymentIds[] = $document->getId();
|
||||
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
|
||||
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::success('Deleted deployment files: '.$document->getAttribute('path', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::error('Failed to delete deployment files: '.$document->getAttribute('path', ''));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete builds
|
||||
*/
|
||||
Console::info("Deleting builds for function " . $functionId);
|
||||
Console::info('Deleting builds for function '.$functionId);
|
||||
$storageBuilds = $this->getBuildsDevice($projectId);
|
||||
foreach ($deploymentIds as $deploymentId) {
|
||||
$this->deleteByGroup('builds', [
|
||||
Query::equal('deploymentId', [$deploymentId])
|
||||
], $dbForProject, function (Document $document) use ($storageBuilds, $deploymentId) {
|
||||
Query::equal('deploymentId', [$deploymentId]),
|
||||
], $dbForProject, function (Document $document) use ($storageBuilds) {
|
||||
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
|
||||
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::success('Deleted build files: '.$document->getAttribute('outputPath', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', ''));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -637,17 +646,17 @@ class DeletesV1 extends Worker
|
||||
/**
|
||||
* Delete Executions
|
||||
*/
|
||||
Console::info("Deleting executions for function " . $functionId);
|
||||
Console::info('Deleting executions for function '.$functionId);
|
||||
$this->deleteByGroup('executions', [
|
||||
Query::equal('functionId', [$functionId])
|
||||
Query::equal('functionId', [$functionId]),
|
||||
], $dbForProject);
|
||||
|
||||
// TODO: Request executor to delete runtime
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document deployment document
|
||||
* @param Document $project
|
||||
* @param Document $document deployment document
|
||||
* @param Document $project
|
||||
*/
|
||||
protected function deleteDeployment(Document $document, Document $project): void
|
||||
{
|
||||
@@ -659,45 +668,44 @@ class DeletesV1 extends Worker
|
||||
/**
|
||||
* Delete deployment files
|
||||
*/
|
||||
Console::info("Deleting deployment files for deployment " . $deploymentId);
|
||||
Console::info('Deleting deployment files for deployment '.$deploymentId);
|
||||
$storageFunctions = $this->getFunctionsDevice($projectId);
|
||||
if ($storageFunctions->delete($document->getAttribute('path', ''), true)) {
|
||||
Console::success('Deleted deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::success('Deleted deployment files: '.$document->getAttribute('path', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete deployment files: ' . $document->getAttribute('path', ''));
|
||||
Console::error('Failed to delete deployment files: '.$document->getAttribute('path', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete builds
|
||||
*/
|
||||
Console::info("Deleting builds for deployment " . $deploymentId);
|
||||
Console::info('Deleting builds for deployment '.$deploymentId);
|
||||
$storageBuilds = $this->getBuildsDevice($projectId);
|
||||
$this->deleteByGroup('builds', [
|
||||
Query::equal('deploymentId', [$deploymentId])
|
||||
Query::equal('deploymentId', [$deploymentId]),
|
||||
], $dbForProject, function (Document $document) use ($storageBuilds) {
|
||||
if ($storageBuilds->delete($document->getAttribute('outputPath', ''), true)) {
|
||||
Console::success('Deleted build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::success('Deleted build files: '.$document->getAttribute('outputPath', ''));
|
||||
} else {
|
||||
Console::error('Failed to delete build files: ' . $document->getAttribute('outputPath', ''));
|
||||
Console::error('Failed to delete build files: '.$document->getAttribute('outputPath', ''));
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Request executor to delete runtime
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Document $document to be deleted
|
||||
* @param Database $database to delete it from
|
||||
* @param callable|null $callback to perform after document is deleted
|
||||
*
|
||||
* @param Document $document to be deleted
|
||||
* @param Database $database to delete it from
|
||||
* @param callable|null $callback to perform after document is deleted
|
||||
* @return bool
|
||||
*
|
||||
* @throws \Utopia\Database\Exception\Authorization
|
||||
*/
|
||||
protected function deleteById(Document $document, Database $database, callable $callback = null): bool
|
||||
{
|
||||
if ($database->deleteDocument($document->getCollection(), $document->getId())) {
|
||||
Console::success('Deleted document "' . $document->getId() . '" successfully');
|
||||
Console::success('Deleted document "'.$document->getId().'" successfully');
|
||||
|
||||
if (is_callable($callback)) {
|
||||
$callback($document);
|
||||
@@ -705,13 +713,15 @@ class DeletesV1 extends Worker
|
||||
|
||||
return true;
|
||||
} else {
|
||||
Console::error('Failed to delete document: ' . $document->getId());
|
||||
Console::error('Failed to delete document: '.$document->getId());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
* @param callable $callback
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteForProjectIds(callable $callback): void
|
||||
@@ -733,7 +743,7 @@ class DeletesV1 extends Worker
|
||||
/** @var string[] $projectIds */
|
||||
$sum = count($projects);
|
||||
|
||||
Console::info('Executing delete function for chunk #' . $chunk . '. Found ' . $sum . ' projects');
|
||||
Console::info('Executing delete function for chunk #'.$chunk.'. Found '.$sum.' projects');
|
||||
foreach ($projects as $project) {
|
||||
$callback($project);
|
||||
$count++;
|
||||
@@ -741,14 +751,15 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
Console::info("Found {$count} projects " . ($executionEnd - $executionStart) . " seconds");
|
||||
Console::info("Found {$count} projects ".($executionEnd - $executionStart).' seconds');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $collection collectionID
|
||||
* @param array $queries
|
||||
* @param Database $database
|
||||
* @param callable|null $callback
|
||||
* @param string $collection collectionID
|
||||
* @param array $queries
|
||||
* @param Database $database
|
||||
* @param callable|null $callback
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deleteByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
|
||||
@@ -769,7 +780,7 @@ class DeletesV1 extends Worker
|
||||
|
||||
$sum = count($results);
|
||||
|
||||
Console::info('Deleting chunk #' . $chunk . '. Found ' . $sum . ' documents in collection ' . $database->getNamespace() . '_' . $collection);
|
||||
Console::info('Deleting chunk #'.$chunk.'. Found '.$sum.' documents in collection '.$database->getNamespace().'_'.$collection);
|
||||
|
||||
foreach ($results as $document) {
|
||||
$this->deleteById($document, $database, $callback);
|
||||
@@ -782,14 +793,14 @@ class DeletesV1 extends Worker
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
Console::info("Deleted {$count} document by group in " . ($executionEnd - $executionStart) . " seconds");
|
||||
Console::info("Deleted {$count} document by group in ".($executionEnd - $executionStart).' seconds');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $collection collectionID
|
||||
* @param Query[] $queries
|
||||
* @param Database $database
|
||||
* @param callable $callback
|
||||
* @param string $collection collectionID
|
||||
* @param Query[] $queries
|
||||
* @param Database $database
|
||||
* @param callable $callback
|
||||
*/
|
||||
protected function listByGroup(string $collection, array $queries, Database $database, callable $callback = null): void
|
||||
{
|
||||
@@ -829,11 +840,12 @@ class DeletesV1 extends Worker
|
||||
|
||||
$executionEnd = \microtime(true);
|
||||
|
||||
Console::info("Listed {$count} document by group in " . ($executionEnd - $executionStart) . " seconds");
|
||||
Console::info("Listed {$count} document by group in ".($executionEnd - $executionStart).' seconds');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $document certificates document
|
||||
* @param Document $document certificates document
|
||||
*
|
||||
* @throws \Utopia\Database\Exception\Authorization
|
||||
*/
|
||||
protected function deleteCertificates(Document $document): void
|
||||
@@ -843,10 +855,10 @@ class DeletesV1 extends Worker
|
||||
// If domain has certificate generated
|
||||
if (isset($document['certificateId'])) {
|
||||
$domainUsingCertificate = $consoleDB->findOne('domains', [
|
||||
Query::equal('certificateId', [$document['certificateId']])
|
||||
Query::equal('certificateId', [$document['certificateId']]),
|
||||
]);
|
||||
|
||||
if (!$domainUsingCertificate) {
|
||||
if (! $domainUsingCertificate) {
|
||||
$mainDomain = App::getEnv('_APP_DOMAIN_TARGET', '');
|
||||
if ($mainDomain === $document->getAttribute('domain')) {
|
||||
$domainUsingCertificate = $mainDomain;
|
||||
@@ -856,13 +868,14 @@ class DeletesV1 extends Worker
|
||||
// If certificate is still used by some domain, mark we can't delete.
|
||||
// Current domain should not be found, because we only have copy. Original domain is already deleted from database.
|
||||
if ($domainUsingCertificate) {
|
||||
Console::warning("Skipping certificate deletion, because a domain is still using it.");
|
||||
Console::warning('Skipping certificate deletion, because a domain is still using it.');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$domain = $document->getAttribute('domain');
|
||||
$directory = APP_STORAGE_CERTIFICATES . '/' . $domain;
|
||||
$directory = APP_STORAGE_CERTIFICATES.'/'.$domain;
|
||||
$checkTraversal = realpath($directory) === $directory;
|
||||
|
||||
if ($domain && $checkTraversal && is_dir($directory)) {
|
||||
@@ -872,7 +885,7 @@ class DeletesV1 extends Worker
|
||||
}
|
||||
|
||||
// Delete files, so Traefik is aware of change
|
||||
array_map('unlink', glob($directory . '/*.*'));
|
||||
array_map('unlink', glob($directory.'/*.*'));
|
||||
rmdir($directory);
|
||||
Console::info("Deleted certificate files for {$domain}");
|
||||
} else {
|
||||
@@ -884,7 +897,7 @@ class DeletesV1 extends Worker
|
||||
{
|
||||
$projectId = $project->getId();
|
||||
$dbForProject = $this->getProjectDB($project);
|
||||
$dbForProject->deleteCollection('bucket_' . $document->getInternalId());
|
||||
$dbForProject->deleteCollection('bucket_'.$document->getInternalId());
|
||||
|
||||
$device = $this->getFilesDevice($projectId);
|
||||
|
||||
|
||||
+20
-20
@@ -1,11 +1,10 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../worker.php';
|
||||
require_once __DIR__.'/../worker.php';
|
||||
|
||||
use Appwrite\Event\Usage;
|
||||
use Utopia\Queue\Message;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Utopia\Response\Model\Execution;
|
||||
use Executor\Executor;
|
||||
@@ -16,11 +15,12 @@ use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Queue\Message;
|
||||
use Utopia\Queue\Server;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
Authorization::disable();
|
||||
Authorization::setDefaultStatus(false);
|
||||
@@ -74,8 +74,8 @@ Server::setResource('execute', function () {
|
||||
/** Check if runtime is supported */
|
||||
$runtimes = Config::getParam('runtimes', []);
|
||||
|
||||
if (!\array_key_exists($function->getAttribute('runtime'), $runtimes)) {
|
||||
throw new Exception('Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||
if (! \array_key_exists($function->getAttribute('runtime'), $runtimes)) {
|
||||
throw new Exception('Runtime "'.$function->getAttribute('runtime', '').'" is not supported');
|
||||
}
|
||||
|
||||
$runtime = $runtimes[$function->getAttribute('runtime')];
|
||||
@@ -109,7 +109,6 @@ Server::setResource('execute', function () {
|
||||
/**
|
||||
* Usage
|
||||
*/
|
||||
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_EXECUTIONS, 1) // per project
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1); // per function
|
||||
@@ -120,6 +119,7 @@ Server::setResource('execute', function () {
|
||||
|
||||
$vars = array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value');
|
||||
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
@@ -164,7 +164,7 @@ Server::setResource('execute', function () {
|
||||
} catch (\Throwable $th) {
|
||||
$interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt()));
|
||||
$execution
|
||||
->setAttribute('duration', (float)$interval->format('%s.%f'))
|
||||
->setAttribute('duration', (float) $interval->format('%s.%f'))
|
||||
->setAttribute('status', 'failed')
|
||||
->setAttribute('statusCode', $th->getCode())
|
||||
->setAttribute('stderr', $th->getMessage());
|
||||
@@ -195,7 +195,7 @@ Server::setResource('execute', function () {
|
||||
/** Trigger realtime event */
|
||||
$allEvents = Event::generateEvents('functions.[functionId].executions.[executionId].update', [
|
||||
'functionId' => $function->getId(),
|
||||
'executionId' => $execution->getId()
|
||||
'executionId' => $execution->getId(),
|
||||
]);
|
||||
$target = Realtime::fromPayload(
|
||||
// Pass first, most verbose event pattern
|
||||
@@ -220,10 +220,9 @@ Server::setResource('execute', function () {
|
||||
/** Trigger usage queue */
|
||||
$queueForUsage
|
||||
->setProject($project)
|
||||
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000))// per project
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000))
|
||||
->trigger()
|
||||
;
|
||||
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int) ($execution->getAttribute('duration') * 1000))// per project
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int) ($execution->getAttribute('duration') * 1000))
|
||||
->trigger();
|
||||
};
|
||||
});
|
||||
|
||||
@@ -253,7 +252,7 @@ $server->job()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($events)) {
|
||||
if (! empty($events)) {
|
||||
$limit = 30;
|
||||
$sum = 30;
|
||||
$offset = 0;
|
||||
@@ -262,19 +261,19 @@ $server->job()
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::limit($limit),
|
||||
Query::offset($offset)
|
||||
Query::offset($offset),
|
||||
]);
|
||||
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
|
||||
Console::log('Fetched ' . $sum . ' functions...');
|
||||
Console::log('Fetched '.$sum.' functions...');
|
||||
|
||||
foreach ($functions as $function) {
|
||||
if (!array_intersect($events, $function->getAttribute('events', []))) {
|
||||
if (! array_intersect($events, $function->getAttribute('events', []))) {
|
||||
continue;
|
||||
}
|
||||
Console::success('Iterating function: ' . $function->getAttribute('name'));
|
||||
Console::success('Iterating function: '.$function->getAttribute('name'));
|
||||
try {
|
||||
$execute(
|
||||
log: $log,
|
||||
@@ -291,12 +290,13 @@ $server->job()
|
||||
executionId: null,
|
||||
jwt: null
|
||||
);
|
||||
Console::success('Triggered function: ' . $events[0]);
|
||||
Console::success('Triggered function: '.$events[0]);
|
||||
} catch (\Throwable $th) {
|
||||
Console::error("Failed to execute " . $function->getId() . " with error: " . $th->getMessage());
|
||||
Console::error('Failed to execute '.$function->getId().' with error: '.$th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Resque\Worker;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Mails V1 Worker');
|
||||
Console::success(APP_NAME . ' mails worker v1 has started' . "\n");
|
||||
Console::success(APP_NAME.' mails worker v1 has started'."\n");
|
||||
|
||||
class MailsV1 extends Worker
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return "mails";
|
||||
return 'mails';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -29,10 +29,10 @@ class MailsV1 extends Worker
|
||||
|
||||
if (empty($smtp) && empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
Console::info('Skipped mail processing. No SMTP configuration has been set.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$recipient = $this->args['recipient'];
|
||||
$subject = $this->args['subject'];
|
||||
$name = $this->args['name'];
|
||||
@@ -49,7 +49,7 @@ class MailsV1 extends Worker
|
||||
$mail->clearBCCs();
|
||||
$mail->clearCCs();
|
||||
|
||||
$mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server')) : $from));
|
||||
$mail->setFrom(App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), (empty($from) ? \urldecode(App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server')) : $from));
|
||||
$mail->addAddress($recipient, $name);
|
||||
if (isset($smtp['replyTo'])) {
|
||||
$mail->addReplyTo($smtp['replyTo']);
|
||||
@@ -61,7 +61,7 @@ class MailsV1 extends Worker
|
||||
try {
|
||||
$mail->send();
|
||||
} catch (\Exception $error) {
|
||||
throw new Exception('Error sending mail: ' . $error->getMessage(), 500);
|
||||
throw new Exception('Error sending mail: '.$error->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,14 +77,14 @@ class MailsV1 extends Worker
|
||||
$mail->XMailer = 'Appwrite Mailer';
|
||||
$mail->Host = $smtp['host'];
|
||||
$mail->Port = $smtp['port'];
|
||||
$mail->SMTPAuth = (!empty($username) && !empty($password));
|
||||
$mail->SMTPAuth = (! empty($username) && ! empty($password));
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->SMTPSecure = $smtp['secure'] === 'tls';
|
||||
$mail->SMTPAutoTLS = false;
|
||||
$mail->CharSet = 'UTF-8';
|
||||
|
||||
$from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'));
|
||||
$from = \urldecode($smtp['senderName'] ?? App::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server'));
|
||||
$email = $smtp['senderEmail'] ?? App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
|
||||
|
||||
$mail->setFrom($email, $from);
|
||||
|
||||
+20
-17
@@ -2,41 +2,43 @@
|
||||
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Messaging\Adapters\Email as EmailAdapter;
|
||||
use Utopia\Messaging\Adapters\Email\Mailgun;
|
||||
use Utopia\Messaging\Adapters\Email\SendGrid;
|
||||
use Utopia\Messaging\Adapters\Push\APNS;
|
||||
use Utopia\Messaging\Adapters\Push as PushAdapter;
|
||||
use Utopia\Messaging\Adapters\Push\FCM;
|
||||
use Utopia\Messaging\Adapters\SMS as SMSAdapter;
|
||||
use Utopia\Messaging\Adapters\SMS\Msg91;
|
||||
use Utopia\Messaging\Adapters\SMS\Telesign;
|
||||
use Utopia\Messaging\Adapters\SMS\TextMagic;
|
||||
use Utopia\Messaging\Adapters\SMS\Twilio;
|
||||
use Utopia\Messaging\Adapters\SMS\Vonage;
|
||||
use Utopia\Messaging\Adapters\Push as PushAdapter;
|
||||
use Utopia\Messaging\Adapters\Push\APNS;
|
||||
use Utopia\Messaging\Adapters\Push\FCM;
|
||||
use Utopia\Messaging\Adapters\Email as EmailAdapter;
|
||||
use Utopia\Messaging\Adapters\Email\Mailgun;
|
||||
use Utopia\Messaging\Adapters\Email\SendGrid;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Messaging V1 Worker');
|
||||
Console::success(APP_NAME . ' messaging worker v1 has started' . "\n");
|
||||
Console::success(APP_NAME.' messaging worker v1 has started'."\n");
|
||||
|
||||
class MessagingV1 extends Worker
|
||||
{
|
||||
protected ?SMSAdapter $sms = null;
|
||||
protected ?PushAdapter $push = null;
|
||||
protected ?EmailAdapter $email = null;
|
||||
|
||||
protected ?PushAdapter $push = null;
|
||||
|
||||
protected ?EmailAdapter $email = null;
|
||||
|
||||
protected ?string $from = null;
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "mails";
|
||||
return 'mails';
|
||||
}
|
||||
|
||||
public function sms($record): ?SMSAdapter
|
||||
{
|
||||
$credentials = $record->getAttribute('credentials');
|
||||
|
||||
return match ($record->getAttribute('provider')) {
|
||||
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']),
|
||||
'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']),
|
||||
@@ -50,6 +52,7 @@ class MessagingV1 extends Worker
|
||||
public function push($record): ?PushAdapter
|
||||
{
|
||||
$credentials = $record->getAttribute('credentials');
|
||||
|
||||
return match ($record->getAttribute('provider')) {
|
||||
'apns' => new APNS(
|
||||
$credentials['authKey'],
|
||||
@@ -66,6 +69,7 @@ class MessagingV1 extends Worker
|
||||
public function email($record): ?EmailAdapter
|
||||
{
|
||||
$credentials = $record->getAttribute('credentials');
|
||||
|
||||
return match ($record->getAttribute('provider')) {
|
||||
'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain']),
|
||||
'sendgrid' => new SendGrid($credentials['apiKey']),
|
||||
@@ -92,9 +96,9 @@ class MessagingV1 extends Worker
|
||||
default => null
|
||||
};
|
||||
|
||||
// Query for the provider
|
||||
// switch on provider name
|
||||
// call function passing needed credentials returns required provider.
|
||||
// Query for the provider
|
||||
// switch on provider name
|
||||
// call function passing needed credentials returns required provider.
|
||||
|
||||
$messageId = $this->args['messageId'];
|
||||
$messageRecord =
|
||||
@@ -109,7 +113,6 @@ class MessagingV1 extends Worker
|
||||
default => null
|
||||
};
|
||||
|
||||
|
||||
$provider->send($message);
|
||||
}
|
||||
|
||||
@@ -141,7 +144,7 @@ class MessagingV1 extends Worker
|
||||
return [
|
||||
'from' => $from,
|
||||
'to' => $to,
|
||||
'body' => $body
|
||||
'body' => $body,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -156,7 +159,7 @@ class MessagingV1 extends Worker
|
||||
'to' => $to,
|
||||
'title' => $title,
|
||||
'body' => $body,
|
||||
'data' => $data
|
||||
'data' => $data,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ use Utopia\Migration\Sources\NHost;
|
||||
use Utopia\Migration\Sources\Supabase;
|
||||
use Utopia\Migration\Transfer;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Migrations V1 Worker');
|
||||
Console::success(APP_NAME . ' Migrations worker v1 has started');
|
||||
Console::success(APP_NAME.' Migrations worker v1 has started');
|
||||
|
||||
class MigrationsV1 extends Worker
|
||||
{
|
||||
|
||||
+45
-47
@@ -1,17 +1,17 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../worker.php';
|
||||
require_once __DIR__.'/../worker.php';
|
||||
|
||||
use Swoole\Timer;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Queue\Message;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Queue\Server;
|
||||
use Utopia\Registry\Registry;
|
||||
|
||||
@@ -20,8 +20,8 @@ Authorization::setDefaultStatus(false);
|
||||
|
||||
$stats = [];
|
||||
|
||||
$periods['1h'] = 'Y-m-d H:00';
|
||||
$periods['1d'] = 'Y-m-d 00:00';
|
||||
$periods['1h'] = 'Y-m-d H:00';
|
||||
$periods['1d'] = 'Y-m-d 00:00';
|
||||
//$periods['1m'] = 'Y-m-1 00:00';
|
||||
$periods['inf'] = '0000-00-00 00:00';
|
||||
|
||||
@@ -32,7 +32,7 @@ const INFINITY_PERIOD = '_inf_';
|
||||
* When we remove a parent document we need to deduct his children aggregation from the project scope.
|
||||
*/
|
||||
Server::setResource('reduce', function (Cache $cache, Registry $register, $pools) {
|
||||
return function ($database, $projectInternalId, Document $document, array &$metrics) use ($pools, $cache, $register): void {
|
||||
return function ($database, $projectInternalId, Document $document, array &$metrics) use ($pools, $cache): void {
|
||||
try {
|
||||
$dbForProject = new Database(
|
||||
$pools
|
||||
@@ -42,12 +42,12 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools
|
||||
$cache
|
||||
);
|
||||
|
||||
$dbForProject->setNamespace('_' . $projectInternalId);
|
||||
$dbForProject->setNamespace('_'.$projectInternalId);
|
||||
|
||||
switch (true) {
|
||||
case $document->getCollection() === 'users': // users
|
||||
$sessions = count($document->getAttribute(METRIC_SESSIONS, 0));
|
||||
if (!empty($sessions)) {
|
||||
if (! empty($sessions)) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_SESSIONS,
|
||||
'value' => ($sessions * -1),
|
||||
@@ -55,28 +55,28 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools
|
||||
}
|
||||
break;
|
||||
case $document->getCollection() === 'databases': // databases
|
||||
$collections = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS)));
|
||||
$documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS)));
|
||||
if (!empty($collections['value'])) {
|
||||
$collections = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS)));
|
||||
$documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{databaseInternalId}', $document->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS)));
|
||||
if (! empty($collections['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_COLLECTIONS,
|
||||
'value' => ($collections['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($documents['value'])) {
|
||||
if (! empty($documents['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_DOCUMENTS,
|
||||
'value' => ($documents['value'] * -1),
|
||||
];
|
||||
}
|
||||
break;
|
||||
case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections
|
||||
case str_starts_with($document->getCollection(), 'database_') && ! str_contains($document->getCollection(), 'collection'): //collections
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $document->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS)));
|
||||
$documents = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $document->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS)));
|
||||
|
||||
if (!empty($documents['value'])) {
|
||||
if (! empty($documents['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_DOCUMENTS,
|
||||
'value' => ($documents['value'] * -1),
|
||||
@@ -89,17 +89,17 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools
|
||||
break;
|
||||
|
||||
case $document->getCollection() === 'buckets':
|
||||
$files = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES)));
|
||||
$storage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE)));
|
||||
$files = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES)));
|
||||
$storage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE)));
|
||||
|
||||
if (!empty($files['value'])) {
|
||||
if (! empty($files['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_FILES,
|
||||
'value' => ($files['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($storage['value'])) {
|
||||
if (! empty($storage['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_FILES_STORAGE,
|
||||
'value' => ($storage['value'] * -1),
|
||||
@@ -108,57 +108,57 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools
|
||||
break;
|
||||
|
||||
case $document->getCollection() === 'functions':
|
||||
$deployments = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS)));
|
||||
$deploymentsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE)));
|
||||
$builds = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS)));
|
||||
$buildsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE)));
|
||||
$buildsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE)));
|
||||
$executions = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS)));
|
||||
$executionsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD . str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE)));
|
||||
$deployments = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS)));
|
||||
$deploymentsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace(['{resourceType}', '{resourceInternalId}'], ['functions', $document->getInternalId()], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE)));
|
||||
$builds = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS)));
|
||||
$buildsStorage = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE)));
|
||||
$buildsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE)));
|
||||
$executions = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS)));
|
||||
$executionsCompute = $dbForProject->getDocument('stats', md5(INFINITY_PERIOD.str_replace('{functionInternalId}', $document->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE)));
|
||||
|
||||
if (!empty($deployments['value'])) {
|
||||
if (! empty($deployments['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_DEPLOYMENTS,
|
||||
'value' => ($deployments['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($deploymentsStorage['value'])) {
|
||||
if (! empty($deploymentsStorage['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_DEPLOYMENTS_STORAGE,
|
||||
'value' => ($deploymentsStorage['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($builds['value'])) {
|
||||
if (! empty($builds['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_BUILDS,
|
||||
'value' => ($builds['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($buildsStorage['value'])) {
|
||||
if (! empty($buildsStorage['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_BUILDS_STORAGE,
|
||||
'value' => ($buildsStorage['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($buildsCompute['value'])) {
|
||||
if (! empty($buildsCompute['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_BUILDS_COMPUTE,
|
||||
'value' => ($buildsCompute['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($executions['value'])) {
|
||||
if (! empty($executions['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_EXECUTIONS,
|
||||
'value' => ($executions['value'] * -1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($executionsCompute['value'])) {
|
||||
if (! empty($executionsCompute['value'])) {
|
||||
$metrics[] = [
|
||||
'key' => METRIC_EXECUTIONS_COMPUTE,
|
||||
'value' => ($executionsCompute['value'] * -1),
|
||||
@@ -169,20 +169,18 @@ Server::setResource('reduce', function (Cache $cache, Registry $register, $pools
|
||||
break;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
console::error("[reducer] " . " {DateTime::now()} " . " {$projectInternalId} " . " {$e->getMessage()}");
|
||||
console::error('[reducer] '.' {DateTime::now()} '." {$projectInternalId} "." {$e->getMessage()}");
|
||||
} finally {
|
||||
$pools->reclaim();
|
||||
}
|
||||
};
|
||||
}, ['cache', 'register', 'pools']);
|
||||
|
||||
|
||||
$server->job()
|
||||
->inject('message')
|
||||
->inject('reduce')
|
||||
|
||||
->action(function (Message $message, callable $reduce) use (&$stats) {
|
||||
|
||||
$payload = $message->getPayload() ?? [];
|
||||
$project = new Document($payload['project'] ?? []);
|
||||
$projectId = $project->getInternalId();
|
||||
@@ -191,18 +189,19 @@ $server->job()
|
||||
continue;
|
||||
}
|
||||
|
||||
$reduce(
|
||||
database: $project->getAttribute('database'),
|
||||
projectInternalId: $project->getInternalId(),
|
||||
document: new Document($document),
|
||||
metrics: $payload['metrics'],
|
||||
);
|
||||
$reduce(
|
||||
database: $project->getAttribute('database'),
|
||||
projectInternalId: $project->getInternalId(),
|
||||
document: new Document($document),
|
||||
metrics: $payload['metrics'],
|
||||
);
|
||||
}
|
||||
|
||||
$stats[$projectId]['database'] = $project->getAttribute('database');
|
||||
foreach ($payload['metrics'] ?? [] as $metric) {
|
||||
if (!isset($stats[$projectId]['keys'][$metric['key']])) {
|
||||
if (! isset($stats[$projectId]['keys'][$metric['key']])) {
|
||||
$stats[$projectId]['keys'][$metric['key']] = $metric['value'];
|
||||
|
||||
continue;
|
||||
}
|
||||
$stats[$projectId]['keys'][$metric['key']] += $metric['value'];
|
||||
@@ -215,8 +214,7 @@ $server
|
||||
->inject('cache')
|
||||
->inject('pools')
|
||||
->action(function ($register, $cache, $pools) use ($periods, &$stats) {
|
||||
Timer::tick(30000, function () use ($register, $cache, $pools, $periods, &$stats) {
|
||||
|
||||
Timer::tick(30000, function () use ($cache, $pools, $periods, &$stats) {
|
||||
$offset = count($stats);
|
||||
$projects = array_slice($stats, 0, $offset, true);
|
||||
array_splice($stats, 0, $offset);
|
||||
@@ -231,7 +229,7 @@ $server
|
||||
$cache
|
||||
);
|
||||
|
||||
$dbForProject->setNamespace('_' . $projectInternalId);
|
||||
$dbForProject->setNamespace('_'.$projectInternalId);
|
||||
|
||||
foreach ($project['keys'] ?? [] as $key => $value) {
|
||||
if ($value == 0) {
|
||||
@@ -270,7 +268,7 @@ $server
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($project['keys'])) {
|
||||
if (! empty($project['keys'])) {
|
||||
$dbForProject->createDocument('statsLogger', new Document([
|
||||
'time' => DateTime::now(),
|
||||
'metrics' => $project['keys'],
|
||||
@@ -278,7 +276,7 @@ $server
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$now = DateTime::now();
|
||||
console::error("[Error] " . " Time: {$now} " . " projectInternalId: {$projectInternalId}" . " File: {$e->getFile()}" . " Line: {$e->getLine()} " . " message: {$e->getMessage()}");
|
||||
console::error('[Error] '." Time: {$now} "." projectInternalId: {$projectInternalId}"." File: {$e->getFile()}"." Line: {$e->getLine()} "." message: {$e->getMessage()}");
|
||||
} finally {
|
||||
$pools->reclaim();
|
||||
}
|
||||
|
||||
+15
-15
@@ -5,10 +5,10 @@ use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
require_once __DIR__ . '/../init.php';
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
Console::title('Webhooks V1 Worker');
|
||||
Console::success(APP_NAME . ' webhooks worker v1 has started');
|
||||
Console::success(APP_NAME.' webhooks worker v1 has started');
|
||||
|
||||
class WebhooksV1 extends Worker
|
||||
{
|
||||
@@ -16,7 +16,7 @@ class WebhooksV1 extends Worker
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return "webhooks";
|
||||
return 'webhooks';
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
@@ -36,7 +36,7 @@ class WebhooksV1 extends Worker
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->errors)) {
|
||||
if (! empty($this->errors)) {
|
||||
throw new Exception(\implode(" / \n\n", $this->errors));
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class WebhooksV1 extends Worker
|
||||
{
|
||||
$url = \rawurldecode($webhook->getAttribute('url'));
|
||||
$signatureKey = $webhook->getAttribute('signatureKey');
|
||||
$signature = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true));
|
||||
$signature = base64_encode(hash_hmac('sha1', $url.$payload, $signatureKey, true));
|
||||
$httpUser = $webhook->getAttribute('httpUser');
|
||||
$httpPass = $webhook->getAttribute('httpPass');
|
||||
$ch = \curl_init($webhook->getAttribute('url'));
|
||||
@@ -64,28 +64,28 @@ class WebhooksV1 extends Worker
|
||||
CURLOPT_HTTPHEADER,
|
||||
[
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . \strlen($payload),
|
||||
'X-' . APP_NAME . '-Webhook-Id: ' . $webhook->getId(),
|
||||
'X-' . APP_NAME . '-Webhook-Events: ' . implode(',', $events),
|
||||
'X-' . APP_NAME . '-Webhook-Name: ' . $webhook->getAttribute('name', ''),
|
||||
'X-' . APP_NAME . '-Webhook-User-Id: ' . $user->getId(),
|
||||
'X-' . APP_NAME . '-Webhook-Project-Id: ' . $project->getId(),
|
||||
'X-' . APP_NAME . '-Webhook-Signature: ' . $signature,
|
||||
'Content-Length: '.\strlen($payload),
|
||||
'X-'.APP_NAME.'-Webhook-Id: '.$webhook->getId(),
|
||||
'X-'.APP_NAME.'-Webhook-Events: '.implode(',', $events),
|
||||
'X-'.APP_NAME.'-Webhook-Name: '.$webhook->getAttribute('name', ''),
|
||||
'X-'.APP_NAME.'-Webhook-User-Id: '.$user->getId(),
|
||||
'X-'.APP_NAME.'-Webhook-Project-Id: '.$project->getId(),
|
||||
'X-'.APP_NAME.'-Webhook-Signature: '.$signature,
|
||||
]
|
||||
);
|
||||
|
||||
if (!$webhook->getAttribute('security', true)) {
|
||||
if (! $webhook->getAttribute('security', true)) {
|
||||
\curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
\curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
}
|
||||
|
||||
if (!empty($httpUser) && !empty($httpPass)) {
|
||||
if (! empty($httpUser) && ! empty($httpPass)) {
|
||||
\curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass");
|
||||
\curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
}
|
||||
|
||||
if (false === \curl_exec($ch)) {
|
||||
$this->errors[] = \curl_error($ch) . ' in events ' . implode(', ', $events) . ' for webhook ' . $webhook->getAttribute('name');
|
||||
$this->errors[] = \curl_error($ch).' in events '.implode(', ', $events).' for webhook '.$webhook->getAttribute('name');
|
||||
}
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
+69
-48
@@ -9,8 +9,8 @@ use Appwrite\Auth\Hash\Phpass;
|
||||
use Appwrite\Auth\Hash\Scrypt;
|
||||
use Appwrite\Auth\Hash\Scryptmodified;
|
||||
use Appwrite\Auth\Hash\Sha;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
@@ -25,49 +25,69 @@ class Auth
|
||||
'phpass',
|
||||
'scrypt',
|
||||
'scryptMod',
|
||||
'plaintext'
|
||||
'plaintext',
|
||||
];
|
||||
|
||||
public const DEFAULT_ALGO = 'argon2';
|
||||
|
||||
public const DEFAULT_ALGO_OPTIONS = ['type' => 'argon2', 'memoryCost' => 2048, 'timeCost' => 4, 'threads' => 3];
|
||||
|
||||
/**
|
||||
* User Roles.
|
||||
*/
|
||||
public const USER_ROLE_ANY = 'any';
|
||||
|
||||
public const USER_ROLE_GUESTS = 'guests';
|
||||
|
||||
public const USER_ROLE_USERS = 'users';
|
||||
|
||||
public const USER_ROLE_ADMIN = 'admin';
|
||||
|
||||
public const USER_ROLE_DEVELOPER = 'developer';
|
||||
|
||||
public const USER_ROLE_OWNER = 'owner';
|
||||
|
||||
public const USER_ROLE_APPS = 'apps';
|
||||
|
||||
public const USER_ROLE_SYSTEM = 'system';
|
||||
|
||||
/**
|
||||
* Token Types.
|
||||
*/
|
||||
public const TOKEN_TYPE_LOGIN = 1; // Deprecated
|
||||
|
||||
public const TOKEN_TYPE_VERIFICATION = 2;
|
||||
|
||||
public const TOKEN_TYPE_RECOVERY = 3;
|
||||
|
||||
public const TOKEN_TYPE_INVITE = 4;
|
||||
|
||||
public const TOKEN_TYPE_MAGIC_URL = 5;
|
||||
|
||||
public const TOKEN_TYPE_PHONE = 6;
|
||||
|
||||
/**
|
||||
* Session Providers.
|
||||
*/
|
||||
public const SESSION_PROVIDER_EMAIL = 'email';
|
||||
|
||||
public const SESSION_PROVIDER_ANONYMOUS = 'anonymous';
|
||||
|
||||
public const SESSION_PROVIDER_MAGIC_URL = 'magic-url';
|
||||
|
||||
public const SESSION_PROVIDER_PHONE = 'phone';
|
||||
|
||||
/**
|
||||
* Token Expiration times.
|
||||
*/
|
||||
public const TOKEN_EXPIRATION_LOGIN_LONG = 31536000; /* 1 year */
|
||||
|
||||
public const TOKEN_EXPIRATION_LOGIN_SHORT = 3600; /* 1 hour */
|
||||
|
||||
public const TOKEN_EXPIRATION_RECOVERY = 3600; /* 1 hour */
|
||||
|
||||
public const TOKEN_EXPIRATION_CONFIRM = 3600 * 24 * 7; /* 7 days */
|
||||
|
||||
public const TOKEN_EXPIRATION_PHONE = 60 * 15; /* 15 minutes */
|
||||
|
||||
/**
|
||||
@@ -93,7 +113,6 @@ class Auth
|
||||
* Set Cookie Name.
|
||||
*
|
||||
* @param $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function setCookieName($string)
|
||||
@@ -104,9 +123,8 @@ class Auth
|
||||
/**
|
||||
* Encode Session.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $secret
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $secret
|
||||
* @return string
|
||||
*/
|
||||
public static function encodeSession($id, $secret)
|
||||
@@ -120,8 +138,7 @@ class Auth
|
||||
/**
|
||||
* Decode Session.
|
||||
*
|
||||
* @param string $session
|
||||
*
|
||||
* @param string $session
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -131,7 +148,7 @@ class Auth
|
||||
$session = \json_decode(\base64_decode($session), true);
|
||||
$default = ['id' => null, 'secret' => ''];
|
||||
|
||||
if (!\is_array($session)) {
|
||||
if (! \is_array($session)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
@@ -144,7 +161,6 @@ class Auth
|
||||
* One-way encryption
|
||||
*
|
||||
* @param $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function hash(string $string)
|
||||
@@ -157,10 +173,9 @@ class Auth
|
||||
*
|
||||
* One way string hashing for user passwords
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $algo hashing algorithm to use
|
||||
* @param array $options algo-specific options
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $algo hashing algorithm to use
|
||||
* @param array $options algo-specific options
|
||||
* @return bool|string|null
|
||||
*/
|
||||
public static function passwordHash(string $string, string $algo, array $options = [])
|
||||
@@ -171,45 +186,51 @@ class Auth
|
||||
$options = Auth::DEFAULT_ALGO_OPTIONS;
|
||||
}
|
||||
|
||||
if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
|
||||
switch ($algo) {
|
||||
case 'argon2':
|
||||
$hasher = new Argon2($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'bcrypt':
|
||||
$hasher = new Bcrypt($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'md5':
|
||||
$hasher = new Md5($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'sha':
|
||||
$hasher = new Sha($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'phpass':
|
||||
$hasher = new Phpass($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'scrypt':
|
||||
$hasher = new Scrypt($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
case 'scryptMod':
|
||||
$hasher = new Scryptmodified($options);
|
||||
|
||||
return $hasher->hash($string);
|
||||
default:
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Password verify.
|
||||
*
|
||||
* @param string $plain
|
||||
* @param string $hash
|
||||
* @param string $algo hashing algorithm used to hash
|
||||
* @param array $options algo-specific options
|
||||
*
|
||||
* @param string $plain
|
||||
* @param string $hash
|
||||
* @param string $algo hashing algorithm used to hash
|
||||
* @param array $options algo-specific options
|
||||
* @return bool
|
||||
*/
|
||||
public static function passwordVerify(string $plain, string $hash, string $algo, array $options = [])
|
||||
@@ -220,34 +241,41 @@ class Auth
|
||||
$options = Auth::DEFAULT_ALGO_OPTIONS;
|
||||
}
|
||||
|
||||
if (!\in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
if (! \in_array($algo, Auth::SUPPORTED_ALGOS)) {
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
|
||||
switch ($algo) {
|
||||
case 'argon2':
|
||||
$hasher = new Argon2($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'bcrypt':
|
||||
$hasher = new Bcrypt($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'md5':
|
||||
$hasher = new Md5($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'sha':
|
||||
$hasher = new Sha($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'phpass':
|
||||
$hasher = new Phpass($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'scrypt':
|
||||
$hasher = new Scrypt($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
case 'scryptMod':
|
||||
$hasher = new Scryptmodified($options);
|
||||
|
||||
return $hasher->verify($plain, $hash);
|
||||
default:
|
||||
throw new \Exception('Hashing algorithm \'' . $algo . '\' is not supported.');
|
||||
throw new \Exception('Hashing algorithm \''.$algo.'\' is not supported.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,8 +284,7 @@ class Auth
|
||||
*
|
||||
* Generate random password string
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public static function passwordGenerator(int $length = 20): string
|
||||
@@ -270,8 +297,7 @@ class Auth
|
||||
*
|
||||
* Generate random password string
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public static function tokenGenerator(int $length = 128): string
|
||||
@@ -284,8 +310,7 @@ class Auth
|
||||
*
|
||||
* Generate random code string
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
public static function codeGenerator(int $length = 6): string
|
||||
@@ -302,10 +327,9 @@ class Auth
|
||||
/**
|
||||
* Verify token and check that its not expired.
|
||||
*
|
||||
* @param array $tokens
|
||||
* @param int $type
|
||||
* @param string $secret
|
||||
*
|
||||
* @param array $tokens
|
||||
* @param int $type
|
||||
* @param string $secret
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function tokenVerify(array $tokens, int $type, string $secret)
|
||||
@@ -320,7 +344,7 @@ class Auth
|
||||
$token->getAttribute('secret') === self::hash($secret) &&
|
||||
DateTime::formatTz($token->getAttribute('expire')) >= DateTime::formatTz(DateTime::now())
|
||||
) {
|
||||
return (string)$token->getId();
|
||||
return (string) $token->getId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,10 +373,9 @@ class Auth
|
||||
/**
|
||||
* Verify session and check that its not expired.
|
||||
*
|
||||
* @param array $sessions
|
||||
* @param string $secret
|
||||
* @param string $expires
|
||||
*
|
||||
* @param array $sessions
|
||||
* @param string $secret
|
||||
* @param string $expires
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function sessionVerify(array $sessions, string $secret, int $expires)
|
||||
@@ -375,8 +398,7 @@ class Auth
|
||||
/**
|
||||
* Is Privileged User?
|
||||
*
|
||||
* @param array $roles
|
||||
*
|
||||
* @param array $roles
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPrivilegedUser(array $roles): bool
|
||||
@@ -395,8 +417,7 @@ class Auth
|
||||
/**
|
||||
* Is App User?
|
||||
*
|
||||
* @param array $roles
|
||||
*
|
||||
* @param array $roles
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAppUser(array $roles): bool
|
||||
@@ -411,14 +432,14 @@ class Auth
|
||||
/**
|
||||
* Returns all roles for a user.
|
||||
*
|
||||
* @param Document $user
|
||||
* @param Document $user
|
||||
* @return array
|
||||
*/
|
||||
public static function getRoles(Document $user): array
|
||||
{
|
||||
$roles = [];
|
||||
|
||||
if (!self::isPrivilegedUser(Authorization::getRoles()) && !self::isAppUser(Authorization::getRoles())) {
|
||||
if (! self::isPrivilegedUser(Authorization::getRoles()) && ! self::isAppUser(Authorization::getRoles())) {
|
||||
if ($user->getId()) {
|
||||
$roles[] = Role::user($user->getId())->toString();
|
||||
$roles[] = Role::users()->toString();
|
||||
@@ -439,7 +460,7 @@ class Auth
|
||||
}
|
||||
|
||||
foreach ($user->getAttribute('memberships', []) as $node) {
|
||||
if (!isset($node['confirm']) || !$node['confirm']) {
|
||||
if (! isset($node['confirm']) || ! $node['confirm']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -456,7 +477,7 @@ class Auth
|
||||
}
|
||||
|
||||
foreach ($user->getAttribute('labels', []) as $label) {
|
||||
$roles[] = 'label:' . $label;
|
||||
$roles[] = 'label:'.$label;
|
||||
}
|
||||
|
||||
return $roles;
|
||||
|
||||
+12
-13
@@ -5,13 +5,13 @@ namespace Appwrite\Auth;
|
||||
abstract class Hash
|
||||
{
|
||||
/**
|
||||
* @var array $options Hashing-algo specific options
|
||||
*/
|
||||
* @var array Hashing-algo specific options
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->setOptions($options);
|
||||
@@ -20,11 +20,12 @@ abstract class Hash
|
||||
/**
|
||||
* Set hashing algo options
|
||||
*
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
* @param array $options Hashing-algo specific options
|
||||
*/
|
||||
public function setOptions(array $options): self
|
||||
{
|
||||
$this->options = \array_merge([], $this->getDefaultOptions(), $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -32,24 +33,22 @@ abstract class Hash
|
||||
* Get hashing algo options
|
||||
*
|
||||
* @return array $options Hashing-algo specific options
|
||||
*/
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
abstract public function hash(string $password): string;
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
abstract public function verify(string $password, string $hash): bool;
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ use Appwrite\Auth\Hash;
|
||||
class Argon2 extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -25,10 +24,9 @@ class Argon2 extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
|
||||
@@ -14,8 +14,7 @@ use Appwrite\Auth\Hash;
|
||||
class Bcrypt extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -24,10 +23,9 @@ class Bcrypt extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -41,6 +39,6 @@ class Bcrypt extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'cost' => 8 ];
|
||||
return ['cost' => 8];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ use Appwrite\Auth\Hash;
|
||||
class Md5 extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -22,10 +21,9 @@ class Md5 extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@ class Phpass extends Hash
|
||||
* Alphabet used in itoa64 conversions.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @since 0.1.0
|
||||
*/
|
||||
protected string $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
@@ -59,8 +60,7 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -68,7 +68,7 @@ class Phpass extends Hash
|
||||
$options = $this->getDefaultOptions();
|
||||
|
||||
$random = '';
|
||||
if (CRYPT_BLOWFISH === 1 && !$options['portable_hashes']) {
|
||||
if (CRYPT_BLOWFISH === 1 && ! $options['portable_hashes']) {
|
||||
$random = $this->getRandomBytes(16, $options);
|
||||
$hash = crypt($password, $this->gensaltBlowfish($random, $options));
|
||||
if (strlen($hash) === 60) {
|
||||
@@ -92,10 +92,9 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -114,15 +113,16 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $count
|
||||
* @param int $count
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*
|
||||
* @throws Exception Thows an Exception if the $count parameter is not a positive integer.
|
||||
*/
|
||||
protected function getRandomBytes(int $count, array $options): string
|
||||
{
|
||||
if (!is_int($count) || $count < 1) {
|
||||
if (! is_int($count) || $count < 1) {
|
||||
throw new \Exception('Argument count must be a positive integer');
|
||||
}
|
||||
$output = '';
|
||||
@@ -135,7 +135,7 @@ class Phpass extends Hash
|
||||
$output = '';
|
||||
|
||||
for ($i = 0; $i < $count; $i += 16) {
|
||||
$options['iteration_count_log2'] = md5(microtime() . $options['iteration_count_log2']);
|
||||
$options['iteration_count_log2'] = md5(microtime().$options['iteration_count_log2']);
|
||||
$output .= md5($options['iteration_count_log2'], true);
|
||||
}
|
||||
|
||||
@@ -146,47 +146,48 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
* @param int $count
|
||||
* @param string $input
|
||||
* @param int $count
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*
|
||||
* @throws Exception Thows an Exception if the $count parameter is not a positive integer.
|
||||
*/
|
||||
protected function encode64($input, $count)
|
||||
{
|
||||
if (!is_int($count) || $count < 1) {
|
||||
if (! is_int($count) || $count < 1) {
|
||||
throw new \Exception('Argument count must be a positive integer');
|
||||
}
|
||||
$output = '';
|
||||
$i = 0;
|
||||
do {
|
||||
$value = ord($input[$i++]);
|
||||
$output .= $this->itoa64[$value & 0x3f];
|
||||
$output .= $this->itoa64[$value & 0x3F];
|
||||
if ($i < $count) {
|
||||
$value |= ord($input[$i]) << 8;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 6) & 0x3f];
|
||||
$output .= $this->itoa64[($value >> 6) & 0x3F];
|
||||
if ($i++ >= $count) {
|
||||
break;
|
||||
}
|
||||
if ($i < $count) {
|
||||
$value |= ord($input[$i]) << 16;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 12) & 0x3f];
|
||||
$output .= $this->itoa64[($value >> 12) & 0x3F];
|
||||
if ($i++ >= $count) {
|
||||
break;
|
||||
}
|
||||
$output .= $this->itoa64[($value >> 18) & 0x3f];
|
||||
$output .= $this->itoa64[($value >> 18) & 0x3F];
|
||||
} while ($i < $count);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
* @param string $input
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function gensaltPrivate($input, $options)
|
||||
@@ -199,10 +200,10 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $password
|
||||
* @param String $setting
|
||||
* @param string $password
|
||||
* @param string $setting
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function cryptPrivate($password, $setting)
|
||||
@@ -233,9 +234,9 @@ class Phpass extends Hash
|
||||
* consequently in lower iteration counts and hashes that are
|
||||
* quicker to crack (by non-PHP code).
|
||||
*/
|
||||
$hash = md5($salt . $password, true);
|
||||
$hash = md5($salt.$password, true);
|
||||
do {
|
||||
$hash = md5($hash . $password, true);
|
||||
$hash = md5($hash.$password, true);
|
||||
} while (--$count);
|
||||
$output = substr($setting, 0, 12);
|
||||
$output .= $this->encode64($hash, 16);
|
||||
@@ -244,9 +245,9 @@ class Phpass extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $input
|
||||
* @param string $input
|
||||
* @return string $output
|
||||
*
|
||||
* @return String $output
|
||||
* @since 0.1.0
|
||||
*/
|
||||
private function gensaltBlowfish($input, $options)
|
||||
@@ -278,11 +279,11 @@ class Phpass extends Hash
|
||||
$c2 = ord($input[$i++]);
|
||||
$c1 |= $c2 >> 4;
|
||||
$output .= $itoa64[$c1];
|
||||
$c1 = ($c2 & 0x0f) << 2;
|
||||
$c1 = ($c2 & 0x0F) << 2;
|
||||
$c2 = ord($input[$i++]);
|
||||
$c1 |= $c2 >> 6;
|
||||
$output .= $itoa64[$c1];
|
||||
$output .= $itoa64[$c2 & 0x3f];
|
||||
$output .= $itoa64[$c2 & 0x3F];
|
||||
} while (1);
|
||||
|
||||
return $output;
|
||||
|
||||
@@ -17,8 +17,7 @@ use Appwrite\Auth\Hash;
|
||||
class Scrypt extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -29,10 +28,9 @@ class Scrypt extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -46,6 +44,6 @@ class Scrypt extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64 ];
|
||||
return ['costCpu' => 8, 'costMemory' => 14, 'costParallel' => 1, 'length' => 64];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ use Appwrite\Auth\Hash;
|
||||
class Scryptmodified extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -33,10 +32,9 @@ class Scryptmodified extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -50,7 +48,7 @@ class Scryptmodified extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ ];
|
||||
return [];
|
||||
}
|
||||
|
||||
private function generateDerivedKey(string $password)
|
||||
@@ -60,7 +58,7 @@ class Scryptmodified extends Hash
|
||||
$saltBytes = \base64_decode($options['salt']);
|
||||
$saltSeparatorBytes = \base64_decode($options['saltSeparator']);
|
||||
|
||||
$derivedKey = \scrypt(\utf8_encode($password), $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64);
|
||||
$derivedKey = \scrypt(\utf8_encode($password), $saltBytes.$saltSeparatorBytes, 16384, 8, 1, 64);
|
||||
$derivedKey = \hex2bin($derivedKey);
|
||||
|
||||
return $derivedKey;
|
||||
|
||||
@@ -16,8 +16,7 @@ use Appwrite\Auth\Hash;
|
||||
class Sha extends Hash
|
||||
{
|
||||
/**
|
||||
* @param string $password Input password to hash
|
||||
*
|
||||
* @param string $password Input password to hash
|
||||
* @return string hash
|
||||
*/
|
||||
public function hash(string $password): string
|
||||
@@ -28,10 +27,9 @@ class Sha extends Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
*
|
||||
* @return boolean true if password matches hash
|
||||
* @param string $password Input password to validate
|
||||
* @param string $hash Hash to verify password against
|
||||
* @return bool true if password matches hash
|
||||
*/
|
||||
public function verify(string $password, string $hash): bool
|
||||
{
|
||||
@@ -45,6 +43,6 @@ class Sha extends Hash
|
||||
*/
|
||||
public function getDefaultOptions(): array
|
||||
{
|
||||
return [ 'version' => 'sha3-512' ];
|
||||
return ['version' => 'sha3-512'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@ abstract class OAuth2
|
||||
/**
|
||||
* OAuth2 constructor.
|
||||
*
|
||||
* @param string $appId
|
||||
* @param string $appSecret
|
||||
* @param string $callback
|
||||
* @param array $state
|
||||
* @param array $scopes
|
||||
* @param string $appId
|
||||
* @param string $appSecret
|
||||
* @param string $callback
|
||||
* @param array $state
|
||||
* @param array $scopes
|
||||
*/
|
||||
public function __construct(string $appId, string $appSecret, string $callback, array $state = [], array $scopes = [])
|
||||
{
|
||||
@@ -62,29 +62,25 @@ abstract class OAuth2
|
||||
abstract public function getLoginURL(): string;
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getTokens(string $code): array;
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
abstract public function refreshTokens(string $refreshToken): array;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserID(string $accessToken): string;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserEmail(string $accessToken): string;
|
||||
@@ -92,28 +88,25 @@ abstract class OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isEmailVerified(string $accessToken): bool;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserName(string $accessToken): string;
|
||||
|
||||
/**
|
||||
* @param $scope
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addScope(string $scope): OAuth2
|
||||
{
|
||||
// Add a scope to the scopes array if it isn't already present
|
||||
if (!\in_array($scope, $this->scopes)) {
|
||||
if (! \in_array($scope, $this->scopes)) {
|
||||
$this->scopes[] = $scope;
|
||||
}
|
||||
|
||||
@@ -129,8 +122,7 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken(string $code): string
|
||||
@@ -141,8 +133,7 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken(string $code): string
|
||||
@@ -153,8 +144,7 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessTokenExpiry(string $code): int
|
||||
@@ -169,7 +159,6 @@ abstract class OAuth2
|
||||
// json_decoding
|
||||
/**
|
||||
* @param $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parseState(string $state)
|
||||
@@ -178,11 +167,10 @@ abstract class OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param string $url
|
||||
* @param array $headers
|
||||
* @param string $payload
|
||||
*
|
||||
* @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 = ''): string
|
||||
@@ -194,11 +182,11 @@ abstract class OAuth2
|
||||
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
\curl_setopt($ch, CURLOPT_USERAGENT, 'Appwrite OAuth2');
|
||||
|
||||
if (!empty($payload)) {
|
||||
if (! empty($payload)) {
|
||||
\curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
}
|
||||
|
||||
$headers[] = 'Content-length: ' . \strlen($payload);
|
||||
$headers[] = 'Content-length: '.\strlen($payload);
|
||||
\curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
// Send the request & save response to $response
|
||||
@@ -212,6 +200,6 @@ abstract class OAuth2
|
||||
throw new Exception($response, $code);
|
||||
}
|
||||
|
||||
return (string)$response;
|
||||
return (string) $response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class Amazon extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"profile"
|
||||
'profile',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -37,8 +37,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function parseState(string $state)
|
||||
@@ -46,24 +45,22 @@ class Amazon extends OAuth2
|
||||
return \json_decode(\html_entity_decode($state), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.amazon.com/ap/oa?' . \http_build_query([
|
||||
return 'https://www.amazon.com/ap/oa?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -79,7 +76,7 @@ class Amazon extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -88,8 +85,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -103,7 +99,7 @@ class Amazon extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -115,8 +111,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -127,8 +122,7 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -143,20 +137,18 @@ class Amazon extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Amazon sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -167,16 +159,16 @@ class Amazon extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ class Apple extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"name",
|
||||
"email"
|
||||
'name',
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -46,19 +46,18 @@ class Apple extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://appleid.apple.com/auth/authorize?' . \http_build_query([
|
||||
return 'https://appleid.apple.com/auth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code',
|
||||
'response_mode' => 'form_post',
|
||||
'scope' => \implode(' ', $this->getScopes())
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -86,8 +85,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -116,8 +114,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -126,8 +123,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -140,8 +136,7 @@ class Apple extends OAuth2
|
||||
*
|
||||
* @link https://developer.apple.com/forums/thread/121411
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -154,15 +149,14 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
if (
|
||||
isset($this->claims['email']) &&
|
||||
!empty($this->claims['email']) &&
|
||||
! empty($this->claims['email']) &&
|
||||
isset($this->claims['email_verified']) &&
|
||||
$this->claims['email_verified'] === 'true'
|
||||
) {
|
||||
@@ -183,7 +177,7 @@ class Apple extends OAuth2
|
||||
$keyfile = (isset($secret['p8'])) ? $secret['p8'] : ''; // Your p8 Key file
|
||||
$keyID = (isset($secret['keyID'])) ? $secret['keyID'] : ''; // Your Key ID
|
||||
$teamID = (isset($secret['teamID'])) ? $secret['teamID'] : ''; // Your Team ID (see Developer Portal)
|
||||
$bundleID = $this->appID; // Your Bundle ID
|
||||
$bundleID = $this->appID; // Your Bundle ID
|
||||
|
||||
$headers = [
|
||||
'alg' => 'ES256',
|
||||
@@ -200,22 +194,21 @@ class Apple extends OAuth2
|
||||
|
||||
$pkey = \openssl_pkey_get_private($keyfile);
|
||||
|
||||
$payload = $this->encode(\json_encode($headers)) . '.' . $this->encode(\json_encode($claims));
|
||||
$payload = $this->encode(\json_encode($headers)).'.'.$this->encode(\json_encode($claims));
|
||||
|
||||
$signature = '';
|
||||
|
||||
$success = \openssl_sign($payload, $signature, $pkey, OPENSSL_ALGO_SHA256);
|
||||
|
||||
if (!$success) {
|
||||
if (! $success) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $payload . '.' . $this->encode($this->fromDER($signature, 64));
|
||||
return $payload.'.'.$this->encode($this->fromDER($signature, 64));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
protected function encode($data): string
|
||||
@@ -224,7 +217,7 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param string $data
|
||||
*/
|
||||
protected function retrievePositiveInteger(string $data): string
|
||||
{
|
||||
@@ -236,8 +229,8 @@ class Apple extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $der
|
||||
* @param int $partLength
|
||||
* @param string $der
|
||||
* @param int $partLength
|
||||
*/
|
||||
protected function fromDER(string $der, int $partLength): string
|
||||
{
|
||||
@@ -270,6 +263,6 @@ class Apple extends OAuth2
|
||||
$S = $this->retrievePositiveInteger(\mb_substr($hex, 4, $Sl * 2, '8bit'));
|
||||
$S = \str_pad($S, $partLength, '0', STR_PAD_LEFT);
|
||||
|
||||
return \pack('H*', $R . $S);
|
||||
return \pack('H*', $R.$S);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class Auth0 extends OAuth2
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
'offline_access',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,18 +42,17 @@ class Auth0 extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://' . $this->getAuth0Domain() . '/authorize?' . \http_build_query([
|
||||
return 'https://'.$this->getAuth0Domain().'/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Auth0 extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuth0Domain() . '/oauth/token',
|
||||
'https://'.$this->getAuth0Domain().'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,7 +69,7 @@ class Auth0 extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -78,10 +77,8 @@ class Auth0 extends OAuth2
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -89,13 +86,13 @@ class Auth0 extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuth0Domain() . '/oauth/token',
|
||||
'https://'.$this->getAuth0Domain().'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -107,8 +104,7 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -119,8 +115,7 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -135,8 +130,7 @@ class Auth0 extends OAuth2
|
||||
*
|
||||
* @link https://auth0.com/docs/api/authentication?javascript#user-profile
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -151,8 +145,7 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -163,15 +156,14 @@ class Auth0 extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getAuth0Domain() . '/userinfo', $headers);
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getAuth0Domain().'/userinfo', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -214,6 +206,7 @@ class Auth0 extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class Authentik extends OAuth2
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
'offline_access',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,18 +42,17 @@ class Authentik extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://' . $this->getAuthentikDomain() . '/application/o/authorize?' . \http_build_query([
|
||||
return 'https://'.$this->getAuthentikDomain().'/application/o/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Authentik extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuthentikDomain() . '/application/o/token/',
|
||||
'https://'.$this->getAuthentikDomain().'/application/o/token/',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,17 +69,16 @@ class Authentik extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -88,13 +86,13 @@ class Authentik extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getAuthentikDomain() . '/application/o/token/',
|
||||
'https://'.$this->getAuthentikDomain().'/application/o/token/',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -106,8 +104,7 @@ class Authentik extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,8 +119,7 @@ class Authentik extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -140,8 +136,7 @@ class Authentik extends OAuth2
|
||||
/**
|
||||
* Check if the User email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -156,8 +151,7 @@ class Authentik extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -171,16 +165,15 @@ class Authentik extends OAuth2
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
/**
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getAuthentikDomain() . '/application/o/userinfo/', $headers);
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getAuthentikDomain().'/application/o/userinfo/', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -199,7 +192,7 @@ class Authentik extends OAuth2
|
||||
return $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Extracts the authentik Domain from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
@@ -207,6 +200,7 @@ class Authentik extends OAuth2
|
||||
protected function getAuthentikDomain(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
return $secret['authentikDomain'] ?? '';
|
||||
}
|
||||
|
||||
@@ -222,6 +216,7 @@ class Authentik extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,18 +36,17 @@ class Autodesk extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://developer.api.autodesk.com/authentication/v1/authorize?' . \http_build_query([
|
||||
return 'https://developer.api.autodesk.com/authentication/v1/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -63,7 +62,7 @@ class Autodesk extends OAuth2
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
);
|
||||
|
||||
@@ -74,8 +73,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -105,8 +103,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -117,8 +114,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -133,8 +129,7 @@ class Autodesk extends OAuth2
|
||||
*
|
||||
* @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -149,8 +144,7 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -161,14 +155,13 @@ class Autodesk extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://developer.api.autodesk.com/userprofile/v1/users/@me', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class Bitbucket extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://bitbucket.org/site/oauth2/authorize?' . \http_build_query([
|
||||
return 'https://bitbucket.org/site/oauth2/authorize?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
@@ -46,8 +46,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -63,7 +62,7 @@ class Bitbucket extends OAuth2
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,8 +71,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -87,7 +85,7 @@ class Bitbucket extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -99,8 +97,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -111,8 +108,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -125,8 +121,7 @@ class Bitbucket extends OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -141,8 +136,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -153,17 +147,16 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
$emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token=' . \urlencode($accessToken));
|
||||
$emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token='.\urlencode($accessToken));
|
||||
$emails = \json_decode($emails, true);
|
||||
if (isset($emails['values'])) {
|
||||
foreach ($emails['values'] as $email) {
|
||||
@@ -175,6 +168,7 @@ class Bitbucket extends OAuth2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,17 +47,16 @@ class Bitly extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?' .
|
||||
return $this->endpoint.'authorize?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -65,14 +64,14 @@ class Bitly extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint . 'oauth/access_token',
|
||||
["Content-Type: application/x-www-form-urlencoded"],
|
||||
$this->resourceEndpoint.'oauth/access_token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"code" => $code,
|
||||
"redirect_uri" => $this->callback,
|
||||
"state" => \json_encode($this->state)
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
])
|
||||
);
|
||||
|
||||
@@ -85,21 +84,20 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint . 'oauth/access_token',
|
||||
["Content-Type: application/x-www-form-urlencoded"],
|
||||
$this->resourceEndpoint.'oauth/access_token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"refresh_token" => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
);
|
||||
|
||||
@@ -115,8 +113,7 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -127,8 +124,7 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -151,8 +147,7 @@ class Bitly extends OAuth2
|
||||
*
|
||||
* @link https://dev.bitly.com/api-reference#getUser
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -161,8 +156,7 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -173,19 +167,18 @@ class Bitly extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
"Accept: application/json"
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Accept: application/json',
|
||||
];
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', $this->resourceEndpoint . "v4/user", $headers), true);
|
||||
$this->user = \json_decode($this->request('GET', $this->resourceEndpoint.'v4/user', $headers), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -49,7 +49,7 @@ class Box extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . 'authorize?' .
|
||||
$url = $this->endpoint.'authorize?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
@@ -62,8 +62,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -72,15 +71,15 @@ class Box extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'token',
|
||||
$this->endpoint.'token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"code" => $code,
|
||||
"grant_type" => "authorization_code",
|
||||
"scope" => \implode(',', $this->getScopes()),
|
||||
"redirect_uri" => $this->callback
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
'scope' => \implode(',', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -89,8 +88,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -98,13 +96,13 @@ class Box extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'token',
|
||||
$this->endpoint.'token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"refresh_token" => $refreshToken,
|
||||
"grant_type" => "refresh_token",
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -116,8 +114,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -128,8 +125,7 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -144,20 +140,18 @@ class Box extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Box sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -168,19 +162,18 @@ class Box extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$header = [
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
];
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint . 'me',
|
||||
$this->resourceEndpoint.'me',
|
||||
$header
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
@@ -24,7 +24,7 @@ class Dailymotion extends OAuth2
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'userinfo',
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -34,7 +34,7 @@ class Dailymotion extends OAuth2
|
||||
'email',
|
||||
'id',
|
||||
'fullname',
|
||||
'verified'
|
||||
'verified',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -68,21 +68,20 @@ class Dailymotion extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->authEndpoint . '?' .
|
||||
$url = $this->authEndpoint.'?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes())
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -90,33 +89,31 @@ class Dailymotion extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
["Content-Type: application/x-www-form-urlencoded"],
|
||||
$this->endpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
"client_id" => $this->appID,
|
||||
"client_secret" => $this->appSecret,
|
||||
"redirect_uri" => $this->callback,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'code' => $code,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -130,13 +127,11 @@ class Dailymotion extends OAuth2
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -149,8 +144,7 @@ class Dailymotion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -166,8 +160,7 @@ class Dailymotion extends OAuth2
|
||||
*
|
||||
* @link https://developers.dailymotion.com/api/#user-fields
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -178,23 +171,20 @@ class Dailymotion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
|
||||
$username = $user['fullname'] ?? '';
|
||||
|
||||
return $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -202,8 +192,8 @@ class Dailymotion extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '/user/me?fields=' . \implode(',', $this->getFields()),
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)],
|
||||
$this->endpoint.'/user/me?fields='.\implode(',', $this->getFields()),
|
||||
['Authorization: Bearer '.\urlencode($accessToken)],
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ class Discord extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'identify',
|
||||
'email'
|
||||
'identify',
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -45,21 +45,20 @@ class Discord extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . '/oauth2/authorize?' .
|
||||
$url = $this->endpoint.'/oauth2/authorize?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -67,7 +66,7 @@ class Discord extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth2/token',
|
||||
$this->endpoint.'/oauth2/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -75,7 +74,7 @@ class Discord extends OAuth2
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'scope' => \implode(' ', $this->getScopes())
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -84,15 +83,14 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth2/token',
|
||||
$this->endpoint.'/oauth2/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -110,8 +108,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,8 +119,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -138,8 +134,7 @@ class Discord extends OAuth2
|
||||
*
|
||||
* @link https://discord.com/developers/docs/resources/user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -154,8 +149,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -166,8 +160,7 @@ class Discord extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -175,8 +168,8 @@ class Discord extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '/users/@me',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->endpoint.'/users/@me',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -45,21 +45,20 @@ class Disqus extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . 'oauth/2.0/authorize/?' .
|
||||
$url = $this->endpoint.'oauth/2.0/authorize/?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(',', $this->getScopes())
|
||||
'scope' => \implode(',', $this->getScopes()),
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -67,7 +66,7 @@ class Disqus extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'oauth/2.0/access_token/',
|
||||
$this->endpoint.'oauth/2.0/access_token/',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -79,19 +78,19 @@ class Disqus extends OAuth2
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'oauth/2.0/access_token/?',
|
||||
$this->endpoint.'oauth/2.0/access_token/?',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -104,12 +103,12 @@ class Disqus extends OAuth2
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @param string $token
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,8 +121,7 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -136,13 +134,11 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
|
||||
// Look out for the change in their enpoint.
|
||||
// It's in Beta so they may provide a parameter in the future.
|
||||
// https://disqus.com/api/docs/users/details/
|
||||
@@ -151,8 +147,7 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -165,8 +160,7 @@ class Disqus extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -174,10 +168,10 @@ class Disqus extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->endpoint . '3.0/users/details.json?' . \http_build_query([
|
||||
$this->endpoint.'3.0/users/details.json?'.\http_build_query([
|
||||
'access_token' => $accessToken,
|
||||
'api_key' => $this->appID,
|
||||
'api_secret' => $this->appSecret
|
||||
'api_secret' => $this->appSecret,
|
||||
]),
|
||||
);
|
||||
$this->user = \json_decode($user, true)['response'];
|
||||
|
||||
@@ -38,17 +38,16 @@ class Dropbox extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.dropbox.com/oauth2/authorize?' . \http_build_query([
|
||||
return 'https://www.dropbox.com/oauth2/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -64,7 +63,7 @@ class Dropbox extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -73,8 +72,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -88,7 +86,7 @@ class Dropbox extends OAuth2
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -100,8 +98,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -112,8 +109,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -128,8 +124,7 @@ class Dropbox extends OAuth2
|
||||
*
|
||||
* @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -144,8 +139,7 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -156,14 +150,13 @@ class Dropbox extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('POST', 'https://api.dropboxapi.com/2/users/get_current_account', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ class Etsy extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"email_r",
|
||||
"profile_r",
|
||||
'email_r',
|
||||
'profile_r',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ class Etsy extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.etsy.com/oauth/connect/oauth/authorize?' . \http_build_query([
|
||||
return 'https://www.etsy.com/oauth/connect/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
@@ -76,8 +76,7 @@ class Etsy extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -87,7 +86,7 @@ class Etsy extends OAuth2
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -103,8 +102,7 @@ class Etsy extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -113,7 +111,7 @@ class Etsy extends OAuth2
|
||||
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -131,7 +129,6 @@ class Etsy extends OAuth2
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -143,7 +140,6 @@ class Etsy extends OAuth2
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -156,20 +152,18 @@ class Etsy extends OAuth2
|
||||
*
|
||||
* OAuth is only allowed if account has been verified through Etsy, itself.
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -178,21 +172,20 @@ class Etsy extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (!empty($this->user)) {
|
||||
if (! empty($this->user)) {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
$headers = ['Authorization: Bearer ' . $accessToken];
|
||||
$headers = ['Authorization: Bearer '.$accessToken];
|
||||
|
||||
$this->user = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://api.etsy.com/v3/application/users/' . $this->getUserID($accessToken),
|
||||
'https://api.etsy.com/v3/application/users/'.$this->getUserID($accessToken),
|
||||
), true);
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -7,7 +7,9 @@ use Appwrite\Extend\Exception as AppwriteException;
|
||||
class Exception extends AppwriteException
|
||||
{
|
||||
protected string $response = '';
|
||||
|
||||
protected string $error = '';
|
||||
|
||||
protected string $errorDescription = '';
|
||||
|
||||
public function __construct(string $response = '', int $code = 0, \Throwable $previous = null)
|
||||
@@ -19,11 +21,11 @@ class Exception extends AppwriteException
|
||||
if (\is_array($decoded['error'])) {
|
||||
$this->error = $decoded['error']['status'];
|
||||
$this->errorDescription = $decoded['error']['message'];
|
||||
$this->message = $this->error . ': ' . $this->errorDescription;
|
||||
$this->message = $this->error.': '.$this->errorDescription;
|
||||
} else {
|
||||
$this->error = $decoded['error'];
|
||||
$this->errorDescription = $decoded['error_description'];
|
||||
$this->message = $this->error . ': ' . $this->errorDescription;
|
||||
$this->message = $this->error.': '.$this->errorDescription;
|
||||
}
|
||||
}
|
||||
$type = match ($code) {
|
||||
|
||||
@@ -25,7 +25,7 @@ class Facebook extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -41,17 +41,16 @@ class Facebook extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.facebook.com/' . $this->version . '/dialog/oauth?' . \http_build_query([
|
||||
return 'https://www.facebook.com/'.$this->version.'/dialog/oauth?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -59,11 +58,11 @@ class Facebook extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([
|
||||
'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,20 +71,19 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([
|
||||
'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -97,8 +95,7 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -109,8 +106,7 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -125,20 +121,18 @@ class Facebook extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Facebook sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -149,14 +143,13 @@ class Facebook extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://graph.facebook.com/' . $this->version . '/me?fields=email,name&access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/me?fields=email,name&access_token='.\urlencode($accessToken));
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class Firebase extends OAuth2
|
||||
'https://www.googleapis.com/auth/datastore',
|
||||
'https://www.googleapis.com/auth/cloud-platform',
|
||||
'https://www.googleapis.com/auth/identitytoolkit',
|
||||
'https://www.googleapis.com/auth/userinfo.profile'
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ class Firebase extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?'.\http_build_query([
|
||||
'access_type' => 'offline',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
@@ -52,8 +52,7 @@ class Firebase extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -68,19 +67,18 @@ class Firebase extends OAuth2
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
);
|
||||
|
||||
$this->tokens = \json_decode($response, true);
|
||||
$this->tokens = \json_decode($response, true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -93,7 +91,7 @@ class Firebase extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
);
|
||||
|
||||
@@ -108,10 +106,8 @@ class Firebase extends OAuth2
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,8 +118,7 @@ class Firebase extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -133,14 +128,12 @@ class Firebase extends OAuth2
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -155,8 +148,7 @@ class Firebase extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -167,8 +159,7 @@ class Firebase extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
@@ -176,7 +167,7 @@ class Firebase extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$response = $this->request(
|
||||
'GET',
|
||||
'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' . \urlencode($accessToken),
|
||||
'https://www.googleapis.com/oauth2/v1/userinfo?access_token='.\urlencode($accessToken),
|
||||
[],
|
||||
);
|
||||
|
||||
@@ -188,7 +179,7 @@ class Firebase extends OAuth2
|
||||
|
||||
public function getProjects(string $accessToken): array
|
||||
{
|
||||
$projects = $this->request('GET', 'https://firebase.googleapis.com/v1beta1/projects', ['Authorization: Bearer ' . \urlencode($accessToken)]);
|
||||
$projects = $this->request('GET', 'https://firebase.googleapis.com/v1beta1/projects', ['Authorization: Bearer '.\urlencode($accessToken)]);
|
||||
|
||||
$projects = \json_decode($projects, true);
|
||||
|
||||
@@ -201,9 +192,9 @@ class Firebase extends OAuth2
|
||||
public function assignIAMRoles(string $accessToken, string $email, string $projectId)
|
||||
{
|
||||
// Get IAM Roles
|
||||
$iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':getIamPolicy', [
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Content-Type: application/json'
|
||||
$iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':getIamPolicy', [
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Content-Type: application/json',
|
||||
]);
|
||||
|
||||
$iamRoles = \json_decode($iamRoles, true);
|
||||
@@ -211,23 +202,23 @@ class Firebase extends OAuth2
|
||||
$iamRoles['bindings'][] = [
|
||||
'role' => 'roles/identitytoolkit.admin',
|
||||
'members' => [
|
||||
'serviceAccount:' . $email
|
||||
]
|
||||
'serviceAccount:'.$email,
|
||||
],
|
||||
];
|
||||
|
||||
$iamRoles['bindings'][] = [
|
||||
'role' => 'roles/firebase.admin',
|
||||
'members' => [
|
||||
'serviceAccount:' . $email
|
||||
]
|
||||
'serviceAccount:'.$email,
|
||||
],
|
||||
];
|
||||
|
||||
// Set IAM Roles
|
||||
$this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/' . $projectId . ':setIamPolicy', [
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Content-Type: application/json'
|
||||
$this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':setIamPolicy', [
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Content-Type: application/json',
|
||||
], json_encode([
|
||||
'policy' => $iamRoles
|
||||
'policy' => $iamRoles,
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -236,16 +227,16 @@ class Firebase extends OAuth2
|
||||
// Create Service Account
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts',
|
||||
'https://iam.googleapis.com/v1/projects/'.$projectId.'/serviceAccounts',
|
||||
[
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Content-Type: application/json'
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Content-Type: application/json',
|
||||
],
|
||||
json_encode([
|
||||
'accountId' => 'appwrite-migrations',
|
||||
'serviceAccount' => [
|
||||
'displayName' => 'Appwrite Migrations'
|
||||
]
|
||||
'displayName' => 'Appwrite Migrations',
|
||||
],
|
||||
])
|
||||
);
|
||||
|
||||
@@ -256,10 +247,10 @@ class Firebase extends OAuth2
|
||||
// Create Service Account Key
|
||||
$responseKey = $this->request(
|
||||
'POST',
|
||||
'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts/' . $response['email'] . '/keys',
|
||||
'https://iam.googleapis.com/v1/projects/'.$projectId.'/serviceAccounts/'.$response['email'].'/keys',
|
||||
[
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Content-Type: application/json'
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Content-Type: application/json',
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -36,17 +36,16 @@ class Github extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://github.com/login/oauth/authorize?' . \http_build_query([
|
||||
return 'https://github.com/login/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -60,7 +59,7 @@ class Github extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
);
|
||||
|
||||
@@ -73,8 +72,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -87,7 +85,7 @@ class Github extends OAuth2
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken
|
||||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
);
|
||||
|
||||
@@ -103,8 +101,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -115,8 +112,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -131,8 +127,7 @@ class Github extends OAuth2
|
||||
*
|
||||
* @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -147,8 +142,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -159,8 +153,7 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserSlug(string $accessToken): string
|
||||
@@ -171,16 +164,15 @@ class Github extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token ' . \urlencode($accessToken)]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token '.\urlencode($accessToken)]), true);
|
||||
|
||||
$emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token ' . \urlencode($accessToken)]);
|
||||
$emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token '.\urlencode($accessToken)]);
|
||||
|
||||
$emails = \json_decode($emails, true);
|
||||
|
||||
@@ -197,10 +189,10 @@ class Github extends OAuth2
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($primaryEmail)) {
|
||||
if (! empty($primaryEmail)) {
|
||||
$this->user['email'] = $primaryEmail['email'];
|
||||
$this->user['verified'] = $primaryEmail['verified'];
|
||||
} elseif (!empty($verifiedEmail)) {
|
||||
} elseif (! empty($verifiedEmail)) {
|
||||
$this->user['email'] = $verifiedEmail['email'];
|
||||
$this->user['verified'] = $verifiedEmail['verified'];
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class Gitlab extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'read_user'
|
||||
'read_user',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -39,18 +39,17 @@ class Gitlab extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->getEndpoint() . '/oauth/authorize?' . \http_build_query([
|
||||
return $this->getEndpoint().'/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -58,12 +57,12 @@ class Gitlab extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->getEndpoint() . '/oauth/token?' . \http_build_query([
|
||||
$this->getEndpoint().'/oauth/token?'.\http_build_query([
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getAppSecret()['clientSecret'],
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,19 +71,18 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->getEndpoint() . '/oauth/token?' . \http_build_query([
|
||||
$this->getEndpoint().'/oauth/token?'.\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getAppSecret()['clientSecret'],
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -96,8 +94,7 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -112,8 +109,7 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -128,8 +124,7 @@ class Gitlab extends OAuth2
|
||||
*
|
||||
* @link https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -144,8 +139,7 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -156,14 +150,13 @@ class Gitlab extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', $this->getEndpoint() . '/api/v4/user?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', $this->getEndpoint().'/api/v4/user?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -182,10 +175,10 @@ class Gitlab extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the Tenant Id from the JSON stored in appSecret. Defaults to 'common' as a fallback
|
||||
*
|
||||
@@ -196,6 +189,7 @@ class Gitlab extends OAuth2
|
||||
$defaultEndpoint = 'https://gitlab.com';
|
||||
$secret = $this->getAppSecret();
|
||||
$endpoint = $secret['endpoint'] ?? $defaultEndpoint;
|
||||
|
||||
return empty($endpoint) ? $defaultEndpoint : $endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class Google extends OAuth2
|
||||
protected array $scopes = [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'openid'
|
||||
'openid',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -48,18 +48,17 @@ class Google extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -67,13 +66,13 @@ class Google extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://oauth2.googleapis.com/token?' . \http_build_query([
|
||||
'https://oauth2.googleapis.com/token?'.\http_build_query([
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => null,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -82,19 +81,18 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://oauth2.googleapis.com/token?' . \http_build_query([
|
||||
'https://oauth2.googleapis.com/token?'.\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -106,8 +104,7 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -118,8 +115,7 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -134,8 +130,7 @@ class Google extends OAuth2
|
||||
*
|
||||
* @link https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info/
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -150,8 +145,7 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -162,14 +156,13 @@ class Google extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class Linkedin extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.linkedin.com/oauth/v2/authorization?' . \http_build_query([
|
||||
return 'https://www.linkedin.com/oauth/v2/authorization?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
@@ -60,8 +60,7 @@ class Linkedin extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -80,12 +79,12 @@ class Linkedin extends OAuth2
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -106,12 +105,12 @@ class Linkedin extends OAuth2
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -122,13 +121,12 @@ class Linkedin extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer ' . \urlencode($accessToken)]), true);
|
||||
$email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer '.\urlencode($accessToken)]), true);
|
||||
|
||||
return $email['elements'][0]['handle~']['emailAddress'] ?? '';
|
||||
}
|
||||
@@ -138,20 +136,18 @@ class Linkedin extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Linkedin sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -164,21 +160,20 @@ class Linkedin extends OAuth2
|
||||
}
|
||||
|
||||
if (isset($user['localizedLastName'])) {
|
||||
$name = (empty($name)) ? $user['localizedLastName'] : $name . ' ' . $user['localizedLastName'];
|
||||
$name = (empty($name)) ? $user['localizedLastName'] : $name.' '.$user['localizedLastName'];
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer ' . \urlencode($accessToken)]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer '.\urlencode($accessToken)]), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -25,7 +25,7 @@ class Microsoft extends OAuth2
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'offline_access',
|
||||
'user.read'
|
||||
'user.read',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -41,19 +41,18 @@ class Microsoft extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/authorize?' . \http_build_query([
|
||||
return 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code',
|
||||
'response_mode' => 'query'
|
||||
'response_mode' => 'query',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Microsoft extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token',
|
||||
'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,7 +69,7 @@ class Microsoft extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -79,8 +78,7 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -88,13 +86,13 @@ class Microsoft extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/token',
|
||||
'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -106,8 +104,7 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -118,8 +115,7 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -134,20 +130,18 @@ class Microsoft extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Microsoft sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -158,14 +152,13 @@ class Microsoft extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://graph.microsoft.com/v1.0/me', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
@@ -185,6 +178,7 @@ class Microsoft extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
class Mock extends OAuth2
|
||||
{
|
||||
@@ -16,7 +15,7 @@ class Mock extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,17 +41,16 @@ class Mock extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'http://localhost/' . $this->version . '/mock/tests/general/oauth2?' . \http_build_query([
|
||||
return 'http://localhost/'.$this->version.'/mock/tests/general/oauth2?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -60,12 +58,12 @@ class Mock extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' .
|
||||
'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -74,20 +72,19 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' .
|
||||
'http://localhost/'.$this->version.'/mock/tests/general/oauth2/token?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -99,8 +96,7 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -111,8 +107,7 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -125,8 +120,7 @@ class Mock extends OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -135,8 +129,7 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -147,14 +140,13 @@ class Mock extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/user?token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/user?token='.\urlencode($accessToken));
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -44,32 +44,31 @@ class Notion extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . '/oauth/authorize?' . \http_build_query([
|
||||
return $this->endpoint.'/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
'state' => \json_encode($this->state),
|
||||
'owner' => 'user'
|
||||
'owner' => 'user',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback,
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -78,16 +77,15 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . '/oauth/token',
|
||||
$this->endpoint.'/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -103,8 +101,7 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -115,8 +112,7 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -131,20 +127,18 @@ class Notion extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Notion sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -155,19 +149,18 @@ class Notion extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Notion-Version: ' . $this->version,
|
||||
'Authorization: Bearer ' . \urlencode($accessToken)
|
||||
'Notion-Version: '.$this->version,
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
];
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', $this->endpoint . '/users/me', $headers), true);
|
||||
$this->user = \json_decode($this->request('GET', $this->endpoint.'/users/me', $headers), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
||||
@@ -43,7 +43,7 @@ class Oidc extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->getAuthorizationEndpoint() . '?' . \http_build_query([
|
||||
return $this->getAuthorizationEndpoint().'?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
@@ -53,8 +53,7 @@ class Oidc extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -71,17 +70,16 @@ class Oidc extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -95,7 +93,7 @@ class Oidc extends OAuth2
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -107,8 +105,7 @@ class Oidc extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -123,8 +120,7 @@ class Oidc extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -141,8 +137,7 @@ class Oidc extends OAuth2
|
||||
/**
|
||||
* Check if the User email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -153,8 +148,7 @@ class Oidc extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -168,15 +162,14 @@ class Oidc extends OAuth2
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
/**
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', $this->getUserinfoEndpoint(), $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
@@ -196,7 +189,7 @@ class Oidc extends OAuth2
|
||||
return $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Extracts the well known endpoint from the JSON stored in appSecret.
|
||||
*
|
||||
* @return string
|
||||
@@ -204,13 +197,14 @@ class Oidc extends OAuth2
|
||||
protected function getWellKnownEndpoint(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
return $secret['wellKnownEndpoint'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the authorization endpoint from the JSON stored in appSecret.
|
||||
*
|
||||
* If one is not provided, it will be retrieved from the well-known configuration.
|
||||
* Extracts the authorization endpoint from the JSON stored in appSecret.
|
||||
*
|
||||
* If one is not provided, it will be retrieved from the well-known configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -219,56 +213,59 @@ class Oidc extends OAuth2
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
$endpoint = $secret['authorizationEndpoint'] ?? '';
|
||||
if (!empty($endpoint)) {
|
||||
if (! empty($endpoint)) {
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
$wellKnownConfiguration = $this->getWellKnownConfiguration();
|
||||
|
||||
return $wellKnownConfiguration['authorization_endpoint'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the token endpoint from the JSON stored in appSecret.
|
||||
*
|
||||
* If one is not provided, it will be retrieved from the well-known configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
* Extracts the token endpoint from the JSON stored in appSecret.
|
||||
*
|
||||
* If one is not provided, it will be retrieved from the well-known configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenEndpoint(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
$endpoint = $secret['tokenEndpoint'] ?? '';
|
||||
if (!empty($endpoint)) {
|
||||
if (! empty($endpoint)) {
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
$wellKnownConfiguration = $this->getWellKnownConfiguration();
|
||||
|
||||
return $wellKnownConfiguration['token_endpoint'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the userinfo endpoint from the JSON stored in appSecret.
|
||||
*
|
||||
* If one is not provided, it will be retrieved from the well-known configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
* Extracts the userinfo endpoint from the JSON stored in appSecret.
|
||||
*
|
||||
* If one is not provided, it will be retrieved from the well-known configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getUserinfoEndpoint(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
$endpoint = $secret['userinfoEndpoint'] ?? '';
|
||||
if (!empty($endpoint)) {
|
||||
if (! empty($endpoint)) {
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
$wellKnownConfiguration = $this->getWellKnownConfiguration();
|
||||
|
||||
return $wellKnownConfiguration['userinfo_endpoint'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the well-known configuration using the well known endpoint
|
||||
*/
|
||||
/**
|
||||
* Get the well-known configuration using the well known endpoint
|
||||
*/
|
||||
protected function getWellKnownConfiguration(): array
|
||||
{
|
||||
if (empty($this->wellKnownConfiguration)) {
|
||||
@@ -291,6 +288,7 @@ class Oidc extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class Okta extends OAuth2
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
'offline_access',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -42,18 +42,17 @@ class Okta extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/authorize?' . \http_build_query([
|
||||
return 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
'response_type' => 'code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -62,7 +61,7 @@ class Okta extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token',
|
||||
'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
@@ -70,7 +69,7 @@ class Okta extends OAuth2
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -78,10 +77,8 @@ class Okta extends OAuth2
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -89,13 +86,13 @@ class Okta extends OAuth2
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token',
|
||||
'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -107,8 +104,7 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -119,8 +115,7 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -135,8 +130,7 @@ class Okta extends OAuth2
|
||||
*
|
||||
* @link https://developer.okta.com/docs/reference/api/oidc/#userinfo
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -151,8 +145,7 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -163,15 +156,14 @@ class Okta extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/userinfo', $headers);
|
||||
$headers = ['Authorization: Bearer '.\urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/userinfo', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
@@ -226,6 +218,7 @@ class Okta extends OAuth2
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception('Invalid secret');
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class Paypal extends OAuth2
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'profile',
|
||||
'email'
|
||||
'email',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -62,14 +62,14 @@ class Paypal extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint[$this->environment] . 'connect/?' .
|
||||
$url = $this->endpoint[$this->environment].'connect/?'.
|
||||
\http_build_query([
|
||||
'flowEntry' => 'static',
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
// paypal is not accepting localhost string into return uri
|
||||
'redirect_uri' => \str_replace("localhost", "127.0.0.1", $this->callback),
|
||||
'redirect_uri' => \str_replace('localhost', '127.0.0.1', $this->callback),
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
|
||||
@@ -77,8 +77,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -86,8 +85,8 @@ class Paypal extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint[$this->environment] . 'oauth2/token',
|
||||
['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)],
|
||||
$this->resourceEndpoint[$this->environment].'oauth2/token',
|
||||
['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)],
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
@@ -99,16 +98,15 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint[$this->environment] . 'oauth2/token',
|
||||
['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)],
|
||||
$this->resourceEndpoint[$this->environment].'oauth2/token',
|
||||
['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)],
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -123,8 +121,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -135,8 +132,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -148,7 +144,7 @@ class Paypal extends OAuth2
|
||||
return $email['primary'] === true;
|
||||
});
|
||||
|
||||
if (!empty($email)) {
|
||||
if (! empty($email)) {
|
||||
return $email[0]['value'];
|
||||
}
|
||||
}
|
||||
@@ -161,8 +157,7 @@ class Paypal extends OAuth2
|
||||
*
|
||||
* @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -177,8 +172,7 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -189,20 +183,19 @@ class Paypal extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$header = [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
];
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint[$this->environment] . 'identity/oauth2/userinfo?schema=paypalv1.1',
|
||||
$this->resourceEndpoint[$this->environment].'identity/oauth2/userinfo?schema=paypalv1.1',
|
||||
$header
|
||||
);
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Paypal;
|
||||
|
||||
class PaypalSandbox extends Paypal
|
||||
{
|
||||
protected string $environment = 'sandbox';
|
||||
|
||||
@@ -51,19 +51,18 @@ class Podio extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . '/authorize?' .
|
||||
$url = $this->endpoint.'/authorize?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
]);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -71,14 +70,14 @@ class Podio extends OAuth2
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->apiEndpoint . '/oauth/token',
|
||||
$this->apiEndpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret
|
||||
'client_secret' => $this->appSecret,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -87,15 +86,14 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->apiEndpoint . '/oauth/token',
|
||||
$this->apiEndpoint.'/oauth/token',
|
||||
['Content-Type: application/x-www-form-urlencoded'],
|
||||
\http_build_query([
|
||||
'grant_type' => 'refresh_token',
|
||||
@@ -113,8 +111,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -125,8 +122,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -139,8 +135,7 @@ class Podio extends OAuth2
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -148,7 +143,7 @@ class Podio extends OAuth2
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
$mails = $user['mails'];
|
||||
$mainMailIndex = \array_search($user['mail'], \array_map(fn($m) => $m['mail'], $mails));
|
||||
$mainMailIndex = \array_search($user['mail'], \array_map(fn ($m) => $m['mail'], $mails));
|
||||
$mainMain = $mails[$mainMailIndex];
|
||||
|
||||
if ($mainMain['verified'] ?? false) {
|
||||
@@ -159,8 +154,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -171,8 +165,7 @@ class Podio extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -180,14 +173,14 @@ class Podio extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->apiEndpoint . '/user',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->apiEndpoint.'/user',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
), true);
|
||||
|
||||
$profile = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->apiEndpoint . '/user/profile',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->apiEndpoint.'/user/profile',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
), true);
|
||||
|
||||
$this->user = $user;
|
||||
|
||||
@@ -25,7 +25,7 @@ class Salesforce extends OAuth2
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"openid"
|
||||
'openid',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -37,8 +37,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @param string $state
|
||||
* @return array
|
||||
*/
|
||||
public function parseState(string $state)
|
||||
@@ -46,31 +45,29 @@ class Salesforce extends OAuth2
|
||||
return \json_decode(\html_entity_decode($state), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://login.salesforce.com/services/oauth2/authorize?' . \http_build_query([
|
||||
return 'https://login.salesforce.com/services/oauth2/authorize?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
@@ -80,7 +77,7 @@ class Salesforce extends OAuth2
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback,
|
||||
'grant_type' => 'authorization_code'
|
||||
'grant_type' => 'authorization_code',
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -89,14 +86,13 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
@@ -105,7 +101,7 @@ class Salesforce extends OAuth2
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -117,8 +113,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -129,8 +124,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -145,8 +139,7 @@ class Salesforce extends OAuth2
|
||||
*
|
||||
* @link https://help.salesforce.com/s/articleView?id=sf.remoteaccess_using_userinfo_endpoint.htm&type=5
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -161,8 +154,7 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -173,16 +165,16 @@ class Salesforce extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token=' . \urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token='.\urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class Slack extends OAuth2
|
||||
'identity.avatar',
|
||||
'identity.basic',
|
||||
'identity.email',
|
||||
'identity.team'
|
||||
'identity.team',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -40,17 +40,16 @@ class Slack extends OAuth2
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
// https://api.slack.com/docs/oauth#step_1_-_sending_users_to_authorize_and_or_install
|
||||
return 'https://slack.com/oauth/authorize?' . \http_build_query([
|
||||
return 'https://slack.com/oauth/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -59,11 +58,11 @@ class Slack extends OAuth2
|
||||
// https://api.slack.com/docs/oauth#step_3_-_exchanging_a_verification_code_for_an_access_token
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://slack.com/api/oauth.access?' . \http_build_query([
|
||||
'https://slack.com/api/oauth.access?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->callback
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -72,19 +71,18 @@ class Slack extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://slack.com/api/oauth.access?' . \http_build_query([
|
||||
'https://slack.com/api/oauth.access?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -96,8 +94,7 @@ class Slack extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -108,8 +105,7 @@ class Slack extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -126,20 +122,18 @@ class Slack extends OAuth2
|
||||
*
|
||||
* @link https://slack.com/help/articles/207262907-Change-your-email-address
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -152,8 +146,7 @@ class Slack extends OAuth2
|
||||
/**
|
||||
* @link https://api.slack.com/methods/users.identity
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
@@ -161,7 +154,7 @@ class Slack extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
'https://slack.com/api/users.identity?token=' . \urlencode($accessToken)
|
||||
'https://slack.com/api/users.identity?token='.\urlencode($accessToken)
|
||||
);
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
@@ -49,33 +49,32 @@ class Spotify extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?' .
|
||||
return $this->endpoint.'authorize?'.
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'api/token',
|
||||
$this->endpoint.'api/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"code" => $code,
|
||||
"grant_type" => "authorization_code",
|
||||
"redirect_uri" => $this->callback
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
'redirect_uri' => $this->callback,
|
||||
])
|
||||
), true);
|
||||
}
|
||||
@@ -84,20 +83,19 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$headers = ['Authorization: Basic '.\base64_encode($this->appID.':'.$this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'api/token',
|
||||
$this->endpoint.'api/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
"refresh_token" => $refreshToken,
|
||||
"grant_type" => "refresh_token",
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token',
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -109,8 +107,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -121,8 +118,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -139,8 +135,7 @@ class Spotify extends OAuth2
|
||||
*
|
||||
* @link https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
@@ -149,8 +144,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -161,8 +155,7 @@ class Spotify extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
@@ -170,8 +163,8 @@ class Spotify extends OAuth2
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint . 'me',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
$this->resourceEndpoint.'me',
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
class Stripe extends OAuth2
|
||||
{
|
||||
@@ -50,18 +49,17 @@ class Stripe extends OAuth2
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://connect.stripe.com/oauth/authorize?' . \http_build_query([
|
||||
return 'https://connect.stripe.com/oauth/authorize?'.\http_build_query([
|
||||
'response_type' => 'code', // The only option at the moment is "code."
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
@@ -73,7 +71,7 @@ class Stripe extends OAuth2
|
||||
[],
|
||||
\http_build_query([
|
||||
'grant_type' => $this->grantType['authorize'],
|
||||
'code' => $code
|
||||
'code' => $code,
|
||||
])
|
||||
), true);
|
||||
|
||||
@@ -84,8 +82,7 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @param string $refreshToken
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
@@ -105,12 +102,12 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
$this->stripeAccountId = $this->tokens['stripe_user_id'];
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
@@ -121,8 +118,7 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
@@ -141,20 +137,18 @@ class Stripe extends OAuth2
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Stripe sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
return ! empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
@@ -165,18 +159,17 @@ class Stripe extends OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user) && !empty($this->stripeAccountId)) {
|
||||
if (empty($this->user) && ! empty($this->stripeAccountId)) {
|
||||
$this->user = \json_decode(
|
||||
$this->request(
|
||||
'GET',
|
||||
'https://api.stripe.com/v1/accounts/' . $this->stripeAccountId,
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
'https://api.stripe.com/v1/accounts/'.$this->stripeAccountId,
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user