mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 00:49:02 +00:00
Merge pull request #7132 from appwrite/feat-target-provider-type
Feat target provider type
This commit is contained in:
commit
71b5e1194f
14 changed files with 269 additions and 631 deletions
|
|
@ -1845,7 +1845,7 @@ $commonCollections = [
|
|||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('providerId'),
|
||||
'$id' => ID::custom('providerType'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
|
|
@ -1855,13 +1855,24 @@ $commonCollections = [
|
|||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('providerId'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('providerInternalId'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
|
|
@ -1909,18 +1920,11 @@ $commonCollections = [
|
|||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_identifier'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'type' => Database::INDEX_UNIQUE,
|
||||
'attributes' => ['identifier'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_identifier_providerId'),
|
||||
'type' => Database::INDEX_UNIQUE,
|
||||
'attributes' => ['providerId', 'identifier'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -781,6 +781,11 @@ return [
|
|||
'description' => 'Provider with the requested ID is of incorrect type: ',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::PROVIDER_INTERNAL_UPDATE_DISABLED => [
|
||||
'name' => Exception::PROVIDER_INTERNAL_UPDATE_DISABLED,
|
||||
'description' => 'Provider with the requested ID cannot be disabled.',
|
||||
'code' => 400,
|
||||
],
|
||||
|
||||
/** Topic Errors */
|
||||
Exception::TOPIC_NOT_FOUND => [
|
||||
|
|
|
|||
|
|
@ -148,7 +148,20 @@ App::post('/v1/account')
|
|||
'accessedAt' => DateTime::now(),
|
||||
]);
|
||||
$user->removeAttribute('$internalId');
|
||||
Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||
$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(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerType' => 'email',
|
||||
'identifier' => $email,
|
||||
])));
|
||||
$user->setAttribute('targets', [$target]);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
|
|
@ -656,7 +669,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
'accessedAt' => DateTime::now(),
|
||||
]);
|
||||
$user->removeAttribute('$internalId');
|
||||
Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||
$userDoc = Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||
$dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $userDoc->getId(),
|
||||
'userInternalId' => $userDoc->getInternalId(),
|
||||
'providerType' => 'email',
|
||||
'identifier' => $email,
|
||||
]));
|
||||
} catch (Duplicate) {
|
||||
$failureRedirect(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
|
|
@ -1240,6 +1264,7 @@ App::post('/v1/account/sessions/phone')
|
|||
Query::equal('internal', [true]),
|
||||
Query::equal('type', ['sms'])
|
||||
]));
|
||||
|
||||
if ($provider === false || $provider->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
|
||||
}
|
||||
|
|
@ -1328,17 +1353,21 @@ App::post('/v1/account/sessions/phone')
|
|||
|
||||
$target = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$phone]),
|
||||
Query::equal('providerInternalId', [$provider->getInternalId()])
|
||||
]);
|
||||
|
||||
if (!$target) {
|
||||
if (!$target || $target->isEmpty()) {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerId' => $provider->getId(),
|
||||
'providerInternalId' => $provider->getInternalId(),
|
||||
'providerType' => 'sms',
|
||||
'identifier' => $phone,
|
||||
]));
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
}
|
||||
|
||||
$messageDoc = $dbForProject->createDocument('messages', new Document([
|
||||
|
|
@ -1995,6 +2024,7 @@ App::patch('/v1/account/email')
|
|||
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
|
||||
}
|
||||
|
||||
$oldEmail = $user->getAttribute('email');
|
||||
$email = \strtolower($email);
|
||||
|
||||
// Makes sure this email is not already used in another identity
|
||||
|
|
@ -2019,6 +2049,23 @@ App::patch('/v1/account/email')
|
|||
->setAttribute('passwordUpdate', DateTime::now());
|
||||
}
|
||||
|
||||
$target = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$email]),
|
||||
]);
|
||||
|
||||
if ($target && !$target->isEmpty()) {
|
||||
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Document $oldTarget
|
||||
*/
|
||||
$oldTarget = $user->find('identifier', $oldEmail, 'targets');
|
||||
|
||||
if ($oldTarget !== false && !$oldTarget->isEmpty()) {
|
||||
$dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $email));
|
||||
}
|
||||
|
||||
try {
|
||||
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
||||
} catch (Duplicate) {
|
||||
|
|
@ -2065,6 +2112,19 @@ App::patch('/v1/account/phone')
|
|||
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
|
||||
}
|
||||
|
||||
$target = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$phone]),
|
||||
]);
|
||||
|
||||
if ($target && !$target->isEmpty()) {
|
||||
throw new Exception(Exception::USER_TARGET_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Document $oldTarget
|
||||
*/
|
||||
$oldTarget = $user->find('identifier', $user->getAttribute('phone'), 'targets');
|
||||
|
||||
$user
|
||||
->setAttribute('phone', $phone)
|
||||
->setAttribute('phoneVerification', false) // After this user needs to confirm phone number again
|
||||
|
|
@ -2078,6 +2138,10 @@ App::patch('/v1/account/phone')
|
|||
->setAttribute('passwordUpdate', DateTime::now());
|
||||
}
|
||||
|
||||
if ($oldTarget !== false && !$oldTarget->isEmpty()) {
|
||||
$dbForProject->updateDocument('targets', $oldTarget->getId(), $oldTarget->setAttribute('identifier', $phone));
|
||||
}
|
||||
|
||||
try {
|
||||
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
|
||||
} catch (Duplicate $th) {
|
||||
|
|
@ -2904,6 +2968,7 @@ App::post('/v1/account/verification/phone')
|
|||
Query::equal('internal', [true]),
|
||||
Query::equal('type', ['sms'])
|
||||
]));
|
||||
|
||||
if ($provider === false || $provider->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
|
||||
}
|
||||
|
|
@ -2952,17 +3017,21 @@ App::post('/v1/account/verification/phone')
|
|||
|
||||
$target = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$user->getAttribute('phone')]),
|
||||
Query::equal('providerInternalId', [$provider->getInternalId()])
|
||||
]);
|
||||
|
||||
if (!$target) {
|
||||
if (!$target || $target->isEmpty()) {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerId' => $provider->getId(),
|
||||
'providerInternalId' => $provider->getInternalId(),
|
||||
'providerType' => 'sms',
|
||||
'identifier' => $user->getAttribute('phone'),
|
||||
]));
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
}
|
||||
|
||||
$messageDoc = $dbForProject->createDocument('messages', new Document([
|
||||
|
|
|
|||
|
|
@ -806,14 +806,17 @@ App::patch('/v1/messaging/providers/mailgun/:providerId')
|
|||
]);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
$credentials = $provider->getAttribute('credentials');
|
||||
|
||||
if ($isEuRegion === true || $isEuRegion === false) {
|
||||
|
|
@ -893,14 +896,17 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId')
|
|||
]);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if (!empty($apiKey)) {
|
||||
$provider->setAttribute('credentials', [
|
||||
'apiKey' => $apiKey,
|
||||
|
|
@ -971,14 +977,17 @@ App::patch('/v1/messaging/providers/msg91/:providerId')
|
|||
]);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
$credentials = $provider->getAttribute('credentials');
|
||||
|
||||
if (!empty($senderId)) {
|
||||
|
|
@ -1055,14 +1064,17 @@ App::patch('/v1/messaging/providers/telesign/:providerId')
|
|||
]);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
$credentials = $provider->getAttribute('credentials');
|
||||
|
||||
if (!empty($username)) {
|
||||
|
|
@ -1139,14 +1151,17 @@ App::patch('/v1/messaging/providers/textmagic/:providerId')
|
|||
]);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
$credentials = $provider->getAttribute('credentials');
|
||||
|
||||
if (!empty($username)) {
|
||||
|
|
@ -1223,14 +1238,17 @@ App::patch('/v1/messaging/providers/twilio/:providerId')
|
|||
]);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
$credentials = $provider->getAttribute('credentials');
|
||||
|
||||
if (!empty($accountSid)) {
|
||||
|
|
@ -1307,14 +1325,17 @@ App::patch('/v1/messaging/providers/vonage/:providerId')
|
|||
]);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
$credentials = $provider->getAttribute('credentials');
|
||||
|
||||
if (!empty($apiKey)) {
|
||||
|
|
@ -1383,14 +1404,17 @@ App::patch('/v1/messaging/providers/fcm/:providerId')
|
|||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if (!empty($serverKey)) {
|
||||
$provider->setAttribute('credentials', ['serverKey' => $serverKey]);
|
||||
}
|
||||
|
|
@ -1456,14 +1480,17 @@ App::patch('/v1/messaging/providers/apns/:providerId')
|
|||
$provider->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
if ($internal === true) {
|
||||
$provider->setAttribute('internal', $internal);
|
||||
}
|
||||
|
||||
if ($enabled === true || $enabled === false) {
|
||||
if ($provider->getAttribute('internal') === true && $enabled === false) {
|
||||
throw new Exception(Exception::PROVIDER_INTERNAL_UPDATE_DISABLED);
|
||||
}
|
||||
$provider->setAttribute('enabled', $enabled);
|
||||
}
|
||||
|
||||
$credentials = $provider->getAttribute('credentials');
|
||||
|
||||
if (!empty($authKey)) {
|
||||
|
|
|
|||
|
|
@ -650,8 +650,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'userId' => $invitee->getId(),
|
||||
'userInternalId' => $invitee->getInternalId(),
|
||||
'providerId' => $provider->getId(),
|
||||
'providerInternalId' => $provider->getInternalId(),
|
||||
'providerType' => 'sms',
|
||||
'identifier' => $phone,
|
||||
]));
|
||||
|
||||
|
|
|
|||
|
|
@ -394,18 +394,25 @@ App::post('/v1/users/:userId/targets')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->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('userId', '', new UID(), 'User ID.')
|
||||
->param('targetId', '', new UID(), 'Target ID.')
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerType', '', new WhiteList(['email', 'sms', '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('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)
|
||||
->inject('queueForEvents')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, string $targetId, string $providerId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
->action(function (string $targetId, string $userId, string $providerType, string $identifier, string $providerId, Event $queueForEvents, Response $response, Database $dbForProject) {
|
||||
$targetId = $targetId == 'unique()' ? ID::unique() : $targetId;
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
$provider = new Document();
|
||||
|
||||
if ($providerType === 'push') {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
|
@ -423,8 +430,9 @@ App::post('/v1/users/:userId/targets')
|
|||
try {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$id' => $targetId,
|
||||
'providerId' => $providerId,
|
||||
'providerInternalId' => $provider->getInternalId(),
|
||||
'providerId' => $providerId ?? null,
|
||||
'providerInternalId' => $provider->getInternalId() ?? null,
|
||||
'providerType' => $providerType,
|
||||
'userId' => $userId,
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'identifier' => $identifier,
|
||||
|
|
@ -1223,8 +1231,8 @@ App::patch('/v1/users/:userId/prefs')
|
|||
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
|
||||
});
|
||||
|
||||
App::patch('/v1/users/:userId/targets/:targetId/identifier')
|
||||
->desc('Update user target\'s identifier')
|
||||
App::patch('/v1/users/:userId/targets/:targetId')
|
||||
->desc('Update User target')
|
||||
->groups(['api', 'users'])
|
||||
->label('audits.event', 'target.update')
|
||||
->label('audits.resource', 'target/{response.$id}')
|
||||
|
|
@ -1232,19 +1240,19 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier')
|
|||
->label('scope', 'targets.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'users')
|
||||
->label('sdk.method', 'updateTargetIdentifier')
|
||||
->label('sdk.description', '/docs/references/users/update-target-identifier.md')
|
||||
->label('sdk.method', 'updateTarget')
|
||||
->label('sdk.description', '/docs/references/users/update-target.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TARGET)
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('targetId', '', new UID(), 'Target ID.')
|
||||
->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('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true)
|
||||
->inject('queueForEvents')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, string $targetId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) {
|
||||
|
||||
->action(function (string $userId, string $targetId, string $providerId, string $identifier, Event $queueForEvents, Response $response, Database $dbForProject) {
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty()) {
|
||||
|
|
@ -1261,7 +1269,20 @@ App::patch('/v1/users/:userId/targets/:targetId/identifier')
|
|||
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$target->setAttribute('identifier', $identifier);
|
||||
if ($identifier) {
|
||||
$target->setAttribute('identifier', $identifier);
|
||||
}
|
||||
|
||||
if ($providerId) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
|
||||
if ($provider->isEmpty()) {
|
||||
throw new Exception(Exception::PROVIDER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$target->setAttribute('providerId', $provider->getId());
|
||||
$target->setAttribute('providerInternalId', $provider->getInternalId());
|
||||
}
|
||||
|
||||
$target = $dbForProject->updateDocument('targets', $target->getId(), $target);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ class Exception extends \Exception
|
|||
public const PROVIDER_NOT_FOUND = 'provider_not_found';
|
||||
public const PROVIDER_ALREADY_EXISTS = 'provider_already_exists';
|
||||
public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type';
|
||||
public const PROVIDER_INTERNAL_UPDATE_DISABLED = 'provider_internal_update_disabled';
|
||||
|
||||
/** Topic */
|
||||
public const TOPIC_NOT_FOUND = 'topic_not_found';
|
||||
|
|
|
|||
|
|
@ -98,6 +98,11 @@ class Messaging extends Action
|
|||
$recipients = \array_merge($recipients, $targets);
|
||||
}
|
||||
|
||||
$internalProvider = $dbForProject->findOne('providers', [
|
||||
Query::equal('internal', [true]),
|
||||
Query::equal('type', [$recipients[0]->getAttribute('providerType')]),
|
||||
]);
|
||||
|
||||
/**
|
||||
* @var array<string, array<string>> $identifiersByProviderId
|
||||
*/
|
||||
|
|
@ -109,6 +114,11 @@ class Messaging extends Action
|
|||
$providers = [];
|
||||
foreach ($recipients as $recipient) {
|
||||
$providerId = $recipient->getAttribute('providerId');
|
||||
|
||||
if (!$providerId) {
|
||||
$providerId = $internalProvider->getId();
|
||||
}
|
||||
|
||||
if (!isset($identifiersByProviderId[$providerId])) {
|
||||
$identifiersByProviderId[$providerId] = [];
|
||||
}
|
||||
|
|
@ -118,17 +128,26 @@ class Messaging extends Action
|
|||
/**
|
||||
* @var array[] $results
|
||||
*/
|
||||
$results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $message, $dbForProject) {
|
||||
return function () use ($providerId, $identifiersByProviderId, $providers, $message, $dbForProject) {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
$results = batch(\array_map(function ($providerId) use ($identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) {
|
||||
return function () use ($providerId, $identifiersByProviderId, $providers, $internalProvider, $message, $dbForProject) {
|
||||
$provider = new Document();
|
||||
|
||||
if ($internalProvider->getId() === $providerId) {
|
||||
$provider = $internalProvider;
|
||||
} else {
|
||||
$provider = $dbForProject->getDocument('providers', $providerId);
|
||||
}
|
||||
|
||||
$providers[] = $provider;
|
||||
$identifiers = $identifiersByProviderId[$providerId];
|
||||
|
||||
$adapter = match ($provider->getAttribute('type')) {
|
||||
'sms' => $this->sms($provider),
|
||||
'push' => $this->push($provider),
|
||||
'email' => $this->email($provider),
|
||||
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
||||
};
|
||||
|
||||
$maxBatchSize = $adapter->getMaxMessagesPerRequest();
|
||||
$batches = \array_chunk($identifiers, $maxBatchSize);
|
||||
$batchIndex = 0;
|
||||
|
|
@ -139,12 +158,14 @@ class Messaging extends Action
|
|||
$deliveryErrors = [];
|
||||
$messageData = clone $message;
|
||||
$messageData->setAttribute('to', $batch);
|
||||
|
||||
$data = match ($provider->getAttribute('type')) {
|
||||
'sms' => $this->buildSMSMessage($messageData, $provider),
|
||||
'push' => $this->buildPushMessage($messageData),
|
||||
'email' => $this->buildEmailMessage($messageData, $provider),
|
||||
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
||||
};
|
||||
|
||||
try {
|
||||
$adapter->send($data);
|
||||
$deliveredTotal += \count($batch);
|
||||
|
|
@ -168,10 +189,12 @@ class Messaging extends Action
|
|||
|
||||
$deliveredTotal = 0;
|
||||
$deliveryErrors = [];
|
||||
|
||||
foreach ($results as $result) {
|
||||
$deliveredTotal += $result['deliveredTotal'];
|
||||
$deliveryErrors = \array_merge($deliveryErrors, $result['deliveryErrors']);
|
||||
}
|
||||
|
||||
$message->setAttribute('deliveryErrors', $deliveryErrors);
|
||||
|
||||
if (\count($message->getAttribute('deliveryErrors')) > 0) {
|
||||
|
|
@ -179,6 +202,7 @@ class Messaging extends Action
|
|||
} else {
|
||||
$message->setAttribute('status', 'sent');
|
||||
}
|
||||
|
||||
$message->removeAttribute('to');
|
||||
|
||||
foreach ($providers as $provider) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,12 @@ class Target extends Model
|
|||
'default' => '',
|
||||
'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' => 'email',
|
||||
])
|
||||
->addRule('identifier', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The target identifier.',
|
||||
|
|
|
|||
|
|
@ -934,10 +934,11 @@ trait Base
|
|||
}
|
||||
}';
|
||||
case self::$CREATE_USER_TARGET:
|
||||
return 'mutation createUserTarget($userId: String!, $targetId: String!, $providerId: String!, $identifier: String!){
|
||||
usersCreateTarget(userId: $userId, targetId: $targetId, providerId: $providerId, identifier: $identifier) {
|
||||
return 'mutation createUserTarget($userId: String!, $targetId: String!, $providerType: String!, $identifier: String! $providerId: String){
|
||||
usersCreateTarget(userId: $userId, targetId: $targetId, providerType: $providerType, identifier: $identifier, providerId: $providerId) {
|
||||
_id
|
||||
userId
|
||||
providerType
|
||||
providerId
|
||||
identifier
|
||||
}
|
||||
|
|
@ -949,6 +950,7 @@ trait Base
|
|||
targets {
|
||||
_id
|
||||
userId
|
||||
providerType
|
||||
providerId
|
||||
identifier
|
||||
}
|
||||
|
|
@ -959,15 +961,17 @@ trait Base
|
|||
usersGetTarget(userId: $userId, targetId: $targetId) {
|
||||
_id
|
||||
userId
|
||||
providerType
|
||||
providerId
|
||||
identifier
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_USER_TARGET:
|
||||
return 'mutation updateUserTarget($userId: String!, $targetId: String!, $identifier: String!){
|
||||
usersUpdateTargetIdentifier(userId: $userId, targetId: $targetId, identifier: $identifier) {
|
||||
return 'mutation updateUserTarget($userId: String!, $targetId: String!, $providerId: String, $identifier: String){
|
||||
usersUpdateTarget(userId: $userId, targetId: $targetId, providerId: $providerId, identifier: $identifier) {
|
||||
_id
|
||||
userId
|
||||
providerType
|
||||
providerId
|
||||
identifier
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ class MessagingTest extends Scope
|
|||
'query' => $query,
|
||||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'email',
|
||||
'userId' => $userId,
|
||||
'providerId' => $providerId,
|
||||
'identifier' => 'token',
|
||||
|
|
@ -604,6 +605,7 @@ class MessagingTest extends Scope
|
|||
'query' => $query,
|
||||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'email',
|
||||
'userId' => $user['body']['data']['usersCreate']['_id'],
|
||||
'providerId' => $providerId,
|
||||
'identifier' => $to,
|
||||
|
|
@ -678,119 +680,13 @@ class MessagingTest extends Scope
|
|||
*/
|
||||
public function testUpdateEmail(array $email)
|
||||
{
|
||||
if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) {
|
||||
$this->markTestSkipped('Email DSN not provided');
|
||||
}
|
||||
|
||||
$emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'));
|
||||
$to = $emailDSN->getParam('to');
|
||||
$from = $emailDSN->getParam('from');
|
||||
$isEuRegion = $emailDSN->getParam('isEuRegion');
|
||||
$apiKey = $emailDSN->getPassword();
|
||||
$domain = $emailDSN->getUser();
|
||||
|
||||
if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) {
|
||||
$this->markTestSkipped('Email provider not configured');
|
||||
}
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_MAILGUN_PROVIDER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'providerId' => ID::unique(),
|
||||
'name' => 'Mailgun2',
|
||||
'apiKey' => $apiKey,
|
||||
'domain' => $domain,
|
||||
'from' => $from,
|
||||
'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN),
|
||||
],
|
||||
];
|
||||
$provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $provider['headers']['status-code']);
|
||||
|
||||
$providerId = $provider['body']['data']['messagingCreateMailgunProvider']['_id'];
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_TOPIC);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'topicId' => ID::unique(),
|
||||
'name' => 'topic1',
|
||||
'description' => 'Active users',
|
||||
],
|
||||
];
|
||||
$topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $topic['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_USER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'userId' => ID::unique(),
|
||||
'email' => 'random2-mail@mail.org',
|
||||
'password' => 'password',
|
||||
'name' => 'Messaging User',
|
||||
]
|
||||
];
|
||||
$user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $user['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_USER_TARGET);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'userId' => $user['body']['data']['usersCreate']['_id'],
|
||||
'providerId' => $providerId,
|
||||
'identifier' => $to,
|
||||
],
|
||||
];
|
||||
$target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $target['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_SUBSCRIBER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'subscriberId' => ID::unique(),
|
||||
'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'],
|
||||
'targetId' => $target['body']['data']['usersCreateTarget']['_id'],
|
||||
],
|
||||
];
|
||||
$subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $subscriber['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_EMAIL);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'messageId' => ID::unique(),
|
||||
'status' => 'draft',
|
||||
'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']],
|
||||
'topics' => [$email['topics'][0]],
|
||||
'subject' => 'Khali beats Undertaker',
|
||||
'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||
],
|
||||
|
|
@ -916,6 +812,7 @@ class MessagingTest extends Scope
|
|||
'query' => $query,
|
||||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'sms',
|
||||
'userId' => $user['body']['data']['usersCreate']['_id'],
|
||||
'providerId' => $providerId,
|
||||
'identifier' => $to,
|
||||
|
|
@ -988,117 +885,13 @@ class MessagingTest extends Scope
|
|||
*/
|
||||
public function testUpdateSMS(array $sms)
|
||||
{
|
||||
if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) {
|
||||
$this->markTestSkipped('SMS DSN not provided');
|
||||
}
|
||||
|
||||
$smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'));
|
||||
$to = $smsDSN->getParam('to');
|
||||
$from = $smsDSN->getParam('from');
|
||||
$authKey = $smsDSN->getPassword();
|
||||
$senderId = $smsDSN->getUser();
|
||||
|
||||
if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) {
|
||||
$this->markTestSkipped('SMS provider not configured');
|
||||
}
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_MSG91_PROVIDER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'providerId' => ID::unique(),
|
||||
'name' => 'Msg91-2',
|
||||
'senderId' => $senderId,
|
||||
'authKey' => $authKey,
|
||||
'from' => $from,
|
||||
],
|
||||
];
|
||||
$provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $provider['headers']['status-code']);
|
||||
|
||||
$providerId = $provider['body']['data']['messagingCreateMsg91Provider']['_id'];
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_TOPIC);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'topicId' => ID::unique(),
|
||||
'name' => 'topic1',
|
||||
'description' => 'Active users',
|
||||
],
|
||||
];
|
||||
$topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $topic['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_USER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'userId' => ID::unique(),
|
||||
'email' => 'random4-email@mail.org',
|
||||
'password' => 'password',
|
||||
'name' => 'Messaging User',
|
||||
]
|
||||
];
|
||||
$user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $user['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_USER_TARGET);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'userId' => $user['body']['data']['usersCreate']['_id'],
|
||||
'providerId' => $providerId,
|
||||
'identifier' => $to,
|
||||
],
|
||||
];
|
||||
$target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $target['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_SUBSCRIBER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'subscriberId' => ID::unique(),
|
||||
'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'],
|
||||
'targetId' => $target['body']['data']['usersCreateTarget']['_id'],
|
||||
],
|
||||
];
|
||||
$subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $subscriber['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_SMS);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'messageId' => ID::unique(),
|
||||
'status' => 'draft',
|
||||
'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']],
|
||||
'topics' => [$sms['topics'][0]],
|
||||
'content' => '345463',
|
||||
],
|
||||
];
|
||||
|
|
@ -1219,6 +1012,7 @@ class MessagingTest extends Scope
|
|||
'query' => $query,
|
||||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'push',
|
||||
'userId' => $user['body']['data']['usersCreate']['_id'],
|
||||
'providerId' => $providerId,
|
||||
'identifier' => $to,
|
||||
|
|
@ -1293,112 +1087,13 @@ class MessagingTest extends Scope
|
|||
*/
|
||||
public function testUpdatePushNotification(array $push)
|
||||
{
|
||||
if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) {
|
||||
$this->markTestSkipped('Push DSN empty');
|
||||
}
|
||||
|
||||
$pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'));
|
||||
$to = $pushDSN->getParam('to');
|
||||
$serverKey = $pushDSN->getPassword();
|
||||
|
||||
if (empty($to) || empty($serverKey)) {
|
||||
$this->markTestSkipped('Push provider not configured');
|
||||
}
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_FCM_PROVIDER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'providerId' => ID::unique(),
|
||||
'name' => 'FCM2',
|
||||
'serverKey' => $serverKey,
|
||||
],
|
||||
];
|
||||
$provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $provider['headers']['status-code']);
|
||||
$providerId = $provider['body']['data']['messagingCreateFcmProvider']['_id'];
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_TOPIC);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'topicId' => ID::unique(),
|
||||
'name' => 'topic1',
|
||||
'description' => 'Active users',
|
||||
],
|
||||
];
|
||||
$topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $topic['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_USER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'userId' => ID::unique(),
|
||||
'email' => 'random5-email@mail.org',
|
||||
'password' => 'password',
|
||||
'name' => 'Messaging User',
|
||||
]
|
||||
];
|
||||
$user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $user['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_USER_TARGET);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'userId' => $user['body']['data']['usersCreate']['_id'],
|
||||
'providerId' => $providerId,
|
||||
'identifier' => $to,
|
||||
],
|
||||
];
|
||||
$target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $target['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_SUBSCRIBER);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'subscriberId' => ID::unique(),
|
||||
'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'],
|
||||
'targetId' => $target['body']['data']['usersCreateTarget']['_id'],
|
||||
],
|
||||
];
|
||||
$subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $subscriber['headers']['status-code']);
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_PUSH_NOTIFICATION);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'messageId' => ID::unique(),
|
||||
'status' => 'draft',
|
||||
'topics' => [$topic['body']['data']['messagingCreateTopic']['_id']],
|
||||
'topics' => [$push['topics'][0]],
|
||||
'title' => 'Push Notification Title',
|
||||
'body' => 'Push Notifiaction Body',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ class UsersTest extends Scope
|
|||
'variables' => [
|
||||
'targetId' => ID::unique(),
|
||||
'userId' => $user['_id'],
|
||||
'providerType' => 'email',
|
||||
'providerId' => $providerId,
|
||||
'identifier' => 'identifier',
|
||||
]
|
||||
|
|
@ -479,7 +480,7 @@ class UsersTest extends Scope
|
|||
], $this->getHeaders()), $graphQLPayload);
|
||||
|
||||
$this->assertEquals(200, $target['headers']['status-code']);
|
||||
$this->assertEquals('newidentifier', $target['body']['data']['usersUpdateTargetIdentifier']['identifier']);
|
||||
$this->assertEquals('newidentifier', $target['body']['data']['usersUpdateTarget']['identifier']);
|
||||
}
|
||||
|
||||
public function testDeleteUserSessions()
|
||||
|
|
|
|||
|
|
@ -317,6 +317,7 @@ trait MessagingBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'email',
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'identifier' => 'my-token',
|
||||
]);
|
||||
|
|
@ -558,6 +559,7 @@ trait MessagingBase
|
|||
'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN),
|
||||
'from' => $from
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $provider['headers']['status-code']);
|
||||
|
||||
// Create Topic
|
||||
|
|
@ -570,6 +572,7 @@ trait MessagingBase
|
|||
'name' => 'topic1',
|
||||
'description' => 'Test Topic'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $topic['headers']['status-code']);
|
||||
|
||||
// Create User
|
||||
|
|
@ -593,6 +596,7 @@ trait MessagingBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'email',
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'identifier' => $to,
|
||||
]);
|
||||
|
|
@ -645,21 +649,6 @@ trait MessagingBase
|
|||
*/
|
||||
public function testUpdateEmail(array $email)
|
||||
{
|
||||
if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) {
|
||||
$this->markTestSkipped('Email DSN not provided');
|
||||
}
|
||||
|
||||
$emailDSN = new DSN(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'));
|
||||
$to = $emailDSN->getParam('to');
|
||||
$from = $emailDSN->getParam('from');
|
||||
$isEuRegion = $emailDSN->getParam('isEuRegion');
|
||||
$apiKey = $emailDSN->getPassword();
|
||||
$domain = $emailDSN->getUser();
|
||||
|
||||
if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) {
|
||||
$this->markTestSkipped('Email provider not configured');
|
||||
}
|
||||
|
||||
$message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
@ -669,71 +658,6 @@ trait MessagingBase
|
|||
// Test failure as the message has already been sent.
|
||||
$this->assertEquals(400, $message['headers']['status-code']);
|
||||
|
||||
// Create provider
|
||||
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/mailgun', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'providerId' => ID::unique(),
|
||||
'name' => 'Mailgun-provider-2',
|
||||
'apiKey' => $apiKey,
|
||||
'domain' => $domain,
|
||||
'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN),
|
||||
'from' => $from
|
||||
]);
|
||||
$this->assertEquals(201, $provider['headers']['status-code']);
|
||||
|
||||
// Create Topic
|
||||
$topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'topicId' => ID::unique(),
|
||||
'name' => 'topic1',
|
||||
'description' => 'Test Topic'
|
||||
]);
|
||||
$this->assertEquals(201, $topic['headers']['status-code']);
|
||||
|
||||
// Create User
|
||||
$user = $this->client->call(Client::METHOD_POST, '/users', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'userId' => ID::unique(),
|
||||
'email' => 'random-email@mail.org',
|
||||
'password' => 'password',
|
||||
'name' => 'Messaging User',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $user['headers']['status-code']);
|
||||
|
||||
// Create Target
|
||||
$target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'targetId' => ID::unique(),
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'identifier' => $to,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $target['headers']['status-code']);
|
||||
|
||||
// Create Subscriber
|
||||
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'subscriberId' => ID::unique(),
|
||||
'targetId' => $target['body']['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $subscriber['headers']['status-code']);
|
||||
|
||||
// Create Email
|
||||
$email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -742,7 +666,7 @@ trait MessagingBase
|
|||
], [
|
||||
'messageId' => ID::unique(),
|
||||
'status' => 'draft',
|
||||
'topics' => [$topic['body']['$id']],
|
||||
'topics' => [$email['body']['topics'][0]],
|
||||
'subject' => 'Khali beats Undertaker',
|
||||
'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||
]);
|
||||
|
|
@ -801,6 +725,7 @@ trait MessagingBase
|
|||
'authKey' => $authKey,
|
||||
'from' => $from
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $provider['headers']['status-code']);
|
||||
|
||||
// Create Topic
|
||||
|
|
@ -813,6 +738,7 @@ trait MessagingBase
|
|||
'name' => 'topic1',
|
||||
'description' => 'Test Topic'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $topic['headers']['status-code']);
|
||||
|
||||
// Create User
|
||||
|
|
@ -836,6 +762,7 @@ trait MessagingBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'sms',
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'identifier' => $to,
|
||||
]);
|
||||
|
|
@ -887,20 +814,6 @@ trait MessagingBase
|
|||
*/
|
||||
public function testUpdateSMS(array $sms)
|
||||
{
|
||||
if (empty(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'))) {
|
||||
$this->markTestSkipped('SMS DSN not provided');
|
||||
}
|
||||
|
||||
$smsDSN = new DSN(App::getEnv('_APP_MESSAGE_SMS_TEST_DSN'));
|
||||
$to = $smsDSN->getParam('to');
|
||||
$from = $smsDSN->getParam('from');
|
||||
$authKey = $smsDSN->getPassword();
|
||||
$senderId = $smsDSN->getUser();
|
||||
|
||||
if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) {
|
||||
$this->markTestSkipped('SMS provider not configured');
|
||||
}
|
||||
|
||||
$message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/sms/' . $sms['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
@ -910,70 +823,6 @@ trait MessagingBase
|
|||
// Test failure as the message has already been sent.
|
||||
$this->assertEquals(400, $message['headers']['status-code']);
|
||||
|
||||
// Create provider
|
||||
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'providerId' => ID::unique(),
|
||||
'name' => 'Msg91-2',
|
||||
'senderId' => $senderId,
|
||||
'authKey' => $authKey,
|
||||
'from' => $from
|
||||
]);
|
||||
$this->assertEquals(201, $provider['headers']['status-code']);
|
||||
|
||||
// Create Topic
|
||||
$topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'topicId' => ID::unique(),
|
||||
'name' => 'topic1',
|
||||
'description' => 'Test Topic'
|
||||
]);
|
||||
$this->assertEquals(201, $topic['headers']['status-code']);
|
||||
|
||||
// Create User
|
||||
$user = $this->client->call(Client::METHOD_POST, '/users', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'userId' => ID::unique(),
|
||||
'email' => 'random2-email@mail.org',
|
||||
'password' => 'password',
|
||||
'name' => 'Messaging User',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $user['headers']['status-code']);
|
||||
|
||||
// Create Target
|
||||
$target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'targetId' => ID::unique(),
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'identifier' => $to,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $target['headers']['status-code']);
|
||||
|
||||
// Create Subscriber
|
||||
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'subscriberId' => ID::unique(),
|
||||
'targetId' => $target['body']['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $subscriber['headers']['status-code']);
|
||||
|
||||
// Create SMS
|
||||
$sms = $this->client->call(Client::METHOD_POST, '/messaging/messages/sms', [
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -982,7 +831,7 @@ trait MessagingBase
|
|||
], [
|
||||
'messageId' => ID::unique(),
|
||||
'status' => 'draft',
|
||||
'topics' => [$topic['body']['$id']],
|
||||
'topics' => [$sms['body']['topics'][0]],
|
||||
'content' => '047487',
|
||||
]);
|
||||
|
||||
|
|
@ -1036,6 +885,7 @@ trait MessagingBase
|
|||
'name' => 'FCM-1',
|
||||
'serverKey' => $serverKey,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $provider['headers']['status-code']);
|
||||
|
||||
// Create Topic
|
||||
|
|
@ -1048,6 +898,7 @@ trait MessagingBase
|
|||
'name' => 'topic1',
|
||||
'description' => 'Test Topic'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $topic['headers']['status-code']);
|
||||
|
||||
// Create User
|
||||
|
|
@ -1071,6 +922,7 @@ trait MessagingBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'targetId' => ID::unique(),
|
||||
'providerType' => 'push',
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'identifier' => $to,
|
||||
]);
|
||||
|
|
@ -1123,18 +975,6 @@ trait MessagingBase
|
|||
*/
|
||||
public function testUpdatePushNotification(array $push)
|
||||
{
|
||||
if (empty(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'))) {
|
||||
$this->markTestSkipped('Push DSN empty');
|
||||
}
|
||||
|
||||
$pushDSN = new DSN(App::getEnv('_APP_MESSAGE_PUSH_TEST_DSN'));
|
||||
$to = $pushDSN->getParam('to');
|
||||
$serverKey = $pushDSN->getPassword();
|
||||
|
||||
if (empty($to) || empty($serverKey)) {
|
||||
$this->markTestSkipped('Push provider not configured');
|
||||
}
|
||||
|
||||
$message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/push/' . $push['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
@ -1144,68 +984,6 @@ trait MessagingBase
|
|||
// Test failure as the message has already been sent.
|
||||
$this->assertEquals(400, $message['headers']['status-code']);
|
||||
|
||||
// Create provider
|
||||
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/fcm', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'providerId' => ID::unique(),
|
||||
'name' => 'FCM-2',
|
||||
'serverKey' => $serverKey,
|
||||
]);
|
||||
$this->assertEquals(201, $provider['headers']['status-code']);
|
||||
|
||||
// Create Topic
|
||||
$topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'topicId' => ID::unique(),
|
||||
'name' => 'topic1',
|
||||
'description' => 'Test Topic'
|
||||
]);
|
||||
$this->assertEquals(201, $topic['headers']['status-code']);
|
||||
|
||||
// Create User
|
||||
$user = $this->client->call(Client::METHOD_POST, '/users', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'userId' => ID::unique(),
|
||||
'email' => 'random4-email@mail.org',
|
||||
'password' => 'password',
|
||||
'name' => 'Messaging User',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $user['headers']['status-code']);
|
||||
|
||||
// Create Target
|
||||
$target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'targetId' => ID::unique(),
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'identifier' => $to,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $target['headers']['status-code']);
|
||||
|
||||
// Create Subscriber
|
||||
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'subscriberId' => ID::unique(),
|
||||
'targetId' => $target['body']['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $subscriber['headers']['status-code']);
|
||||
|
||||
// Create push notification
|
||||
$push = $this->client->call(Client::METHOD_POST, '/messaging/messages/push', [
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -1214,7 +992,7 @@ trait MessagingBase
|
|||
], [
|
||||
'messageId' => ID::unique(),
|
||||
'status' => 'draft',
|
||||
'topics' => [$topic['body']['$id']],
|
||||
'topics' => [$push['body']['topics'][0]],
|
||||
'title' => 'Test-Notification',
|
||||
'body' => 'Test-Notification-Body',
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -1232,7 +1232,7 @@ trait UsersBase
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'providerId' => 'unique()',
|
||||
'providerId' => ID::unique(),
|
||||
'name' => 'Sengrid1',
|
||||
'apiKey' => 'my-apikey',
|
||||
'from' => 'from@domain.com',
|
||||
|
|
@ -1244,6 +1244,7 @@ trait UsersBase
|
|||
], $this->getHeaders()), [
|
||||
'targetId' => ID::unique(),
|
||||
'providerId' => $provider['body']['$id'],
|
||||
'providerType' => 'email',
|
||||
'identifier' => 'my-token',
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
|
@ -1257,7 +1258,7 @@ trait UsersBase
|
|||
*/
|
||||
public function testUpdateUserTarget(array $data): array
|
||||
{
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'] . '/identifier', array_merge([
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/targets/' . $data['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
|
|
@ -1303,11 +1304,14 @@ trait UsersBase
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(0, $response['body']['total']);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue