Merge branch '1.5.x' into feat-block-countries

This commit is contained in:
Khushboo Verma 2024-02-01 17:49:14 +05:30
commit d3b002a48e
35 changed files with 602 additions and 348 deletions

View file

@ -344,13 +344,13 @@ Things to remember when releasing SDKs:
## Debug ## Debug
Appwrite uses [yasd](https://github.com/swoole/yasd) debugger, which can be made available during build of Appwrite. You can connect to the debugger using VS Code's [PHP Debug](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) extension. Appwrite uses [XDebug](https://github.com/xdebug/xdebug) debugger, which can be made available during build of Appwrite. You can connect to the debugger using VS Code's [PHP Debug](https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug) extension.
If you are in PHP Storm you don't need any plugin. Below are the settings required for remote debugger connection: If you are in PHP Storm you don't need any plugin. Below are the settings required for remote debugger connection:
1. Create an init file. 1. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
2. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php**. 2. If needed edit the **dev/xdebug.ini** file to your needs.
3. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file. 3. Launch your Appwrite instance while your debugger is listening for connections.
### VS Code Launch Configuration ### VS Code Launch Configuration

View file

@ -29,7 +29,7 @@ ENV VITE_APPWRITE_GROWTH_ENDPOINT=$VITE_APPWRITE_GROWTH_ENDPOINT
RUN npm ci RUN npm ci
RUN npm run build RUN npm run build
FROM appwrite/base:0.4.3 as final FROM appwrite/base:0.7.2 as final
LABEL maintainer="team@appwrite.io" LABEL maintainer="team@appwrite.io"
@ -56,6 +56,7 @@ COPY ./public /usr/src/code/public
COPY ./bin /usr/local/bin COPY ./bin /usr/local/bin
COPY ./docs /usr/src/code/docs COPY ./docs /usr/src/code/docs
COPY ./src /usr/src/code/src COPY ./src /usr/src/code/src
COPY ./dev /usr/src/code/dev
# Set Volumes # Set Volumes
RUN mkdir -p /storage/uploads && \ RUN mkdir -p /storage/uploads && \
@ -126,9 +127,10 @@ RUN chmod +x /usr/local/bin/calc-tier-stats && \
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/ RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions # Enable Extensions
RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/src/code/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi RUN if [ "$DEBUG" == "true" ]; then cp /usr/src/code/dev/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini; fi
RUN if [ "$DEBUG" == "true" ]; then echo "opcache.enable=0" >> /usr/local/etc/php/conf.d/appwrite.ini; fi RUN if [ "$DEBUG" == "true" ]; then echo "opcache.enable=0" >> /usr/local/etc/php/conf.d/appwrite.ini; fi
RUN if [ "$DEBUG" = "false" ]; then rm -rf /usr/src/code/dev; fi
RUN if [ "$DEBUG" = "false" ]; then rm -f /usr/local/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so; fi
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.preload=/usr/src/code/app/preload.php" >> /usr/local/etc/php/conf.d/appwrite.ini RUN echo "opcache.preload=/usr/src/code/app/preload.php" >> /usr/local/etc/php/conf.d/appwrite.ini
RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/appwrite.ini RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/conf.d/appwrite.ini

View file

@ -1573,17 +1573,6 @@ $commonCollections = [
'array' => false, 'array' => false,
'filters' => [], 'filters' => [],
], ],
[
'$id' => ID::custom('description'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[ [
'$id' => ID::custom('status'), '$id' => ID::custom('status'),
'type' => Database::VAR_STRING, 'type' => Database::VAR_STRING,
@ -1744,17 +1733,6 @@ $commonCollections = [
'array' => false, 'array' => false,
'filters' => [], 'filters' => [],
], ],
[
'$id' => ID::custom('description'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[ [
'$id' => ID::custom('total'), '$id' => ID::custom('total'),
'type' => Database::VAR_INTEGER, 'type' => Database::VAR_INTEGER,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2035,6 +2035,9 @@ App::get('/v1/account')
->inject('response') ->inject('response')
->inject('user') ->inject('user')
->action(function (Response $response, Document $user) { ->action(function (Response $response, Document $user) {
if ($user->isEmpty()) {
throw new Exception(Exception::USER_NOT_FOUND);
}
$response->dynamic($user, Response::MODEL_ACCOUNT); $response->dynamic($user, Response::MODEL_ACCOUNT);
}); });

View file

@ -521,7 +521,7 @@ App::get('/v1/avatars/initials')
// if there is no space, try to split by `_` underscore // if there is no space, try to split by `_` underscore
$words = (count($words) == 1) ? \explode('_', \strtoupper($name)) : $words; $words = (count($words) == 1) ? \explode('_', \strtoupper($name)) : $words;
$initials = null; $initials = '';
$code = 0; $code = 0;
foreach ($words as $key => $w) { foreach ($words as $key => $w) {

View file

@ -35,6 +35,7 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean; use Utopia\Validator\Boolean;
use Utopia\Validator\Integer; use Utopia\Validator\Integer;
use Utopia\Validator\JSON; use Utopia\Validator\JSON;
use Utopia\Validator\Range;
use Utopia\Validator\Text; use Utopia\Validator\Text;
use MaxMind\Db\Reader; use MaxMind\Db\Reader;
use Utopia\Database\DateTime; use Utopia\Database\DateTime;
@ -61,30 +62,20 @@ App::post('/v1/messaging/providers/mailgun')
->param('apiKey', '', new Text(0), 'Mailgun API Key.', true) ->param('apiKey', '', new Text(0), 'Mailgun API Key.', true)
->param('domain', '', new Text(0), 'Mailgun Domain.', true) ->param('domain', '', new Text(0), 'Mailgun Domain.', true)
->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true) ->param('isEuRegion', null, new Boolean(), 'Set as EU region.', true)
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
->param('fromName', '', new Text(128, 0), 'Sender Name.', true) ->param('fromName', '', new Text(128, 0), 'Sender Name.', true)
->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true)
->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name. Reply to name must have reply to email as well.', true) ->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name. Reply to name must have reply to email as well.', true)
->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email. Reply to email must have reply to name as well.', true) ->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email. Reply to email must have reply to name as well.', true)
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
->inject('queueForEvents') ->inject('queueForEvents')
->inject('dbForProject') ->inject('dbForProject')
->inject('response') ->inject('response')
->action(function (string $providerId, string $name, string $apiKey, string $domain, ?bool $isEuRegion, ?bool $enabled, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { ->action(function (string $providerId, string $name, string $apiKey, string $domain, ?bool $isEuRegion, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) {
$providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $providerId = $providerId == 'unique()' ? ID::unique() : $providerId;
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
];
if (!empty($replyToName) && !empty($replyToEmail)) {
$options['replyToName'] = $replyToName;
$options['replyToEmail'] = $replyToEmail;
}
$credentials = []; $credentials = [];
if ($isEuRegion === true || $isEuRegion === false) { if (!\is_null($isEuRegion)) {
$credentials['isEuRegion'] = $isEuRegion; $credentials['isEuRegion'] = $isEuRegion;
} }
@ -96,12 +87,19 @@ App::post('/v1/messaging/providers/mailgun')
$credentials['domain'] = $domain; $credentials['domain'] = $domain;
} }
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
'replyToName' => $replyToName,
'replyToEmail' => $replyToEmail,
];
if ( if (
$enabled === true && $enabled === true
\array_key_exists('isEuRegion', $credentials) && && !empty($fromEmail)
\array_key_exists('apiKey', $credentials) && && \array_key_exists('isEuRegion', $credentials)
\array_key_exists('domain', $credentials) && && \array_key_exists('apiKey', $credentials)
\array_key_exists('fromEmail', $options) && \array_key_exists('domain', $credentials)
) { ) {
$enabled = true; $enabled = true;
} else { } else {
@ -149,37 +147,34 @@ App::post('/v1/messaging/providers/sendgrid')
->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('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('name', '', new Text(128), 'Provider name.') ->param('name', '', new Text(128), 'Provider name.')
->param('apiKey', '', new Text(0), 'Sendgrid API key.', true) ->param('apiKey', '', new Text(0), 'Sendgrid API key.', true)
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
->param('fromName', '', new Text(128, 0), 'Sender Name.', true) ->param('fromName', '', new Text(128, 0), 'Sender Name.', true)
->param('fromEmail', '', new Email(), 'Sender email address.', true) ->param('fromEmail', '', new Email(), 'Sender email address.', true)
->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name.', true) ->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name.', true)
->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email.', true) ->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email.', true)
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
->inject('queueForEvents') ->inject('queueForEvents')
->inject('dbForProject') ->inject('dbForProject')
->inject('response') ->inject('response')
->action(function (string $providerId, string $name, string $apiKey, ?bool $enabled, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, Event $queueForEvents, Database $dbForProject, Response $response) { ->action(function (string $providerId, string $name, string $apiKey, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) {
$providerId = $providerId == 'unique()' ? ID::unique() : $providerId; $providerId = $providerId == 'unique()' ? ID::unique() : $providerId;
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
];
if (!empty($replyToName) && !empty($replyToEmail)) {
$options['replyToName'] = $replyToName;
$options['replyToEmail'] = $replyToEmail;
}
$credentials = []; $credentials = [];
if (!empty($apiKey)) { if (!empty($apiKey)) {
$credentials['apiKey'] = $apiKey; $credentials['apiKey'] = $apiKey;
} }
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
'replyToName' => $replyToName,
'replyToEmail' => $replyToEmail,
];
if ( if (
$enabled === true $enabled === true
&& !empty($fromEmail)
&& \array_key_exists('apiKey', $credentials) && \array_key_exists('apiKey', $credentials)
&& \array_key_exists('fromEmail', $options)
) { ) {
$enabled = true; $enabled = true;
} else { } else {
@ -210,6 +205,94 @@ App::post('/v1/messaging/providers/sendgrid')
->dynamic($provider, Response::MODEL_PROVIDER); ->dynamic($provider, Response::MODEL_PROVIDER);
}); });
App::post('/v1/messaging/providers/smtp')
->desc('Create SMTP provider')
->groups(['api', 'messaging'])
->label('audits.event', 'provider.create')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].create')
->label('scope', 'providers.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'createSMTPProvider')
->label('sdk.description', '/docs/references/messaging/create-smtp-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('name', '', new Text(128), 'Provider name.')
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host by using this format: [hostname:port] (e.g. "smtp1.example.com:25;smtp2.example.com"). You can also specify encryption type, for example: (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). Hosts will be tried in order.')
->param('port', 587, new Range(1, 65535), 'The default SMTP server port.', true)
->param('username', '', new Text(0), 'Authentication username.', true)
->param('password', '', new Text(0), 'Authentication password.', true)
->param('encryption', '', new WhiteList(['none', 'ssl', 'tls']), 'Encryption type. Can be omitted, \'ssl\', or \'tls\'', true)
->param('autoTLS', true, new Boolean(), 'Enable SMTP AutoTLS feature.', true)
->param('mailer', '', new Text(0), 'The value to use for the X-Mailer header.', true)
->param('fromName', '', new Text(128, 0), 'Sender Name.', true)
->param('fromEmail', '', new Email(), 'Sender email address.', true)
->param('replyToName', '', new Text(128, 0), 'Name set in the reply to field for the mail. Default value is sender name.', true)
->param('replyToEmail', '', new Email(), 'Email set in the reply to field for the mail. Default value is sender email.', true)
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
->inject('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, string $host, int $port, string $username, string $password, string $encryption, bool $autoTLS, string $mailer, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) {
$providerId = $providerId == 'unique()' ? ID::unique() : $providerId;
$credentials = [
'port' => $port,
'username' => $username,
'password' => $password,
];
if (!empty($host)) {
$credentials['host'] = $host;
}
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
'replyToName' => $replyToName,
'replyToEmail' => $replyToEmail,
'encryption' => $encryption === 'none' ? '' : $encryption,
'autoTLS' => $autoTLS,
'mailer' => $mailer,
];
if (
$enabled === true
&& !empty($fromEmail)
&& \array_key_exists('host', $credentials)
) {
$enabled = true;
} else {
$enabled = false;
}
$provider = new Document([
'$id' => $providerId,
'name' => $name,
'provider' => 'smtp',
'type' => MESSAGE_TYPE_EMAIL,
'enabled' => $enabled,
'credentials' => $credentials,
'options' => $options,
]);
try {
$provider = $dbForProject->createDocument('providers', $provider);
} catch (DuplicateException) {
throw new Exception(Exception::PROVIDER_ALREADY_EXISTS);
}
$queueForEvents
->setParam('providerId', $provider->getId());
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($provider, Response::MODEL_PROVIDER);
});
App::post('/v1/messaging/providers/msg91') App::post('/v1/messaging/providers/msg91')
->desc('Create Msg91 provider') ->desc('Create Msg91 provider')
->groups(['api', 'messaging']) ->groups(['api', 'messaging'])
@ -1085,6 +1168,125 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId')
->dynamic($provider, Response::MODEL_PROVIDER); ->dynamic($provider, Response::MODEL_PROVIDER);
}); });
App::patch('/v1/messaging/providers/smtp/:providerId')
->desc('Update SMTP provider')
->groups(['api', 'messaging'])
->label('audits.event', 'provider.update')
->label('audits.resource', 'provider/{response.$id}')
->label('event', 'providers.[providerId].update')
->label('scope', 'providers.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'updateSMTPProvider')
->label('sdk.description', '/docs/references/messaging/update-smtp-provider.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('providerId', '', new UID(), 'Provider ID.')
->param('name', '', new Text(128), 'Provider name.', true)
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host by using this format: [hostname:port] (e.g. "smtp1.example.com:25;smtp2.example.com"). You can also specify encryption type, for example: (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). Hosts will be tried in order.', true)
->param('port', null, new Range(1, 65535), 'SMTP port.', true)
->param('username', '', new Text(0), 'Authentication username.', true)
->param('password', '', new Text(0), 'Authentication password.', true)
->param('encryption', '', new WhiteList(['none', 'ssl', 'tls']), 'Encryption type. Can be \'ssl\' or \'tls\'', true)
->param('autoTLS', null, new Boolean(), 'Enable SMTP AutoTLS feature.', true)
->param('fromName', '', new Text(128), 'Sender Name.', true)
->param('fromEmail', '', new Email(), 'Sender email address.', true)
->param('replyToName', '', new Text(128), 'Name set in the Reply To field for the mail. Default value is Sender Name.', true)
->param('replyToEmail', '', new Text(128), 'Email set in the Reply To field for the mail. Default value is Sender Email.', true)
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
->inject('queueForEvents')
->inject('dbForProject')
->inject('response')
->action(function (string $providerId, string $name, string $host, ?int $port, string $username, string $password, string $encryption, ?bool $autoTLS, string $fromName, string $fromEmail, string $replyToName, string $replyToEmail, ?bool $enabled, Event $queueForEvents, Database $dbForProject, Response $response) {
$provider = $dbForProject->getDocument('providers', $providerId);
if ($provider->isEmpty()) {
throw new Exception(Exception::PROVIDER_NOT_FOUND);
}
$providerAttr = $provider->getAttribute('provider');
if ($providerAttr !== 'smtp') {
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
}
if (!empty($name)) {
$provider->setAttribute('name', $name);
}
$options = $provider->getAttribute('options');
if (!empty($fromName)) {
$options['fromName'] = $fromName;
}
if (!empty($fromEmail)) {
$options['fromEmail'] = $fromEmail;
}
if (!empty($replyToName)) {
$options['replyToName'] = $replyToName;
}
if (!empty($replyToEmail)) {
$options['replyToEmail'] = $replyToEmail;
}
$provider->setAttribute('options', $options);
$credentials = $provider->getAttribute('credentials');
if (!empty($host)) {
$credentials['host'] = $host;
}
if (!\is_null($port)) {
$credentials['port'] = $port;
}
if (!empty($username)) {
$credentials['username'] = $username;
}
if (!empty($password)) {
$credentials['password'] = $password;
}
if (!empty($encryption)) {
$credentials['encryption'] = $encryption === 'none' ? '' : $encryption;
}
if (!\is_null($autoTLS)) {
$credentials['autoTLS'] = $autoTLS;
}
$provider->setAttribute('credentials', $credentials);
if (!\is_null($enabled)) {
if ($enabled) {
if (
!empty($options['fromEmail'])
&& \array_key_exists('host', $credentials)
) {
$provider->setAttribute('enabled', true);
} else {
throw new Exception(Exception::PROVIDER_MISSING_CREDENTIALS);
}
} else {
$provider->setAttribute('enabled', false);
}
}
$provider = $dbForProject->updateDocument('providers', $provider->getId(), $provider);
$queueForEvents
->setParam('providerId', $provider->getId());
$response
->dynamic($provider, Response::MODEL_PROVIDER);
});
App::patch('/v1/messaging/providers/msg91/:providerId') App::patch('/v1/messaging/providers/msg91/:providerId')
->desc('Update Msg91 provider') ->desc('Update Msg91 provider')
->groups(['api', 'messaging']) ->groups(['api', 'messaging'])
@ -1701,17 +1903,15 @@ App::post('/v1/messaging/topics')
->label('sdk.response.model', Response::MODEL_TOPIC) ->label('sdk.response.model', Response::MODEL_TOPIC)
->param('topicId', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.') ->param('topicId', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.')
->param('name', '', new Text(128), 'Topic Name.') ->param('name', '', new Text(128), 'Topic Name.')
->param('description', '', new Text(2048), 'Topic Description.', true)
->inject('queueForEvents') ->inject('queueForEvents')
->inject('dbForProject') ->inject('dbForProject')
->inject('response') ->inject('response')
->action(function (string $topicId, string $name, string $description, Event $queueForEvents, Database $dbForProject, Response $response) { ->action(function (string $topicId, string $name, Event $queueForEvents, Database $dbForProject, Response $response) {
$topicId = $topicId == 'unique()' ? ID::unique() : $topicId; $topicId = $topicId == 'unique()' ? ID::unique() : $topicId;
$topic = new Document([ $topic = new Document([
'$id' => $topicId, '$id' => $topicId,
'name' => $name, 'name' => $name,
'description' => $description
]); ]);
try { try {
@ -1898,11 +2098,10 @@ App::patch('/v1/messaging/topics/:topicId')
->label('sdk.response.model', Response::MODEL_TOPIC) ->label('sdk.response.model', Response::MODEL_TOPIC)
->param('topicId', '', new UID(), 'Topic ID.') ->param('topicId', '', new UID(), 'Topic ID.')
->param('name', '', new Text(128), 'Topic Name.', true) ->param('name', '', new Text(128), 'Topic Name.', true)
->param('description', '', new Text(2048), 'Topic Description.', true)
->inject('queueForEvents') ->inject('queueForEvents')
->inject('dbForProject') ->inject('dbForProject')
->inject('response') ->inject('response')
->action(function (string $topicId, string $name, string $description, Event $queueForEvents, Database $dbForProject, Response $response) { ->action(function (string $topicId, string $name, Event $queueForEvents, Database $dbForProject, Response $response) {
$topic = $dbForProject->getDocument('topics', $topicId); $topic = $dbForProject->getDocument('topics', $topicId);
if ($topic->isEmpty()) { if ($topic->isEmpty()) {
@ -1913,10 +2112,6 @@ App::patch('/v1/messaging/topics/:topicId')
$topic->setAttribute('name', $name); $topic->setAttribute('name', $name);
} }
if (!empty($description)) {
$topic->setAttribute('description', $description);
}
$topic = $dbForProject->updateDocument('topics', $topicId, $topic); $topic = $dbForProject->updateDocument('topics', $topicId, $topic);
$queueForEvents $queueForEvents
@ -2301,7 +2496,6 @@ App::post('/v1/messaging/messages/email')
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true) ->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('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('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true)
->param('description', '', new Text(256), 'Description for message.', 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('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('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) ->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)
@ -2311,7 +2505,7 @@ App::post('/v1/messaging/messages/email')
->inject('project') ->inject('project')
->inject('queueForMessaging') ->inject('queueForMessaging')
->inject('response') ->inject('response')
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, string $description, 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, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$messageId = $messageId == 'unique()' $messageId = $messageId == 'unique()'
? ID::unique() ? ID::unique()
: $messageId; : $messageId;
@ -2350,7 +2544,6 @@ App::post('/v1/messaging/messages/email')
'topics' => $topics, 'topics' => $topics,
'users' => $users, 'users' => $users,
'targets' => $targets, 'targets' => $targets,
'description' => $description,
'scheduledAt' => $scheduledAt, 'scheduledAt' => $scheduledAt,
'data' => [ 'data' => [
'subject' => $subject, 'subject' => $subject,
@ -2420,7 +2613,6 @@ App::post('/v1/messaging/messages/sms')
->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true) ->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true)
->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true) ->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true)
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('description', '', new Text(256), 'Description for Message.', 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('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('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) ->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)
->inject('queueForEvents') ->inject('queueForEvents')
@ -2429,7 +2621,7 @@ App::post('/v1/messaging/messages/sms')
->inject('project') ->inject('project')
->inject('queueForMessaging') ->inject('queueForMessaging')
->inject('response') ->inject('response')
->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $description, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) { ->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$messageId = $messageId == 'unique()' $messageId = $messageId == 'unique()'
? ID::unique() ? ID::unique()
: $messageId; : $messageId;
@ -2466,7 +2658,6 @@ App::post('/v1/messaging/messages/sms')
'topics' => $topics, 'topics' => $topics,
'users' => $users, 'users' => $users,
'targets' => $targets, 'targets' => $targets,
'description' => $description,
'data' => [ 'data' => [
'content' => $content, 'content' => $content,
], ],
@ -2532,7 +2723,6 @@ App::post('/v1/messaging/messages/push')
->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true) ->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true)
->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true) ->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true)
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('description', '', new Text(256), 'Description for Message.', true)
->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true)
->param('action', '', new Text(256), 'Action for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true)
->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true) ->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true)
@ -2548,7 +2738,7 @@ App::post('/v1/messaging/messages/push')
->inject('project') ->inject('project')
->inject('queueForMessaging') ->inject('queueForMessaging')
->inject('response') ->inject('response')
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) { ->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$messageId = $messageId == 'unique()' $messageId = $messageId == 'unique()'
? ID::unique() ? ID::unique()
: $messageId; : $messageId;
@ -2595,7 +2785,6 @@ App::post('/v1/messaging/messages/push')
'topics' => $topics, 'topics' => $topics,
'users' => $users, 'users' => $users,
'targets' => $targets, 'targets' => $targets,
'description' => $description,
'scheduledAt' => $scheduledAt, 'scheduledAt' => $scheduledAt,
'data' => $pushData, 'data' => $pushData,
'status' => $status, 'status' => $status,
@ -2869,7 +3058,6 @@ App::patch('/v1/messaging/messages/email/:messageId')
->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true)
->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('subject', null, new Text(998), 'Email Subject.', true) ->param('subject', null, new Text(998), 'Email Subject.', true)
->param('description', null, new Text(256), 'Description for Message.', true)
->param('content', null, new Text(64230), 'Email Content.', true) ->param('content', null, new Text(64230), 'Email Content.', 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('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', null, new Boolean(), 'Is content of type HTML', true) ->param('html', null, new Boolean(), 'Is content of type HTML', true)
@ -2882,7 +3070,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
->inject('project') ->inject('project')
->inject('queueForMessaging') ->inject('queueForMessaging')
->inject('response') ->inject('response')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $subject, ?string $description, ?string $content, ?string $status, ?bool $html, ?array $cc, ?array $bcc, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) { ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $subject, ?string $content, ?string $status, ?bool $html, ?array $cc, ?array $bcc, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$message = $dbForProject->getDocument('messages', $messageId); $message = $dbForProject->getDocument('messages', $messageId);
if ($message->isEmpty()) { if ($message->isEmpty()) {
@ -2933,10 +3121,6 @@ App::patch('/v1/messaging/messages/email/:messageId')
$message->setAttribute('data', $data); $message->setAttribute('data', $data);
if (!\is_null($description)) {
$message->setAttribute('description', $description);
}
if (!\is_null($status)) { if (!\is_null($status)) {
$message->setAttribute('status', $status); $message->setAttribute('status', $status);
} }
@ -3007,7 +3191,6 @@ App::patch('/v1/messaging/messages/sms/:messageId')
->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true)
->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true)
->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('description', null, new Text(256), 'Description for Message.', true)
->param('content', null, new Text(64230), 'Email Content.', true) ->param('content', null, new Text(64230), 'Email Content.', true)
->param('status', null, new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true) ->param('status', null, new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', 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) ->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)
@ -3017,7 +3200,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
->inject('project') ->inject('project')
->inject('queueForMessaging') ->inject('queueForMessaging')
->inject('response') ->inject('response')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $description, ?string $content, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) { ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $content, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$message = $dbForProject->getDocument('messages', $messageId); $message = $dbForProject->getDocument('messages', $messageId);
if ($message->isEmpty()) { if ($message->isEmpty()) {
@ -3056,10 +3239,6 @@ App::patch('/v1/messaging/messages/sms/:messageId')
$message->setAttribute('status', $status); $message->setAttribute('status', $status);
} }
if (!\is_null($description)) {
$message->setAttribute('description', $description);
}
if (!\is_null($scheduledAt)) { if (!\is_null($scheduledAt)) {
if (\is_null($message->getAttribute(('scheduleId')))) { if (\is_null($message->getAttribute(('scheduleId')))) {
$schedule = $dbForConsole->createDocument('schedules', new Document([ $schedule = $dbForConsole->createDocument('schedules', new Document([
@ -3126,7 +3305,6 @@ App::patch('/v1/messaging/messages/push/:messageId')
->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true) ->param('topics', null, new ArrayList(new UID()), 'List of Topic IDs.', true)
->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true) ->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true)
->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true) ->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('description', null, new Text(256), 'Description for Message.', true)
->param('title', null, new Text(256), 'Title for push notification.', true) ->param('title', null, new Text(256), 'Title for push notification.', true)
->param('body', null, new Text(64230), 'Body for push notification.', true) ->param('body', null, new Text(64230), 'Body for push notification.', true)
->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true)
@ -3144,7 +3322,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
->inject('project') ->inject('project')
->inject('queueForMessaging') ->inject('queueForMessaging')
->inject('response') ->inject('response')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $description, ?string $title, ?string $body, ?array $data, ?string $action, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) { ->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$message = $dbForProject->getDocument('messages', $messageId); $message = $dbForProject->getDocument('messages', $messageId);
if ($message->isEmpty()) { if ($message->isEmpty()) {
@ -3215,10 +3393,6 @@ App::patch('/v1/messaging/messages/push/:messageId')
$message->setAttribute('status', $status); $message->setAttribute('status', $status);
} }
if (!\is_null($description)) {
$message->setAttribute('description', $description);
}
if (!\is_null($scheduledAt)) { if (!\is_null($scheduledAt)) {
if (\is_null($message->getAttribute(('scheduleId')))) { if (\is_null($message->getAttribute(('scheduleId')))) {
$schedule = $dbForConsole->createDocument('schedules', new Document([ $schedule = $dbForConsole->createDocument('schedules', new Document([
@ -3266,3 +3440,59 @@ App::patch('/v1/messaging/messages/push/:messageId')
$response $response
->dynamic($message, Response::MODEL_MESSAGE); ->dynamic($message, Response::MODEL_MESSAGE);
}); });
App::delete('/v1/messaging/messages/:messageId')
->desc('Delete a message')
->groups(['api', 'messaging'])
->label('audits.event', 'message.delete')
->label('audits.resource', 'message/{request.route.messageId}')
->label('event', 'messages.[messageId].delete')
->label('scope', 'messages.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'messaging')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/messaging/delete-message.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('messageId', '', new UID(), 'Message ID.')
->inject('dbForProject')
->inject('dbForConsole')
->inject('response')
->action(function (string $messageId, Database $dbForProject, Database $dbForConsole, Response $response) {
$message = $dbForProject->getDocument('messages', $messageId);
if ($message->isEmpty()) {
throw new Exception(Exception::MESSAGE_NOT_FOUND);
}
switch ($message->getAttribute('status')) {
case MessageStatus::PROCESSING:
throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED);
case MessageStatus::SCHEDULED:
$scheduleId = $message->getAttribute('scheduleId');
$scheduledAt = $message->getAttribute('scheduledAt');
$now = DateTime::now();
$scheduledDate = DateTime::formatTz($scheduledAt);
if ($now > $scheduledDate) {
throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED);
}
if (!empty($scheduleId)) {
try {
$dbForConsole->deleteDocument('schedules', $scheduleId);
} catch (Exception) {
// Ignore
}
}
break;
default:
break;
}
$dbForProject->deleteDocument('messages', $message->getId());
$response->noContent();
});

View file

@ -963,7 +963,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
break; break;
} }
$image = new Image($source); try {
$image = new Image($source);
} catch (ImagickException $e) {
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED, $e->getMessage());
}
$image->crop((int) $width, (int) $height, $gravity); $image->crop((int) $width, (int) $height, $gravity);

View file

@ -1417,76 +1417,6 @@ App::patch('/v1/users/:userId/targets/:targetId')
->dynamic($target, Response::MODEL_TARGET); ->dynamic($target, Response::MODEL_TARGET);
}); });
App::post('/v1/users/:userId/sessions')
->desc('Create session')
->groups(['api', 'users'])
->label('event', 'users.[userId].sessions.[sessionId].create')
->label('scope', 'users.write')
->label('audits.event', 'session.create')
->label('audits.resource', 'user/{request.userId}')
->label('usage.metric', 'sessions.{scope}.requests.create')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'users')
->label('sdk.method', 'createSession')
->label('sdk.description', '/docs/references/users/create-session.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_SESSION)
->param('userId', '', new CustomId(), 'User 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.')
->inject('request')
->inject('response')
->inject('dbForProject')
->inject('project')
->inject('locale')
->inject('geodb')
->inject('queueForEvents')
->action(function (string $userId, Request $request, Response $response, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents) {
$user = $dbForProject->getDocument('users', $userId);
if ($user === false || $user->isEmpty()) {
throw new Exception(Exception::USER_NOT_FOUND);
}
$secret = Auth::codeGenerator();
$detector = new Detector($request->getUserAgent('UNKNOWN'));
$record = $geodb->get($request->getIP());
$duration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration));
$session = new Document(array_merge(
[
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'provider' => Auth::SESSION_PROVIDER_SERVER,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
],
$detector->getOS(),
$detector->getClient(),
$detector->getDevice()
));
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
$session = $dbForProject->createDocument('sessions', $session);
$session
->setAttribute('secret', $secret)
->setAttribute('expire', $expire)
->setAttribute('countryName', $countryName);
$queueForEvents
->setParam('userId', $user->getId())
->setParam('sessionId', $session->getId())
->setPayload($response->output($session, Response::MODEL_SESSION));
return $response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($session, Response::MODEL_SESSION);
});
App::post('/v1/users/:userId/tokens') App::post('/v1/users/:userId/tokens')
->desc('Create token') ->desc('Create token')
->groups(['api', 'users']) ->groups(['api', 'users'])

View file

@ -740,7 +740,7 @@ App::error()
'code' => $code, 'code' => $code,
'file' => $file, 'file' => $file,
'line' => $line, 'line' => $line,
'trace' => $trace, 'trace' => \json_encode($trace, JSON_UNESCAPED_UNICODE) === false ? [] : $trace, // check for failing encode
'version' => $version, 'version' => $version,
'type' => $type, 'type' => $type,
] : [ ] : [

View file

@ -51,12 +51,12 @@
"utopia-php/config": "0.2.*", "utopia-php/config": "0.2.*",
"utopia-php/database": "0.48.*", "utopia-php/database": "0.48.*",
"utopia-php/domains": "0.5.*", "utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.1.*", "utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*", "utopia-php/framework": "0.33.*",
"utopia-php/image": "0.5.*", "utopia-php/image": "0.6.*",
"utopia-php/locale": "0.4.*", "utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.3.*", "utopia-php/logger": "0.3.*",
"utopia-php/messaging": "0.8.*", "utopia-php/messaging": "0.9.*",
"utopia-php/migration": "0.3.*", "utopia-php/migration": "0.3.*",
"utopia-php/orchestration": "0.9.*", "utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.5.*", "utopia-php/platform": "0.5.*",
@ -74,7 +74,7 @@
"chillerlan/php-qrcode": "4.3.4", "chillerlan/php-qrcode": "4.3.4",
"adhocore/jwt": "1.1.2", "adhocore/jwt": "1.1.2",
"webonyx/graphql-php": "14.11.*", "webonyx/graphql-php": "14.11.*",
"league/csv": "9.7.1" "league/csv": "^9.14"
}, },
"repositories": [ "repositories": [
{ {
@ -96,7 +96,7 @@
}, },
"config": { "config": {
"platform": { "platform": {
"php": "8.0" "php": "8.2"
} }
} }
} }

93
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "463c5722b5b926ea567fe24d8b983755", "content-hash": "4b9b6ff602a179493e0196636d961e9c",
"packages": [ "packages": [
{ {
"name": "adhocore/jwt", "name": "adhocore/jwt",
@ -463,34 +463,39 @@
}, },
{ {
"name": "league/csv", "name": "league/csv",
"version": "9.7.1", "version": "9.14.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/csv.git", "url": "https://github.com/thephpleague/csv.git",
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1" "reference": "34bf0df7340b60824b9449b5c526fcc3325070d5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/0ec57e8264ec92565974ead0d1724cf1026e10c1", "url": "https://api.github.com/repos/thephpleague/csv/zipball/34bf0df7340b60824b9449b5c526fcc3325070d5",
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1", "reference": "34bf0df7340b60824b9449b5c526fcc3325070d5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-filter": "*",
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"php": "^7.3 || ^8.0" "php": "^8.1.2"
}, },
"require-dev": { "require-dev": {
"ext-curl": "*", "doctrine/collections": "^2.1.4",
"ext-dom": "*", "ext-dom": "*",
"friendsofphp/php-cs-fixer": "^2.16", "ext-xdebug": "*",
"phpstan/phpstan": "^0.12.0", "friendsofphp/php-cs-fixer": "^v3.22.0",
"phpstan/phpstan-phpunit": "^0.12.0", "phpbench/phpbench": "^1.2.15",
"phpstan/phpstan-strict-rules": "^0.12.0", "phpstan/phpstan": "^1.10.50",
"phpunit/phpunit": "^9.5" "phpstan/phpstan-deprecation-rules": "^1.1.4",
"phpstan/phpstan-phpunit": "^1.3.15",
"phpstan/phpstan-strict-rules": "^1.5.2",
"phpunit/phpunit": "^10.5.3",
"symfony/var-dumper": "^6.4.0"
}, },
"suggest": { "suggest": {
"ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", "ext-dom": "Required to use the XMLConverter and the HTMLConverter classes",
"ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters"
}, },
"type": "library", "type": "library",
@ -520,7 +525,7 @@
} }
], ],
"description": "CSV data manipulation made easy in PHP", "description": "CSV data manipulation made easy in PHP",
"homepage": "http://csv.thephpleague.com", "homepage": "https://csv.thephpleague.com",
"keywords": [ "keywords": [
"convert", "convert",
"csv", "csv",
@ -543,7 +548,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-04-17T16:32:08+00:00" "time": "2023-12-29T07:34:53+00:00"
}, },
{ {
"name": "matomo/device-detector", "name": "matomo/device-detector",
@ -1306,16 +1311,16 @@
}, },
{ {
"name": "utopia-php/dsn", "name": "utopia-php/dsn",
"version": "0.1.0", "version": "0.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/utopia-php/dsn.git", "url": "https://github.com/utopia-php/dsn.git",
"reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea" "reference": "c11f37a12c3f6aaf9fea97ca7cb363dcc93668d7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/utopia-php/dsn/zipball/17a5935eab1b89fb4b95600db50a1b6d5faa6cea", "url": "https://api.github.com/repos/utopia-php/dsn/zipball/c11f37a12c3f6aaf9fea97ca7cb363dcc93668d7",
"reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea", "reference": "c11f37a12c3f6aaf9fea97ca7cb363dcc93668d7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1347,22 +1352,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/utopia-php/dsn/issues", "issues": "https://github.com/utopia-php/dsn/issues",
"source": "https://github.com/utopia-php/dsn/tree/0.1.0" "source": "https://github.com/utopia-php/dsn/tree/0.2.0"
}, },
"time": "2022-10-26T10:06:20+00:00" "time": "2023-11-02T12:01:43+00:00"
}, },
{ {
"name": "utopia-php/framework", "name": "utopia-php/framework",
"version": "0.33.1", "version": "0.33.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/utopia-php/http.git", "url": "https://github.com/utopia-php/http.git",
"reference": "b745607aa1875554a0ad52e28f6db918da1ce11c" "reference": "b1423ca3e3b61c6c4c2e619d2cb80672809a19f3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/utopia-php/http/zipball/b745607aa1875554a0ad52e28f6db918da1ce11c", "url": "https://api.github.com/repos/utopia-php/http/zipball/b1423ca3e3b61c6c4c2e619d2cb80672809a19f3",
"reference": "b745607aa1875554a0ad52e28f6db918da1ce11c", "reference": "b1423ca3e3b61c6c4c2e619d2cb80672809a19f3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1392,22 +1397,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/utopia-php/http/issues", "issues": "https://github.com/utopia-php/http/issues",
"source": "https://github.com/utopia-php/http/tree/0.33.1" "source": "https://github.com/utopia-php/http/tree/0.33.2"
}, },
"time": "2024-01-17T16:48:32+00:00" "time": "2024-01-31T10:35:59+00:00"
}, },
{ {
"name": "utopia-php/image", "name": "utopia-php/image",
"version": "0.5.4", "version": "0.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/utopia-php/image.git", "url": "https://github.com/utopia-php/image.git",
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336" "reference": "88f7209172bdabd81e76ac981c95fac117dc6e08"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/utopia-php/image/zipball/ca5f436f9aa22dedaa6648f24f3687733808e336", "url": "https://api.github.com/repos/utopia-php/image/zipball/88f7209172bdabd81e76ac981c95fac117dc6e08",
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336", "reference": "88f7209172bdabd81e76ac981c95fac117dc6e08",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1415,6 +1420,8 @@
"php": ">=8.0" "php": ">=8.0"
}, },
"require-dev": { "require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.9.x-dev",
"phpunit/phpunit": "^9.3", "phpunit/phpunit": "^9.3",
"vimeo/psalm": "4.13.1" "vimeo/psalm": "4.13.1"
}, },
@ -1428,12 +1435,6 @@
"license": [ "license": [
"MIT" "MIT"
], ],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
}
],
"description": "A simple Image manipulation library", "description": "A simple Image manipulation library",
"keywords": [ "keywords": [
"framework", "framework",
@ -1444,9 +1445,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/utopia-php/image/issues", "issues": "https://github.com/utopia-php/image/issues",
"source": "https://github.com/utopia-php/image/tree/0.5.4" "source": "https://github.com/utopia-php/image/tree/0.6.0"
}, },
"time": "2022-05-11T12:30:41+00:00" "time": "2024-01-24T06:59:44+00:00"
}, },
{ {
"name": "utopia-php/locale", "name": "utopia-php/locale",
@ -1554,16 +1555,16 @@
}, },
{ {
"name": "utopia-php/messaging", "name": "utopia-php/messaging",
"version": "0.8.1", "version": "0.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/utopia-php/messaging.git", "url": "https://github.com/utopia-php/messaging.git",
"reference": "bfb5014d3a8752901e50da1ae21bf309a6af5006" "reference": "df54ba51570e886724590edeb03dbd455bb0464d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/bfb5014d3a8752901e50da1ae21bf309a6af5006", "url": "https://api.github.com/repos/utopia-php/messaging/zipball/df54ba51570e886724590edeb03dbd455bb0464d",
"reference": "bfb5014d3a8752901e50da1ae21bf309a6af5006", "reference": "df54ba51570e886724590edeb03dbd455bb0464d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1598,9 +1599,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/utopia-php/messaging/issues", "issues": "https://github.com/utopia-php/messaging/issues",
"source": "https://github.com/utopia-php/messaging/tree/0.8.1" "source": "https://github.com/utopia-php/messaging/tree/0.9.0"
}, },
"time": "2024-01-10T23:55:03+00:00" "time": "2024-01-31T11:51:27+00:00"
}, },
{ {
"name": "utopia-php/migration", "name": "utopia-php/migration",
@ -5172,7 +5173,7 @@
"ext-fileinfo": "*" "ext-fileinfo": "*"
}, },
"platform-overrides": { "platform-overrides": {
"php": "8.0" "php": "8.2"
}, },
"plugin-api-version": "2.3.0" "plugin-api-version": "2.3.0"
} }

