Merge pull request #7594 from appwrite/feat-push-images
Allow push images
This commit is contained in:
commit
bc517ed69b
4 changed files with 120 additions and 45 deletions
|
@ -420,6 +420,11 @@ return [
|
|||
'description' => 'The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is a valid id and not unique().',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::STORAGE_FILE_NOT_PUBLIC => [
|
||||
'name' => Exception::STORAGE_FILE_NOT_PUBLIC,
|
||||
'description' => 'The requested file is not publicly readable.',
|
||||
'code' => 403,
|
||||
],
|
||||
|
||||
/** VCS */
|
||||
Exception::INSTALLATION_NOT_FOUND => [
|
||||
|
|
|
@ -28,11 +28,13 @@ use Utopia\Database\Helpers\ID;
|
|||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
|
@ -2826,6 +2828,7 @@ App::post('/v1/messaging/messages/push')
|
|||
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
|
||||
->param('data', null, new JSON(), 'Additional Data for push notification.', true)
|
||||
->param('action', '', new Text(256), 'Action for push notification.', true)
|
||||
->param('image', '', new CompoundUID(), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage.', true)
|
||||
->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true)
|
||||
->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true)
|
||||
->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true)
|
||||
|
@ -2839,7 +2842,7 @@ App::post('/v1/messaging/messages/push')
|
|||
->inject('project')
|
||||
->inject('queueForMessaging')
|
||||
->inject('response')
|
||||
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, ?array $data, string $action, string $image, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
$messageId = $messageId == 'unique()'
|
||||
? ID::unique()
|
||||
: $messageId;
|
||||
|
@ -2870,9 +2873,41 @@ App::post('/v1/messaging/messages/push')
|
|||
}
|
||||
}
|
||||
|
||||
if (!empty($image)) {
|
||||
[$bucketId, $fileId] = CompoundUID::parse($image);
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\in_array(Permission::read(Role::any()), \array_merge($file->getRead(), $bucket->getRead()))) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
if (!\in_array($file->getAttribute('mimeType'), ['image/png', 'image/jpeg'])) {
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$host = App::getEnv('_APP_DOMAIN', 'localhost');
|
||||
$domain = new Domain(\parse_url($host, PHP_URL_HOST));
|
||||
$protocol = App::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
|
||||
if (!$domain->isKnown()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
$image = "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/view?project={$project->getId()}";
|
||||
}
|
||||
|
||||
$pushData = [];
|
||||
|
||||
$keys = ['title', 'body', 'data', 'action', 'icon', 'sound', 'color', 'tag', 'badge'];
|
||||
$keys = ['title', 'body', 'data', 'action', 'image', 'icon', 'sound', 'color', 'tag', 'badge'];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (!empty($$key)) {
|
||||
|
@ -3436,6 +3471,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
->param('body', null, new Text(64230), 'Body for push notification.', true)
|
||||
->param('data', null, new JSON(), 'Additional Data for push notification.', true)
|
||||
->param('action', null, new Text(256), 'Action for push notification.', true)
|
||||
->param('image', null, new CompoundUID(), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage.', true)
|
||||
->param('icon', null, new Text(256), 'Icon for push notification. Available only for Android and Web platforms.', true)
|
||||
->param('sound', null, new Text(256), 'Sound for push notification. Available only for Android and iOS platforms.', true)
|
||||
->param('color', null, new Text(256), 'Color for push notification. Available only for Android platforms.', true)
|
||||
|
@ -3449,7 +3485,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
->inject('project')
|
||||
->inject('queueForMessaging')
|
||||
->inject('response')
|
||||
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $image, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
$message = $dbForProject->getDocument('messages', $messageId);
|
||||
|
||||
if ($message->isEmpty()) {
|
||||
|
@ -3519,6 +3555,38 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
$pushData['badge'] = $badge;
|
||||
}
|
||||
|
||||
if (!\is_null($image)) {
|
||||
[$bucketId, $fileId] = CompoundUID::parse($image);
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\in_array(Permission::read(Role::any()), \array_merge($file->getRead(), $bucket->getRead()))) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
if (!\in_array($file->getAttribute('mimeType'), ['image/png', 'image/jpeg'])) {
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$host = App::getEnv('_APP_DOMAIN', 'localhost');
|
||||
$domain = new Domain(\parse_url($host, PHP_URL_HOST));
|
||||
$protocol = App::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
|
||||
if (!$domain->isKnown()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
$pushData['image'] = "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/view?project={$project->getId()}";
|
||||
}
|
||||
|
||||
$message->setAttribute('data', $pushData);
|
||||
|
||||
if (!\is_null($status)) {
|
||||
|
|
|
@ -92,8 +92,8 @@ class Exception extends \Exception
|
|||
public const USER_OAUTH2_BAD_REQUEST = 'user_oauth2_bad_request';
|
||||
public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized';
|
||||
public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error';
|
||||
public const USER_EMAIL_ALREADY_VERIFIED = 'user_email_alread_verified';
|
||||
public const USER_PHONE_ALREADY_VERIFIED = 'user_phone_already_verified';
|
||||
public const USER_EMAIL_ALREADY_VERIFIED = 'user_email_already_verified';
|
||||
public const USER_PHONE_ALREADY_VERIFIED = 'user_phone_already_verified';
|
||||
public const USER_TARGET_NOT_FOUND = 'user_target_not_found';
|
||||
public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists';
|
||||
|
||||
|
@ -130,18 +130,19 @@ class Exception extends \Exception
|
|||
public const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range';
|
||||
public const STORAGE_INVALID_RANGE = 'storage_invalid_range';
|
||||
public const STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id';
|
||||
public const STORAGE_FILE_NOT_PUBLIC = 'storage_file_not_public';
|
||||
|
||||
/** VCS */
|
||||
public const INSTALLATION_NOT_FOUND = 'installation_not_found';
|
||||
public const PROVIDER_REPOSITORY_NOT_FOUND = 'provider_repository_not_found';
|
||||
public const REPOSITORY_NOT_FOUND = 'repository_not_found';
|
||||
public const PROVIDER_CONTRIBUTION_CONFLICT = 'provider_contribution_conflict';
|
||||
public const GENERAL_PROVIDER_FAILURE = 'general_provider_failure';
|
||||
public const INSTALLATION_NOT_FOUND = 'installation_not_found';
|
||||
public const PROVIDER_REPOSITORY_NOT_FOUND = 'provider_repository_not_found';
|
||||
public const REPOSITORY_NOT_FOUND = 'repository_not_found';
|
||||
public const PROVIDER_CONTRIBUTION_CONFLICT = 'provider_contribution_conflict';
|
||||
public const GENERAL_PROVIDER_FAILURE = 'general_provider_failure';
|
||||
|
||||
/** Functions */
|
||||
public const FUNCTION_NOT_FOUND = 'function_not_found';
|
||||
public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported';
|
||||
public const FUNCTION_ENTRYPOINT_MISSING = 'function_entrypoint_missing';
|
||||
public const FUNCTION_ENTRYPOINT_MISSING = 'function_entrypoint_missing';
|
||||
|
||||
/** Deployments */
|
||||
public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found';
|
||||
|
@ -214,10 +215,10 @@ class Exception extends \Exception
|
|||
public const ROUTER_DOMAIN_NOT_CONFIGURED = 'router_domain_not_configured';
|
||||
|
||||
/** Proxy */
|
||||
public const RULE_RESOURCE_NOT_FOUND = 'rule_resource_not_found';
|
||||
public const RULE_NOT_FOUND = 'rule_not_found';
|
||||
public const RULE_ALREADY_EXISTS = 'rule_already_exists';
|
||||
public const RULE_VERIFICATION_FAILED = 'rule_verification_failed';
|
||||
public const RULE_RESOURCE_NOT_FOUND = 'rule_resource_not_found';
|
||||
public const RULE_NOT_FOUND = 'rule_not_found';
|
||||
public const RULE_ALREADY_EXISTS = 'rule_already_exists';
|
||||
public const RULE_VERIFICATION_FAILED = 'rule_verification_failed';
|
||||
|
||||
/** Keys */
|
||||
public const KEY_NOT_FOUND = 'key_not_found';
|
||||
|
@ -234,53 +235,52 @@ class Exception extends \Exception
|
|||
public const GRAPHQL_TOO_MANY_QUERIES = 'graphql_too_many_queries';
|
||||
|
||||
/** Migrations */
|
||||
public const MIGRATION_NOT_FOUND = 'migration_not_found';
|
||||
public const MIGRATION_ALREADY_EXISTS = 'migration_already_exists';
|
||||
public const MIGRATION_IN_PROGRESS = 'migration_in_progress';
|
||||
public const MIGRATION_PROVIDER_ERROR = 'migration_provider_error';
|
||||
public const MIGRATION_NOT_FOUND = 'migration_not_found';
|
||||
public const MIGRATION_ALREADY_EXISTS = 'migration_already_exists';
|
||||
public const MIGRATION_IN_PROGRESS = 'migration_in_progress';
|
||||
public const MIGRATION_PROVIDER_ERROR = 'migration_provider_error';
|
||||
|
||||
/** Realtime */
|
||||
public const REALTIME_MESSAGE_FORMAT_INVALID = 'realtime_message_format_invalid';
|
||||
public const REALTIME_TOO_MANY_MESSAGES = 'realtime_too_many_messages';
|
||||
public const REALTIME_POLICY_VIOLATION = 'realtime_policy_violation';
|
||||
public const REALTIME_MESSAGE_FORMAT_INVALID = 'realtime_message_format_invalid';
|
||||
public const REALTIME_TOO_MANY_MESSAGES = 'realtime_too_many_messages';
|
||||
public const REALTIME_POLICY_VIOLATION = 'realtime_policy_violation';
|
||||
|
||||
/** Health */
|
||||
public const HEALTH_QUEUE_SIZE_EXCEEDED = 'health_queue_size_exceeded';
|
||||
public const HEALTH_CERTIFICATE_EXPIRED = 'health_certificate_expired';
|
||||
public const HEALTH_INVALID_HOST = 'health_invalid_host';
|
||||
public const HEALTH_QUEUE_SIZE_EXCEEDED = 'health_queue_size_exceeded';
|
||||
public const HEALTH_CERTIFICATE_EXPIRED = 'health_certificate_expired';
|
||||
public const HEALTH_INVALID_HOST = 'health_invalid_host';
|
||||
|
||||
/** Provider */
|
||||
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';
|
||||
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 */
|
||||
public const TOPIC_NOT_FOUND = 'topic_not_found';
|
||||
public const TOPIC_ALREADY_EXISTS = 'topic_already_exists';
|
||||
public const TOPIC_NOT_FOUND = 'topic_not_found';
|
||||
public const TOPIC_ALREADY_EXISTS = 'topic_already_exists';
|
||||
|
||||
/** Subscriber */
|
||||
public const SUBSCRIBER_NOT_FOUND = 'subscriber_not_found';
|
||||
public const SUBSCRIBER_ALREADY_EXISTS = 'subscriber_already_exists';
|
||||
public const SUBSCRIBER_NOT_FOUND = 'subscriber_not_found';
|
||||
public const SUBSCRIBER_ALREADY_EXISTS = 'subscriber_already_exists';
|
||||
|
||||
/** Message */
|
||||
public const MESSAGE_NOT_FOUND = 'message_not_found';
|
||||
public const MESSAGE_MISSING_TARGET = 'message_missing_target';
|
||||
public const MESSAGE_ALREADY_SENT = 'message_already_sent';
|
||||
public const MESSAGE_ALREADY_PROCESSING = 'message_already_processing';
|
||||
public const MESSAGE_ALREADY_FAILED = 'message_already_failed';
|
||||
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';
|
||||
public const MESSAGE_MISSING_SCHEDULE = 'message_missing_schedule';
|
||||
public const MESSAGE_NOT_FOUND = 'message_not_found';
|
||||
public const MESSAGE_MISSING_TARGET = 'message_missing_target';
|
||||
public const MESSAGE_ALREADY_SENT = 'message_already_sent';
|
||||
public const MESSAGE_ALREADY_PROCESSING = 'message_already_processing';
|
||||
public const MESSAGE_ALREADY_FAILED = 'message_already_failed';
|
||||
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';
|
||||
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';
|
||||
public const SCHEDULE_NOT_FOUND = 'schedule_not_found';
|
||||
|
||||
|
||||
protected string $type = '';
|
||||
|
|
|
@ -626,6 +626,7 @@ class Messaging extends Action
|
|||
$body = $message['data']['body'];
|
||||
$data = $message['data']['data'] ?? null;
|
||||
$action = $message['data']['action'] ?? null;
|
||||
$image = $message['data']['image'] ?? null;
|
||||
$sound = $message['data']['sound'] ?? null;
|
||||
$icon = $message['data']['icon'] ?? null;
|
||||
$color = $message['data']['color'] ?? null;
|
||||
|
@ -639,6 +640,7 @@ class Messaging extends Action
|
|||
$data,
|
||||
$action,
|
||||
$sound,
|
||||
$image,
|
||||
$icon,
|
||||
$color,
|
||||
$tag,
|
||||
|
|
Loading…
Reference in a new issue