Merge branch '0.16.x' of https://github.com/appwrite/appwrite into matej-qa-3

This commit is contained in:
Christy Jacob
2022-09-13 18:21:44 +00:00
35 changed files with 639 additions and 285 deletions
+3 -3
View File
@@ -2672,7 +2672,7 @@ $collections = [
'filters' => [],
],
[
'$id' => ID::custom('time'),
'$id' => ID::custom('duration'),
'type' => Database::VAR_FLOAT,
'format' => '',
'size' => 0,
@@ -2731,9 +2731,9 @@ $collections = [
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_time'),
'$id' => ID::custom('_key_duration'),
'type' => Database::INDEX_KEY,
'attributes' => ['time'],
'attributes' => ['duration'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
+1 -1
View File
@@ -360,7 +360,7 @@ App::get('/v1/avatars/initials')
->action(function (string $name, int $width, int $height, string $background, Response $response, Document $user) {
$themes = [
['background' => '#F2F2F8'], // Default
['background' => '#FFA1CE'], // Default (Pink)
['background' => '#FDC584'], // Orange
['background' => '#94DBD1'], // Green
['background' => '#A1C4FF'], // Blue
+4 -4
View File
@@ -1008,7 +1008,7 @@ App::post('/v1/functions/:functionId/executions')
'statusCode' => 0,
'response' => '',
'stderr' => '',
'time' => 0.0,
'duration' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
])));
@@ -1095,11 +1095,11 @@ App::post('/v1/functions/:functionId/executions')
$execution->setAttribute('response', $executionResponse['response']);
$execution->setAttribute('stdout', $executionResponse['stdout']);
$execution->setAttribute('stderr', $executionResponse['stderr']);
$execution->setAttribute('time', $executionResponse['time']);
$execution->setAttribute('duration', $executionResponse['duration']);
} catch (\Throwable $th) {
$interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt()));
$execution
->setAttribute('time', (float)$interval->format('%s.%f'))
->setAttribute('duration', (float)$interval->format('%s.%f'))
->setAttribute('status', 'failed')
->setAttribute('statusCode', $th->getCode())
->setAttribute('stderr', $th->getMessage());
@@ -1113,7 +1113,7 @@ App::post('/v1/functions/:functionId/executions')
->setParam('functionId', $function->getId())
->setParam('executions.{scope}.compute', 1)
->setParam('executionStatus', $execution->getAttribute('status', ''))
->setParam('executionTime', $execution->getAttribute('time')); // ms
->setParam('executionTime', $execution->getAttribute('duration')); // ms
$roles = Authorization::getRoles();
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
+2 -2
View File
@@ -503,7 +503,7 @@ App::post('/v1/execution')
$ch = \curl_init();
$body = \json_encode([
'env' => $vars,
'variables' => $vars,
'payload' => $data,
'timeout' => $timeout
]);
@@ -574,7 +574,7 @@ App::post('/v1/execution')
'response' => \mb_strcut($res, 0, 1000000), // Limit to 1MB
'stdout' => \mb_strcut($stdout, 0, 1000000), // Limit to 1MB
'stderr' => \mb_strcut($stderr, 0, 1000000), // Limit to 1MB
'time' => $executionTime,
'duration' => $executionTime,
];
/** Update swoole table */
+1 -1
View File
@@ -108,7 +108,7 @@ $cli
$time = DateTime::now();
$certificates = $dbForConsole->find('certificates', [
Query::lessThanEqual('attempts', 5), // Maximum 5 attempts
Query::lessThan('attempts', 5), // Maximum 5 attempts
Query::lessThanEqual('renewDate', $time), // includes 60 days cooldown (we have 30 days to renew)
Query::limit(200), // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains)
]);
@@ -46,8 +46,20 @@ $escapedPermissions = \array_map(function ($perm) {
<?php endif; ?>
:value="rawPermissions"/>
<table class="u-table-layout-normal" data-ls-attrs="x-init=load({{<?php if (!empty($data)) echo $data . '.$permissions' ?>}})">
<thead>
<datalist id="types">
<option value="user:">
<option value="team:">
<option value="member:">
<option value="users">
<option value="guests">
<option value="any">
</datalist>
<table
class="u-table-layout-normal"
data-ls-attrs="x-init=load({{<?php if (!empty($data)) echo $data . '.$permissions' ?>}})">
<thead x-show="permissions.length > 0">
<tr>
<th>Role</th>
<?php foreach ($permissions as $permission): ?>
@@ -60,7 +72,16 @@ $escapedPermissions = \array_map(function ($perm) {
<template x-for="(permission, index) in permissions">
<tr>
<td>
<p x-text="permission.role"></p>
<input
required
autocomplete="off"
:id="'<?php echo $form; ?>Input' + index"
name="<?php echo $form; ?>"
form="<?php echo $form ?>"
list="types"
type="text"
x-model="permission.role"
@keyup="updatePermission(index)"/>
</td>
<?php foreach ($escapedPermissions as $permission): ?>
<td>
@@ -78,38 +99,11 @@ $escapedPermissions = \array_map(function ($perm) {
</td>
</tr>
</template>
<tr x-data="permissionsRow"
@addrow<?php echo \strtolower($form); ?>.window="addPermission('<?php echo $form; ?>', role, { <?php echo \implode(',', $escapedPermissions) ?> })">
<td>
<datalist id="types">
<option value="user:">
<option value="team:">
<option value="users">
<option value="guests">
<option value="any">
</datalist>
<input
required
id="<?php echo $form; ?>Input"
name="<?php echo $form; ?>"
form="<?php echo $form ?>"
list="types"
type="text"
x-model="role" />
</td>
<?php foreach ($escapedPermissions as $permission): ?>
<td>
<input type="checkbox" name="<?php echo $permission ?>" x-model="<?php echo $permission; ?>"/>
</td>
<?php endforeach; ?>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="<?php \count($permissions) + 2 ?>">
<button type="button" class="margin-top-small reverse" @click="$dispatch('addrow<?php echo \strtolower($form); ?>')">Add</button>
<button type="button" class="margin-top-small reverse" @click="addPermission('<?php echo $form ?>')">Add Role</button>
</td>
</tr>
</tfoot>
+2 -2
View File
@@ -508,7 +508,7 @@ $permissions = $this->getParam('permissions', null);
<li data-state="/console/databases/collection/settings?id={{router.params.id}}&databaseId={{router.params.databaseId}}&project={{router.params.project}}">
<h2>Settings</h2>
<div class="row responsive margin-top-negative">
<div class="row responsive">
<div class="col span-8 margin-bottom">
<form id="<?php echo $permissions->getParam('form') ?>"></form>
@@ -607,7 +607,7 @@ $permissions = $this->getParam('permissions', null);
data-success="alert,trigger,redirect"
data-success-param-alert-text="Collection deleted successfully"
data-success-param-trigger-events="databases.deleteCollection"
data-success-param-redirect-url="/console/databases?project={{router.params.project}}"
data-success-param-redirect-url="/console/databases?project={{router.params.project}}&databaseId={{router.params.databaseId}}"
data-failure="alert"
data-failure-param-alert-text="Failed to delete collection"
data-failure-param-alert-classname="error">
+1 -1
View File
@@ -416,7 +416,7 @@ sort($patterns);
<span data-ls-bind="{{execution.trigger}}"></span>
</td>
<td data-title="Time: ">
<span data-ls-if="{{execution.status}} === 'completed' || {{execution.status}} === 'failed'" data-ls-bind="{{execution.time|seconds2hum}}"></span>
<span data-ls-if="{{execution.status}} === 'completed' || {{execution.status}} === 'failed'" data-ls-bind="{{execution.duration|seconds2hum}}"></span>
<span data-ls-if="{{execution.status}} === 'waiting' || {{execution.status}} === 'processing'">-</span>
</td>
<td data-title="">
+21 -11
View File
@@ -8,6 +8,7 @@ use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\DateTime;
use Utopia\Database\ID;
use Utopia\Database\Query;
use Utopia\Domains\Domain;
@@ -100,8 +101,11 @@ class CertificatesV1 extends Worker
throw new Exception('Renew isn\'t required.');
}
// Prepare folder name for certbot. Using this helps prevent miss-match in LetsEncrypt configuration when renewing certificate
$folder = ID::unique();
// Generate certificate files using Let's Encrypt
$letsEncryptData = $this->issueCertificate($domain->get(), $email);
$letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email);
// Command succeeded, store all data into document
// We store stderr too, because it may include warnings
@@ -111,7 +115,7 @@ class CertificatesV1 extends Worker
]));
// Give certificates to Traefik
$this->applyCertificateFiles($domain->get(), $letsEncryptData);
$this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData);
// Update certificate info stored in database
$certificate->setAttribute('renewDate', $this->getRenewDate($domain->get()));
@@ -125,6 +129,9 @@ class CertificatesV1 extends Worker
$attempts = $certificate->getAttribute('attempts', 0) + 1;
$certificate->setAttribute('attempts', $attempts);
// Store cuttent time as renew date to ensure another attempt in next maintenance cycle
$certificate->setAttribute('renewDate', DateTime::now());
// Send email to security email
$this->notifyError($domain->get(), $e->getMessage(), $attempts);
} finally {
@@ -259,11 +266,12 @@ 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
*
* @return array Named array with keys 'stdout' and 'stderr', both string
*/
private function issueCertificate(string $domain, string $email): array
private function issueCertificate(string $folder, string $domain, string $email): array
{
$stdout = '';
$stderr = '';
@@ -271,6 +279,7 @@ 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);
@@ -290,9 +299,9 @@ class CertificatesV1 extends Worker
*
* @param string $domain Domain which certificate was generated for
*
* @return int
* @return string
*/
private function getRenewDate(string $domain): int
private function getRenewDate(string $domain): string
{
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
$certData = openssl_x509_parse(file_get_contents($certPath));
@@ -305,11 +314,12 @@ class CertificatesV1 extends Worker
* 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
*
* @return void
*/
private function applyCertificateFiles(string $domain, array $letsEncryptData): void
private function applyCertificateFiles(string $folder, string $domain, array $letsEncryptData): void
{
// Prepare folder in storage for domain
$path = APP_STORAGE_CERTIFICATES . '/' . $domain;
@@ -319,20 +329,20 @@ class CertificatesV1 extends Worker
}
}
// Move generated files from certbot into our storage
if (!@\rename('/etc/letsencrypt/live/' . $domain . '/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) {
// 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/' . $domain . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) {
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/' . $domain . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) {
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/' . $domain . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) {
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']);
}
+4 -4
View File
@@ -248,7 +248,7 @@ class FunctionsV1 extends Worker
'statusCode' => 0,
'response' => '',
'stderr' => '',
'time' => 0.0,
'duration' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]));
@@ -301,11 +301,11 @@ class FunctionsV1 extends Worker
->setAttribute('response', $executionResponse['response'])
->setAttribute('stdout', $executionResponse['stdout'])
->setAttribute('stderr', $executionResponse['stderr'])
->setAttribute('time', $executionResponse['time']);
->setAttribute('duration', $executionResponse['duration']);
} catch (\Throwable $th) {
$interval = (new \DateTime())->diff(new \DateTime($execution->getCreatedAt()));
$execution
->setAttribute('time', (float)$interval->format('%s.%f'))
->setAttribute('duration', (float)$interval->format('%s.%f'))
->setAttribute('status', 'failed')
->setAttribute('statusCode', $th->getCode())
->setAttribute('stderr', $th->getMessage());
@@ -367,7 +367,7 @@ class FunctionsV1 extends Worker
->setParam('functionId', $function->getId())
->setParam('executions.{scope}.compute', 1)
->setParam('executionStatus', $execution->getAttribute('status', ''))
->setParam('executionTime', $execution->getAttribute('time'))
->setParam('executionTime', $execution->getAttribute('duration'))
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0)
->submit();