6
dev/xdebug.ini Normal file
View file

@ -0,0 +1,6 @@
zend_extension=xdebug
[xdebug]
xdebug.mode=develop,debug
xdebug.client_host=host.docker.internal
xdebug.start_with_request=yes

View file

@ -1,4 +0,0 @@
<?php
echo 'execute init_file success' . PHP_EOL;
Yasd\Api\setRemoteHost('host.docker.internal'); //Set your development machine's IP

View file

@ -0,0 +1 @@
Delete a message by its unique ID.

View file

@ -60,7 +60,8 @@ class Scryptmodified extends Hash
$saltBytes = \base64_decode($options['salt']); $saltBytes = \base64_decode($options['salt']);
$saltSeparatorBytes = \base64_decode($options['saltSeparator']); $saltSeparatorBytes = \base64_decode($options['saltSeparator']);
$derivedKey = \scrypt(\utf8_encode($password), $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64); $password = mb_convert_encoding($password, 'UTF-8');
$derivedKey = \scrypt($password, $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64);
$derivedKey = \hex2bin($derivedKey); $derivedKey = \hex2bin($derivedKey);
return $derivedKey; return $derivedKey;

View file

@ -43,10 +43,10 @@ class PersonalData extends Password
if (!$this->strict) { if (!$this->strict) {
$password = strtolower($password); $password = strtolower($password);
$this->userId = strtolower($this->userId); $this->userId = strtolower($this->userId ?? '');
$this->email = strtolower($this->email); $this->email = strtolower($this->email ?? '');
$this->name = strtolower($this->name); $this->name = strtolower($this->name ?? '');
$this->phone = strtolower($this->phone); $this->phone = strtolower($this->phone ?? '');
} }
if ($this->userId && strpos($password, $this->userId) !== false) { if ($this->userId && strpos($password, $this->userId) !== false) {

View file

@ -18,6 +18,7 @@ use Utopia\Database\Query;
use Utopia\Messaging\Adapter\Email as EmailAdapter; use Utopia\Messaging\Adapter\Email as EmailAdapter;
use Utopia\Messaging\Adapter\Email\Mailgun; use Utopia\Messaging\Adapter\Email\Mailgun;
use Utopia\Messaging\Adapter\Email\Sendgrid; use Utopia\Messaging\Adapter\Email\Sendgrid;
use Utopia\Messaging\Adapter\Email\SMTP;
use Utopia\Messaging\Adapter\Push as PushAdapter; use Utopia\Messaging\Adapter\Push as PushAdapter;
use Utopia\Messaging\Adapter\Push\APNS; use Utopia\Messaging\Adapter\Push\APNS;
use Utopia\Messaging\Adapter\Push\FCM; use Utopia\Messaging\Adapter\Push\FCM;
@ -216,8 +217,8 @@ class Messaging extends Action
$batches = \array_chunk($identifiers, $maxBatchSize); $batches = \array_chunk($identifiers, $maxBatchSize);
$batchIndex = 0; $batchIndex = 0;
return batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex, $dbForProject) { return batch(\array_map(function ($batch) use ($message, $provider, $adapter, &$batchIndex, $dbForProject) {
return function () use ($batch, $message, $provider, $adapter, $batchIndex, $dbForProject) { return function () use ($batch, $message, $provider, $adapter, &$batchIndex, $dbForProject) {
$deliveredTotal = 0; $deliveredTotal = 0;
$deliveryErrors = []; $deliveryErrors = [];
$messageData = clone $message; $messageData = clone $message;
@ -407,10 +408,24 @@ class Messaging extends Action
private function email(Document $provider): ?EmailAdapter private function email(Document $provider): ?EmailAdapter
{ {
$credentials = $provider->getAttribute('credentials'); $credentials = $provider->getAttribute('credentials', []);
$options = $provider->getAttribute('options', []);
return match ($provider->getAttribute('provider')) { return match ($provider->getAttribute('provider')) {
'mock' => new Mock('username', 'password'), 'mock' => new Mock('username', 'password'),
'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain'], $credentials['isEuRegion']), 'smtp' => new SMTP(
$credentials['host'],
$credentials['port'],
$credentials['username'],
$credentials['password'],
$options['encryption'],
$options['autoTLS'],
$options['mailer'],
),
'mailgun' => new Mailgun(
$credentials['apiKey'],
$credentials['domain'],
$credentials['isEuRegion']
),
'sendgrid' => new Sendgrid($credentials['apiKey']), 'sendgrid' => new Sendgrid($credentials['apiKey']),
default => null default => null
}; };
@ -418,16 +433,10 @@ class Messaging extends Action
private function buildEmailMessage(Database $dbForProject, Document $message, Document $provider): Email private function buildEmailMessage(Database $dbForProject, Document $message, Document $provider): Email
{ {
$fromName = $provider['options']['fromName']; $fromName = $provider['options']['fromName'] ?? null;
$fromEmail = $provider['options']['fromEmail']; $fromEmail = $provider['options']['fromEmail'] ?? null;
$replyToEmail = null; $replyToEmail = $provider['options']['replyToEmail'] ?? null;
$replyToName = null; $replyToName = $provider['options']['replyToName'] ?? null;
if (isset($provider['options']['replyToName']) && isset($provider['options']['replyToEmail'])) {
$replyToName = $provider['options']['replyToName'];
$replyToEmail = $provider['options']['replyToEmail'];
}
$data = $message['data'] ?? []; $data = $message['data'] ?? [];
$ccTargets = $data['cc'] ?? []; $ccTargets = $data['cc'] ?? [];
$bccTargets = $data['bcc'] ?? []; $bccTargets = $data['bcc'] ?? [];

View file

@ -120,6 +120,47 @@ class AccountCustomServerTest extends Scope
]); ]);
} }
/**
* @depends testCreateAccountSession
*/
public function testGetAccount($data): array
{
$email = $data['email'] ?? '';
$name = $data['name'] ?? '';
$session = $data['session'] ?? '';
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-session' => $session,
]));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['registration']));
$this->assertEquals($response['body']['email'], $email);
$this->assertEquals($response['body']['name'], $name);
$this->assertArrayHasKey('accessedAt', $response['body']);
$this->assertNotEmpty($response['body']['accessedAt']);
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(404, $response['headers']['status-code']);
return $data;
}
public function testCreateAnonymousAccount() public function testCreateAnonymousAccount()
{ {
/** /**

View file

@ -29,7 +29,7 @@ class AvatarsTest extends Scope
'x-appwrite-project' => $projectId, 'x-appwrite-project' => $projectId,
], $this->getHeaders()), $graphQLPayload); ], $this->getHeaders()), $graphQLPayload);
$this->assertEquals(18767, \strlen($creditCardIcon['body'])); $this->assertEquals(18546, \strlen($creditCardIcon['body']));
return $creditCardIcon['body']; return $creditCardIcon['body'];
} }
@ -50,7 +50,7 @@ class AvatarsTest extends Scope
'x-appwrite-project' => $projectId, 'x-appwrite-project' => $projectId,
], $this->getHeaders()), $graphQLPayload); ], $this->getHeaders()), $graphQLPayload);
$this->assertEquals(11100, \strlen($browserIcon['body'])); $this->assertEquals(13312, \strlen($browserIcon['body']));
return $browserIcon['body']; return $browserIcon['body'];
} }
@ -71,7 +71,7 @@ class AvatarsTest extends Scope
'x-appwrite-project' => $projectId, 'x-appwrite-project' => $projectId,
], $this->getHeaders()), $graphQLPayload); ], $this->getHeaders()), $graphQLPayload);
$this->assertEquals(7460, \strlen($countryFlag['body'])); $this->assertEquals(8814, \strlen($countryFlag['body']));
return $countryFlag['body']; return $countryFlag['body'];
} }
@ -92,7 +92,7 @@ class AvatarsTest extends Scope
'x-appwrite-project' => $projectId, 'x-appwrite-project' => $projectId,
], $this->getHeaders()), $graphQLPayload); ], $this->getHeaders()), $graphQLPayload);
$this->assertEquals(36036, \strlen($image['body'])); $this->assertEquals(52585, \strlen($image['body']));
return $image['body']; return $image['body'];
} }
@ -134,7 +134,7 @@ class AvatarsTest extends Scope
'x-appwrite-project' => $projectId, 'x-appwrite-project' => $projectId,
], $this->getHeaders()), $graphQLPayload); ], $this->getHeaders()), $graphQLPayload);
$this->assertEquals(14771, \strlen($qrCode['body'])); $this->assertEquals(29428, \strlen($qrCode['body']));
return $qrCode['body']; return $qrCode['body'];
} }
@ -155,7 +155,7 @@ class AvatarsTest extends Scope
'x-appwrite-project' => $projectId, 'x-appwrite-project' => $projectId,
], $this->getHeaders()), $graphQLPayload); ], $this->getHeaders()), $graphQLPayload);
$this->assertEquals(5041, \strlen($initials['body'])); $this->assertEquals(5025, \strlen($initials['body']));
return $initials['body']; return $initials['body'];
} }

View file

@ -207,6 +207,7 @@ trait Base
// Providers // Providers
public static string $CREATE_MAILGUN_PROVIDER = 'create_mailgun_provider'; public static string $CREATE_MAILGUN_PROVIDER = 'create_mailgun_provider';
public static string $CREATE_SENDGRID_PROVIDER = 'create_sendgrid_provider'; public static string $CREATE_SENDGRID_PROVIDER = 'create_sendgrid_provider';
public static string $CREATE_SMTP_PROVIDER = 'create_smtp_provider';
public static string $CREATE_TWILIO_PROVIDER = 'create_twilio_provider'; public static string $CREATE_TWILIO_PROVIDER = 'create_twilio_provider';
public static string $CREATE_TELESIGN_PROVIDER = 'create_telesign_provider'; public static string $CREATE_TELESIGN_PROVIDER = 'create_telesign_provider';
public static string $CREATE_TEXTMAGIC_PROVIDER = 'create_textmagic_provider'; public static string $CREATE_TEXTMAGIC_PROVIDER = 'create_textmagic_provider';
@ -218,6 +219,7 @@ trait Base
public static string $GET_PROVIDER = 'get_provider'; public static string $GET_PROVIDER = 'get_provider';
public static string $UPDATE_MAILGUN_PROVIDER = 'update_mailgun_provider'; public static string $UPDATE_MAILGUN_PROVIDER = 'update_mailgun_provider';
public static string $UPDATE_SENDGRID_PROVIDER = 'update_sendgrid_provider'; public static string $UPDATE_SENDGRID_PROVIDER = 'update_sendgrid_provider';
public static string $UPDATE_SMTP_PROVIDER = 'update_smtp_provider';
public static string $UPDATE_TWILIO_PROVIDER = 'update_twilio_provider'; public static string $UPDATE_TWILIO_PROVIDER = 'update_twilio_provider';
public static string $UPDATE_TELESIGN_PROVIDER = 'update_telesign_provider'; public static string $UPDATE_TELESIGN_PROVIDER = 'update_telesign_provider';
public static string $UPDATE_TEXTMAGIC_PROVIDER = 'update_textmagic_provider'; public static string $UPDATE_TEXTMAGIC_PROVIDER = 'update_textmagic_provider';
@ -1809,6 +1811,16 @@ trait Base
enabled enabled
} }
}'; }';
case self::$CREATE_SMTP_PROVIDER:
return 'mutation createSMTPProvider($providerId: String!, $name: String!, $host: String!, $port: Int!, $username: String!, $password: String!, $encryption: String!, $autoTLS: Boolean! $fromName: String!, $fromEmail: String!, $replyToName: String, $replyToEmail: String) {
messagingCreateSMTPProvider(providerId: $providerId, name: $name, host: $host, port: $port, username: $username, password: $password, encryption: $encryption, autoTLS: $autoTLS, fromName: $fromName, fromEmail: $fromEmail, replyToName: $replyToName, replyToEmail: $replyToEmail) {
_id
name
provider
type
enabled
}
}';
case self::$CREATE_TWILIO_PROVIDER: case self::$CREATE_TWILIO_PROVIDER:
return 'mutation createTwilioProvider($providerId: String!, $name: String!, $from: String!, $accountSid: String!, $authToken: String!) { return 'mutation createTwilioProvider($providerId: String!, $name: String!, $from: String!, $accountSid: String!, $authToken: String!) {
messagingCreateTwilioProvider(providerId: $providerId, name: $name, from: $from, accountSid: $accountSid, authToken: $authToken) { messagingCreateTwilioProvider(providerId: $providerId, name: $name, from: $from, accountSid: $accountSid, authToken: $authToken) {
@ -1923,6 +1935,16 @@ trait Base
enabled enabled
} }
}'; }';
case self::$UPDATE_SMTP_PROVIDER:
return 'mutation updateSMTPProvider($providerId: String!, $name: String!, $host: String!, $port: Int!, $username: String!, $password: String!, $encryption: String!, $autoTLS: Boolean!, $fromName: String, $fromEmail: String, $enabled: Boolean) {
messagingUpdateSMTPProvider(providerId: $providerId, name: $name, host: $host, port: $port, username: $username, password: $password, encryption: $encryption, autoTLS: $autoTLS, fromName: $fromName, fromEmail: $fromEmail, enabled: $enabled) {
_id
name
provider
type
enabled
}
}';
case self::$UPDATE_TWILIO_PROVIDER: case self::$UPDATE_TWILIO_PROVIDER:
return 'mutation updateTwilioProvider($providerId: String!, $name: String!, $accountSid: String!, $authToken: String!) { return 'mutation updateTwilioProvider($providerId: String!, $name: String!, $accountSid: String!, $authToken: String!) {
messagingUpdateTwilioProvider(providerId: $providerId, name: $name, accountSid: $accountSid, authToken: $authToken) { messagingUpdateTwilioProvider(providerId: $providerId, name: $name, accountSid: $accountSid, authToken: $authToken) {
@ -2000,11 +2022,10 @@ trait Base
} }
}'; }';
case self::$CREATE_TOPIC: case self::$CREATE_TOPIC:
return 'mutation createTopic($topicId: String!, $name: String!, $description: String!) { return 'mutation createTopic($topicId: String!, $name: String!) {
messagingCreateTopic(topicId: $topicId, name: $name, description: $description) { messagingCreateTopic(topicId: $topicId, name: $name) {
_id _id
name name
description
} }
}'; }';
case self::$LIST_TOPICS: case self::$LIST_TOPICS:
@ -2014,7 +2035,6 @@ trait Base
topics { topics {
_id _id
name name
description
} }
} }
}'; }';
@ -2023,15 +2043,13 @@ trait Base
messagingGetTopic(topicId: $topicId) { messagingGetTopic(topicId: $topicId) {
_id _id
name name
description
} }
}'; }';
case self::$UPDATE_TOPIC: case self::$UPDATE_TOPIC:
return 'mutation updateTopic($topicId: String!, $name: String!, $description: String!) { return 'mutation updateTopic($topicId: String!, $name: String!) {
messagingUpdateTopic(topicId: $topicId, name: $name, description: $description) { messagingUpdateTopic(topicId: $topicId, name: $name) {
_id _id
name name
description
} }
}'; }';
case self::$DELETE_TOPIC: case self::$DELETE_TOPIC:
@ -2098,8 +2116,8 @@ trait Base
} }
}'; }';
case self::$CREATE_EMAIL: case self::$CREATE_EMAIL:
return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $cc: [String], $bcc: [String], $scheduledAt: String) { return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $html: Boolean, $cc: [String], $bcc: [String], $scheduledAt: String) {
messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) { messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) {
_id _id
topics topics
users users
@ -2109,12 +2127,11 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
}'; }';
case self::$CREATE_SMS: case self::$CREATE_SMS:
return 'mutation createSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String!, $status: String, $description: String, $scheduledAt: String) { return 'mutation createSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String!, $status: String, $scheduledAt: String) {
messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) { messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, scheduledAt: $scheduledAt) {
_id _id
topics topics
users users
@ -2124,12 +2141,11 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
}'; }';
case self::$CREATE_PUSH_NOTIFICATION: case self::$CREATE_PUSH_NOTIFICATION:
return 'mutation createPushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $scheduledAt: String) { return 'mutation createPushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $scheduledAt: String) {
messagingCreatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, scheduledAt: $scheduledAt) { messagingCreatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, scheduledAt: $scheduledAt) {
_id _id
topics topics
users users
@ -2139,7 +2155,6 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
}'; }';
case self::$LIST_MESSAGES: case self::$LIST_MESSAGES:
@ -2157,7 +2172,6 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
} }
}'; }';
@ -2174,12 +2188,11 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
}'; }';
case self::$UPDATE_EMAIL: case self::$UPDATE_EMAIL:
return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $cc: [String], $bcc: [String], $scheduledAt: String) { return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, , $html: Boolean, $cc: [String], $bcc: [String], $scheduledAt: String) {
messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) { messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) {
_id _id
topics topics
users users
@ -2189,12 +2202,11 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
}'; }';
case self::$UPDATE_SMS: case self::$UPDATE_SMS:
return 'mutation updateSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String, $status: String, $description: String, $scheduledAt: String) { return 'mutation updateSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String, $status: String, $scheduledAt: String) {
messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) { messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, scheduledAt: $scheduledAt) {
_id _id
topics topics
users users
@ -2204,12 +2216,11 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
}'; }';
case self::$UPDATE_PUSH_NOTIFICATION: case self::$UPDATE_PUSH_NOTIFICATION:
return 'mutation updatePushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $scheduledAt: String) { return 'mutation updatePushNotification($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $scheduledAt: String) {
messagingUpdatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, scheduledAt: $scheduledAt) { messagingUpdatePushNotification(messageId: $messageId, topics: $topics, users: $users, targets: $targets, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, scheduledAt: $scheduledAt) {
_id _id
topics topics
users users
@ -2219,7 +2230,6 @@ trait Base
deliveryErrors deliveryErrors
deliveredTotal deliveredTotal
status status
description
} }
}'; }';
case self::$COMPLEX_QUERY: case self::$COMPLEX_QUERY:

View file

@ -285,7 +285,6 @@ class MessagingTest extends Scope
'variables' => [ 'variables' => [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'topic1', 'name' => 'topic1',
'description' => 'Active users',
], ],
]; ];
$response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
@ -296,7 +295,6 @@ class MessagingTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('topic1', $response['body']['data']['messagingCreateTopic']['name']); $this->assertEquals('topic1', $response['body']['data']['messagingCreateTopic']['name']);
$this->assertEquals('Active users', $response['body']['data']['messagingCreateTopic']['description']);
return $response['body']['data']['messagingCreateTopic']; return $response['body']['data']['messagingCreateTopic'];
} }
@ -313,7 +311,6 @@ class MessagingTest extends Scope
'variables' => [ 'variables' => [
'topicId' => $topicId, 'topicId' => $topicId,
'name' => 'topic2', 'name' => 'topic2',
'description' => 'Inactive users',
], ],
]; ];
$response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
@ -324,7 +321,6 @@ class MessagingTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('topic2', $response['body']['data']['messagingUpdateTopic']['name']); $this->assertEquals('topic2', $response['body']['data']['messagingUpdateTopic']['name']);
$this->assertEquals('Inactive users', $response['body']['data']['messagingUpdateTopic']['description']);
return $topicId; return $topicId;
} }
@ -368,7 +364,6 @@ class MessagingTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('topic2', $response['body']['data']['messagingGetTopic']['name']); $this->assertEquals('topic2', $response['body']['data']['messagingGetTopic']['name']);
$this->assertEquals('Inactive users', $response['body']['data']['messagingGetTopic']['description']);
} }
/** /**
@ -594,7 +589,6 @@ class MessagingTest extends Scope
'variables' => [ 'variables' => [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'topic1', 'name' => 'topic1',
'description' => 'Active users',
], ],
]; ];
$topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
@ -801,7 +795,6 @@ class MessagingTest extends Scope
'variables' => [ 'variables' => [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'topic1', 'name' => 'topic1',
'description' => 'Active users',
], ],
]; ];
$topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
@ -1006,7 +999,6 @@ class MessagingTest extends Scope
'variables' => [ 'variables' => [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'topic1', 'name' => 'topic1',
'description' => 'Active users',
], ],
]; ];
$topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([

View file

@ -34,7 +34,7 @@ class ScopeTest extends Scope
'x-appwrite-key' => $apiKey, 'x-appwrite-key' => $apiKey,
], $gqlPayload); ], $gqlPayload);
$message = "app.${projectId}@service.localhost (role: applications) missing scope (databases.write)"; $message = "app.{$projectId}@service.localhost (role: applications) missing scope (databases.write)";
$this->assertArrayHasKey('errors', $database['body']); $this->assertArrayHasKey('errors', $database['body']);
$this->assertEquals($message, $database['body']['errors'][0]['message']); $this->assertEquals($message, $database['body']['errors'][0]['message']);
} }

View file

@ -29,6 +29,17 @@ trait MessagingBase
'fromEmail' => 'sender-email@my-domain.com', 'fromEmail' => 'sender-email@my-domain.com',
'isEuRegion' => false, 'isEuRegion' => false,
], ],
'smtp' => [
'providerId' => ID::unique(),
'name' => 'SMTP1',
'host' => 'smtp.appwrite.io',
'port' => 587,
'security' => 'tls',
'username' => 'my-username',
'password' => 'my-password',
'fromName' => 'sender name',
'fromEmail' => 'tester@appwrite.io',
],
'twilio' => [ 'twilio' => [
'providerId' => ID::unique(), 'providerId' => ID::unique(),
'name' => 'Twilio1', 'name' => 'Twilio1',
@ -115,6 +126,14 @@ trait MessagingBase
'apiKey' => 'my-apikey', 'apiKey' => 'my-apikey',
'domain' => 'my-domain', 'domain' => 'my-domain',
], ],
'smtp' => [
'name' => 'SMTP2',
'host' => 'smtp.appwrite.io',
'port' => 587,
'security' => 'tls',
'username' => 'my-username',
'password' => 'my-password',
],
'twilio' => [ 'twilio' => [
'name' => 'Twilio2', 'name' => 'Twilio2',
'accountSid' => 'my-accountSid', 'accountSid' => 'my-accountSid',
@ -224,7 +243,7 @@ trait MessagingBase
]); ]);
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(10, \count($response['body']['providers'])); $this->assertEquals(11, \count($response['body']['providers']));
return $providers; return $providers;
} }
@ -270,7 +289,6 @@ trait MessagingBase
]); ]);
$this->assertEquals(201, $response['headers']['status-code']); $this->assertEquals(201, $response['headers']['status-code']);
$this->assertEquals('my-app', $response['body']['name']); $this->assertEquals('my-app', $response['body']['name']);
$this->assertEquals('', $response['body']['description']);
return $response['body']; return $response['body'];
} }
@ -286,11 +304,9 @@ trait MessagingBase
'x-appwrite-key' => $this->getProject()['apiKey'], 'x-appwrite-key' => $this->getProject()['apiKey'],
], [ ], [
'name' => 'android-app', 'name' => 'android-app',
'description' => 'updated-description'
]); ]);
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('android-app', $response['body']['name']); $this->assertEquals('android-app', $response['body']['name']);
$this->assertEquals('updated-description', $response['body']['description']);
return $response['body']['$id']; return $response['body']['$id'];
} }
@ -299,17 +315,6 @@ trait MessagingBase
*/ */
public function testListTopic(string $topicId) public function testListTopic(string $topicId)
{ {
$response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'search' => 'updated-description',
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, \count($response['body']['topics']));
$response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [ $response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
@ -351,7 +356,6 @@ trait MessagingBase
]); ]);
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('android-app', $response['body']['name']); $this->assertEquals('android-app', $response['body']['name']);
$this->assertEquals('updated-description', $response['body']['description']);
$this->assertEquals(0, $response['body']['total']); $this->assertEquals(0, $response['body']['total']);
} }
@ -408,7 +412,6 @@ trait MessagingBase
$this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals(200, $topic['headers']['status-code']);
$this->assertEquals('android-app', $topic['body']['name']); $this->assertEquals('android-app', $topic['body']['name']);
$this->assertEquals('updated-description', $topic['body']['description']);
$this->assertEquals(1, $topic['body']['total']); $this->assertEquals(1, $topic['body']['total']);
return [ return [
@ -644,7 +647,6 @@ trait MessagingBase
$this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals(200, $topic['headers']['status-code']);
$this->assertEquals('android-app', $topic['body']['name']); $this->assertEquals('android-app', $topic['body']['name']);
$this->assertEquals('updated-description', $topic['body']['description']);
$this->assertEquals(0, $topic['body']['total']); $this->assertEquals(0, $topic['body']['total']);
} }
@ -661,6 +663,60 @@ trait MessagingBase
$this->assertEquals(204, $response['headers']['status-code']); $this->assertEquals(204, $response['headers']['status-code']);
} }
/**
* @depends testCreateDraftEmail
*/
public function testListTargets(array $message)
{
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/does_not_exist/targets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(404, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['$id'] . '/targets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$targetList = $response['body'];
$this->assertEquals(1, $targetList['total']);
$this->assertEquals(1, count($targetList['targets']));
$this->assertEquals($message['targets'][0], $targetList['targets'][0]['$id']);
// Test for empty targets
$response = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'messageId' => ID::unique(),
'subject' => 'New blog post',
'content' => 'Check out the new blog post at http://localhost',
]);
$this->assertEquals(201, $response['headers']['status-code']);
$message = $response['body'];
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['$id'] . '/targets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$targetList = $response['body'];
$this->assertEquals(0, $targetList['total']);
$this->assertEquals(0, count($targetList['targets']));
}
public function testCreateDraftEmail() public function testCreateDraftEmail()
{ {
// Create User // Create User
@ -742,7 +798,6 @@ trait MessagingBase
], [ ], [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'topic1', 'name' => 'topic1',
'description' => 'Test Topic'
]); ]);
$this->assertEquals(201, $topic['headers']['status-code']); $this->assertEquals(201, $topic['headers']['status-code']);
@ -764,7 +819,6 @@ trait MessagingBase
// Get target // Get target
$target = $user['body']['targets'][0]; $target = $user['body']['targets'][0];
// Create Subscriber // Create Subscriber
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
@ -803,14 +857,19 @@ trait MessagingBase
$this->assertEquals(1, $message['body']['deliveredTotal']); $this->assertEquals(1, $message['body']['deliveredTotal']);
$this->assertEquals(0, \count($message['body']['deliveryErrors'])); $this->assertEquals(0, \count($message['body']['deliveryErrors']));
return $message; return [
'message' => $email['body'],
'topic' => $topic['body'],
];
} }
/** /**
* @depends testSendEmail * @depends testSendEmail
*/ */
public function testUpdateEmail(array $email): void public function testUpdateEmail(array $params): void
{ {
$email = $params['message'];
$message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
@ -899,7 +958,6 @@ trait MessagingBase
], [ ], [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'topic1', 'name' => 'topic1',
'description' => 'Test Topic'
]); ]);
$this->assertEquals(201, $topic['headers']['status-code']); $this->assertEquals(201, $topic['headers']['status-code']);
@ -1060,7 +1118,6 @@ trait MessagingBase
], [ ], [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'topic1', 'name' => 'topic1',
'description' => 'Test Topic'
]); ]);
$this->assertEquals(201, $topic['headers']['status-code']); $this->assertEquals(201, $topic['headers']['status-code']);
@ -1188,56 +1245,50 @@ trait MessagingBase
} }
/** /**
* @depends testCreateDraftEmail * @depends testSendEmail
* @return void
* @throws \Exception
*/ */
public function testListTargets(array $message) public function testDeleteMessage(array $params): void
{ {
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/does_not_exist/targets', [ $message = $params['message'];
$topic = $params['topic'];
$response = $this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $message['$id'], [
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'], 'x-appwrite-key' => $this->getProject()['apiKey'],
]); ]);
$this->assertEquals(404, $response['headers']['status-code']); $this->assertEquals(204, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['$id'] . '/targets', [ // Test for FAILURE
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$targetList = $response['body'];
$this->assertEquals(1, $targetList['total']);
$this->assertEquals(1, count($targetList['targets']));
$this->assertEquals($message['targets'][0], $targetList['targets'][0]['$id']);
// Test for empty targets
$response = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [ $response = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'], 'x-appwrite-key' => $this->getProject()['apiKey'],
], [ ], [
'messageId' => ID::unique(), 'messageId' => ID::unique(),
'subject' => 'New blog post', 'status' => 'processing',
'content' => 'Check out the new blog post at http://localhost', 'topics' => [$topic['$id']],
'subject' => 'Test subject',
'content' => 'Test content',
]); ]);
$this->assertEquals(201, $response['headers']['status-code']); $response = $this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $response['body']['$id'], [
$message = $response['body'];
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['$id'] . '/targets', [
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'], 'x-appwrite-key' => $this->getProject()['apiKey'],
]); ]);
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(400, $response['headers']['status-code']);
$targetList = $response['body']; $response = $this->client->call(Client::METHOD_DELETE, '/messaging/messages/does_not_exist', [
$this->assertEquals(0, $targetList['total']); 'content-type' => 'application/json',
$this->assertEquals(0, count($targetList['targets'])); 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(404, $response['headers']['status-code']);
} }
} }

View file

@ -188,7 +188,6 @@ class MessagingConsoleClientTest extends Scope
], $this->getHeaders()), [ ], $this->getHeaders()), [
'topicId' => ID::unique(), 'topicId' => ID::unique(),
'name' => 'my-app', 'name' => 'my-app',
'description' => 'web app'
]); ]);
$this->assertEquals(201, $topic['headers']['status-code']); $this->assertEquals(201, $topic['headers']['status-code']);
@ -196,7 +195,7 @@ class MessagingConsoleClientTest extends Scope
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
'description' => 'updated-description' 'name' => 'android-app'
]); ]);
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);

View file

@ -28,7 +28,7 @@ trait StorageBase
'name' => 'Test Bucket', 'name' => 'Test Bucket',
'fileSecurity' => true, 'fileSecurity' => true,
'maximumFileSize' => 2000000, //2MB 'maximumFileSize' => 2000000, //2MB
'allowedFileExtensions' => ["jpg", "png", 'jfif'], 'allowedFileExtensions' => ['jpg', 'png', 'jfif'],
'permissions' => [ 'permissions' => [
Permission::read(Role::any()), Permission::read(Role::any()),
Permission::create(Role::any()), Permission::create(Role::any()),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB