Merge branch '1.5.x' into fix-limit-failed-webhook-attempts
This commit is contained in:
commit
ff7cfc6602
2
.env
2
.env
|
@ -87,7 +87,7 @@ _APP_LOGGING_PROVIDER=
|
||||||
_APP_LOGGING_CONFIG=
|
_APP_LOGGING_CONFIG=
|
||||||
_APP_GRAPHQL_MAX_BATCH_SIZE=10
|
_APP_GRAPHQL_MAX_BATCH_SIZE=10
|
||||||
_APP_GRAPHQL_MAX_COMPLEXITY=250
|
_APP_GRAPHQL_MAX_COMPLEXITY=250
|
||||||
_APP_GRAPHQL_MAX_DEPTH=3
|
_APP_GRAPHQL_MAX_DEPTH=4
|
||||||
_APP_DOCKER_HUB_USERNAME=
|
_APP_DOCKER_HUB_USERNAME=
|
||||||
_APP_DOCKER_HUB_PASSWORD=
|
_APP_DOCKER_HUB_PASSWORD=
|
||||||
_APP_VCS_GITHUB_APP_NAME=
|
_APP_VCS_GITHUB_APP_NAME=
|
||||||
|
|
|
@ -466,7 +466,7 @@
|
||||||
## Features
|
## Features
|
||||||
- Added Phone Authentication by @TorstenDittmann in https://github.com/appwrite/appwrite/pull/3357
|
- Added Phone Authentication by @TorstenDittmann in https://github.com/appwrite/appwrite/pull/3357
|
||||||
- Added Twilio Support
|
- Added Twilio Support
|
||||||
- Added TextMagic Support
|
- Added Textmagic Support
|
||||||
- Added Telesign Support
|
- Added Telesign Support
|
||||||
- Added Endpoint to create Phone Session (`POST:/v1/account/sessions/phone`)
|
- Added Endpoint to create Phone Session (`POST:/v1/account/sessions/phone`)
|
||||||
- Added Endpoint to confirm Phone Session (`PUT:/v1/account/sessions/phone`)
|
- Added Endpoint to confirm Phone Session (`PUT:/v1/account/sessions/phone`)
|
||||||
|
|
|
@ -1505,6 +1505,17 @@ $commonCollections = [
|
||||||
'$id' => ID::custom('messages'),
|
'$id' => ID::custom('messages'),
|
||||||
'name' => 'Messages',
|
'name' => 'Messages',
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('providerType'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => Database::LENGTH_KEY,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => true,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('description'),
|
'$id' => ID::custom('description'),
|
||||||
'type' => Database::VAR_STRING,
|
'type' => Database::VAR_STRING,
|
||||||
|
@ -1572,7 +1583,7 @@ $commonCollections = [
|
||||||
'filters' => [],
|
'filters' => [],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('deliveryTime'),
|
'$id' => ID::custom('scheduledAt'),
|
||||||
'type' => Database::VAR_DATETIME,
|
'type' => Database::VAR_DATETIME,
|
||||||
'format' => '',
|
'format' => '',
|
||||||
'size' => 0,
|
'size' => 0,
|
||||||
|
@ -1722,28 +1733,6 @@ $commonCollections = [
|
||||||
'$id' => ID::custom('subscribers'),
|
'$id' => ID::custom('subscribers'),
|
||||||
'name' => 'Subscribers',
|
'name' => 'Subscribers',
|
||||||
'attributes' => [
|
'attributes' => [
|
||||||
[
|
|
||||||
'$id' => ID::custom('userId'),
|
|
||||||
'type' => Database::VAR_STRING,
|
|
||||||
'format' => '',
|
|
||||||
'size' => Database::LENGTH_KEY,
|
|
||||||
'signed' => true,
|
|
||||||
'required' => true,
|
|
||||||
'default' => null,
|
|
||||||
'array' => false,
|
|
||||||
'filters' => [],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'$id' => ID::custom('userInternalId'),
|
|
||||||
'type' => Database::VAR_STRING,
|
|
||||||
'format' => '',
|
|
||||||
'size' => Database::LENGTH_KEY,
|
|
||||||
'signed' => true,
|
|
||||||
'required' => true,
|
|
||||||
'default' => null,
|
|
||||||
'array' => false,
|
|
||||||
'filters' => [],
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('targetId'),
|
'$id' => ID::custom('targetId'),
|
||||||
'type' => Database::VAR_STRING,
|
'type' => Database::VAR_STRING,
|
||||||
|
@ -1766,6 +1755,28 @@ $commonCollections = [
|
||||||
'array' => false,
|
'array' => false,
|
||||||
'filters' => [],
|
'filters' => [],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('userId'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => Database::LENGTH_KEY,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => true,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('userInternalId'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => Database::LENGTH_KEY,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => true,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('topicId'),
|
'$id' => ID::custom('topicId'),
|
||||||
'type' => Database::VAR_STRING,
|
'type' => Database::VAR_STRING,
|
||||||
|
@ -1788,22 +1799,19 @@ $commonCollections = [
|
||||||
'array' => false,
|
'array' => false,
|
||||||
'filters' => [],
|
'filters' => [],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('providerType'),
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => 128,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => true,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'indexes' => [
|
'indexes' => [
|
||||||
[
|
|
||||||
'$id' => ID::custom('_key_userId'),
|
|
||||||
'type' => Database::INDEX_KEY,
|
|
||||||
'attributes' => ['userId'],
|
|
||||||
'lengths' => [],
|
|
||||||
'orders' => [],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'$id' => ID::custom('_key_userInternalId'),
|
|
||||||
'type' => Database::INDEX_KEY,
|
|
||||||
'attributes' => ['userInternalId'],
|
|
||||||
'lengths' => [],
|
|
||||||
'orders' => [],
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('_key_targetId'),
|
'$id' => ID::custom('_key_targetId'),
|
||||||
'type' => Database::INDEX_KEY,
|
'type' => Database::INDEX_KEY,
|
||||||
|
@ -1818,6 +1826,20 @@ $commonCollections = [
|
||||||
'lengths' => [],
|
'lengths' => [],
|
||||||
'orders' => [],
|
'orders' => [],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('_key_userId'),
|
||||||
|
'type' => Database::INDEX_KEY,
|
||||||
|
'attributes' => ['userId'],
|
||||||
|
'lengths' => [],
|
||||||
|
'orders' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('_key_userInternalId'),
|
||||||
|
'type' => Database::INDEX_KEY,
|
||||||
|
'attributes' => ['userInternalId'],
|
||||||
|
'lengths' => [],
|
||||||
|
'orders' => [],
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('_key_topicId'),
|
'$id' => ID::custom('_key_topicId'),
|
||||||
'type' => Database::INDEX_KEY,
|
'type' => Database::INDEX_KEY,
|
||||||
|
|
|
@ -103,6 +103,16 @@ return [
|
||||||
'description' => 'This method was not fully implemented yet. If you believe this is a mistake, please upgrade your Appwrite server version.',
|
'description' => 'This method was not fully implemented yet. If you believe this is a mistake, please upgrade your Appwrite server version.',
|
||||||
'code' => 405,
|
'code' => 405,
|
||||||
],
|
],
|
||||||
|
Exception::GENERAL_INVALID_EMAIL => [
|
||||||
|
'name' => Exception::GENERAL_INVALID_EMAIL,
|
||||||
|
'description' => 'Value must be a valid email address.',
|
||||||
|
'code' => 400,
|
||||||
|
],
|
||||||
|
Exception::GENERAL_INVALID_PHONE => [
|
||||||
|
'name' => Exception::GENERAL_INVALID_PHONE,
|
||||||
|
'description' => 'Value must be a valid phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.',
|
||||||
|
'code' => 400,
|
||||||
|
],
|
||||||
|
|
||||||
/** User Errors */
|
/** User Errors */
|
||||||
Exception::USER_COUNT_EXCEEDED => [
|
Exception::USER_COUNT_EXCEEDED => [
|
||||||
|
@ -837,5 +847,20 @@ return [
|
||||||
'description' => 'Message with the requested ID has already been scheduled for delivery.',
|
'description' => 'Message with the requested ID has already been scheduled for delivery.',
|
||||||
'code' => 400,
|
'code' => 400,
|
||||||
],
|
],
|
||||||
|
Exception::MESSAGE_TARGET_NOT_EMAIL => [
|
||||||
|
'name' => Exception::MESSAGE_TARGET_NOT_EMAIL,
|
||||||
|
'description' => 'Message with the target ID is not an email target:',
|
||||||
|
'code' => 400,
|
||||||
|
],
|
||||||
|
Exception::MESSAGE_TARGET_NOT_SMS => [
|
||||||
|
'name' => Exception::MESSAGE_TARGET_NOT_SMS,
|
||||||
|
'description' => 'Message with the target ID is not an SMS target:',
|
||||||
|
'code' => 400,
|
||||||
|
],
|
||||||
|
Exception::MESSAGE_TARGET_NOT_PUSH => [
|
||||||
|
'name' => Exception::MESSAGE_TARGET_NOT_PUSH,
|
||||||
|
'description' => 'Message with the target ID is not a push target:',
|
||||||
|
'code' => 400,
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -440,7 +440,7 @@ return [
|
||||||
'variables' => [
|
'variables' => [
|
||||||
[
|
[
|
||||||
'name' => '_APP_SMS_PROVIDER',
|
'name' => '_APP_SMS_PROVIDER',
|
||||||
'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, textmagic, telesign, msg91, and vonage.",
|
'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, Textmagic, telesign, msg91, and vonage.",
|
||||||
'introduction' => '0.15.0',
|
'introduction' => '0.15.0',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
|
|
@ -149,18 +149,20 @@ App::post('/v1/account')
|
||||||
]);
|
]);
|
||||||
$user->removeAttribute('$internalId');
|
$user->removeAttribute('$internalId');
|
||||||
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||||
|
try {
|
||||||
$target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([
|
$target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([
|
||||||
'$permissions' => [
|
|
||||||
Permission::read(Role::any()),
|
|
||||||
Permission::update(Role::user($userId)),
|
|
||||||
Permission::delete(Role::user($userId)),
|
|
||||||
],
|
|
||||||
'userId' => $user->getId(),
|
'userId' => $user->getId(),
|
||||||
'userInternalId' => $user->getInternalId(),
|
'userInternalId' => $user->getInternalId(),
|
||||||
'providerType' => 'email',
|
'providerType' => MESSAGE_TYPE_EMAIL,
|
||||||
'identifier' => $email,
|
'identifier' => $email,
|
||||||
])));
|
])));
|
||||||
$user->setAttribute('targets', [$target]);
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]);
|
||||||
|
} catch (Duplicate) {
|
||||||
|
$existingTarget = $dbForProject->findOne('targets', [
|
||||||
|
Query::equal('identifier', [$email]),
|
||||||
|
]);
|
||||||
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]);
|
||||||
|
}
|
||||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
} catch (Duplicate) {
|
} catch (Duplicate) {
|
||||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||||
|
@ -678,7 +680,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||||
],
|
],
|
||||||
'userId' => $userDoc->getId(),
|
'userId' => $userDoc->getId(),
|
||||||
'userInternalId' => $userDoc->getInternalId(),
|
'userInternalId' => $userDoc->getInternalId(),
|
||||||
'providerType' => 'email',
|
'providerType' => MESSAGE_TYPE_EMAIL,
|
||||||
'identifier' => $email,
|
'identifier' => $email,
|
||||||
]));
|
]));
|
||||||
} catch (Duplicate) {
|
} catch (Duplicate) {
|
||||||
|
@ -1309,6 +1311,21 @@ App::post('/v1/account/sessions/phone')
|
||||||
|
|
||||||
$user->removeAttribute('$internalId');
|
$user->removeAttribute('$internalId');
|
||||||
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||||
|
try {
|
||||||
|
$target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'userInternalId' => $user->getInternalId(),
|
||||||
|
'providerType' => MESSAGE_TYPE_SMS,
|
||||||
|
'identifier' => $phone,
|
||||||
|
])));
|
||||||
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]);
|
||||||
|
} catch (Duplicate) {
|
||||||
|
$existingTarget = $dbForProject->findOne('targets', [
|
||||||
|
Query::equal('identifier', [$phone]),
|
||||||
|
]);
|
||||||
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]);
|
||||||
|
}
|
||||||
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
$secret = Auth::codeGenerator();
|
$secret = Auth::codeGenerator();
|
||||||
|
@ -1357,7 +1374,7 @@ App::post('/v1/account/sessions/phone')
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessage($messageDoc)
|
->setMessage($messageDoc)
|
||||||
->setRecipients([$phone])
|
->setRecipients([$phone])
|
||||||
->setProviderType('SMS')
|
->setProviderType(MESSAGE_TYPE_SMS)
|
||||||
->setProject($project)
|
->setProject($project)
|
||||||
->trigger();
|
->trigger();
|
||||||
|
|
||||||
|
@ -1732,7 +1749,7 @@ App::post('/v1/account/targets/push')
|
||||||
],
|
],
|
||||||
'providerId' => $providerId ?? null,
|
'providerId' => $providerId ?? null,
|
||||||
'providerInternalId' => $provider->getInternalId() ?? null,
|
'providerInternalId' => $provider->getInternalId() ?? null,
|
||||||
'providerType' => 'push',
|
'providerType' => MESSAGE_TYPE_PUSH,
|
||||||
'userId' => $user->getId(),
|
'userId' => $user->getId(),
|
||||||
'userInternalId' => $user->getInternalId(),
|
'userInternalId' => $user->getInternalId(),
|
||||||
'identifier' => $identifier,
|
'identifier' => $identifier,
|
||||||
|
@ -2102,25 +2119,25 @@ App::patch('/v1/account/email')
|
||||||
->setAttribute('passwordUpdate', DateTime::now());
|
->setAttribute('passwordUpdate', DateTime::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
$target = $dbForProject->findOne('targets', [
|
$target = Authorization::skip(fn () => $dbForProject->findOne('targets', [
|
||||||
Query::equal('identifier', [$email]),
|
Query::equal('identifier', [$email]),
|
||||||
]);
|
]));
|
||||||
|
|
||||||
if ($target && !$target->isEmpty()) {
|
if ($target instanceof Document && !$target->isEmpty()) {
|
||||||
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
||||||
/**
|
/**
|
||||||
* @var Document $oldTarget
|
* @var Document $oldTarget
|
||||||
*/
|
*/
|
||||||
$oldTarget = $user->find('identifier', $oldEmail, 'targets');
|
$oldTarget = $user->find('identifier', $oldEmail, 'targets');
|
||||||
|
|
||||||
if ($oldTarget !== false && !$oldTarget->isEmpty()) {
|
if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) {
|
||||||
$dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email));
|
Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email)));
|
||||||
}
|
}
|
||||||
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
try {
|
|
||||||
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
|
||||||
} catch (Duplicate) {
|
} catch (Duplicate) {
|
||||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
@ -2165,18 +2182,15 @@ App::patch('/v1/account/phone')
|
||||||
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
|
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
|
||||||
}
|
}
|
||||||
|
|
||||||
$target = $dbForProject->findOne('targets', [
|
$target = Authorization::skip(fn () => $dbForProject->findOne('targets', [
|
||||||
Query::equal('identifier', [$phone]),
|
Query::equal('identifier', [$phone]),
|
||||||
]);
|
]));
|
||||||
|
|
||||||
if ($target && !$target->isEmpty()) {
|
if ($target instanceof Document && !$target->isEmpty()) {
|
||||||
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$oldPhone = $user->getAttribute('phone');
|
||||||
* @var Document $oldTarget
|
|
||||||
*/
|
|
||||||
$oldTarget = $user->find('identifier', $user->getAttribute('phone'), 'targets');
|
|
||||||
|
|
||||||
$user
|
$user
|
||||||
->setAttribute('phone', $phone)
|
->setAttribute('phone', $phone)
|
||||||
|
@ -2191,12 +2205,17 @@ App::patch('/v1/account/phone')
|
||||||
->setAttribute('passwordUpdate', DateTime::now());
|
->setAttribute('passwordUpdate', DateTime::now());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oldTarget !== false && !$oldTarget->isEmpty()) {
|
|
||||||
$dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
||||||
|
/**
|
||||||
|
* @var Document $oldTarget
|
||||||
|
*/
|
||||||
|
$oldTarget = $user->find('identifier', $oldPhone, 'targets');
|
||||||
|
|
||||||
|
if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) {
|
||||||
|
Authorization::skip(fn () => $dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone)));
|
||||||
|
}
|
||||||
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
} catch (Duplicate $th) {
|
} catch (Duplicate $th) {
|
||||||
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
@ -3081,7 +3100,7 @@ App::post('/v1/account/verification/phone')
|
||||||
$queueForMessaging
|
$queueForMessaging
|
||||||
->setMessage($messageDoc)
|
->setMessage($messageDoc)
|
||||||
->setRecipients([$user->getAttribute('phone')])
|
->setRecipients([$user->getAttribute('phone')])
|
||||||
->setProviderType('SMS')
|
->setProviderType(MESSAGE_TYPE_SMS)
|
||||||
->setProject($project)
|
->setProject($project)
|
||||||
->trigger();
|
->trigger();
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -99,6 +99,42 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||||
'memberships' => null,
|
'memberships' => null,
|
||||||
'search' => implode(' ', [$userId, $email, $phone, $name]),
|
'search' => implode(' ', [$userId, $email, $phone, $name]),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
if ($email) {
|
||||||
|
try {
|
||||||
|
$target = $dbForProject->createDocument('targets', new Document([
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'userInternalId' => $user->getInternalId(),
|
||||||
|
'providerType' => 'email',
|
||||||
|
'identifier' => $email,
|
||||||
|
]));
|
||||||
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]);
|
||||||
|
} catch (Duplicate) {
|
||||||
|
$existingTarget = $dbForProject->findOne('targets', [
|
||||||
|
Query::equal('identifier', [$email]),
|
||||||
|
]);
|
||||||
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($phone) {
|
||||||
|
try {
|
||||||
|
$target = $dbForProject->createDocument('targets', new Document([
|
||||||
|
'userId' => $user->getId(),
|
||||||
|
'userInternalId' => $user->getInternalId(),
|
||||||
|
'providerType' => 'sms',
|
||||||
|
'identifier' => $phone,
|
||||||
|
]));
|
||||||
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $target]);
|
||||||
|
} catch (Duplicate) {
|
||||||
|
$existingTarget = $dbForProject->findOne('targets', [
|
||||||
|
Query::equal('identifier', [$phone]),
|
||||||
|
]);
|
||||||
|
$user->setAttribute('targets', [...$user->getAttribute('targets', []), $existingTarget]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
} catch (Duplicate $th) {
|
} catch (Duplicate $th) {
|
||||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
@ -396,18 +432,19 @@ App::post('/v1/users/:userId/targets')
|
||||||
->label('sdk.response.model', Response::MODEL_TARGET)
|
->label('sdk.response.model', Response::MODEL_TARGET)
|
||||||
->param('targetId', '', new CustomId(), 'Target 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('targetId', '', new CustomId(), 'Target 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('userId', '', new UID(), 'User ID.')
|
->param('userId', '', new UID(), 'User ID.')
|
||||||
->param('providerType', '', new WhiteList(['email', 'sms', 'push']), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.')
|
->param('providerType', '', new WhiteList([MESSAGE_TYPE_EMAIL, MESSAGE_TYPE_SMS, MESSAGE_TYPE_PUSH]), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.')
|
||||||
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)')
|
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)')
|
||||||
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
|
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
|
||||||
|
->param('name', '', new Text(128), 'Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->action(function (string $targetId, string $userId, string $providerType, string $identifier, string $providerId, Event $queueForEvents, Response $response, Database $dbForProject) {
|
->action(function (string $targetId, string $userId, string $providerType, string $identifier, string $providerId, string $name, Event $queueForEvents, Response $response, Database $dbForProject) {
|
||||||
$targetId = $targetId == 'unique()' ? ID::unique() : $targetId;
|
$targetId = $targetId == 'unique()' ? ID::unique() : $targetId;
|
||||||
|
|
||||||
$provider = new Document();
|
$provider = new Document();
|
||||||
|
|
||||||
if ($providerType === 'push') {
|
if ($providerType === MESSAGE_TYPE_PUSH) {
|
||||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||||
|
|
||||||
if ($provider->isEmpty()) {
|
if ($provider->isEmpty()) {
|
||||||
|
@ -415,6 +452,25 @@ App::post('/v1/users/:userId/targets')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ($providerType) {
|
||||||
|
case 'email':
|
||||||
|
$validator = new Email();
|
||||||
|
if (!$validator->isValid($identifier)) {
|
||||||
|
throw new Exception(Exception::GENERAL_INVALID_EMAIL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MESSAGE_TYPE_SMS:
|
||||||
|
$validator = new Phone();
|
||||||
|
if (!$validator->isValid($identifier)) {
|
||||||
|
throw new Exception(Exception::GENERAL_INVALID_PHONE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MESSAGE_TYPE_PUSH:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
$user = $dbForProject->getDocument('users', $userId);
|
$user = $dbForProject->getDocument('users', $userId);
|
||||||
|
|
||||||
if ($user->isEmpty()) {
|
if ($user->isEmpty()) {
|
||||||
|
@ -436,6 +492,7 @@ App::post('/v1/users/:userId/targets')
|
||||||
'userId' => $userId,
|
'userId' => $userId,
|
||||||
'userInternalId' => $user->getInternalId(),
|
'userInternalId' => $user->getInternalId(),
|
||||||
'identifier' => $identifier,
|
'identifier' => $identifier,
|
||||||
|
'name' => ($name !== '') ? $name : null,
|
||||||
]));
|
]));
|
||||||
} catch (Duplicate) {
|
} catch (Duplicate) {
|
||||||
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||||
|
@ -782,7 +839,7 @@ App::get('/v1/users/:userId/targets')
|
||||||
|
|
||||||
if ($cursor) {
|
if ($cursor) {
|
||||||
$targetId = $cursor->getValue();
|
$targetId = $cursor->getValue();
|
||||||
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId));
|
$cursorDocument = $dbForProject->getDocument('targets', $targetId);
|
||||||
|
|
||||||
if ($cursorDocument->isEmpty()) {
|
if ($cursorDocument->isEmpty()) {
|
||||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Target '{$targetId}' for the 'cursor' value not found.");
|
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Target '{$targetId}' for the 'cursor' value not found.");
|
||||||
|
@ -1100,6 +1157,16 @@ App::patch('/v1/users/:userId/email')
|
||||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$target = $dbForProject->findOne('targets', [
|
||||||
|
Query::equal('identifier', [$email]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($target instanceof Document && !$target->isEmpty()) {
|
||||||
|
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldEmail = $user->getAttribute('email');
|
||||||
|
|
||||||
$user
|
$user
|
||||||
->setAttribute('email', $email)
|
->setAttribute('email', $email)
|
||||||
->setAttribute('emailVerification', false)
|
->setAttribute('emailVerification', false)
|
||||||
|
@ -1108,6 +1175,15 @@ App::patch('/v1/users/:userId/email')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||||
|
/**
|
||||||
|
* @var Document $oldTarget
|
||||||
|
*/
|
||||||
|
$oldTarget = $user->find('identifier', $oldEmail, 'targets');
|
||||||
|
|
||||||
|
if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) {
|
||||||
|
$dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email));
|
||||||
|
}
|
||||||
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
} catch (Duplicate $th) {
|
} catch (Duplicate $th) {
|
||||||
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
@ -1145,13 +1221,32 @@ App::patch('/v1/users/:userId/phone')
|
||||||
throw new Exception(Exception::USER_NOT_FOUND);
|
throw new Exception(Exception::USER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$oldPhone = $user->getAttribute('phone');
|
||||||
|
|
||||||
$user
|
$user
|
||||||
->setAttribute('phone', $number)
|
->setAttribute('phone', $number)
|
||||||
->setAttribute('phoneVerification', false)
|
->setAttribute('phoneVerification', false)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
$target = $dbForProject->findOne('targets', [
|
||||||
|
Query::equal('identifier', [$number]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($target instanceof Document && !$target->isEmpty()) {
|
||||||
|
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||||
|
/**
|
||||||
|
* @var Document $oldTarget
|
||||||
|
*/
|
||||||
|
$oldTarget = $user->find('identifier', $oldPhone, 'targets');
|
||||||
|
|
||||||
|
if ($oldTarget instanceof Document && !$oldTarget->isEmpty()) {
|
||||||
|
$dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $number));
|
||||||
|
}
|
||||||
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
} catch (Duplicate $th) {
|
} catch (Duplicate $th) {
|
||||||
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
|
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
@ -1247,12 +1342,13 @@ App::patch('/v1/users/:userId/targets/:targetId')
|
||||||
->label('sdk.response.model', Response::MODEL_TARGET)
|
->label('sdk.response.model', Response::MODEL_TARGET)
|
||||||
->param('userId', '', new UID(), 'User ID.')
|
->param('userId', '', new UID(), 'User ID.')
|
||||||
->param('targetId', '', new UID(), 'Target ID.')
|
->param('targetId', '', new UID(), 'Target ID.')
|
||||||
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
|
|
||||||
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true)
|
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true)
|
||||||
|
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
|
||||||
|
->param('name', '', new Text(128), 'Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.', true)
|
||||||
->inject('queueForEvents')
|
->inject('queueForEvents')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->action(function (string $userId, string $targetId, string $providerId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) {
|
->action(function (string $userId, string $targetId, string $identifier, string $providerId, string $name, Event $queueForEvents, Response $response, Database $dbForProject) {
|
||||||
$user = $dbForProject->getDocument('users', $userId);
|
$user = $dbForProject->getDocument('users', $userId);
|
||||||
|
|
||||||
if ($user->isEmpty()) {
|
if ($user->isEmpty()) {
|
||||||
|
@ -1270,6 +1366,27 @@ App::patch('/v1/users/:userId/targets/:targetId')
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($identifier) {
|
if ($identifier) {
|
||||||
|
$providerType = $target->getAttribute('providerType');
|
||||||
|
|
||||||
|
switch ($providerType) {
|
||||||
|
case 'email':
|
||||||
|
$validator = new Email();
|
||||||
|
if (!$validator->isValid($identifier)) {
|
||||||
|
throw new Exception(Exception::GENERAL_INVALID_EMAIL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MESSAGE_TYPE_SMS:
|
||||||
|
$validator = new Phone();
|
||||||
|
if (!$validator->isValid($identifier)) {
|
||||||
|
throw new Exception(Exception::GENERAL_INVALID_PHONE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MESSAGE_TYPE_PUSH:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
$target->setAttribute('identifier', $identifier);
|
$target->setAttribute('identifier', $identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1280,10 +1397,18 @@ App::patch('/v1/users/:userId/targets/:targetId')
|
||||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($provider->getAttribute('type') !== $target->getAttribute('providerType')) {
|
||||||
|
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
$target->setAttribute('providerId', $provider->getId());
|
$target->setAttribute('providerId', $provider->getId());
|
||||||
$target->setAttribute('providerInternalId', $provider->getInternalId());
|
$target->setAttribute('providerInternalId', $provider->getInternalId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($name) {
|
||||||
|
$target->setAttribute('name', $name);
|
||||||
|
}
|
||||||
|
|
||||||
$target = $dbForProject->updateDocument('targets', $target->getId(), $target);
|
$target = $dbForProject->updateDocument('targets', $target->getId(), $target);
|
||||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||||
|
|
||||||
|
|
15
app/init.php
15
app/init.php
|
@ -190,6 +190,10 @@ const MAX_OUTPUT_CHUNK_SIZE = 2 * 1024 * 1024; // 2MB
|
||||||
// Function headers
|
// Function headers
|
||||||
const FUNCTION_ALLOWLIST_HEADERS_REQUEST = ['content-type', 'agent', 'content-length', 'host'];
|
const FUNCTION_ALLOWLIST_HEADERS_REQUEST = ['content-type', 'agent', 'content-length', 'host'];
|
||||||
const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = ['content-type', 'content-length'];
|
const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = ['content-type', 'content-length'];
|
||||||
|
// Message types
|
||||||
|
const MESSAGE_TYPE_EMAIL = 'email';
|
||||||
|
const MESSAGE_TYPE_SMS = 'sms';
|
||||||
|
const MESSAGE_TYPE_PUSH = 'push';
|
||||||
// Usage metrics
|
// Usage metrics
|
||||||
const METRIC_TEAMS = 'teams';
|
const METRIC_TEAMS = 'teams';
|
||||||
const METRIC_USERS = 'users';
|
const METRIC_USERS = 'users';
|
||||||
|
@ -605,13 +609,14 @@ Database::addFilter(
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = \json_decode($message->getAttribute('data', []), true);
|
$data = \json_decode($message->getAttribute('data', []), true);
|
||||||
|
$providerType = $message->getAttribute('providerType', '');
|
||||||
|
|
||||||
if (\array_key_exists('subject', $data)) {
|
if ($providerType === MESSAGE_TYPE_EMAIL) {
|
||||||
$searchValues = \array_merge($searchValues, [$data['subject'], 'email']);
|
$searchValues = \array_merge($searchValues, [$data['subject'], MESSAGE_TYPE_EMAIL]);
|
||||||
} elseif (\array_key_exists('content', $data)) {
|
} elseif ($providerType === MESSAGE_TYPE_SMS) {
|
||||||
$searchValues = \array_merge($searchValues, [$data['content'], 'sms']);
|
$searchValues = \array_merge($searchValues, [$data['content'], MESSAGE_TYPE_SMS]);
|
||||||
} else {
|
} else {
|
||||||
$searchValues = \array_merge($searchValues, [$data['title'], 'push']);
|
$searchValues = \array_merge($searchValues, [$data['title'], MESSAGE_TYPE_PUSH]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$search = \implode(' ', \array_filter($searchValues));
|
$search = \implode(' ', \array_filter($searchValues));
|
||||||
|
|
|
@ -521,14 +521,20 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- _APP_ENV
|
- _APP_ENV
|
||||||
- _APP_WORKER_PER_CORE
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
- _APP_REDIS_HOST
|
- _APP_REDIS_HOST
|
||||||
- _APP_REDIS_PORT
|
- _APP_REDIS_PORT
|
||||||
- _APP_REDIS_USER
|
- _APP_REDIS_USER
|
||||||
- _APP_REDIS_PASS
|
- _APP_REDIS_PASS
|
||||||
- _APP_SMS_PROVIDER
|
- _APP_DB_HOST
|
||||||
- _APP_SMS_FROM
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
- _APP_LOGGING_PROVIDER
|
- _APP_LOGGING_PROVIDER
|
||||||
- _APP_LOGGING_CONFIG
|
- _APP_LOGGING_CONFIG
|
||||||
|
- _APP_SMS_FROM
|
||||||
|
- _APP_SMS_PROVIDER
|
||||||
|
|
||||||
appwrite-worker-migrations:
|
appwrite-worker-migrations:
|
||||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||||
|
|
75
composer.lock
generated
75
composer.lock
generated
|
@ -156,11 +156,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "appwrite/php-runtimes",
|
"name": "appwrite/php-runtimes",
|
||||||
"version": "0.13.1",
|
"version": "0.13.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/appwrite/runtimes.git",
|
"url": "https://github.com/appwrite/runtimes.git",
|
||||||
"reference": "b584d19cdcd82737d0ee5c34d23de791f5ed3610"
|
"reference": "214a37c2c66e0f2bc9c30fdfde66955d9fd084a1"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.0",
|
"php": ">=8.0",
|
||||||
|
@ -195,7 +195,7 @@
|
||||||
"php",
|
"php",
|
||||||
"runtimes"
|
"runtimes"
|
||||||
],
|
],
|
||||||
"time": "2023-10-16T15:39:53+00:00"
|
"time": "2023-11-22T15:36:00+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "chillerlan/php-qrcode",
|
"name": "chillerlan/php-qrcode",
|
||||||
|
@ -1465,7 +1465,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v3.3.0",
|
"version": "v3.4.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
|
@ -1512,7 +1512,7 @@
|
||||||
"description": "A generic function and convention to trigger deprecation notices",
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0"
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -2217,16 +2217,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/logger",
|
"name": "utopia-php/logger",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/utopia-php/logger.git",
|
"url": "https://github.com/utopia-php/logger.git",
|
||||||
"reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc"
|
"reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/utopia-php/logger/zipball/de623f1ec1c672c795d113dd25c5bf212f7ef4fc",
|
"url": "https://api.github.com/repos/utopia-php/logger/zipball/ba763c10688fe2ed715ad2bed3f13d18dfec6253",
|
||||||
"reference": "de623f1ec1c672c795d113dd25c5bf212f7ef4fc",
|
"reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2264,9 +2264,9 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/utopia-php/logger/issues",
|
"issues": "https://github.com/utopia-php/logger/issues",
|
||||||
"source": "https://github.com/utopia-php/logger/tree/0.3.1"
|
"source": "https://github.com/utopia-php/logger/tree/0.3.2"
|
||||||
},
|
},
|
||||||
"time": "2023-02-10T15:52:50+00:00"
|
"time": "2023-11-22T14:45:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/messaging",
|
"name": "utopia-php/messaging",
|
||||||
|
@ -3136,16 +3136,16 @@
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "appwrite/sdk-generator",
|
"name": "appwrite/sdk-generator",
|
||||||
"version": "0.35.2",
|
"version": "0.35.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||||
"reference": "2dfe0430a64ffd2a07078d83b20144b871acac3b"
|
"reference": "4c431d5324a8f8cd2cab9a5515c170a5b427d44c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/2dfe0430a64ffd2a07078d83b20144b871acac3b",
|
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/4c431d5324a8f8cd2cab9a5515c170a5b427d44c",
|
||||||
"reference": "2dfe0430a64ffd2a07078d83b20144b871acac3b",
|
"reference": "4c431d5324a8f8cd2cab9a5515c170a5b427d44c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3181,9 +3181,9 @@
|
||||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.35.2"
|
"source": "https://github.com/appwrite/sdk-generator/tree/0.35.3"
|
||||||
},
|
},
|
||||||
"time": "2023-09-14T14:59:50+00:00"
|
"time": "2023-11-12T05:56:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/deprecations",
|
"name": "doctrine/deprecations",
|
||||||
|
@ -3890,16 +3890,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpdoc-parser",
|
"name": "phpstan/phpdoc-parser",
|
||||||
"version": "1.24.2",
|
"version": "1.24.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||||
"reference": "bcad8d995980440892759db0c32acae7c8e79442"
|
"reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442",
|
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6bd0c26f3786cd9b7c359675cb789e35a8e07496",
|
||||||
"reference": "bcad8d995980440892759db0c32acae7c8e79442",
|
"reference": "6bd0c26f3786cd9b7c359675cb789e35a8e07496",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -3931,9 +3931,9 @@
|
||||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2"
|
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.4"
|
||||||
},
|
},
|
||||||
"time": "2023-09-26T12:28:12+00:00"
|
"time": "2023-11-26T18:29:22+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
|
@ -5676,16 +5676,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/tokenizer",
|
"name": "theseer/tokenizer",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/theseer/tokenizer.git",
|
"url": "https://github.com/theseer/tokenizer.git",
|
||||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
|
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
|
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
|
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -5714,7 +5714,7 @@
|
||||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/theseer/tokenizer/issues",
|
"issues": "https://github.com/theseer/tokenizer/issues",
|
||||||
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
|
"source": "https://github.com/theseer/tokenizer/tree/1.2.2"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -5722,30 +5722,31 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-07-28T10:34:58+00:00"
|
"time": "2023-11-20T00:12:19+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/twig",
|
"name": "twig/twig",
|
||||||
"version": "v3.7.1",
|
"version": "v3.8.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/twigphp/Twig.git",
|
"url": "https://github.com/twigphp/Twig.git",
|
||||||
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554"
|
"reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554",
|
"url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
|
||||||
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554",
|
"reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.2.5",
|
"php": ">=7.2.5",
|
||||||
"symfony/polyfill-ctype": "^1.8",
|
"symfony/polyfill-ctype": "^1.8",
|
||||||
"symfony/polyfill-mbstring": "^1.3"
|
"symfony/polyfill-mbstring": "^1.3",
|
||||||
|
"symfony/polyfill-php80": "^1.22"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"psr/container": "^1.0|^2.0",
|
"psr/container": "^1.0|^2.0",
|
||||||
"symfony/phpunit-bridge": "^5.4.9|^6.3"
|
"symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -5781,7 +5782,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/twigphp/Twig/issues",
|
"issues": "https://github.com/twigphp/Twig/issues",
|
||||||
"source": "https://github.com/twigphp/Twig/tree/v3.7.1"
|
"source": "https://github.com/twigphp/Twig/tree/v3.8.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -5793,7 +5794,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-28T11:09:02+00:00"
|
"time": "2023-11-21T18:54:41+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Messaging extends Event
|
||||||
protected ?string $messageId = null;
|
protected ?string $messageId = null;
|
||||||
protected ?Document $message = null;
|
protected ?Document $message = null;
|
||||||
protected ?array $recipients = null;
|
protected ?array $recipients = null;
|
||||||
protected ?string $deliveryTime = null;
|
protected ?string $scheduledAt = null;
|
||||||
protected ?string $providerType = null;
|
protected ?string $providerType = null;
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,14 +117,14 @@ class Messaging extends Event
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets Delivery time for the messaging event.
|
* Sets Scheduled delivery time for the messaging event.
|
||||||
*
|
*
|
||||||
* @param string $deliveryTime
|
* @param string $scheduledAt
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public function setDeliveryTime(string $deliveryTime): self
|
public function setScheduledAt(string $scheduledAt): self
|
||||||
{
|
{
|
||||||
$this->deliveryTime = $deliveryTime;
|
$this->scheduledAt = $scheduledAt;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -134,9 +134,9 @@ class Messaging extends Event
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getDeliveryTime(): string
|
public function getScheduledAt(): string
|
||||||
{
|
{
|
||||||
return $this->deliveryTime;
|
return $this->scheduledAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -55,6 +55,8 @@ class Exception extends \Exception
|
||||||
public const GENERAL_CODES_DISABLED = 'general_codes_disabled';
|
public const GENERAL_CODES_DISABLED = 'general_codes_disabled';
|
||||||
public const GENERAL_USAGE_DISABLED = 'general_usage_disabled';
|
public const GENERAL_USAGE_DISABLED = 'general_usage_disabled';
|
||||||
public const GENERAL_NOT_IMPLEMENTED = 'general_not_implemented';
|
public const GENERAL_NOT_IMPLEMENTED = 'general_not_implemented';
|
||||||
|
public const GENERAL_INVALID_EMAIL = 'general_invalid_email';
|
||||||
|
public const GENERAL_INVALID_PHONE = 'general_invalid_phone';
|
||||||
|
|
||||||
/** Users */
|
/** Users */
|
||||||
public const USER_COUNT_EXCEEDED = 'user_count_exceeded';
|
public const USER_COUNT_EXCEEDED = 'user_count_exceeded';
|
||||||
|
@ -254,6 +256,10 @@ class Exception extends \Exception
|
||||||
public const MESSAGE_MISSING_TARGET = 'message_missing_target';
|
public const MESSAGE_MISSING_TARGET = 'message_missing_target';
|
||||||
public const MESSAGE_ALREADY_SENT = 'message_already_sent';
|
public const MESSAGE_ALREADY_SENT = 'message_already_sent';
|
||||||
public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled';
|
public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled';
|
||||||
|
public const MESSAGE_TARGET_NOT_EMAIL = 'message_target_not_email';
|
||||||
|
public const MESSAGE_TARGET_NOT_SMS = 'message_target_not_sms';
|
||||||
|
public const MESSAGE_TARGET_NOT_PUSH = 'message_target_not_push';
|
||||||
|
|
||||||
|
|
||||||
protected string $type = '';
|
protected string $type = '';
|
||||||
protected array $errors = [];
|
protected array $errors = [];
|
||||||
|
|
|
@ -556,6 +556,11 @@ class Deletes extends Action
|
||||||
$this->deleteByGroup('identities', [
|
$this->deleteByGroup('identities', [
|
||||||
Query::equal('userInternalId', [$userInternalId])
|
Query::equal('userInternalId', [$userInternalId])
|
||||||
], $dbForProject);
|
], $dbForProject);
|
||||||
|
|
||||||
|
// Delete targets
|
||||||
|
$this->deleteByGroup('targets', [
|
||||||
|
Query::equal('userInternalId', [$userInternalId])
|
||||||
|
], $dbForProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,7 @@ use Utopia\Messaging\Adapters\SMS as SMSAdapter;
|
||||||
use Utopia\Messaging\Adapters\SMS\Mock;
|
use Utopia\Messaging\Adapters\SMS\Mock;
|
||||||
use Utopia\Messaging\Adapters\SMS\Msg91;
|
use Utopia\Messaging\Adapters\SMS\Msg91;
|
||||||
use Utopia\Messaging\Adapters\SMS\Telesign;
|
use Utopia\Messaging\Adapters\SMS\Telesign;
|
||||||
use Utopia\Messaging\Adapters\SMS\TextMagic;
|
use Utopia\Messaging\Adapters\SMS\Textmagic;
|
||||||
use Utopia\Messaging\Adapters\SMS\Twilio;
|
use Utopia\Messaging\Adapters\SMS\Twilio;
|
||||||
use Utopia\Messaging\Adapters\SMS\Vonage;
|
use Utopia\Messaging\Adapters\SMS\Vonage;
|
||||||
use Utopia\Messaging\Adapters\Push as PushAdapter;
|
use Utopia\Messaging\Adapters\Push as PushAdapter;
|
||||||
|
@ -67,7 +67,7 @@ class Messaging extends Action
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!\is_null($payload['message']) && !\is_null($payload['recipients'])) {
|
if (!\is_null($payload['message']) && !\is_null($payload['recipients'])) {
|
||||||
if ($payload['providerType'] === 'SMS') {
|
if ($payload['providerType'] === MESSAGE_TYPE_SMS) {
|
||||||
$this->processInternalSMSMessage(new Document($payload['message']), $payload['recipients']);
|
$this->processInternalSMSMessage(new Document($payload['message']), $payload['recipients']);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -91,14 +91,16 @@ class Messaging extends Action
|
||||||
if (\count($topicsId) > 0) {
|
if (\count($topicsId) > 0) {
|
||||||
$topics = $dbForProject->find('topics', [Query::equal('$id', $topicsId)]);
|
$topics = $dbForProject->find('topics', [Query::equal('$id', $topicsId)]);
|
||||||
foreach ($topics as $topic) {
|
foreach ($topics as $topic) {
|
||||||
$recipients = \array_merge($recipients, $topic->getAttribute('targets'));
|
$targets = \array_filter($topic->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType'));
|
||||||
|
$recipients = \array_merge($recipients, $targets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\count($usersId) > 0) {
|
if (\count($usersId) > 0) {
|
||||||
$users = $dbForProject->find('users', [Query::equal('$id', $usersId)]);
|
$users = $dbForProject->find('users', [Query::equal('$id', $usersId)]);
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
$recipients = \array_merge($recipients, $user->getAttribute('targets'));
|
$targets = \array_filter($user->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType'));
|
||||||
|
$recipients = \array_merge($recipients, $targets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ class Messaging extends Action
|
||||||
$recipients = \array_merge($recipients, $targets);
|
$recipients = \array_merge($recipients, $targets);
|
||||||
}
|
}
|
||||||
|
|
||||||
$internalProvider = $dbForProject->findOne('providers', [
|
$primaryProvider = $dbForProject->findOne('providers', [
|
||||||
Query::equal('enabled', [true]),
|
Query::equal('enabled', [true]),
|
||||||
Query::equal('type', [$recipients[0]->getAttribute('providerType')]),
|
Query::equal('type', [$recipients[0]->getAttribute('providerType')]),
|
||||||
]);
|
]);
|
||||||
|
@ -124,36 +126,42 @@ class Messaging extends Action
|
||||||
foreach ($recipients as $recipient) {
|
foreach ($recipients as $recipient) {
|
||||||
$providerId = $recipient->getAttribute('providerId');
|
$providerId = $recipient->getAttribute('providerId');
|
||||||
|
|
||||||
if (!$providerId) {
|
if (!$providerId && $primaryProvider instanceof Document && !$primaryProvider->isEmpty()) {
|
||||||
$providerId = $internalProvider->getId();
|
$providerId = $primaryProvider->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($providerId) {
|
||||||
if (!isset($identifiersByProviderId[$providerId])) {
|
if (!isset($identifiersByProviderId[$providerId])) {
|
||||||
$identifiersByProviderId[$providerId] = [];
|
$identifiersByProviderId[$providerId] = [];
|
||||||
}
|
}
|
||||||
$identifiersByProviderId[$providerId][] = $recipient->getAttribute('identifier');
|
$identifiersByProviderId[$providerId][] = $recipient->getAttribute('identifier');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array[] $results
|
* @var array[] $results
|
||||||
*/
|
*/
|
||||||
$results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) {
|
$results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) {
|
||||||
return function () use ($providerId, $identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) {
|
return function () use ($providerId, $identifiersByProviderId, $providers, $primaryProvider, $message, $dbForProject) {
|
||||||
$provider = new Document();
|
$provider = new Document();
|
||||||
|
|
||||||
if ($internalProvider->getId() === $providerId) {
|
if ($primaryProvider->getId() === $providerId) {
|
||||||
$provider = $internalProvider;
|
$provider = $primaryProvider;
|
||||||
} else {
|
} else {
|
||||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
$provider = $dbForProject->getDocument('providers', $providerId, [Query::equal('enabled', [true])]);
|
||||||
|
|
||||||
|
if ($provider->isEmpty()) {
|
||||||
|
$provider = $primaryProvider;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$providers[] = $provider;
|
$providers[] = $provider;
|
||||||
$identifiers = $identifiersByProviderId[$providerId];
|
$identifiers = $identifiersByProviderId[$providerId];
|
||||||
|
|
||||||
$adapter = match ($provider->getAttribute('type')) {
|
$adapter = match ($provider->getAttribute('type')) {
|
||||||
'sms' => $this->sms($provider),
|
MESSAGE_TYPE_SMS => $this->sms($provider),
|
||||||
'push' => $this->push($provider),
|
MESSAGE_TYPE_PUSH => $this->push($provider),
|
||||||
'email' => $this->email($provider),
|
MESSAGE_TYPE_EMAIL => $this->email($provider),
|
||||||
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -169,9 +177,9 @@ class Messaging extends Action
|
||||||
$messageData->setAttribute('to', $batch);
|
$messageData->setAttribute('to', $batch);
|
||||||
|
|
||||||
$data = match ($provider->getAttribute('type')) {
|
$data = match ($provider->getAttribute('type')) {
|
||||||
'sms' => $this->buildSMSMessage($messageData, $provider),
|
MESSAGE_TYPE_SMS => $this->buildSMSMessage($messageData, $provider),
|
||||||
'push' => $this->buildPushMessage($messageData),
|
MESSAGE_TYPE_PUSH => $this->buildPushMessage($messageData),
|
||||||
'email' => $this->buildEmailMessage($messageData, $provider),
|
MESSAGE_TYPE_EMAIL => $this->buildEmailMessage($messageData, $provider),
|
||||||
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -241,7 +249,7 @@ class Messaging extends Action
|
||||||
$provider = new Document([
|
$provider = new Document([
|
||||||
'$id' => ID::unique(),
|
'$id' => ID::unique(),
|
||||||
'provider' => $host,
|
'provider' => $host,
|
||||||
'type' => 'sms',
|
'type' => MESSAGE_TYPE_SMS,
|
||||||
'name' => 'Internal SMS',
|
'name' => 'Internal SMS',
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'credentials' => match ($host) {
|
'credentials' => match ($host) {
|
||||||
|
@ -303,7 +311,7 @@ class Messaging extends Action
|
||||||
return match ($provider->getAttribute('provider')) {
|
return match ($provider->getAttribute('provider')) {
|
||||||
'mock' => new Mock('username', 'password'),
|
'mock' => new Mock('username', 'password'),
|
||||||
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']),
|
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']),
|
||||||
'textmagic' => new TextMagic($credentials['username'], $credentials['apiKey']),
|
'textmagic' => new Textmagic($credentials['username'], $credentials['apiKey']),
|
||||||
'telesign' => new Telesign($credentials['username'], $credentials['password']),
|
'telesign' => new Telesign($credentials['username'], $credentials['password']),
|
||||||
'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']),
|
'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']),
|
||||||
'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']),
|
'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']),
|
||||||
|
|
|
@ -6,7 +6,9 @@ class Subscribers extends Base
|
||||||
{
|
{
|
||||||
public const ALLOWED_ATTRIBUTES = [
|
public const ALLOWED_ATTRIBUTES = [
|
||||||
'targetId',
|
'targetId',
|
||||||
'topicId'
|
'topicId',
|
||||||
|
'userId',
|
||||||
|
'providerType'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,8 +5,9 @@ namespace Appwrite\Utopia\Response\Model;
|
||||||
use Appwrite\Utopia\Response;
|
use Appwrite\Utopia\Response;
|
||||||
use Appwrite\Utopia\Response\Model;
|
use Appwrite\Utopia\Response\Model;
|
||||||
use Utopia\Database\DateTime;
|
use Utopia\Database\DateTime;
|
||||||
|
use Utopia\Database\Document as DatabaseDocument;
|
||||||
|
|
||||||
class Message extends Any
|
class Message extends Model
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -29,6 +30,12 @@ class Message extends Any
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||||
])
|
])
|
||||||
|
->addRule('providerType', [
|
||||||
|
'type' => self::TYPE_STRING,
|
||||||
|
'description' => 'Message provider type.',
|
||||||
|
'default' => '',
|
||||||
|
'example' => MESSAGE_TYPE_EMAIL,
|
||||||
|
])
|
||||||
->addRule('topics', [
|
->addRule('topics', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'Topic IDs set as recipients.',
|
'description' => 'Topic IDs set as recipients.',
|
||||||
|
@ -50,7 +57,7 @@ class Message extends Any
|
||||||
'array' => true,
|
'array' => true,
|
||||||
'example' => ['5e5ea5c16897e'],
|
'example' => ['5e5ea5c16897e'],
|
||||||
])
|
])
|
||||||
->addRule('deliveryTime', [
|
->addRule('scheduledAt', [
|
||||||
'type' => self::TYPE_DATETIME,
|
'type' => self::TYPE_DATETIME,
|
||||||
'description' => 'The scheduled time for message.',
|
'description' => 'The scheduled time for message.',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
@ -91,7 +98,7 @@ class Message extends Any
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'Status of delivery.',
|
'description' => 'Status of delivery.',
|
||||||
'default' => 'processing',
|
'default' => 'processing',
|
||||||
'example' => 'Message status can be one of the following: processing, sent, failed.',
|
'example' => 'Message status can be one of the following: processing, sent, cancelled, failed.',
|
||||||
])
|
])
|
||||||
->addRule('description', [
|
->addRule('description', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
|
|
|
@ -50,7 +50,7 @@ class Provider extends Model
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'Type of provider.',
|
'description' => 'Type of provider.',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => 'sms',
|
'example' => MESSAGE_TYPE_SMS,
|
||||||
])
|
])
|
||||||
->addRule('credentials', [
|
->addRule('credentials', [
|
||||||
'type' => self::TYPE_JSON,
|
'type' => self::TYPE_JSON,
|
||||||
|
|
|
@ -34,9 +34,24 @@ class Subscriber extends Model
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => '259125845563242502',
|
'example' => '259125845563242502',
|
||||||
])
|
])
|
||||||
|
->addRule('target', [
|
||||||
|
'type' => Response::MODEL_TARGET,
|
||||||
|
'description' => 'Target.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => [
|
||||||
|
'$id' => '259125845563242502',
|
||||||
|
'$createdAt' => self::TYPE_DATETIME_EXAMPLE,
|
||||||
|
'$updatedAt' => self::TYPE_DATETIME_EXAMPLE,
|
||||||
|
'providerType' => 'email',
|
||||||
|
'providerId' => '259125845563242502',
|
||||||
|
'name' => 'ageon-app-email',
|
||||||
|
'identifier' => 'random-mail@email.org',
|
||||||
|
'userId' => '5e5ea5c16897e',
|
||||||
|
],
|
||||||
|
])
|
||||||
->addRule('userId', [
|
->addRule('userId', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'User ID.',
|
'description' => 'Topic ID.',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => '5e5ea5c16897e',
|
'example' => '5e5ea5c16897e',
|
||||||
])
|
])
|
||||||
|
@ -51,6 +66,12 @@ class Subscriber extends Model
|
||||||
'description' => 'Topic ID.',
|
'description' => 'Topic ID.',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => '259125845563242502',
|
'example' => '259125845563242502',
|
||||||
|
])
|
||||||
|
->addRule('providerType', [
|
||||||
|
'type' => self::TYPE_STRING,
|
||||||
|
'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.',
|
||||||
|
'default' => '',
|
||||||
|
'example' => MESSAGE_TYPE_EMAIL,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,12 @@ class Target extends Model
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||||
])
|
])
|
||||||
|
->addRule('name', [
|
||||||
|
'type' => self::TYPE_STRING,
|
||||||
|
'description' => 'Target Name.',
|
||||||
|
'default' => '',
|
||||||
|
'example' => 'Aegon apple token',
|
||||||
|
])
|
||||||
->addRule('userId', [
|
->addRule('userId', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'User ID.',
|
'description' => 'User ID.',
|
||||||
|
@ -45,7 +51,7 @@ class Target extends Model
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.',
|
'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => 'email',
|
'example' => MESSAGE_TYPE_EMAIL,
|
||||||
])
|
])
|
||||||
->addRule('identifier', [
|
->addRule('identifier', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
|
|
|
@ -1830,8 +1830,8 @@ trait Base
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
case self::$CREATE_TEXTMAGIC_PROVIDER:
|
case self::$CREATE_TEXTMAGIC_PROVIDER:
|
||||||
return 'mutation createTextMagicProvider($providerId: String!, $name: String!, $from: String!, $username: String!, $apiKey: String!) {
|
return 'mutation createTextmagicProvider($providerId: String!, $name: String!, $from: String!, $username: String!, $apiKey: String!) {
|
||||||
messagingCreateTextMagicProvider(providerId: $providerId, name: $name, from: $from, username: $username, apiKey: $apiKey) {
|
messagingCreateTextmagicProvider(providerId: $providerId, name: $name, from: $from, username: $username, apiKey: $apiKey) {
|
||||||
_id
|
_id
|
||||||
name
|
name
|
||||||
provider
|
provider
|
||||||
|
@ -1944,8 +1944,8 @@ trait Base
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
case self::$UPDATE_TEXTMAGIC_PROVIDER:
|
case self::$UPDATE_TEXTMAGIC_PROVIDER:
|
||||||
return 'mutation updateTextMagicProvider($providerId: String!, $name: String!, $username: String!, $apiKey: String!) {
|
return 'mutation updateTextmagicProvider($providerId: String!, $name: String!, $username: String!, $apiKey: String!) {
|
||||||
messagingUpdateTextMagicProvider(providerId: $providerId, name: $name, username: $username, apiKey: $apiKey) {
|
messagingUpdateTextmagicProvider(providerId: $providerId, name: $name, username: $username, apiKey: $apiKey) {
|
||||||
_id
|
_id
|
||||||
name
|
name
|
||||||
provider
|
provider
|
||||||
|
@ -2044,9 +2044,16 @@ trait Base
|
||||||
return 'mutation createSubscriber($subscriberId: String!, $targetId: String!, $topicId: String!) {
|
return 'mutation createSubscriber($subscriberId: String!, $targetId: String!, $topicId: String!) {
|
||||||
messagingCreateSubscriber(subscriberId: $subscriberId, targetId: $targetId, topicId: $topicId) {
|
messagingCreateSubscriber(subscriberId: $subscriberId, targetId: $targetId, topicId: $topicId) {
|
||||||
_id
|
_id
|
||||||
userId
|
|
||||||
targetId
|
targetId
|
||||||
topicId
|
topicId
|
||||||
|
userName
|
||||||
|
target {
|
||||||
|
_id
|
||||||
|
userId
|
||||||
|
name
|
||||||
|
providerType
|
||||||
|
identifier
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
case self::$LIST_SUBSCRIBERS:
|
case self::$LIST_SUBSCRIBERS:
|
||||||
|
@ -2055,9 +2062,16 @@ trait Base
|
||||||
total
|
total
|
||||||
subscribers {
|
subscribers {
|
||||||
_id
|
_id
|
||||||
userId
|
|
||||||
targetId
|
targetId
|
||||||
topicId
|
topicId
|
||||||
|
userName
|
||||||
|
target {
|
||||||
|
_id
|
||||||
|
userId
|
||||||
|
name
|
||||||
|
providerType
|
||||||
|
identifier
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
|
@ -2065,9 +2079,16 @@ trait Base
|
||||||
return 'query getSubscriber($topicId: String!, $subscriberId: String!) {
|
return 'query getSubscriber($topicId: String!, $subscriberId: String!) {
|
||||||
messagingGetSubscriber(topicId: $topicId, subscriberId: $subscriberId) {
|
messagingGetSubscriber(topicId: $topicId, subscriberId: $subscriberId) {
|
||||||
_id
|
_id
|
||||||
userId
|
|
||||||
targetId
|
targetId
|
||||||
topicId
|
topicId
|
||||||
|
userName
|
||||||
|
target {
|
||||||
|
_id
|
||||||
|
userId
|
||||||
|
name
|
||||||
|
providerType
|
||||||
|
identifier
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
case self::$DELETE_SUBSCRIBER:
|
case self::$DELETE_SUBSCRIBER:
|
||||||
|
@ -2077,13 +2098,13 @@ 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, $deliveryTime: String) {
|
return 'mutation createEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String!, $content: String!, $status: String, $description: String, $html: Boolean, $scheduledAt: String) {
|
||||||
messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) {
|
messagingCreateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, scheduledAt: $scheduledAt) {
|
||||||
_id
|
_id
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2092,13 +2113,13 @@ trait Base
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
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, $deliveryTime: String) {
|
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, deliveryTime: $deliveryTime) {
|
messagingCreateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) {
|
||||||
_id
|
_id
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2107,13 +2128,13 @@ trait Base
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
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, $deliveryTime: 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, $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, deliveryTime: $deliveryTime) {
|
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) {
|
||||||
_id
|
_id
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2127,10 +2148,11 @@ trait Base
|
||||||
total
|
total
|
||||||
messages {
|
messages {
|
||||||
_id
|
_id
|
||||||
|
providerType
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2143,10 +2165,11 @@ trait Base
|
||||||
return 'query getMessage($messageId: String!) {
|
return 'query getMessage($messageId: String!) {
|
||||||
messagingGetMessage(messageId: $messageId) {
|
messagingGetMessage(messageId: $messageId) {
|
||||||
_id
|
_id
|
||||||
|
providerType
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2155,13 +2178,13 @@ trait Base
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
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, $deliveryTime: String) {
|
return 'mutation updateEmail($messageId: String!, $topics: [String!], $users: [String!], $targets: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $scheduledAt: String) {
|
||||||
messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) {
|
messagingUpdateEmail(messageId: $messageId, topics: $topics, users: $users, targets: $targets, subject: $subject, content: $content, status: $status, description: $description, html: $html, scheduledAt: $scheduledAt) {
|
||||||
_id
|
_id
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2170,13 +2193,13 @@ trait Base
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
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, $deliveryTime: String) {
|
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, deliveryTime: $deliveryTime) {
|
messagingUpdateSMS(messageId: $messageId, topics: $topics, users: $users, targets: $targets, content: $content, status: $status, description: $description, scheduledAt: $scheduledAt) {
|
||||||
_id
|
_id
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2185,13 +2208,13 @@ trait Base
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
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, $deliveryTime: 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, $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, deliveryTime: $deliveryTime) {
|
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) {
|
||||||
_id
|
_id
|
||||||
topics
|
topics
|
||||||
users
|
users
|
||||||
targets
|
targets
|
||||||
deliveryTime
|
scheduledAt
|
||||||
deliveredAt
|
deliveredAt
|
||||||
deliveryErrors
|
deliveryErrors
|
||||||
deliveredTotal
|
deliveredTotal
|
||||||
|
@ -2451,7 +2474,7 @@ trait Base
|
||||||
protected string $stdout = '';
|
protected string $stdout = '';
|
||||||
protected string $stderr = '';
|
protected string $stderr = '';
|
||||||
|
|
||||||
protected function packageCode($folder)
|
protected function packageCode($folder): void
|
||||||
{
|
{
|
||||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ class MessagingTest extends Scope
|
||||||
'password' => 'my-password',
|
'password' => 'my-password',
|
||||||
'from' => '+123456789',
|
'from' => '+123456789',
|
||||||
],
|
],
|
||||||
'TextMagic' => [
|
'Textmagic' => [
|
||||||
'providerId' => ID::unique(),
|
'providerId' => ID::unique(),
|
||||||
'name' => 'Textmagic1',
|
'name' => 'Textmagic1',
|
||||||
'username' => 'my-username',
|
'username' => 'my-username',
|
||||||
|
@ -134,7 +134,7 @@ class MessagingTest extends Scope
|
||||||
'username' => 'my-username',
|
'username' => 'my-username',
|
||||||
'password' => 'my-password',
|
'password' => 'my-password',
|
||||||
],
|
],
|
||||||
'TextMagic' => [
|
'Textmagic' => [
|
||||||
'providerId' => $providers[4]['_id'],
|
'providerId' => $providers[4]['_id'],
|
||||||
'name' => 'Textmagic2',
|
'name' => 'Textmagic2',
|
||||||
'username' => 'my-username',
|
'username' => 'my-username',
|
||||||
|
@ -398,7 +398,7 @@ class MessagingTest extends Scope
|
||||||
'providerType' => 'email',
|
'providerType' => 'email',
|
||||||
'userId' => $userId,
|
'userId' => $userId,
|
||||||
'providerId' => $providerId,
|
'providerId' => $providerId,
|
||||||
'identifier' => 'token',
|
'identifier' => 'random-email@mail.org',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
$response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||||
|
@ -409,7 +409,7 @@ class MessagingTest extends Scope
|
||||||
|
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals($userId, $response['body']['data']['usersCreateTarget']['userId']);
|
$this->assertEquals($userId, $response['body']['data']['usersCreateTarget']['userId']);
|
||||||
$this->assertEquals('token', $response['body']['data']['usersCreateTarget']['identifier']);
|
$this->assertEquals('random-email@mail.org', $response['body']['data']['usersCreateTarget']['identifier']);
|
||||||
|
|
||||||
$targetId = $response['body']['data']['usersCreateTarget']['_id'];
|
$targetId = $response['body']['data']['usersCreateTarget']['_id'];
|
||||||
|
|
||||||
|
@ -430,7 +430,7 @@ class MessagingTest extends Scope
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals($response['body']['data']['messagingCreateSubscriber']['topicId'], $topicId);
|
$this->assertEquals($response['body']['data']['messagingCreateSubscriber']['topicId'], $topicId);
|
||||||
$this->assertEquals($response['body']['data']['messagingCreateSubscriber']['targetId'], $targetId);
|
$this->assertEquals($response['body']['data']['messagingCreateSubscriber']['targetId'], $targetId);
|
||||||
$this->assertEquals($response['body']['data']['messagingCreateSubscriber']['userId'], $userId);
|
$this->assertEquals($response['body']['data']['messagingCreateSubscriber']['target']['userId'], $userId);
|
||||||
|
|
||||||
return $response['body']['data']['messagingCreateSubscriber'];
|
return $response['body']['data']['messagingCreateSubscriber'];
|
||||||
}
|
}
|
||||||
|
@ -454,9 +454,9 @@ class MessagingTest extends Scope
|
||||||
]), $graphQLPayload);
|
]), $graphQLPayload);
|
||||||
|
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId'], $subscriber['topicId']);
|
$this->assertEquals($subscriber['topicId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId']);
|
||||||
$this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId'], $subscriber['targetId']);
|
$this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId']);
|
||||||
$this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['userId'], $subscriber['userId']);
|
$this->assertEquals($subscriber['target']['userId'], $response['body']['data']['messagingListSubscribers']['subscribers'][0]['target']['userId']);
|
||||||
$this->assertEquals(1, \count($response['body']['data']['messagingListSubscribers']['subscribers']));
|
$this->assertEquals(1, \count($response['body']['data']['messagingListSubscribers']['subscribers']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +487,7 @@ class MessagingTest extends Scope
|
||||||
$this->assertEquals($subscriberId, $response['body']['data']['messagingGetSubscriber']['_id']);
|
$this->assertEquals($subscriberId, $response['body']['data']['messagingGetSubscriber']['_id']);
|
||||||
$this->assertEquals($topicId, $response['body']['data']['messagingGetSubscriber']['topicId']);
|
$this->assertEquals($topicId, $response['body']['data']['messagingGetSubscriber']['topicId']);
|
||||||
$this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingGetSubscriber']['targetId']);
|
$this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingGetSubscriber']['targetId']);
|
||||||
$this->assertEquals($subscriber['userId'], $response['body']['data']['messagingGetSubscriber']['userId']);
|
$this->assertEquals($subscriber['target']['userId'], $response['body']['data']['messagingGetSubscriber']['target']['userId']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -80,7 +80,7 @@ class UsersTest extends Scope
|
||||||
'userId' => $user['_id'],
|
'userId' => $user['_id'],
|
||||||
'providerType' => 'email',
|
'providerType' => 'email',
|
||||||
'providerId' => $providerId,
|
'providerId' => $providerId,
|
||||||
'identifier' => 'identifier',
|
'identifier' => 'random-email@mail.org',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class UsersTest extends Scope
|
||||||
], $this->getHeaders()), $graphQLPayload);
|
], $this->getHeaders()), $graphQLPayload);
|
||||||
|
|
||||||
$this->assertEquals(200, $target['headers']['status-code']);
|
$this->assertEquals(200, $target['headers']['status-code']);
|
||||||
$this->assertEquals('identifier', $target['body']['data']['usersCreateTarget']['identifier']);
|
$this->assertEquals('random-email@mail.org', $target['body']['data']['usersCreateTarget']['identifier']);
|
||||||
|
|
||||||
return $target['body']['data']['usersCreateTarget'];
|
return $target['body']['data']['usersCreateTarget'];
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,7 @@ class UsersTest extends Scope
|
||||||
|
|
||||||
$this->assertEquals(200, $targets['headers']['status-code']);
|
$this->assertEquals(200, $targets['headers']['status-code']);
|
||||||
$this->assertIsArray($targets['body']['data']['usersListTargets']);
|
$this->assertIsArray($targets['body']['data']['usersListTargets']);
|
||||||
$this->assertCount(1, $targets['body']['data']['usersListTargets']['targets']);
|
$this->assertCount(2, $targets['body']['data']['usersListTargets']['targets']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -271,7 +271,7 @@ class UsersTest extends Scope
|
||||||
], $this->getHeaders()), $graphQLPayload);
|
], $this->getHeaders()), $graphQLPayload);
|
||||||
|
|
||||||
$this->assertEquals(200, $target['headers']['status-code']);
|
$this->assertEquals(200, $target['headers']['status-code']);
|
||||||
$this->assertEquals('identifier', $target['body']['data']['usersGetTarget']['identifier']);
|
$this->assertEquals('random-email@mail.org', $target['body']['data']['usersGetTarget']['identifier']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUpdateUserStatus()
|
public function testUpdateUserStatus()
|
||||||
|
@ -470,7 +470,7 @@ class UsersTest extends Scope
|
||||||
'variables' => [
|
'variables' => [
|
||||||
'userId' => $target['userId'],
|
'userId' => $target['userId'],
|
||||||
'targetId' => $target['_id'],
|
'targetId' => $target['_id'],
|
||||||
'identifier' => 'newidentifier',
|
'identifier' => 'random-email1@mail.org',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ class UsersTest extends Scope
|
||||||
], $this->getHeaders()), $graphQLPayload);
|
], $this->getHeaders()), $graphQLPayload);
|
||||||
|
|
||||||
$this->assertEquals(200, $target['headers']['status-code']);
|
$this->assertEquals(200, $target['headers']['status-code']);
|
||||||
$this->assertEquals('newidentifier', $target['body']['data']['usersUpdateTarget']['identifier']);
|
$this->assertEquals('random-email1@mail.org', $target['body']['data']['usersUpdateTarget']['identifier']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDeleteUserSessions()
|
public function testDeleteUserSessions()
|
||||||
|
|
|
@ -319,7 +319,7 @@ trait MessagingBase
|
||||||
'targetId' => ID::unique(),
|
'targetId' => ID::unique(),
|
||||||
'providerType' => 'email',
|
'providerType' => 'email',
|
||||||
'providerId' => $provider['body']['$id'],
|
'providerId' => $provider['body']['$id'],
|
||||||
'identifier' => 'my-token',
|
'identifier' => 'random-email@mail.org',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(201, $target['headers']['status-code']);
|
$this->assertEquals(201, $target['headers']['status-code']);
|
||||||
|
@ -333,7 +333,8 @@ trait MessagingBase
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(201, $response['headers']['status-code']);
|
$this->assertEquals(201, $response['headers']['status-code']);
|
||||||
$this->assertEquals($target['body']['userId'], $response['body']['userId']);
|
$this->assertEquals($target['body']['userId'], $response['body']['target']['userId']);
|
||||||
|
$this->assertEquals($target['body']['providerType'], $response['body']['target']['providerType']);
|
||||||
|
|
||||||
$topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [
|
$topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
@ -350,7 +351,9 @@ trait MessagingBase
|
||||||
'topicId' => $topic['body']['$id'],
|
'topicId' => $topic['body']['$id'],
|
||||||
'targetId' => $target['body']['$id'],
|
'targetId' => $target['body']['$id'],
|
||||||
'userId' => $target['body']['userId'],
|
'userId' => $target['body']['userId'],
|
||||||
'subscriberId' => $response['body']['$id']
|
'subscriberId' => $response['body']['$id'],
|
||||||
|
'identifier' => $target['body']['identifier'],
|
||||||
|
'providerType' => $target['body']['providerType'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +371,9 @@ trait MessagingBase
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals($data['topicId'], $response['body']['topicId']);
|
$this->assertEquals($data['topicId'], $response['body']['topicId']);
|
||||||
$this->assertEquals($data['targetId'], $response['body']['targetId']);
|
$this->assertEquals($data['targetId'], $response['body']['targetId']);
|
||||||
$this->assertEquals($data['userId'], $response['body']['userId']);
|
$this->assertEquals($data['userId'], $response['body']['target']['userId']);
|
||||||
|
$this->assertEquals($data['providerType'], $response['body']['target']['providerType']);
|
||||||
|
$this->assertEquals($data['identifier'], $response['body']['target']['identifier']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -384,7 +389,9 @@ trait MessagingBase
|
||||||
|
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals(1, $response['body']['total']);
|
$this->assertEquals(1, $response['body']['total']);
|
||||||
$this->assertEquals($data['userId'], $response['body']['subscribers'][0]['userId']);
|
$this->assertEquals($data['userId'], $response['body']['subscribers'][0]['target']['userId']);
|
||||||
|
$this->assertEquals($data['providerType'], $response['body']['subscribers'][0]['target']['providerType']);
|
||||||
|
$this->assertEquals($data['identifier'], $response['body']['subscribers'][0]['target']['identifier']);
|
||||||
$this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']);
|
$this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
|
|
|
@ -23,6 +23,7 @@ trait UsersBase
|
||||||
'password' => 'password',
|
'password' => 'password',
|
||||||
'name' => 'Cristiano Ronaldo',
|
'name' => 'Cristiano Ronaldo',
|
||||||
], false);
|
], false);
|
||||||
|
$this->assertEquals($user['headers']['status-code'], 201);
|
||||||
|
|
||||||
// Test empty prefs is object not array
|
// Test empty prefs is object not array
|
||||||
$bodyString = $user['body'];
|
$bodyString = $user['body'];
|
||||||
|
@ -1245,11 +1246,11 @@ trait UsersBase
|
||||||
'targetId' => ID::unique(),
|
'targetId' => ID::unique(),
|
||||||
'providerId' => $provider['body']['$id'],
|
'providerId' => $provider['body']['$id'],
|
||||||
'providerType' => 'email',
|
'providerType' => 'email',
|
||||||
'identifier' => 'my-token',
|
'identifier' => 'random-email@mail.org',
|
||||||
]);
|
]);
|
||||||
$this->assertEquals(201, $response['headers']['status-code']);
|
$this->assertEquals(201, $response['headers']['status-code']);
|
||||||
$this->assertEquals($provider['body']['$id'], $response['body']['providerId']);
|
$this->assertEquals($provider['body']['$id'], $response['body']['providerId']);
|
||||||
$this->assertEquals('my-token', $response['body']['identifier']);
|
$this->assertEquals('random-email@mail.org', $response['body']['identifier']);
|
||||||
return $response['body'];
|
return $response['body'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1262,10 +1263,10 @@ trait UsersBase
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
'identifier' => 'my-updated-token',
|
'identifier' => 'random-email1@mail.org',
|
||||||
]);
|
]);
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals('my-updated-token', $response['body']['identifier']);
|
$this->assertEquals('random-email1@mail.org', $response['body']['identifier']);
|
||||||
return $response['body'];
|
return $response['body'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1279,7 +1280,7 @@ trait UsersBase
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals(1, \count($response['body']['targets']));
|
$this->assertEquals(2, \count($response['body']['targets']));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1313,7 +1314,7 @@ trait UsersBase
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
|
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals(0, $response['body']['total']);
|
$this->assertEquals(1, $response['body']['total']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue