mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 08:58:35 +00:00
Merge branch '1.8.x' of https://github.com/appwrite/appwrite into migration-endpoint
This commit is contained in:
commit
d89539b56a
15 changed files with 185 additions and 85 deletions
|
|
@ -50,17 +50,12 @@
|
|||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Poppins';
|
||||
src: url('https://assets.appwrite.io/fonts/poppins/poppins-v23-latin-regular.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
.main {
|
||||
max-width: 650px;
|
||||
margin: 0 auto;
|
||||
margin-top: 32px;
|
||||
padding: 32px;
|
||||
line-height: 1.5;
|
||||
color: #616b7c;
|
||||
|
|
@ -68,15 +63,12 @@
|
|||
font-weight: 400;
|
||||
font-family: "Inter", sans-serif;
|
||||
background-color: #ffffff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 150%;
|
||||
}
|
||||
a {
|
||||
.main a {
|
||||
color: currentColor;
|
||||
word-break: break-all;
|
||||
}
|
||||
a.button {
|
||||
.main a.button {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
|
|
@ -87,8 +79,8 @@
|
|||
border: 1px solid #414146;
|
||||
border-radius: 8px;
|
||||
}
|
||||
a.button:hover,
|
||||
a.button:focus {
|
||||
.main a.button:hover,
|
||||
.main a.button:focus {
|
||||
opacity: 0.8;
|
||||
}
|
||||
table {
|
||||
|
|
@ -102,11 +94,6 @@
|
|||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.main {
|
||||
max-width: 650px;
|
||||
margin: 0 auto;
|
||||
margin-top: 32px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
margin-bottom: 0px;
|
||||
|
|
@ -138,9 +125,6 @@
|
|||
border: none;
|
||||
border-top: 1px solid #e8e9f0;
|
||||
}
|
||||
h* {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
|
@ -155,21 +139,20 @@
|
|||
|
||||
<body style="direction: {{direction}}">
|
||||
|
||||
<div style="display: none; overflow: hidden; max-height: 0; max-width: 0; opacity: 0; line-height: 1px;">
|
||||
{{preview}}
|
||||
<div>{{previewWhitespace}}</div>
|
||||
</div>
|
||||
<div style="display: none; overflow: hidden; max-height: 0; max-width: 0; opacity: 0; line-height: 1px;">
|
||||
{{preview}}
|
||||
<div>{{previewWhitespace}}</div>
|
||||
</div>
|
||||
|
||||
<div style="max-width:650px; word-wrap: break-word; overflow-wrap: break-word;
|
||||
word-break: normal; margin:0 auto;">
|
||||
<table style="margin-top: 32px">
|
||||
<tr>
|
||||
<td>
|
||||
{{body}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="main" style="max-width:650px; word-wrap: break-word; overflow-wrap: break-word; word-break: normal; margin:0 auto;">
|
||||
<table style="margin-top: 32px">
|
||||
<tr>
|
||||
<td>
|
||||
{{body}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -23,4 +23,5 @@ return [
|
|||
'privacyUrl' => APP_EMAIL_PRIVACY_URL,
|
||||
'websiteUrl' => 'https://' . APP_DOMAIN,
|
||||
'emailSenderName' => APP_EMAIL_PLATFORM_NAME,
|
||||
'sitePreviewDomain' => System::getEnv('_APP_DOMAIN_SITES', ''),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, arr
|
|||
->setPreview($preview)
|
||||
->setBody($body)
|
||||
->setBodyTemplate($bodyTemplate)
|
||||
->setVariables($emailVariables)
|
||||
->appendVariables($emailVariables)
|
||||
->setRecipient($email);
|
||||
|
||||
// since this is console project, set email sender name!
|
||||
|
|
@ -2301,7 +2301,7 @@ App::post('/v1/account/tokens/magic-url')
|
|||
->setSubject($subject)
|
||||
->setPreview($preview)
|
||||
->setBody($body)
|
||||
->setVariables($emailVariables)
|
||||
->appendVariables($emailVariables)
|
||||
->setRecipient($email);
|
||||
|
||||
if ($project->getId() === 'console') {
|
||||
|
|
@ -2602,7 +2602,7 @@ App::post('/v1/account/tokens/email')
|
|||
->setPreview($preview)
|
||||
->setBody($body)
|
||||
->setBodyTemplate($bodyTemplate)
|
||||
->setVariables($emailVariables)
|
||||
->appendVariables($emailVariables)
|
||||
->setRecipient($email);
|
||||
|
||||
// since this is console project, set email sender name!
|
||||
|
|
@ -3678,7 +3678,7 @@ App::post('/v1/account/recovery')
|
|||
->setRecipient($profile->getAttribute('email', ''))
|
||||
->setName($profile->getAttribute('name', ''))
|
||||
->setBody($body)
|
||||
->setVariables($emailVariables)
|
||||
->appendVariables($emailVariables)
|
||||
->setSubject($subject)
|
||||
->setPreview($preview);
|
||||
|
||||
|
|
@ -4009,7 +4009,7 @@ App::post('/v1/account/verifications/email')
|
|||
->setPreview($preview)
|
||||
->setBody($body)
|
||||
->setBodyTemplate($bodyTemplate)
|
||||
->setVariables($emailVariables)
|
||||
->appendVariables($emailVariables)
|
||||
->setRecipient($user->getAttribute('email'))
|
||||
->setName($user->getAttribute('name') ?? '');
|
||||
|
||||
|
|
|
|||
|
|
@ -779,7 +779,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
->setPreview($preview)
|
||||
->setRecipient($invitee->getAttribute('email'))
|
||||
->setName($invitee->getAttribute('name', ''))
|
||||
->setVariables($emailVariables)
|
||||
->appendVariables($emailVariables)
|
||||
->trigger();
|
||||
} elseif (!empty($phone)) {
|
||||
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
|||
$projectId = $project->getId();
|
||||
|
||||
// Deployment preview
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$sitesDomain = $platform['sitePreviewDomain'];
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
$ruleId = md5($domain);
|
||||
$previewRuleId = $ruleId;
|
||||
|
|
|
|||
|
|
@ -364,6 +364,18 @@ class Mail extends Event
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append variables to the email event.
|
||||
*
|
||||
* @param array $variables
|
||||
* @return self
|
||||
*/
|
||||
public function appendVariables(array $variables): self
|
||||
{
|
||||
$this->variables = \array_merge($this->variables, $variables);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set attachment
|
||||
* @param string $content
|
||||
|
|
|
|||
|
|
@ -39,38 +39,34 @@ class EventProcessor
|
|||
return \json_decode($cachedFunctionEvents, true) ?? [];
|
||||
}
|
||||
|
||||
try {
|
||||
$events = [];
|
||||
$limit = 100;
|
||||
$sum = 100;
|
||||
$offset = 0;
|
||||
$events = [];
|
||||
$limit = 100;
|
||||
$sum = 100;
|
||||
$offset = 0;
|
||||
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::select(['$id', 'events']),
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
Query::orderAsc('$sequence'),
|
||||
]);
|
||||
while ($sum >= $limit) {
|
||||
$functions = $dbForProject->getAuthorization()->skip(fn () => $dbForProject->find('functions', [
|
||||
Query::select(['$id', 'events']),
|
||||
Query::limit($limit),
|
||||
Query::offset($offset),
|
||||
Query::orderAsc('$sequence'),
|
||||
]));
|
||||
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
$sum = \count($functions);
|
||||
$offset = $offset + $limit;
|
||||
|
||||
foreach ($functions as $function) {
|
||||
$functionEvents = $function->getAttribute('events', []);
|
||||
if (!empty($functionEvents)) {
|
||||
$events = array_merge($events, $functionEvents);
|
||||
}
|
||||
foreach ($functions as $function) {
|
||||
$functionEvents = $function->getAttribute('events', []);
|
||||
if (!empty($functionEvents)) {
|
||||
\array_push($events, ...$functionEvents);
|
||||
}
|
||||
}
|
||||
|
||||
$uniqueEvents = \array_flip(\array_unique($events));
|
||||
$dbForProject->getCache()->save($cacheKey, \json_encode($uniqueEvents));
|
||||
|
||||
return $uniqueEvents;
|
||||
} catch (\Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$uniqueEvents = \array_flip(\array_unique($events));
|
||||
$dbForProject->getCache()->save($cacheKey, \json_encode($uniqueEvents));
|
||||
|
||||
return $uniqueEvents;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -97,7 +93,7 @@ class EventProcessor
|
|||
|
||||
$webhookEvents = $webhook->getAttribute('events', []);
|
||||
if (!empty($webhookEvents)) {
|
||||
$events = array_merge($events, $webhookEvents);
|
||||
\array_push($events, ...$webhookEvents);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ class Create extends Action
|
|||
->setPreview($preview)
|
||||
->setBody($body)
|
||||
->setBodyTemplate($bodyTemplate)
|
||||
->setVariables($emailVariables)
|
||||
->appendVariables($emailVariables)
|
||||
->setRecipient($user->getAttribute('email'));
|
||||
|
||||
// since this is console project, set email sender name!
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ class Base extends Action
|
|||
return $deployment;
|
||||
}
|
||||
|
||||
public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, Authorization $authorization, string $referenceType = 'branch', string $reference = ''): Document
|
||||
public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, Authorization $authorization, string $referenceType = 'branch', string $reference = '', array $platform): Document
|
||||
{
|
||||
$deploymentId = ID::unique();
|
||||
$providerInstallationId = $installation->getAttribute('providerInstallationId', '');
|
||||
|
|
@ -235,7 +235,7 @@ class Base extends Action
|
|||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument('sites', $site->getId(), $site);
|
||||
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$sitesDomain = $platform['sitePreviewDomain'];
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
|
|
|
|||
|
|
@ -1037,7 +1037,7 @@ class Builds extends Action
|
|||
// VCS branch
|
||||
$branchName = $deployment->getAttribute('providerBranch');
|
||||
if (!empty($branchName)) {
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$sitesDomain = $platform['sitePreviewDomain'];
|
||||
$branchPrefix = substr($branchName, 0, 16);
|
||||
if (strlen($branchName) > 16) {
|
||||
$remainingChars = substr($branchName, 16);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ class Create extends Action
|
|||
->inject('queueForBuilds')
|
||||
->inject('plan')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +109,8 @@ class Create extends Action
|
|||
Device $deviceForLocal,
|
||||
Build $queueForBuilds,
|
||||
array $plan,
|
||||
Authorization $authorization
|
||||
Authorization $authorization,
|
||||
array $platform,
|
||||
) {
|
||||
$activate = \strval($activate) === 'true' || \strval($activate) === '1';
|
||||
|
||||
|
|
@ -272,7 +274,7 @@ class Create extends Action
|
|||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument('sites', $site->getId(), $site);
|
||||
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$sitesDomain = $platform['sitePreviewDomain'];
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
|
|
@ -342,7 +344,7 @@ class Create extends Action
|
|||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument('sites', $site->getId(), $site);
|
||||
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$sitesDomain = $platform['sitePreviewDomain'];
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
$ruleId = md5($domain);
|
||||
$authorization->skip(
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class Create extends Action
|
|||
->inject('queueForBuilds')
|
||||
->inject('deviceForSites')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +81,8 @@ class Create extends Action
|
|||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
Device $deviceForSites,
|
||||
Authorization $authorization
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
) {
|
||||
$site = $dbForProject->getDocument('sites', $siteId);
|
||||
|
||||
|
|
@ -143,7 +145,7 @@ class Create extends Action
|
|||
$dbForProject->updateDocument('sites', $site->getId(), $site);
|
||||
|
||||
// Preview deployments for sites
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$sitesDomain = $platform['sitePreviewDomain'];
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ class Create extends Base
|
|||
->inject('queueForBuilds')
|
||||
->inject('gitHub')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +100,8 @@ class Create extends Base
|
|||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
GitHub $github,
|
||||
Authorization $authorization
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
) {
|
||||
$site = $dbForProject->getDocument('sites', $siteId);
|
||||
|
||||
|
|
@ -133,6 +135,7 @@ class Create extends Base
|
|||
github: $github,
|
||||
activate: $activate,
|
||||
authorization: $authorization,
|
||||
platform: $platform
|
||||
);
|
||||
|
||||
$queueForEvents
|
||||
|
|
@ -186,7 +189,7 @@ class Create extends Base
|
|||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument('sites', $site->getId(), $site);
|
||||
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$sitesDomain = $platform['sitePreviewDomain'];
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ class Create extends Base
|
|||
->inject('queueForBuilds')
|
||||
->inject('gitHub')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +91,8 @@ class Create extends Base
|
|||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
GitHub $github,
|
||||
Authorization $authorization
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
) {
|
||||
$site = $dbForProject->getDocument('sites', $siteId);
|
||||
|
||||
|
|
@ -115,7 +117,8 @@ class Create extends Base
|
|||
activate: $activate,
|
||||
authorization: $authorization,
|
||||
reference: $reference,
|
||||
referenceType: $type
|
||||
referenceType: $type,
|
||||
platform: $platform
|
||||
);
|
||||
|
||||
$queueForEvents
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Tests\E2E\Scopes\ProjectCustom;
|
|||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\System\System;
|
||||
|
||||
|
|
@ -510,4 +511,101 @@ class FunctionsCustomClientTest extends Scope
|
|||
$template = $this->getTemplate('invalid-template-id');
|
||||
$this->assertEquals(404, $template['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that event-triggered functions work when the triggering request
|
||||
* comes from a client SDK (session auth) that doesn't have permission
|
||||
* to read the functions collection.
|
||||
*/
|
||||
public function testEventTriggerWithClientAuth()
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Client Event Trigger',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'databases.*.collections.*.documents.*.create',
|
||||
],
|
||||
'timeout' => 15,
|
||||
]);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('event-handler'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Test Database',
|
||||
]);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Test Collection',
|
||||
'permissions' => [
|
||||
Permission::create(Role::users()),
|
||||
],
|
||||
'documentSecurity' => false,
|
||||
]);
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
$attribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'key' => 'name',
|
||||
'size' => 255,
|
||||
'required' => false,
|
||||
]);
|
||||
$this->assertEquals(202, $attribute['headers']['status-code']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => ['name' => 'Test Document'],
|
||||
]);
|
||||
$this->assertEquals(201, $document['headers']['status-code']);
|
||||
$documentId = $document['body']['$id'];
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $documentId) {
|
||||
$executions = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/executions', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||
$this->assertGreaterThan(0, count($executions['body']['executions']), 'Function should have been triggered by document creation');
|
||||
|
||||
$lastExecution = $executions['body']['executions'][0];
|
||||
$this->assertEquals('completed', $lastExecution['status']);
|
||||
$this->assertEquals(204, $lastExecution['responseStatusCode']);
|
||||
$this->assertStringContainsString($documentId, $lastExecution['logs']);
|
||||
}, 20000, 500);
|
||||
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue