Merge pull request #7589 from appwrite/feat-topic-totals-per-type
Feat topic totals per type
This commit is contained in:
commit
81532a026c
12 changed files with 160 additions and 17 deletions
|
@ -1903,7 +1903,29 @@ $commonCollections = [
|
|||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('total'),
|
||||
'$id' => ID::custom('emailTotal'),
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => 0,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('smsTotal'),
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => 0,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('pushTotal'),
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
|
|
|
@ -872,7 +872,7 @@ return [
|
|||
],
|
||||
Exception::MESSAGE_MISSING_TARGET => [
|
||||
'name' => Exception::MESSAGE_MISSING_TARGET,
|
||||
'description' => 'Message with the requested ID is missing a target (Topics or Users or Targets).',
|
||||
'description' => 'Message with the requested ID has no recipients (topics or users or targets).',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::MESSAGE_ALREADY_SENT => [
|
||||
|
@ -920,4 +920,11 @@ return [
|
|||
'description' => 'Schedule with the requested ID could not be found.',
|
||||
'code' => 404,
|
||||
],
|
||||
|
||||
/** Targets */
|
||||
Exception::TARGET_PROVIDER_INVALID_TYPE => [
|
||||
'name' => Exception::TARGET_PROVIDER_INVALID_TYPE,
|
||||
'description' => 'Target has an invalid provider type.',
|
||||
'code' => 400,
|
||||
],
|
||||
];
|
||||
|
|
|
@ -163,6 +163,11 @@ App::post('/v1/account')
|
|||
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||
try {
|
||||
$target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerType' => MESSAGE_TYPE_EMAIL,
|
||||
|
@ -707,7 +712,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$userDoc = Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||
$dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
|
@ -1699,6 +1704,11 @@ App::post('/v1/account/tokens/phone')
|
|||
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
|
||||
try {
|
||||
$target = Authorization::skip(fn() => $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerType' => MESSAGE_TYPE_SMS,
|
||||
|
|
|
@ -2260,7 +2260,19 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
|
|||
|
||||
try {
|
||||
$subscriber = $dbForProject->createDocument('subscribers', $subscriber);
|
||||
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('topics', $topicId, 'total', 1));
|
||||
|
||||
$totalAttribute = match ($target->getAttribute('providerType')) {
|
||||
MESSAGE_TYPE_EMAIL => 'emailTotal',
|
||||
MESSAGE_TYPE_SMS => 'smsTotal',
|
||||
MESSAGE_TYPE_PUSH => 'pushTotal',
|
||||
default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE),
|
||||
};
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute(
|
||||
'topics',
|
||||
$topicId,
|
||||
$totalAttribute,
|
||||
));
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS);
|
||||
}
|
||||
|
@ -2311,7 +2323,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
|||
throw new Exception(Exception::TOPIC_NOT_FOUND);
|
||||
}
|
||||
|
||||
\array_push($queries, Query::equal('topicInternalId', [$topic->getInternalId()]));
|
||||
$queries[] = Query::equal('topicInternalId', [$topic->getInternalId()]);
|
||||
|
||||
/**
|
||||
* Get cursor document if there was a cursor query, we use array_filter and reset for reference $cursor to $queries
|
||||
|
@ -2512,8 +2524,23 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
|||
throw new Exception(Exception::SUBSCRIBER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$target = $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId'));
|
||||
|
||||
$dbForProject->deleteDocument('subscribers', $subscriberId);
|
||||
Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('topics', $topicId, 'total', 1));
|
||||
|
||||
$totalAttribute = match ($target->getAttribute('providerType')) {
|
||||
MESSAGE_TYPE_EMAIL => 'emailTotal',
|
||||
MESSAGE_TYPE_SMS => 'smsTotal',
|
||||
MESSAGE_TYPE_PUSH => 'pushTotal',
|
||||
default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE),
|
||||
};
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute(
|
||||
'topics',
|
||||
$topicId,
|
||||
$totalAttribute,
|
||||
min: 0
|
||||
));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('topicId', $topic->getId())
|
||||
|
|
|
@ -115,6 +115,11 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
|||
if ($email) {
|
||||
try {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerType' => 'email',
|
||||
|
@ -132,6 +137,11 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
|||
if ($phone) {
|
||||
try {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerType' => 'sms',
|
||||
|
@ -498,6 +508,11 @@ App::post('/v1/users/:userId/targets')
|
|||
try {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$id' => $targetId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'providerId' => $providerId ?? null,
|
||||
'providerInternalId' => $provider->getInternalId() ?? null,
|
||||
'providerType' => $providerType,
|
||||
|
@ -1227,6 +1242,11 @@ App::patch('/v1/users/:userId/email')
|
|||
} else {
|
||||
if (\strlen($email) !== 0) {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerType' => 'email',
|
||||
|
@ -1305,6 +1325,11 @@ App::patch('/v1/users/:userId/phone')
|
|||
} else {
|
||||
if (\strlen($number) !== 0) {
|
||||
$target = $dbForProject->createDocument('targets', new Document([
|
||||
'$permissions' => [
|
||||
Permission::read(Role::user($user->getId())),
|
||||
Permission::update(Role::user($user->getId())),
|
||||
Permission::delete(Role::user($user->getId())),
|
||||
],
|
||||
'userId' => $user->getId(),
|
||||
'userInternalId' => $user->getInternalId(),
|
||||
'providerType' => 'sms',
|
||||
|
|
|
@ -252,6 +252,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_MISSING_CREDENTIALS = 'provider_missing_credentials';
|
||||
|
||||
/** Topic */
|
||||
|
@ -274,6 +275,9 @@ class Exception extends \Exception
|
|||
public const MESSAGE_TARGET_NOT_PUSH = 'message_target_not_push';
|
||||
public const MESSAGE_MISSING_SCHEDULE = 'message_missing_schedule';
|
||||
|
||||
/** Targets */
|
||||
public const TARGET_PROVIDER_INVALID_TYPE = 'target_provider_invalid_type';
|
||||
|
||||
/** Schedules */
|
||||
public const SCHEDULE_NOT_FOUND = 'schedule_not_found';
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Appwrite\Platform\Workers;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Executor\Executor;
|
||||
use Throwable;
|
||||
use Utopia\Abuse\Abuse;
|
||||
|
@ -263,12 +264,23 @@ class Deletes extends Action
|
|||
Query::equal('targetInternalId', [$target->getInternalId()])
|
||||
],
|
||||
$dbForProject,
|
||||
function (Document $subscriber) use ($dbForProject) {
|
||||
function (Document $subscriber) use ($dbForProject, $target) {
|
||||
$topicId = $subscriber->getAttribute('topicId');
|
||||
$topicInternalId = $subscriber->getAttribute('topicInternalId');
|
||||
$topic = $dbForProject->getDocument('topics', $topicId);
|
||||
if (!$topic->isEmpty() && $topic->getInternalId() === $topicInternalId) {
|
||||
$dbForProject->decreaseDocumentAttribute('topics', $topicId, 'total', min: 0);
|
||||
$totalAttribute = match ($target->getAttribute('providerType')) {
|
||||
MESSAGE_TYPE_EMAIL => 'emailTotal',
|
||||
MESSAGE_TYPE_SMS => 'smsTotal',
|
||||
MESSAGE_TYPE_PUSH => 'pushTotal',
|
||||
default => throw new Exception('Invalid target provider type'),
|
||||
};
|
||||
$dbForProject->decreaseDocumentAttribute(
|
||||
'topics',
|
||||
$topicId,
|
||||
$totalAttribute,
|
||||
min: 0
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -249,7 +249,7 @@ class Messaging extends Action
|
|||
}
|
||||
|
||||
// Deleting push targets when token has expired.
|
||||
if (($result['error'] ?? '') === 'Expired device token.') {
|
||||
if (($result['error'] ?? '') === 'Expired device token') {
|
||||
$target = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$result['recipient']])
|
||||
]);
|
||||
|
|
|
@ -7,7 +7,9 @@ class Topics extends Base
|
|||
public const ALLOWED_ATTRIBUTES = [
|
||||
'name',
|
||||
'description',
|
||||
'total'
|
||||
'emailTotal',
|
||||
'smsTotal',
|
||||
'pushTotal',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,9 +34,21 @@ class Topic extends Model
|
|||
'default' => '',
|
||||
'example' => 'events',
|
||||
])
|
||||
->addRule('total', [
|
||||
->addRule('emailTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total count of subscribers subscribed to topic.',
|
||||
'description' => 'Total count of email subscribers subscribed to the topic.',
|
||||
'default' => 0,
|
||||
'example' => 100,
|
||||
])
|
||||
->addRule('smsTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total count of SMS subscribers subscribed to the topic.',
|
||||
'default' => 0,
|
||||
'example' => 100,
|
||||
])
|
||||
->addRule('pushTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total count of push subscribers subscribed to the topic.',
|
||||
'default' => 0,
|
||||
'example' => 100,
|
||||
])
|
||||
|
|
|
@ -2026,6 +2026,9 @@ trait Base
|
|||
messagingCreateTopic(topicId: $topicId, name: $name) {
|
||||
_id
|
||||
name
|
||||
emailTotal
|
||||
smsTotal
|
||||
pushTotal
|
||||
}
|
||||
}';
|
||||
case self::$LIST_TOPICS:
|
||||
|
@ -2035,6 +2038,9 @@ trait Base
|
|||
topics {
|
||||
_id
|
||||
name
|
||||
emailTotal
|
||||
smsTotal
|
||||
pushTotal
|
||||
}
|
||||
}
|
||||
}';
|
||||
|
@ -2043,6 +2049,9 @@ trait Base
|
|||
messagingGetTopic(topicId: $topicId) {
|
||||
_id
|
||||
name
|
||||
emailTotal
|
||||
smsTotal
|
||||
pushTotal
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_TOPIC:
|
||||
|
@ -2050,6 +2059,9 @@ trait Base
|
|||
messagingUpdateTopic(topicId: $topicId, name: $name) {
|
||||
_id
|
||||
name
|
||||
emailTotal
|
||||
smsTotal
|
||||
pushTotal
|
||||
}
|
||||
}';
|
||||
case self::$DELETE_TOPIC:
|
||||
|
|
|
@ -355,7 +355,9 @@ trait MessagingBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'queries' => [
|
||||
Query::equal('total', [0])->toString(),
|
||||
Query::equal('emailTotal', [0])->toString(),
|
||||
Query::equal('smsTotal', [0])->toString(),
|
||||
Query::equal('pushTotal', [0])->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -368,7 +370,9 @@ trait MessagingBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'queries' => [
|
||||
Query::greaterThan('total', 0)->toString(),
|
||||
Query::greaterThan('emailTotal', 0)->toString(),
|
||||
Query::greaterThan('smsTotal', 0)->toString(),
|
||||
Query::greaterThan('pushTotal', 0)->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
|
@ -390,7 +394,9 @@ trait MessagingBase
|
|||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('android-app', $response['body']['name']);
|
||||
$this->assertEquals(0, $response['body']['total']);
|
||||
$this->assertEquals(0, $response['body']['emailTotal']);
|
||||
$this->assertEquals(0, $response['body']['smsTotal']);
|
||||
$this->assertEquals(0, $response['body']['pushTotal']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -446,7 +452,9 @@ trait MessagingBase
|
|||
|
||||
$this->assertEquals(200, $topic['headers']['status-code']);
|
||||
$this->assertEquals('android-app', $topic['body']['name']);
|
||||
$this->assertEquals(1, $topic['body']['total']);
|
||||
$this->assertEquals(1, $topic['body']['emailTotal']);
|
||||
$this->assertEquals(0, $topic['body']['smsTotal']);
|
||||
$this->assertEquals(0, $topic['body']['pushTotal']);
|
||||
|
||||
$response2 = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topics['private']['$id'] . '/subscribers', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -695,7 +703,9 @@ trait MessagingBase
|
|||
|
||||
$this->assertEquals(200, $topic['headers']['status-code']);
|
||||
$this->assertEquals('android-app', $topic['body']['name']);
|
||||
$this->assertEquals(0, $topic['body']['total']);
|
||||
$this->assertEquals(0, $topic['body']['emailTotal']);
|
||||
$this->assertEquals(0, $topic['body']['smsTotal']);
|
||||
$this->assertEquals(0, $topic['body']['pushTotal']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue