Merge remote-tracking branch 'origin/feat-email-attachments' into feat-push-images
This commit is contained in:
commit
42e1b0dfe3
6 changed files with 277 additions and 49 deletions
|
@ -10,6 +10,7 @@ use Appwrite\Messaging\Status as MessageStatus;
|
|||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Permission;
|
||||
use Appwrite\Role;
|
||||
use Appwrite\Utopia\Database\Validator\CompoundUID;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Messages;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Providers;
|
||||
|
@ -2575,6 +2576,7 @@ App::post('/v1/messaging/messages/email')
|
|||
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
|
||||
->param('cc', [], new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true)
|
||||
->param('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true)
|
||||
->param('attachments', [], new ArrayList(new CompoundUID()), 'Array of compound bucket IDs to file IDs to be attached to the email.', true)
|
||||
->param('status', MessageStatus::DRAFT, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
|
||||
->param('html', false, new Boolean(), 'Is content of type HTML', true)
|
||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||
|
@ -2584,7 +2586,7 @@ App::post('/v1/messaging/messages/email')
|
|||
->inject('project')
|
||||
->inject('queueForMessaging')
|
||||
->inject('response')
|
||||
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, array $attachments, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
$messageId = $messageId == 'unique()'
|
||||
? ID::unique()
|
||||
: $messageId;
|
||||
|
@ -2617,6 +2619,29 @@ App::post('/v1/messaging/messages/email')
|
|||
}
|
||||
}
|
||||
|
||||
if (!empty($attachments)) {
|
||||
foreach ($attachments as &$attachment) {
|
||||
[$bucketId, $fileId] = CompoundUID::parse($attachment);
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$attachment = [
|
||||
'bucketId' => $bucketId,
|
||||
'fileId' => $fileId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$message = $dbForProject->createDocument('messages', new Document([
|
||||
'$id' => $messageId,
|
||||
'providerType' => MESSAGE_TYPE_EMAIL,
|
||||
|
@ -2630,6 +2655,7 @@ App::post('/v1/messaging/messages/email')
|
|||
'html' => $html,
|
||||
'cc' => $cc,
|
||||
'bcc' => $bcc,
|
||||
'attachments' => $attachments,
|
||||
],
|
||||
'status' => $status,
|
||||
]));
|
||||
|
|
|
@ -34,6 +34,7 @@ use Utopia\Logger\Log;
|
|||
use Utopia\Logger\Logger;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Queue\Connection;
|
||||
use Utopia\Storage\Device\Local;
|
||||
|
||||
Authorization::disable();
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
@ -209,6 +210,11 @@ Server::setResource('getCacheDevice', function () {
|
|||
return getDevice(APP_STORAGE_CACHE . '/app-' . $projectId);
|
||||
};
|
||||
});
|
||||
Server::setResource('getLocalCache', function () {
|
||||
return function (string $projectId) {
|
||||
return new Local(APP_STORAGE_CACHE . '/app-' . $projectId);
|
||||
};
|
||||
});
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$platform = new Appwrite();
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"utopia-php/image": "0.6.*",
|
||||
"utopia-php/locale": "0.4.*",
|
||||
"utopia-php/logger": "0.3.*",
|
||||
"utopia-php/messaging": "0.9.*",
|
||||
"utopia-php/messaging": "dev-feat-email-attachments as 0.9.1",
|
||||
"utopia-php/migration": "0.3.*",
|
||||
"utopia-php/orchestration": "0.9.*",
|
||||
"utopia-php/platform": "0.5.*",
|
||||
|
@ -70,7 +70,7 @@
|
|||
"utopia-php/websocket": "0.1.*",
|
||||
"matomo/device-detector": "6.1.*",
|
||||
"dragonmantank/cron-expression": "3.3.2",
|
||||
"phpmailer/phpmailer": "6.8.0",
|
||||
"phpmailer/phpmailer": "6.9.1",
|
||||
"chillerlan/php-qrcode": "4.3.4",
|
||||
"adhocore/jwt": "1.1.2",
|
||||
"spomky-labs/otphp": "^10.0",
|
||||
|
|
64
composer.lock
generated
64
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "609062319cc652e2760367f39604ac77",
|
||||
"content-hash": "eb3dcf01997ff1430676afaab91476dd",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -885,16 +885,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v6.8.0",
|
||||
"version": "v6.9.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "df16b615e371d81fb79e506277faea67a1be18f1"
|
||||
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1",
|
||||
"reference": "df16b615e371d81fb79e506277faea67a1be18f1",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18",
|
||||
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -904,16 +904,17 @@
|
|||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"doctrine/annotations": "^1.2.6 || ^1.13.3",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.2",
|
||||
"phpcompatibility/php-compatibility": "^9.3.5",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"squizlabs/php_codesniffer": "^3.7.1",
|
||||
"squizlabs/php_codesniffer": "^3.7.2",
|
||||
"yoast/phpunit-polyfills": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
||||
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
||||
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
||||
|
@ -953,7 +954,7 @@
|
|||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0"
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -961,7 +962,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-06T14:43:22+00:00"
|
||||
"time": "2023-11-25T22:23:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/otphp",
|
||||
|
@ -1911,28 +1912,28 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/messaging",
|
||||
"version": "0.9.1",
|
||||
"version": "dev-feat-email-attachments",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/messaging.git",
|
||||
"reference": "7beec07684e9e1dfcf4ab5b1ba731fa396dccbdf"
|
||||
"reference": "f05cac806480b5a49dceba737d030a5d6b68bddf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/7beec07684e9e1dfcf4ab5b1ba731fa396dccbdf",
|
||||
"reference": "7beec07684e9e1dfcf4ab5b1ba731fa396dccbdf",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/f05cac806480b5a49dceba737d030a5d6b68bddf",
|
||||
"reference": "f05cac806480b5a49dceba737d030a5d6b68bddf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-openssl": "*",
|
||||
"php": ">=8.0.0"
|
||||
"php": ">=8.0.0",
|
||||
"phpmailer/phpmailer": "6.9.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.13.*",
|
||||
"phpmailer/phpmailer": "6.8.*",
|
||||
"phpstan/phpstan": "1.10.*",
|
||||
"phpunit/phpunit": "9.6.10"
|
||||
"laravel/pint": "1.13.11",
|
||||
"phpstan/phpstan": "1.10.58",
|
||||
"phpunit/phpunit": "10.5.10"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -1955,9 +1956,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/messaging/issues",
|
||||
"source": "https://github.com/utopia-php/messaging/tree/0.9.1"
|
||||
"source": "https://github.com/utopia-php/messaging/tree/feat-email-attachments"
|
||||
},
|
||||
"time": "2024-02-15T03:44:44+00:00"
|
||||
"time": "2024-02-19T07:40:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
|
@ -5019,16 +5020,16 @@
|
|||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.8.1",
|
||||
"version": "3.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7"
|
||||
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7",
|
||||
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
|
||||
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -5095,7 +5096,7 @@
|
|||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-11T20:47:48+00:00"
|
||||
"time": "2024-02-16T15:06:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swoole/ide-helper",
|
||||
|
@ -5499,9 +5500,18 @@
|
|||
"time": "2023-10-10T11:58:32+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "utopia-php/messaging",
|
||||
"version": "dev-feat-email-attachments",
|
||||
"alias": "0.9.1",
|
||||
"alias_normalized": "0.9.1.0"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {
|
||||
"utopia-php/messaging": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
|
||||
namespace Appwrite\Platform\Workers;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Messaging\Status as MessageStatus;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
|
@ -29,10 +32,13 @@ use Utopia\Messaging\Adapter\SMS\Textmagic;
|
|||
use Utopia\Messaging\Adapter\SMS\Twilio;
|
||||
use Utopia\Messaging\Adapter\SMS\Vonage;
|
||||
use Utopia\Messaging\Messages\Email;
|
||||
use Utopia\Messaging\Messages\Email\Attachment;
|
||||
use Utopia\Messaging\Messages\Push;
|
||||
use Utopia\Messaging\Messages\SMS;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Queue\Message;
|
||||
use Utopia\Storage\Device;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
use function Swoole\Coroutine\batch;
|
||||
|
||||
|
@ -53,26 +59,35 @@ class Messaging extends Action
|
|||
->inject('message')
|
||||
->inject('log')
|
||||
->inject('dbForProject')
|
||||
->inject('getLocalCache')
|
||||
->inject('queueForUsage')
|
||||
->callback(fn(Message $message, Log $log, Database $dbForProject, Usage $queueForUsage) => $this->action($message, $log, $dbForProject, $queueForUsage));
|
||||
->callback(fn(Message $message, Log $log, Database $dbForProject, callable $getLocalCache, Usage $queueForUsage) => $this->action($message, $log, $dbForProject, $getLocalCache, $queueForUsage));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Message $message
|
||||
* @param Log $log
|
||||
* @param Database $dbForProject
|
||||
* @param callable $getLocalCache
|
||||
* @param Usage $queueForUsage
|
||||
* @return void
|
||||
* @throws Exception
|
||||
* @throws \Utopia\Database\Exception
|
||||
*/
|
||||
public function action(Message $message, Log $log, Database $dbForProject, Usage $queueForUsage): void
|
||||
{
|
||||
public function action(
|
||||
Message $message,
|
||||
Log $log,
|
||||
Database $dbForProject,
|
||||
callable $getLocalCache,
|
||||
Usage $queueForUsage
|
||||
): void {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
|
||||
if (empty($payload)) {
|
||||
throw new Exception('Missing payload');
|
||||
}
|
||||
|
||||
$project = new Document($payload['project'] ?? []);
|
||||
|
||||
if (
|
||||
!\is_null($payload['message'])
|
||||
|
@ -82,7 +97,7 @@ class Messaging extends Action
|
|||
// Message was triggered internally
|
||||
$this->processInternalSMSMessage(
|
||||
new Document($payload['message']),
|
||||
new Document($payload['project'] ?? []),
|
||||
$project,
|
||||
$payload['recipients'],
|
||||
$queueForUsage,
|
||||
$log,
|
||||
|
@ -90,12 +105,21 @@ class Messaging extends Action
|
|||
} else {
|
||||
$message = $dbForProject->getDocument('messages', $payload['messageId']);
|
||||
|
||||
$this->processMessage($dbForProject, $message);
|
||||
$this->processMessage(
|
||||
$dbForProject,
|
||||
$message,
|
||||
getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()),
|
||||
$getLocalCache($project->getId())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function processMessage(Database $dbForProject, Document $message): void
|
||||
{
|
||||
private function processMessage(
|
||||
Database $dbForProject,
|
||||
Document $message,
|
||||
Device $deviceFiles,
|
||||
Device $localCache,
|
||||
): void {
|
||||
$topicIds = $message->getAttribute('topics', []);
|
||||
$targetIds = $message->getAttribute('targets', []);
|
||||
$userIds = $message->getAttribute('users', []);
|
||||
|
@ -199,8 +223,8 @@ class Messaging extends Action
|
|||
/**
|
||||
* @var array<array> $results
|
||||
*/
|
||||
$results = batch(\array_map(function ($providerId) use ($identifiers, $providers, $fallback, $message, $dbForProject) {
|
||||
return function () use ($providerId, $identifiers, $providers, $fallback, $message, $dbForProject) {
|
||||
$results = batch(\array_map(function ($providerId) use ($identifiers, $providers, $fallback, $message, $dbForProject, $localCache, $deviceFiles) {
|
||||
return function () use ($providerId, $identifiers, $providers, $fallback, $message, $dbForProject, $localCache, $deviceFiles) {
|
||||
if (\array_key_exists($providerId, $providers)) {
|
||||
$provider = $providers[$providerId];
|
||||
} else {
|
||||
|
@ -226,8 +250,8 @@ class Messaging extends Action
|
|||
$batches = \array_chunk($identifiers, $maxBatchSize);
|
||||
$batchIndex = 0;
|
||||
|
||||
return batch(\array_map(function ($batch) use ($message, $provider, $adapter, &$batchIndex, $dbForProject) {
|
||||
return function () use ($batch, $message, $provider, $adapter, &$batchIndex, $dbForProject) {
|
||||
return batch(\array_map(function ($batch) use ($message, $provider, $adapter, &$batchIndex, $dbForProject, $localCache, $deviceFiles) {
|
||||
return function () use ($batch, $message, $provider, $adapter, &$batchIndex, $dbForProject, $localCache, $deviceFiles) {
|
||||
$deliveredTotal = 0;
|
||||
$deliveryErrors = [];
|
||||
$messageData = clone $message;
|
||||
|
@ -236,7 +260,7 @@ class Messaging extends Action
|
|||
$data = match ($provider->getAttribute('type')) {
|
||||
MESSAGE_TYPE_SMS => $this->buildSMSMessage($messageData, $provider),
|
||||
MESSAGE_TYPE_PUSH => $this->buildPushMessage($messageData),
|
||||
MESSAGE_TYPE_EMAIL => $this->buildEmailMessage($dbForProject, $messageData, $provider),
|
||||
MESSAGE_TYPE_EMAIL => $this->buildEmailMessage($dbForProject, $messageData, $provider, $deviceFiles, $localCache),
|
||||
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
||||
};
|
||||
|
||||
|
@ -310,6 +334,37 @@ class Messaging extends Action
|
|||
$message->setAttribute('deliveredAt', DateTime::now());
|
||||
|
||||
$dbForProject->updateDocument('messages', $message->getId(), $message);
|
||||
|
||||
// Delete any attachments that were downloaded to the local cache
|
||||
if ($provider->getAttribute('type') === MESSAGE_TYPE_EMAIL) {
|
||||
if ($deviceFiles->getType() === Storage::DEVICE_LOCAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $message->getAttribute('data');
|
||||
$attachments = $data['attachments'] ?? [];
|
||||
|
||||
foreach ($attachments as $attachment) {
|
||||
$bucketId = $attachment['bucketId'];
|
||||
$fileId = $attachment['fileId'];
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if ($localCache->exists($path)) {
|
||||
$localCache->delete($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function processInternalSMSMessage(Document $message, Document $project, array $recipients, Usage $queueForUsage, Log $log): void
|
||||
|
@ -463,8 +518,13 @@ class Messaging extends Action
|
|||
};
|
||||
}
|
||||
|
||||
private function buildEmailMessage(Database $dbForProject, Document $message, Document $provider): Email
|
||||
{
|
||||
private function buildEmailMessage(
|
||||
Database $dbForProject,
|
||||
Document $message,
|
||||
Document $provider,
|
||||
Device $deviceFiles,
|
||||
Device $localCache,
|
||||
): Email {
|
||||
$fromName = $provider['options']['fromName'] ?? null;
|
||||
$fromEmail = $provider['options']['fromEmail'] ?? null;
|
||||
$replyToEmail = $provider['options']['replyToEmail'] ?? null;
|
||||
|
@ -474,8 +534,9 @@ class Messaging extends Action
|
|||
$bccTargets = $data['bcc'] ?? [];
|
||||
$cc = [];
|
||||
$bcc = [];
|
||||
$attachments = $data['attachments'] ?? [];
|
||||
|
||||
if (\count($ccTargets) > 0) {
|
||||
if (!empty($ccTargets)) {
|
||||
$ccTargets = $dbForProject->find('targets', [
|
||||
Query::equal('$id', $ccTargets),
|
||||
Query::limit(\count($ccTargets)),
|
||||
|
@ -485,7 +546,7 @@ class Messaging extends Action
|
|||
}
|
||||
}
|
||||
|
||||
if (\count($bccTargets) > 0) {
|
||||
if (!empty($bccTargets)) {
|
||||
$bccTargets = $dbForProject->find('targets', [
|
||||
Query::equal('$id', $bccTargets),
|
||||
Query::limit(\count($bccTargets)),
|
||||
|
@ -495,12 +556,64 @@ class Messaging extends Action
|
|||
}
|
||||
}
|
||||
|
||||
if (!empty($attachments)) {
|
||||
foreach ($attachments as &$attachment) {
|
||||
$bucketId = $attachment['bucketId'];
|
||||
$fileId = $attachment['fileId'];
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$mimes = Config::getParam('storage-mimes');
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
}
|
||||
|
||||
$contentType = 'text/plain';
|
||||
|
||||
if (\in_array($file->getAttribute('mimeType'), $mimes)) {
|
||||
$contentType = $file->getAttribute('mimeType');
|
||||
}
|
||||
|
||||
if ($deviceFiles->getType() !== Storage::DEVICE_LOCAL) {
|
||||
$deviceFiles->transfer($path, $path, $localCache);
|
||||
}
|
||||
|
||||
$attachment = new Attachment(
|
||||
$file->getAttribute('name'),
|
||||
$path,
|
||||
$contentType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$to = $message['to'];
|
||||
$subject = $data['subject'];
|
||||
$content = $data['content'];
|
||||
$html = $data['html'] ?? false;
|
||||
|
||||
return new Email($to, $subject, $content, $fromName, $fromEmail, $replyToName, $replyToEmail, $cc, $bcc, null, $html);
|
||||
return new Email(
|
||||
$to,
|
||||
$subject,
|
||||
$content,
|
||||
$fromName,
|
||||
$fromEmail,
|
||||
$replyToName,
|
||||
$replyToEmail,
|
||||
$cc,
|
||||
$bcc,
|
||||
$attachments,
|
||||
$html
|
||||
);
|
||||
}
|
||||
|
||||
private function buildSMSMessage(Document $message, Document $provider): SMS
|
||||
|
@ -509,7 +622,11 @@ class Messaging extends Action
|
|||
$content = $message['data']['content'];
|
||||
$from = $provider['options']['from'];
|
||||
|
||||
return new SMS($to, $content, $from);
|
||||
return new SMS(
|
||||
$to,
|
||||
$content,
|
||||
$from
|
||||
);
|
||||
}
|
||||
|
||||
private function buildPushMessage(Document $message): Push
|
||||
|
@ -525,6 +642,17 @@ class Messaging extends Action
|
|||
$tag = $message['data']['tag'] ?? null;
|
||||
$badge = $message['data']['badge'] ?? null;
|
||||
|
||||
return new Push($to, $title, $body, $data, $action, $sound, $icon, $color, $tag, $badge);
|
||||
return new Push(
|
||||
$to,
|
||||
$title,
|
||||
$body,
|
||||
$data,
|
||||
$action,
|
||||
$sound,
|
||||
$icon,
|
||||
$color,
|
||||
$tag,
|
||||
$badge
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
58
src/Appwrite/Utopia/Database/Validator/CompoundUID.php
Normal file
58
src/Appwrite/Utopia/Database/Validator/CompoundUID.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator;
|
||||
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Validator;
|
||||
|
||||
class CompoundUID extends Validator
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Must consist of multiple UIDs separated by a colon. Each UID must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, and underscore. Can\'t start with a special char.';
|
||||
}
|
||||
|
||||
public function isArray(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isValid($value): bool
|
||||
{
|
||||
if (!\is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ids = static::parse($value);
|
||||
|
||||
if (\count($ids) < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$validator = new UID();
|
||||
if (!$validator->isValid($id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return self::TYPE_STRING;
|
||||
}
|
||||
|
||||
public static function parse(string $key): array
|
||||
{
|
||||
$parts = \explode(':', $key);
|
||||
$result = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$result[] = $part;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue