1
0
Fork 0
mirror of synced 2024-06-27 18:50:47 +12:00

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
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:
1. Create an init file.
2. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php**.
3. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
1. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
2. If needed edit the **dev/xdebug.ini** file to your needs.
3. Launch your Appwrite instance while your debugger is listening for connections.
### VS Code Launch Configuration

View file

@ -29,7 +29,7 @@ ENV VITE_APPWRITE_GROWTH_ENDPOINT=$VITE_APPWRITE_GROWTH_ENDPOINT
RUN npm ci
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"
@ -56,6 +56,7 @@ COPY ./public /usr/src/code/public
COPY ./bin /usr/local/bin
COPY ./docs /usr/src/code/docs
COPY ./src /usr/src/code/src
COPY ./dev /usr/src/code/dev
# Set Volumes
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/
# 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" = "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=/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

View file

@ -1573,17 +1573,6 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('description'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('status'),
'type' => Database::VAR_STRING,
@ -1744,17 +1733,6 @@ $commonCollections = [
'array' => false,
'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'),
'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('user')
->action(function (Response $response, Document $user) {
if ($user->isEmpty()) {
throw new Exception(Exception::USER_NOT_FOUND);
}
$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
$words = (count($words) == 1) ? \explode('_', \strtoupper($name)) : $words;
$initials = null;
$initials = '';
$code = 0;
foreach ($words as $key => $w) {

View file

@ -35,6 +35,7 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Integer;
use Utopia\Validator\JSON;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
use MaxMind\Db\Reader;
use Utopia\Database\DateTime;
@ -61,30 +62,20 @@ App::post('/v1/messaging/providers/mailgun')
->param('apiKey', '', new Text(0), 'Mailgun API Key.', true)
->param('domain', '', new Text(0), 'Mailgun Domain.', 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('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('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('dbForProject')
->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;
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
];
if (!empty($replyToName) && !empty($replyToEmail)) {
$options['replyToName'] = $replyToName;
$options['replyToEmail'] = $replyToEmail;
}
$credentials = [];
if ($isEuRegion === true || $isEuRegion === false) {
if (!\is_null($isEuRegion)) {
$credentials['isEuRegion'] = $isEuRegion;
}
@ -96,12 +87,19 @@ App::post('/v1/messaging/providers/mailgun')
$credentials['domain'] = $domain;
}
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
'replyToName' => $replyToName,
'replyToEmail' => $replyToEmail,
];
if (
$enabled === true &&
\array_key_exists('isEuRegion', $credentials) &&
\array_key_exists('apiKey', $credentials) &&
\array_key_exists('domain', $credentials) &&
\array_key_exists('fromEmail', $options)
$enabled === true
&& !empty($fromEmail)
&& \array_key_exists('isEuRegion', $credentials)
&& \array_key_exists('apiKey', $credentials)
&& \array_key_exists('domain', $credentials)
) {
$enabled = true;
} 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('name', '', new Text(128), 'Provider name.')
->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('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 $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;
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
];
if (!empty($replyToName) && !empty($replyToEmail)) {
$options['replyToName'] = $replyToName;
$options['replyToEmail'] = $replyToEmail;
}
$credentials = [];
if (!empty($apiKey)) {
$credentials['apiKey'] = $apiKey;
}
$options = [
'fromName' => $fromName,
'fromEmail' => $fromEmail,
'replyToName' => $replyToName,
'replyToEmail' => $replyToEmail,
];
if (
$enabled === true
&& !empty($fromEmail)
&& \array_key_exists('apiKey', $credentials)
&& \array_key_exists('fromEmail', $options)
) {
$enabled = true;
} else {
@ -210,6 +205,94 @@ App::post('/v1/messaging/providers/sendgrid')
->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')
->desc('Create Msg91 provider')
->groups(['api', 'messaging'])
@ -1085,6 +1168,125 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId')
->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')
->desc('Update Msg91 provider')
->groups(['api', 'messaging'])
@ -1701,17 +1903,15 @@ App::post('/v1/messaging/topics')
->label('sdk.response.model', Response::MODEL_TOPIC)
->param('topicId', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.')
->param('name', '', new Text(128), 'Topic Name.')
->param('description', '', new Text(2048), 'Topic Description.', true)
->inject('queueForEvents')
->inject('dbForProject')
->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;
$topic = new Document([
'$id' => $topicId,
'name' => $name,
'description' => $description
]);
try {
@ -1898,11 +2098,10 @@ App::patch('/v1/messaging/topics/:topicId')
->label('sdk.response.model', Response::MODEL_TOPIC)
->param('topicId', '', new UID(), 'Topic ID.')
->param('name', '', new Text(128), 'Topic Name.', true)
->param('description', '', new Text(2048), 'Topic Description.', true)
->inject('queueForEvents')
->inject('dbForProject')
->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);
if ($topic->isEmpty()) {
@ -1913,10 +2112,6 @@ App::patch('/v1/messaging/topics/:topicId')
$topic->setAttribute('name', $name);
}
if (!empty($description)) {
$topic->setAttribute('description', $description);
}
$topic = $dbForProject->updateDocument('topics', $topicId, $topic);
$queueForEvents
@ -2301,7 +2496,6 @@ App::post('/v1/messaging/messages/email')
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('cc', [], new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true)
->param('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true)
->param('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('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)
@ -2311,7 +2505,7 @@ App::post('/v1/messaging/messages/email')
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, string $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()'
? ID::unique()
: $messageId;
@ -2350,7 +2544,6 @@ App::post('/v1/messaging/messages/email')
'topics' => $topics,
'users' => $users,
'targets' => $targets,
'description' => $description,
'scheduledAt' => $scheduledAt,
'data' => [
'subject' => $subject,
@ -2420,7 +2613,6 @@ App::post('/v1/messaging/messages/sms')
->param('topics', [], new ArrayList(new UID()), 'List of Topic 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('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('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')
@ -2429,7 +2621,7 @@ App::post('/v1/messaging/messages/sms')
->inject('project')
->inject('queueForMessaging')
->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()'
? ID::unique()
: $messageId;
@ -2466,7 +2658,6 @@ App::post('/v1/messaging/messages/sms')
'topics' => $topics,
'users' => $users,
'targets' => $targets,
'description' => $description,
'data' => [
'content' => $content,
],
@ -2532,7 +2723,6 @@ App::post('/v1/messaging/messages/push')
->param('topics', [], new ArrayList(new UID()), 'List of Topic 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('description', '', new Text(256), 'Description for Message.', true)
->param('data', null, new JSON(), 'Additional Data 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)
@ -2548,7 +2738,7 @@ App::post('/v1/messaging/messages/push')
->inject('project')
->inject('queueForMessaging')
->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()'
? ID::unique()
: $messageId;
@ -2595,7 +2785,6 @@ App::post('/v1/messaging/messages/push')
'topics' => $topics,
'users' => $users,
'targets' => $targets,
'description' => $description,
'scheduledAt' => $scheduledAt,
'data' => $pushData,
'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('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', 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('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)
@ -2882,7 +3070,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
->inject('project')
->inject('queueForMessaging')
->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);
if ($message->isEmpty()) {
@ -2933,10 +3121,6 @@ App::patch('/v1/messaging/messages/email/:messageId')
$message->setAttribute('data', $data);
if (!\is_null($description)) {
$message->setAttribute('description', $description);
}
if (!\is_null($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('users', null, new ArrayList(new UID()), 'List of User 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('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)
@ -3017,7 +3200,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
->inject('project')
->inject('queueForMessaging')
->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);
if ($message->isEmpty()) {
@ -3056,10 +3239,6 @@ App::patch('/v1/messaging/messages/sms/:messageId')
$message->setAttribute('status', $status);
}
if (!\is_null($description)) {
$message->setAttribute('description', $description);
}
if (!\is_null($scheduledAt)) {
if (\is_null($message->getAttribute(('scheduleId')))) {
$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('users', null, new ArrayList(new UID()), 'List of User 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('body', null, new Text(64230), 'Body 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('queueForMessaging')
->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);
if ($message->isEmpty()) {
@ -3215,10 +3393,6 @@ App::patch('/v1/messaging/messages/push/:messageId')
$message->setAttribute('status', $status);
}
if (!\is_null($description)) {
$message->setAttribute('description', $description);
}
if (!\is_null($scheduledAt)) {
if (\is_null($message->getAttribute(('scheduleId')))) {
$schedule = $dbForConsole->createDocument('schedules', new Document([
@ -3266,3 +3440,59 @@ App::patch('/v1/messaging/messages/push/:messageId')
$response
->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;
}
$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);

View file

@ -1417,76 +1417,6 @@ App::patch('/v1/users/:userId/targets/:targetId')
->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')
->desc('Create token')
->groups(['api', 'users'])

View file

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

View file

@ -51,12 +51,12 @@
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.48.*",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.1.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/image": "0.5.*",
"utopia-php/image": "0.6.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.3.*",
"utopia-php/messaging": "0.8.*",
"utopia-php/messaging": "0.9.*",
"utopia-php/migration": "0.3.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.5.*",
@ -74,7 +74,7 @@
"chillerlan/php-qrcode": "4.3.4",
"adhocore/jwt": "1.1.2",
"webonyx/graphql-php": "14.11.*",
"league/csv": "9.7.1"
"league/csv": "^9.14"
},
"repositories": [
{
@ -96,7 +96,7 @@
},
"config": {
"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",
"This file is @generated automatically"
],
"content-hash": "463c5722b5b926ea567fe24d8b983755",
"content-hash": "4b9b6ff602a179493e0196636d961e9c",
"packages": [
{
"name": "adhocore/jwt",
@ -463,34 +463,39 @@
},
{
"name": "league/csv",
"version": "9.7.1",
"version": "9.14.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/csv.git",
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1"
"reference": "34bf0df7340b60824b9449b5c526fcc3325070d5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/0ec57e8264ec92565974ead0d1724cf1026e10c1",
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/34bf0df7340b60824b9449b5c526fcc3325070d5",
"reference": "34bf0df7340b60824b9449b5c526fcc3325070d5",
"shasum": ""
},
"require": {
"ext-filter": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": "^7.3 || ^8.0"
"php": "^8.1.2"
},
"require-dev": {
"ext-curl": "*",
"doctrine/collections": "^2.1.4",
"ext-dom": "*",
"friendsofphp/php-cs-fixer": "^2.16",
"phpstan/phpstan": "^0.12.0",
"phpstan/phpstan-phpunit": "^0.12.0",
"phpstan/phpstan-strict-rules": "^0.12.0",
"phpunit/phpunit": "^9.5"
"ext-xdebug": "*",
"friendsofphp/php-cs-fixer": "^v3.22.0",
"phpbench/phpbench": "^1.2.15",
"phpstan/phpstan": "^1.10.50",
"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": {
"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"
},
"type": "library",
@ -520,7 +525,7 @@
}
],
"description": "CSV data manipulation made easy in PHP",
"homepage": "http://csv.thephpleague.com",
"homepage": "https://csv.thephpleague.com",
"keywords": [
"convert",
"csv",
@ -543,7 +548,7 @@
"type": "github"
}
],
"time": "2021-04-17T16:32:08+00:00"
"time": "2023-12-29T07:34:53+00:00"
},
{
"name": "matomo/device-detector",
@ -1306,16 +1311,16 @@
},
{
"name": "utopia-php/dsn",
"version": "0.1.0",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/dsn.git",
"reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea"
"reference": "c11f37a12c3f6aaf9fea97ca7cb363dcc93668d7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/dsn/zipball/17a5935eab1b89fb4b95600db50a1b6d5faa6cea",
"reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea",
"url": "https://api.github.com/repos/utopia-php/dsn/zipball/c11f37a12c3f6aaf9fea97ca7cb363dcc93668d7",
"reference": "c11f37a12c3f6aaf9fea97ca7cb363dcc93668d7",
"shasum": ""
},
"require": {
@ -1347,22 +1352,22 @@
],
"support": {
"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",
"version": "0.33.1",
"version": "0.33.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/http.git",
"reference": "b745607aa1875554a0ad52e28f6db918da1ce11c"
"reference": "b1423ca3e3b61c6c4c2e619d2cb80672809a19f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/http/zipball/b745607aa1875554a0ad52e28f6db918da1ce11c",
"reference": "b745607aa1875554a0ad52e28f6db918da1ce11c",
"url": "https://api.github.com/repos/utopia-php/http/zipball/b1423ca3e3b61c6c4c2e619d2cb80672809a19f3",
"reference": "b1423ca3e3b61c6c4c2e619d2cb80672809a19f3",
"shasum": ""
},
"require": {
@ -1392,22 +1397,22 @@
],
"support": {
"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",
"version": "0.5.4",
"version": "0.6.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/image.git",
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336"
"reference": "88f7209172bdabd81e76ac981c95fac117dc6e08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/image/zipball/ca5f436f9aa22dedaa6648f24f3687733808e336",
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336",
"url": "https://api.github.com/repos/utopia-php/image/zipball/88f7209172bdabd81e76ac981c95fac117dc6e08",
"reference": "88f7209172bdabd81e76ac981c95fac117dc6e08",
"shasum": ""
},
"require": {
@ -1415,6 +1420,8 @@
"php": ">=8.0"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.9.x-dev",
"phpunit/phpunit": "^9.3",
"vimeo/psalm": "4.13.1"
},
@ -1428,12 +1435,6 @@
"license": [
"MIT"
],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
}
],
"description": "A simple Image manipulation library",
"keywords": [
"framework",
@ -1444,9 +1445,9 @@
],
"support": {
"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",
@ -1554,16 +1555,16 @@
},
{
"name": "utopia-php/messaging",
"version": "0.8.1",
"version": "0.9.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
"reference": "bfb5014d3a8752901e50da1ae21bf309a6af5006"
"reference": "df54ba51570e886724590edeb03dbd455bb0464d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/bfb5014d3a8752901e50da1ae21bf309a6af5006",
"reference": "bfb5014d3a8752901e50da1ae21bf309a6af5006",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/df54ba51570e886724590edeb03dbd455bb0464d",
"reference": "df54ba51570e886724590edeb03dbd455bb0464d",
"shasum": ""
},
"require": {
@ -1598,9 +1599,9 @@
],
"support": {
"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",
@ -5172,7 +5173,7 @@
"ext-fileinfo": "*"
},
"platform-overrides": {
"php": "8.0"
"php": "8.2"
},
"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']);
$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);
return $derivedKey;

View file

@ -43,10 +43,10 @@ class PersonalData extends Password
if (!$this->strict) {
$password = strtolower($password);
$this->userId = strtolower($this->userId);
$this->email = strtolower($this->email);
$this->name = strtolower($this->name);
$this->phone = strtolower($this->phone);
$this->userId = strtolower($this->userId ?? '');
$this->email = strtolower($this->email ?? '');
$this->name = strtolower($this->name ?? '');
$this->phone = strtolower($this->phone ?? '');
}
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\Mailgun;
use Utopia\Messaging\Adapter\Email\Sendgrid;
use Utopia\Messaging\Adapter\Email\SMTP;
use Utopia\Messaging\Adapter\Push as PushAdapter;
use Utopia\Messaging\Adapter\Push\APNS;
use Utopia\Messaging\Adapter\Push\FCM;
@ -216,8 +217,8 @@ class Messaging extends Action
$batches = \array_chunk($identifiers, $maxBatchSize);
$batchIndex = 0;
return batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex, $dbForProject) {
return function () use ($batch, $message, $provider, $adapter, $batchIndex, $dbForProject) {
return batch(\array_map(function ($batch) use ($message, $provider, $adapter, &$batchIndex, $dbForProject) {
return function () use ($batch, $message, $provider, $adapter, &$batchIndex, $dbForProject) {
$deliveredTotal = 0;
$deliveryErrors = [];
$messageData = clone $message;
@ -407,10 +408,24 @@ class Messaging extends Action
private function email(Document $provider): ?EmailAdapter
{
$credentials = $provider->getAttribute('credentials');
$credentials = $provider->getAttribute('credentials', []);
$options = $provider->getAttribute('options', []);
return match ($provider->getAttribute('provider')) {
'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']),
default => null
};
@ -418,16 +433,10 @@ class Messaging extends Action
private function buildEmailMessage(Database $dbForProject, Document $message, Document $provider): Email
{
$fromName = $provider['options']['fromName'];
$fromEmail = $provider['options']['fromEmail'];
$replyToEmail = null;
$replyToName = null;
if (isset($provider['options']['replyToName']) && isset($provider['options']['replyToEmail'])) {
$replyToName = $provider['options']['replyToName'];
$replyToEmail = $provider['options']['replyToEmail'];
}
$fromName = $provider['options']['fromName'] ?? null;
$fromEmail = $provider['options']['fromEmail'] ?? null;
$replyToEmail = $provider['options']['replyToEmail'] ?? null;
$replyToName = $provider['options']['replyToName'] ?? null;
$data = $message['data'] ?? [];
$ccTargets = $data['cc'] ?? [];
$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()
{
/**

View file

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

View file

@ -207,6 +207,7 @@ trait Base
// Providers
public static string $CREATE_MAILGUN_PROVIDER = 'create_mailgun_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_TELESIGN_PROVIDER = 'create_telesign_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 $UPDATE_MAILGUN_PROVIDER = 'update_mailgun_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_TELESIGN_PROVIDER = 'update_telesign_provider';
public static string $UPDATE_TEXTMAGIC_PROVIDER = 'update_textmagic_provider';
@ -1809,6 +1811,16 @@ trait Base
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:
return 'mutation createTwilioProvider($providerId: String!, $name: String!, $from: String!, $accountSid: String!, $authToken: String!) {
messagingCreateTwilioProvider(providerId: $providerId, name: $name, from: $from, accountSid: $accountSid, authToken: $authToken) {
@ -1923,6 +1935,16 @@ trait Base
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:
return 'mutation updateTwilioProvider($providerId: String!, $name: String!, $accountSid: String!, $authToken: String!) {
messagingUpdateTwilioProvider(providerId: $providerId, name: $name, accountSid: $accountSid, authToken: $authToken) {
@ -2000,11 +2022,10 @@ trait Base
}
}';
case self::$CREATE_TOPIC:
return 'mutation createTopic($topicId: String!, $name: String!, $description: String!) {
messagingCreateTopic(topicId: $topicId, name: $name, description: $description) {
return 'mutation createTopic($topicId: String!, $name: String!) {
messagingCreateTopic(topicId: $topicId, name: $name) {
_id
name
description
}
}';
case self::$LIST_TOPICS:
@ -2014,7 +2035,6 @@ trait Base
topics {
_id
name
description
}
}
}';
@ -2023,15 +2043,13 @@ trait Base
messagingGetTopic(topicId: $topicId) {
_id
name
description
}
}';
case self::$UPDATE_TOPIC:
return 'mutation updateTopic($topicId: String!, $name: String!, $description: String!) {
messagingUpdateTopic(topicId: $topicId, name: $name, description: $description) {
return 'mutation updateTopic($topicId: String!, $name: String!) {
messagingUpdateTopic(topicId: $topicId, name: $name) {
_id
name
description
}
}';
case self::$DELETE_TOPIC:
@ -2098,8 +2116,8 @@ trait Base
}
}';
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) {
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) {
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, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) {
_id
topics
users
@ -2109,12 +2127,11 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}';
case self::$CREATE_SMS:
return 'mutation createSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String!, $status: String, $description: String, $scheduledAt: String) {
messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) {
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, scheduledAt: $scheduledAt) {
_id
topics
users
@ -2124,12 +2141,11 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}';
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) {
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) {
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, scheduledAt: $scheduledAt) {
_id
topics
users
@ -2139,7 +2155,6 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}';
case self::$LIST_MESSAGES:
@ -2157,7 +2172,6 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}
}';
@ -2174,12 +2188,11 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}';
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) {
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) {
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, html: $html, cc: $cc, bcc: $bcc, scheduledAt: $scheduledAt) {
_id
topics
users
@ -2189,12 +2202,11 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}';
case self::$UPDATE_SMS:
return 'mutation updateSMS($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $content: String, $status: String, $description: String, $scheduledAt: String) {
messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) {
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, scheduledAt: $scheduledAt) {
_id
topics
users
@ -2204,12 +2216,11 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}';
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) {
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) {
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, scheduledAt: $scheduledAt) {
_id
topics
users
@ -2219,7 +2230,6 @@ trait Base
deliveryErrors
deliveredTotal
status
description
}
}';
case self::$COMPLEX_QUERY:

View file

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

View file

@ -34,7 +34,7 @@ class ScopeTest extends Scope
'x-appwrite-key' => $apiKey,
], $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->assertEquals($message, $database['body']['errors'][0]['message']);
}

View file

@ -29,6 +29,17 @@ trait MessagingBase
'fromEmail' => 'sender-email@my-domain.com',
'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' => [
'providerId' => ID::unique(),
'name' => 'Twilio1',
@ -115,6 +126,14 @@ trait MessagingBase
'apiKey' => 'my-apikey',
'domain' => 'my-domain',
],
'smtp' => [
'name' => 'SMTP2',
'host' => 'smtp.appwrite.io',
'port' => 587,
'security' => 'tls',
'username' => 'my-username',
'password' => 'my-password',
],
'twilio' => [
'name' => 'Twilio2',
'accountSid' => 'my-accountSid',
@ -224,7 +243,7 @@ trait MessagingBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(10, \count($response['body']['providers']));
$this->assertEquals(11, \count($response['body']['providers']));
return $providers;
}
@ -270,7 +289,6 @@ trait MessagingBase
]);
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertEquals('my-app', $response['body']['name']);
$this->assertEquals('', $response['body']['description']);
return $response['body'];
}
@ -286,11 +304,9 @@ trait MessagingBase
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'name' => 'android-app',
'description' => 'updated-description'
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('android-app', $response['body']['name']);
$this->assertEquals('updated-description', $response['body']['description']);
return $response['body']['$id'];
}
@ -299,17 +315,6 @@ trait MessagingBase
*/
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', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@ -351,7 +356,6 @@ trait MessagingBase
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('android-app', $response['body']['name']);
$this->assertEquals('updated-description', $response['body']['description']);
$this->assertEquals(0, $response['body']['total']);
}
@ -408,7 +412,6 @@ trait MessagingBase
$this->assertEquals(200, $topic['headers']['status-code']);
$this->assertEquals('android-app', $topic['body']['name']);
$this->assertEquals('updated-description', $topic['body']['description']);
$this->assertEquals(1, $topic['body']['total']);
return [
@ -644,7 +647,6 @@ trait MessagingBase
$this->assertEquals(200, $topic['headers']['status-code']);
$this->assertEquals('android-app', $topic['body']['name']);
$this->assertEquals('updated-description', $topic['body']['description']);
$this->assertEquals(0, $topic['body']['total']);
}
@ -661,6 +663,60 @@ trait MessagingBase
$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()
{
// Create User
@ -742,7 +798,6 @@ trait MessagingBase
], [
'topicId' => ID::unique(),
'name' => 'topic1',
'description' => 'Test Topic'
]);
$this->assertEquals(201, $topic['headers']['status-code']);
@ -764,7 +819,6 @@ trait MessagingBase
// Get target
$target = $user['body']['targets'][0];
// Create Subscriber
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([
'content-type' => 'application/json',
@ -803,14 +857,19 @@ trait MessagingBase
$this->assertEquals(1, $message['body']['deliveredTotal']);
$this->assertEquals(0, \count($message['body']['deliveryErrors']));
return $message;
return [
'message' => $email['body'],
'topic' => $topic['body'],
];
}
/**
* @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'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@ -899,7 +958,6 @@ trait MessagingBase
], [
'topicId' => ID::unique(),
'name' => 'topic1',
'description' => 'Test Topic'
]);
$this->assertEquals(201, $topic['headers']['status-code']);
@ -1060,7 +1118,6 @@ trait MessagingBase
], [
'topicId' => ID::unique(),
'name' => 'topic1',
'description' => 'Test Topic'
]);
$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',
'x-appwrite-project' => $this->getProject()['$id'],
'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', [
'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
// Test for FAILURE
$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',
'status' => 'processing',
'topics' => [$topic['$id']],
'subject' => 'Test subject',
'content' => 'Test content',
]);
$this->assertEquals(201, $response['headers']['status-code']);
$message = $response['body'];
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['$id'] . '/targets', [
$response = $this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $response['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(400, $response['headers']['status-code']);
$targetList = $response['body'];
$this->assertEquals(0, $targetList['total']);
$this->assertEquals(0, count($targetList['targets']));
$response = $this->client->call(Client::METHOD_DELETE, '/messaging/messages/does_not_exist', [
'content-type' => 'application/json',
'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()), [
'topicId' => ID::unique(),
'name' => 'my-app',
'description' => 'web app'
]);
$this->assertEquals(201, $topic['headers']['status-code']);
@ -196,7 +195,7 @@ class MessagingConsoleClientTest extends Scope
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'description' => 'updated-description'
'name' => 'android-app'
]);
$this->assertEquals(200, $response['headers']['status-code']);

View file

@ -28,7 +28,7 @@ trait StorageBase
'name' => 'Test Bucket',
'fileSecurity' => true,
'maximumFileSize' => 2000000, //2MB
'allowedFileExtensions' => ["jpg", "png", 'jfif'],
'allowedFileExtensions' => ['jpg', 'png', 'jfif'],
'permissions' => [
Permission::read(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