diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index efc81cb370..1d73fac7c5 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -8,7 +8,6 @@ use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; use Appwrite\Event\Event; use Appwrite\Event\Mail; -use Appwrite\Event\Phone as EventPhone; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; use Utopia\Validator\Host; @@ -45,6 +44,7 @@ use Utopia\Validator\WhiteList; use Appwrite\Auth\Validator\PasswordHistory; use Appwrite\Auth\Validator\PasswordDictionary; use Appwrite\Auth\Validator\PersonalData; +use Appwrite\Event\Messaging; $oauthDefaultSuccess = '/auth/oauth2/success'; $oauthDefaultFailure = '/auth/oauth2/failure'; @@ -1227,6 +1227,7 @@ App::post('/v1/account/sessions/phone') ->label('abuse-key', 'url:{url},email:{param-phone}') ->param('userId', '', new CustomId(), 'Unique 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('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.') + ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('request') ->inject('response') ->inject('user') @@ -1235,9 +1236,12 @@ App::post('/v1/account/sessions/phone') ->inject('events') ->inject('messaging') ->inject('locale') - ->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, EventPhone $messaging, Locale $locale) { - - if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { + ->action(function (string $userId, string $phone, string $from, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $events, Messaging $messaging, Locale $locale) { + $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ + Query::equal('default', [true, false]), + Query::equal('type', ['sms']) + ])); + if ($provider === false || $provider->isEmpty()) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -1322,11 +1326,22 @@ App::post('/v1/account/sessions/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); - $messaging - ->setRecipient($phone) - ->setMessage($message) - ->trigger(); + $messageDoc = $dbForProject->createDocument('messages', new Document([ + 'to' => [$phone], + 'data' => [ + 'content' => $message, + 'from' => $from, + ], + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'deliveryTime' => Datetime::now(), + ])); + $messaging + ->setMessage($messageDoc) + ->setProject($project) + ->trigger(); + $events->setPayload( $response->output( $token->setAttribute('secret', $secret), @@ -2872,6 +2887,7 @@ App::post('/v1/account/verification/phone') ->label('sdk.response.model', Response::MODEL_TOKEN) ->label('abuse-limit', 10) ->label('abuse-key', 'userId:{userId}') + ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('request') ->inject('response') ->inject('user') @@ -2880,10 +2896,13 @@ App::post('/v1/account/verification/phone') ->inject('messaging') ->inject('project') ->inject('locale') - ->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events, EventPhone $messaging, Document $project, Locale $locale) { - - if (empty(App::getEnv('_APP_SMS_PROVIDER'))) { - throw new Exception(Exception::GENERAL_PHONE_DISABLED); + ->action(function (string $from, Request $request, Response $response, Document $user, Database $dbForProject, Event $events, Messaging $messaging, Document $project, Locale $locale) { + $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ + Query::equal('default', [true, false]), + Query::equal('type', ['sms']) + ])); + if ($provider === false || $provider->isEmpty()) { + throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } if (empty($user->getAttribute('phone'))) { @@ -2928,11 +2947,21 @@ App::post('/v1/account/verification/phone') $message = $message->setParam('{{token}}', $secret); $message = $message->render(); + $messageDoc = $dbForProject->createDocument('messages', new Document([ + 'to' => [$user->getAttribute('phone')], + 'data' => [ + 'content' => $message, + 'from' => $from, + ], + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'deliveryTime' => Datetime::now(), + ])); + $messaging - ->setRecipient($user->getAttribute('phone')) - ->setMessage($message) - ->trigger() - ; + ->setMessage($messageDoc) + ->setProject($project) + ->trigger(); $events ->setParam('userId', $user->getId()) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e91eb48fb7..e4302883c1 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -16,7 +16,9 @@ use Utopia\Database\Validator\Datetime; use Utopia\Database\Validator\UID; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\JSON; use Utopia\Validator\Text; +use Utopia\Validator\WhiteList; App::get('/v1/messaging/providers') ->desc('List Providers') @@ -1065,6 +1067,101 @@ App::patch('/v1/messaging/providers/:id/apns') ->dynamic($provider, Response::MODEL_PROVIDER); }); +/** + * General Purpose Provider + */ +App::post('/v1/messaging/providers/general') + ->desc('Create General Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.create') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createGeneralProvider') + ->label('sdk.description', '/docs/references/messaging/create-general-provider.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('providerId', '', new CustomId(), 'Provider 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('provider', '', new Text(128), 'Provider Internal Name') + ->param('name', '', new Text(128), 'Provider name.') + ->param('type', '', new WhiteList(['push', 'email', 'sms']), 'Provider type.') + ->param('default', false, new Boolean(), 'Set as default provider.', true) + ->param('credentials', '', new JSON(), 'Provider credentials object.') + ->inject('dbForProject') + ->inject('response') + ->action(function (string $providerId, string $provider, string $name, string $type, bool $default, array $credentials, Database $dbForProject, Response $response) { + $providerId = $providerId == 'unique()' ? ID::unique() : $providerId; + $provider = new Document([ + '$id' => $providerId, + 'name' => $name, + 'provider' => $provider, + 'type' => $type, + 'default' => $default, + 'credentials' => $credentials, + ]); + + // Check if a default provider exists, if not, set this one as default + if ( + empty($dbForProject->findOne('providers', [ + Query::equal('default', [true]), + ])) + ) { + $provider->setAttribute('default', true); + } + + try { + $provider = $dbForProject->createDocument('providers', $provider); + } catch (DuplicateException) { + throw new Exception(Exception::PROVIDER_ALREADY_EXISTS, 'Provider already exists.'); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + +App::patch('/v1/messaging/providers/:id/general') + ->desc('Update General Provider') + ->groups(['api', 'messaging']) + ->label('audits.event', 'providers.update') + ->label('audits.resource', 'providers/{response.$id}') + ->label('scope', 'providers.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateProviderGeneral') + ->label('sdk.description', '/docs/references/messaging/update-provider-general.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_PROVIDER) + ->param('id', '', new UID(), 'Provider ID.') + ->param('name', '', new Text(128), 'Provider name.', true) + ->param('credentials', '', new JSON(), 'Provider credentials.', true) + ->inject('dbForProject') + ->inject('response') + ->action(function (string $id, string $name, array $credentials, Database $dbForProject, Response $response) { + $provider = $dbForProject->getDocument('providers', $id); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + if ($name) { + $provider->setAttribute('name', $name); + } + + if (!empty($credentials)) { + $provider->setAttribute('credentials', $credentials); + } + + $provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider); + $dbForProject->deleteCachedDocument('providers', $provider->getId()); + + $response + ->dynamic($provider, Response::MODEL_PROVIDER); + }); + App::delete('/v1/messaging/providers/:id') ->desc('Delete Provider') ->groups(['api', 'messaging']) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index c5dd3eed12..c453eaaea1 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -6,7 +6,7 @@ use Appwrite\Detector\Detector; use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Mail; -use Appwrite\Event\Phone as EventPhone; +use Appwrite\Event\Messaging; use Appwrite\Extend\Exception; use Appwrite\Network\Validator\Email; use Utopia\Validator\Host; @@ -380,6 +380,7 @@ App::post('/v1/teams/:teamId/memberships') ->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) + ->param('from', '', new Text(128), 'Sender of the message. It can be alphanumeric (Ex: MyCompany20). Restrictions may apply depending of the destination.', true) ->inject('response') ->inject('project') ->inject('user') @@ -388,7 +389,7 @@ App::post('/v1/teams/:teamId/memberships') ->inject('mails') ->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) { + ->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, string $from, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, Messaging $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'); @@ -625,6 +626,15 @@ App::post('/v1/teams/:teamId/memberships') ->trigger() ; } elseif (!empty($phone)) { + $provider = Authorization::skip(fn () => $dbForProject->findOne('providers', [ + Query::equal('default', [true, false]), + Query::equal('type', ['sms']) + ])); + + if ($provider === false || $provider->isEmpty()) { + throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); + } + $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); $customTemplate = $project->getAttribute('templates', [])['sms.invitation-' . $locale->default] ?? []; @@ -635,9 +645,20 @@ App::post('/v1/teams/:teamId/memberships') $message = $message->setParam('{{token}}', $url); $message = $message->render(); + $messageDoc = $dbForProject->createDocument('messages', new Document([ + 'to' => [$phone], + 'data' => [ + 'content' => $message, + 'from' => $from, + ], + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'deliveryTime' => Datetime::now(), + ])); + $messaging - ->setRecipient($phone) - ->setMessage($message) + ->setMessage($messageDoc) + ->setProject($project) ->trigger(); } } diff --git a/app/init.php b/app/init.php index 55757e3d28..6d90ea6dd9 100644 --- a/app/init.php +++ b/app/init.php @@ -25,7 +25,7 @@ use Appwrite\Event\Audit; use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Event; use Appwrite\Event\Mail; -use Appwrite\Event\Phone; +use Appwrite\Event\Messaging; use Appwrite\Event\Delete; use Appwrite\GraphQL\Schema; use Appwrite\Network\Validator\Email; @@ -948,7 +948,7 @@ 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('messaging', fn() => new Messaging()); App::setResource('queue', function (Group $pools) { return $pools->get('queue')->pop()->getResource(); }, ['pools']); diff --git a/app/workers/messaging.php b/app/workers/messaging.php index 84af6fa802..ad0e5bcc4b 100644 --- a/app/workers/messaging.php +++ b/app/workers/messaging.php @@ -2,7 +2,9 @@ use Appwrite\Resque\Worker; use Utopia\CLI\Console; +use Utopia\Database\Document; use Utopia\Messaging\Adapters\SMS as SMSAdapter; +use Utopia\Messaging\Adapters\SMS\Mock; use Utopia\Messaging\Adapters\SMS\Msg91; use Utopia\Messaging\Adapters\SMS\Telesign; use Utopia\Messaging\Adapters\SMS\TextMagic; @@ -14,6 +16,9 @@ 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; +use Utopia\Messaging\Messages\Email; +use Utopia\Messaging\Messages\Push; +use Utopia\Messaging\Messages\SMS; require_once __DIR__ . '/../init.php'; @@ -38,6 +43,7 @@ class MessagingV1 extends Worker { $credentials = $record->getAttribute('credentials'); return match ($record->getAttribute('provider')) { + 'mock' => new Mock('username', 'password'), 'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']), 'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']), 'telesign' => new Telesign($credentials['username'], $credentials['password']), @@ -79,11 +85,13 @@ class MessagingV1 extends Worker public function run(): void { - $providerId = $this->args['providerId']; - $providerRecord = - $this - ->getConsoleDB() - ->getDocument('providers', $providerId); + $project = new Document($this->args['project']); + + $dbForProject = $this->getProjectDB($project); + $message = new Document($this->args['message']); + + $providerId = $message->getAttribute('providerId'); + $providerRecord =$dbForProject->getDocument('providers', $providerId); $provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed. 'sms' => $this->sms($providerRecord), @@ -96,19 +104,13 @@ class MessagingV1 extends Worker // switch on provider name // call function passing needed credentials returns required provider. - $messageId = $this->args['messageId']; - $messageRecord = - $this - ->getConsoleDB() - ->getDocument('messages', $messageId); - $message = match ($providerRecord->getAttribute('type')) { - 'sms' => $this->buildSMSMessage($messageRecord->getArrayCopy()), - 'push' => $this->buildPushMessage($messageRecord->getArrayCopy()), - 'email' => $this->buildEmailMessage($messageRecord->getArrayCopy()), + 'sms' => $this->buildSMSMessage($message->getArrayCopy()), + 'push' => $this->buildPushMessage($message->getArrayCopy()), + 'email' => $this->buildEmailMessage($message->getArrayCopy()), default => null }; - + $provider->send($message); } @@ -117,46 +119,37 @@ class MessagingV1 extends Worker { } - private function buildEmailMessage($data): array + private function buildEmailMessage($data): Email { - $from = $data['from']; + $from = $data['data']['from']; $to = $data['to']; - $subject = $data['subject']; - $body = $data['content']; - - return [ - 'from' => $from, - 'to' => $to, - 'subject' => $subject, - 'body' => $body, - ]; + $subject = $data['data']['subject']; + $content = $data['data']['content']; + $html = $data['data']['html']; + return new Email(to: $to, subject: $subject, content: $content, from: $from, html: $html); } - private function buildSMSMessage($data): array + private function buildSMSMessage($data): SMS { - $from = $data['from']; $to = $data['to']; - $body = $data['content']; + $content = $data['data']['content']; + $from = $data['data']['from']; - return [ - 'from' => $from, - 'to' => $to, - 'body' => $body - ]; + return new SMS($to, $content, $from); } - private function buildPushMessage($data): array + private function buildPushMessage($data): Push { $to = $data['to']; - $title = $data['title']; - $body = $data['body']; - $data = $data['data']; - - return [ - 'to' => $to, - 'title' => $title, - 'body' => $body, - 'data' => $data - ]; + $title = $data['data']['title']; + $body = $data['data']['body']; + $data = $data['data']['data']; + $action = $data['data']['action']; + $sound = $data['data']['sound']; + $icon = $data['data']['icon']; + $color = $data['data']['color']; + $tag = $data['data']['tag']; + $badge = $data['data']['badge']; + return new Push($to, $title, $body, $data, $action, $sound, $icon, $color, $tag, $badge); } } diff --git a/composer.lock b/composer.lock index aeff7ad9d6..8eb26d06d7 100644 --- a/composer.lock +++ b/composer.lock @@ -386,79 +386,6 @@ }, "time": "2023-04-18T15:34:23+00:00" }, - { - "name": "composer/package-versions-deprecated", - "version": "1.11.99.5", - "source": { - "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" - }, - "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "ext-zip": "^1.13", - "phpunit/phpunit": "^6.5 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "support": { - "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-01-17T14:14:24+00:00" - }, { "name": "dragonmantank/cron-expression", "version": "v3.3.2", @@ -914,24 +841,28 @@ }, { "name": "jean85/pretty-package-versions", - "version": "1.6.0", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "1e0104b46f045868f11942aea058cd7186d6c303" + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/1e0104b46f045868f11942aea058cd7186d6c303", - "reference": "1e0104b46f045868f11942aea058cd7186d6c303", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", "shasum": "" }, "require": { - "composer/package-versions-deprecated": "^1.8.0", - "php": "^7.0|^8.0" + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.0|^8.5|^9.2" + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" }, "type": "library", "extra": { @@ -954,7 +885,7 @@ "email": "alessandro.lai85@gmail.com" } ], - "description": "A wrapper for ocramius/package-versions to get pretty versions strings", + "description": "A library to get pretty versions strings of installed dependencies", "keywords": [ "composer", "package", @@ -963,9 +894,9 @@ ], "support": { "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/1.6.0" + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" }, - "time": "2021-02-04T16:20:16+00:00" + "time": "2021-10-08T21:21:46+00:00" }, { "name": "laravel/pint", @@ -1188,34 +1119,35 @@ }, { "name": "mongodb/mongodb", - "version": "1.8.0", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/mongodb/mongo-php-library.git", - "reference": "953dbc19443aa9314c44b7217a16873347e6840d" + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/953dbc19443aa9314c44b7217a16873347e6840d", - "reference": "953dbc19443aa9314c44b7217a16873347e6840d", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488", + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488", "shasum": "" }, "require": { "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.8.1", - "jean85/pretty-package-versions": "^1.2", - "php": "^7.0 || ^8.0", + "ext-mongodb": "^1.11.0", + "jean85/pretty-package-versions": "^1.2 || ^2.0.1", + "php": "^7.1 || ^8.0", "symfony/polyfill-php80": "^1.19" }, "require-dev": { - "squizlabs/php_codesniffer": "^3.5, <3.5.5", - "symfony/phpunit-bridge": "5.x-dev" + "doctrine/coding-standard": "^9.0", + "squizlabs/php_codesniffer": "^3.6", + "symfony/phpunit-bridge": "^5.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { @@ -1250,9 +1182,9 @@ ], "support": { "issues": "https://github.com/mongodb/mongo-php-library/issues", - "source": "https://github.com/mongodb/mongo-php-library/tree/1.8.0" + "source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0" }, - "time": "2020-11-25T12:26:02+00:00" + "time": "2021-10-20T22:22:37+00:00" }, { "name": "mustangostang/spyc", @@ -2220,16 +2152,16 @@ }, { "name": "utopia-php/database", - "version": "0.43.0", + "version": "0.43.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "fb96fc6c94d5efcd43913c34bece62daba76a5e9" + "reference": "cc0247f4f0c402b39f663bf9f77b29d69b95f9d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/fb96fc6c94d5efcd43913c34bece62daba76a5e9", - "reference": "fb96fc6c94d5efcd43913c34bece62daba76a5e9", + "url": "https://api.github.com/repos/utopia-php/database/zipball/cc0247f4f0c402b39f663bf9f77b29d69b95f9d6", + "reference": "cc0247f4f0c402b39f663bf9f77b29d69b95f9d6", "shasum": "" }, "require": { @@ -2238,12 +2170,11 @@ "php": ">=8.0", "utopia-php/cache": "0.8.*", "utopia-php/framework": "0.*.*", - "utopia-php/mongo": "0.2.*" + "utopia-php/mongo": "0.3.*" }, "require-dev": { "fakerphp/faker": "^1.14", "laravel/pint": "1.4.*", - "mongodb/mongodb": "1.8.0", "pcov/clobber": "^2.0", "phpstan/phpstan": "1.10.*", "phpunit/phpunit": "^9.4", @@ -2271,9 +2202,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.43.0" + "source": "https://github.com/utopia-php/database/tree/0.43.1" }, - "time": "2023-08-29T10:18:39+00:00" + "time": "2023-09-01T20:38:36+00:00" }, { "name": "utopia-php/domains", @@ -2589,12 +2520,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "36aee6ae3c601b796364e35be083b909e02bef66" + "reference": "4ebebe97d80bb1de10d362c2464ba28717d333ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/36aee6ae3c601b796364e35be083b909e02bef66", - "reference": "36aee6ae3c601b796364e35be083b909e02bef66", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/4ebebe97d80bb1de10d362c2464ba28717d333ac", + "reference": "4ebebe97d80bb1de10d362c2464ba28717d333ac", "shasum": "" }, "require": { @@ -2629,7 +2560,7 @@ "issues": "https://github.com/utopia-php/messaging/issues", "source": "https://github.com/utopia-php/messaging/tree/feat-push" }, - "time": "2023-08-30T18:32:54+00:00" + "time": "2023-09-01T14:13:03+00:00" }, { "name": "utopia-php/migration", @@ -2691,21 +2622,21 @@ }, { "name": "utopia-php/mongo", - "version": "0.2.0", + "version": "0.3.1", "source": { "type": "git", "url": "https://github.com/utopia-php/mongo.git", - "reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09" + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/mongo/zipball/b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09", - "reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09", + "url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", + "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee", "shasum": "" }, "require": { "ext-mongodb": "*", - "mongodb/mongodb": "1.8.0", + "mongodb/mongodb": "1.10.0", "php": ">=8.0" }, "require-dev": { @@ -2745,9 +2676,9 @@ ], "support": { "issues": "https://github.com/utopia-php/mongo/issues", - "source": "https://github.com/utopia-php/mongo/tree/0.2.0" + "source": "https://github.com/utopia-php/mongo/tree/0.3.1" }, - "time": "2023-03-22T10:44:29+00:00" + "time": "2023-09-01T17:25:28+00:00" }, { "name": "utopia-php/orchestration", @@ -3460,16 +3391,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.34.1", + "version": "0.34.2", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "81538d10abacd81350c265b516c72ef315116013" + "reference": "06ea25aace27790e42d57fdbc7ccf97e0b31a6ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/81538d10abacd81350c265b516c72ef315116013", - "reference": "81538d10abacd81350c265b516c72ef315116013", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/06ea25aace27790e42d57fdbc7ccf97e0b31a6ba", + "reference": "06ea25aace27790e42d57fdbc7ccf97e0b31a6ba", "shasum": "" }, "require": { @@ -3505,9 +3436,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/0.34.1" + "source": "https://github.com/appwrite/sdk-generator/tree/0.34.2" }, - "time": "2023-08-30T07:57:31+00:00" + "time": "2023-08-31T14:10:33+00:00" }, { "name": "doctrine/deprecations", diff --git a/docker-compose.yml b/docker-compose.yml index b27c3581af..fe1237c95f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -544,8 +544,11 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_SMS_PROVIDER - - _APP_SMS_FROM + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG diff --git a/src/Appwrite/Event/Messaging.php b/src/Appwrite/Event/Messaging.php new file mode 100644 index 0000000000..db60d2ee23 --- /dev/null +++ b/src/Appwrite/Event/Messaging.php @@ -0,0 +1,56 @@ +message = $message; + + return $this; + } + + /** + * Returns set message for the messaging event. + * + * @return Document + */ + public function getMessage(): Document + { + return $this->message; + } + + /** + * Executes the event and sends it to the messaging worker. + * + * @return string|bool + * @throws \InvalidArgumentException + */ + public function trigger(): string|bool + { + return Resque::enqueue($this->queue, $this->class, [ + 'project' => $this->project, + 'user' => $this->user, + 'message' => $this->message, + ]); + } +} diff --git a/src/Appwrite/Event/Phone.php b/src/Appwrite/Event/Phone.php deleted file mode 100644 index 8baa5120c9..0000000000 --- a/src/Appwrite/Event/Phone.php +++ /dev/null @@ -1,80 +0,0 @@ -recipient = $recipient; - - return $this; - } - - /** - * Returns set recipient for this messaging event. - * - * @return string - */ - public function getRecipient(): string - { - return $this->recipient; - } - - /** - * Sets url for the messaging event. - * - * @param string $message - * @return self - */ - public function setMessage(string $message): self - { - $this->message = $message; - - return $this; - } - - /** - * Returns set url for the messaging event. - * - * @return string - */ - public function getMessage(): string - { - return $this->message; - } - - /** - * Executes the event and sends it to the messaging worker. - * - * @return string|bool - * @throws \InvalidArgumentException - */ - public function trigger(): string|bool - { - return Resque::enqueue($this->queue, $this->class, [ - 'project' => $this->project, - 'user' => $this->user, - 'payload' => $this->payload, - 'recipient' => $this->recipient, - 'message' => $this->message, - 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) - ]); - } -} diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 1441ab7f98..55ad0ddae3 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -2,8 +2,6 @@ namespace Tests\E2E\Services\Account; -use Appwrite\Extend\Exception; -use Appwrite\SMS\Adapter\Mock; use Appwrite\Tests\Retry; use Tests\E2E\Client; use Tests\E2E\Scopes\Scope; @@ -745,7 +743,22 @@ class AccountCustomClientTest extends Scope public function testCreatePhone(): array { $number = '+123456789'; - + $response = $this->client->call(Client::METHOD_POST, '/messaging/providers/general' , \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => 'unique()', + 'name' => 'Mock', + 'provider' => 'mock', + 'type' => 'sms', + 'credentials' => [ + 'username' => 'username', + 'password' => 'password', + ], + 'default' => true, + ]); + $this->assertEquals(201, $response['headers']['status-code']); /** * Test for SUCCESS */ @@ -756,6 +769,7 @@ class AccountCustomClientTest extends Scope ]), [ 'userId' => ID::unique(), 'phone' => $number, + 'from' => $number, ]); $this->assertEquals(201, $response['headers']['status-code']); @@ -999,7 +1013,7 @@ class AccountCustomClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - ])); + ]), ['from' => 'Appwrite']); $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']);