Add templates interaction
This commit is contained in:
parent
a05cf2cc09
commit
8a20b86b17
@ -11,9 +11,8 @@
|
||||
namespace RetailCrm\Mg\Bot;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use RetailCrm\Common\Url;
|
||||
use RetailCrm\Common\Serializer;
|
||||
use RetailCrm\Mg\Bot\Model\ModelAdapter;
|
||||
use RetailCrm\Common\Url;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Bot;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Channel\Channel;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Chat\Chat;
|
||||
@ -22,13 +21,15 @@ use RetailCrm\Mg\Bot\Model\Entity\Command;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Customer;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Dialog;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Message\Message;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Template\Template;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\User;
|
||||
use RetailCrm\Mg\Bot\Model\ModelAdapter;
|
||||
use RetailCrm\Mg\Bot\Model\Request\UploadFileByUrlRequest;
|
||||
use RetailCrm\Mg\Bot\Model\Response\AssignResponse;
|
||||
use RetailCrm\Mg\Bot\Model\Response\UnassignResponse;
|
||||
use RetailCrm\Mg\Bot\Model\Response\ErrorOnlyResponse;
|
||||
use RetailCrm\Mg\Bot\Model\Response\FullFileResponse;
|
||||
use RetailCrm\Mg\Bot\Model\Response\MessageSendResponse;
|
||||
use RetailCrm\Mg\Bot\Model\Response\UnassignResponse;
|
||||
use RetailCrm\Mg\Bot\Model\Response\UploadFileResponse;
|
||||
|
||||
/**
|
||||
@ -460,6 +461,38 @@ class Client
|
||||
return $adapter->getResponseModel($response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns templates list
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function templates()
|
||||
{
|
||||
$response = $this->client->makeRequest(
|
||||
'/templates',
|
||||
HttpClient::METHOD_GET
|
||||
);
|
||||
|
||||
$adapter = new ModelAdapter(Template::class);
|
||||
|
||||
return $adapter->getResponseList($response);
|
||||
}
|
||||
|
||||
public function templateSend(string $templateId, Model\Request\TemplateSendRequest $request)
|
||||
{
|
||||
$response = $this->client->makeRequest(
|
||||
sprintf('/templates/%d/send', $templateId),
|
||||
HttpClient::METHOD_POST,
|
||||
$request
|
||||
);
|
||||
|
||||
$adapter = new ModelAdapter(MessageSendResponse::class);
|
||||
|
||||
return $adapter->getResponseModel($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns filtered users list
|
||||
*
|
||||
|
385
src/Bot/Model/Entity/Template/Template.php
Normal file
385
src/Bot/Model/Entity/Template/Template.php
Normal file
@ -0,0 +1,385 @@
|
||||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* Template entity
|
||||
*
|
||||
* @package RetailCrm\Mg\Bot\Model\Entity\Template
|
||||
*/
|
||||
|
||||
namespace RetailCrm\Mg\Bot\Model\Entity\Template;
|
||||
|
||||
use RetailCrm\Mg\Bot\Model\ModelInterface;
|
||||
use JMS\Serializer\Annotation\Accessor;
|
||||
use JMS\Serializer\Annotation\SkipWhenEmpty;
|
||||
use JMS\Serializer\Annotation\Type;
|
||||
|
||||
/**
|
||||
* Template class
|
||||
*
|
||||
* @package RetailCrm\Mg\Bot\Model\Entity\Template
|
||||
*/
|
||||
class Template implements ModelInterface
|
||||
{
|
||||
/**
|
||||
* @var int $id
|
||||
*
|
||||
* @Type("int")
|
||||
* @Accessor(getter="getId",setter="setId")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string $code
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getCode",setter="setCode")
|
||||
*/
|
||||
private $code;
|
||||
|
||||
/**
|
||||
* @var int $channelId
|
||||
*
|
||||
* @Type("int")
|
||||
* @Accessor(getter="getChannelId",setter="setChannelId")
|
||||
*/
|
||||
private $channelId;
|
||||
|
||||
/**
|
||||
* @var string $name
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getName",setter="setName")
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var bool $enabled
|
||||
*
|
||||
* @Type("bool")
|
||||
* @Accessor(getter="getEnabled",setter="setEnabled")
|
||||
*/
|
||||
private $enabled;
|
||||
|
||||
/**
|
||||
* @var string $type
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getType",setter="setType")
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @var array $template
|
||||
*
|
||||
* @Type("array")
|
||||
* @Accessor(getter="getTemplate",setter="setTemplate")
|
||||
*/
|
||||
private $template;
|
||||
|
||||
/**
|
||||
* @var string $body
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getBody",setter="setBody")
|
||||
*/
|
||||
private $body;
|
||||
|
||||
/**
|
||||
* @var string $lang
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getLang",setter="setLang")
|
||||
*/
|
||||
private $lang;
|
||||
|
||||
/**
|
||||
* @var string $category
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getCategory",setter="setCategory")
|
||||
*/
|
||||
private $category;
|
||||
|
||||
/**
|
||||
* @var string $verificationStatus
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getVerificationStatus",setter="setVerificationStatus")
|
||||
*/
|
||||
private $verificationStatus;
|
||||
|
||||
/**
|
||||
* @var string $rejectionReason
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getRejectionReason",setter="setRejectionReason")
|
||||
*/
|
||||
private $rejectionReason;
|
||||
|
||||
/**
|
||||
* @var string $quality
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getQuality",setter="setQuality")
|
||||
* @SkipWhenEmpty()
|
||||
*/
|
||||
private $quality;
|
||||
|
||||
/**
|
||||
* @var array $header
|
||||
*
|
||||
* @Type("array")
|
||||
* @Accessor(getter="getHeader",setter="setHeader")
|
||||
* @SkipWhenEmpty()
|
||||
*/
|
||||
private $header;
|
||||
|
||||
/**
|
||||
* @var array $header
|
||||
*
|
||||
* @Type("array")
|
||||
* @Accessor(getter="getButtons",setter="setButtons")
|
||||
* @SkipWhenEmpty()
|
||||
*/
|
||||
private $buttons;
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*/
|
||||
public function setId(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCode(): ?string
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*/
|
||||
public function setCode(string $code): void
|
||||
{
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getChannelId(): ?int
|
||||
{
|
||||
return $this->channelId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $channelId
|
||||
*/
|
||||
public function setChannelId(int $channelId): void
|
||||
{
|
||||
$this->channelId = $channelId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName(string $name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|null
|
||||
*/
|
||||
public function getEnabled(): ?bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $enabled
|
||||
*/
|
||||
public function setEnabled(bool $enabled): void
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getType(): ?string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
public function setType(string $type): void
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getTemplate(): ?array
|
||||
{
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $template
|
||||
*/
|
||||
public function setTemplate($template): void
|
||||
{
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getBody(): ?string
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $body
|
||||
*/
|
||||
public function setBody(string $body): void
|
||||
{
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getVerificationStatus(): ?string
|
||||
{
|
||||
return $this->verificationStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $verificationStatus
|
||||
*/
|
||||
public function setVerificationStatus(string $verificationStatus): void
|
||||
{
|
||||
$this->verificationStatus = $verificationStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getLang(): ?string
|
||||
{
|
||||
return $this->lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
*/
|
||||
public function setLang(string $lang): void
|
||||
{
|
||||
$this->lang = $lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCategory(): ?string
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $category
|
||||
*/
|
||||
public function setCategory(string $category): void
|
||||
{
|
||||
$this->category = $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRejectionReason(): ?string
|
||||
{
|
||||
return $this->rejectionReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $rejectionReason
|
||||
*/
|
||||
public function setRejectionReason(string $rejectionReason): void
|
||||
{
|
||||
$this->rejectionReason = $rejectionReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getQuality(): ?string
|
||||
{
|
||||
return $this->quality;
|
||||
}
|
||||
|
||||
public function setQuality(string $quality): void
|
||||
{
|
||||
$this->quality = $quality;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getHeader(): ?array
|
||||
{
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $header
|
||||
*/
|
||||
public function setHeader(array $header): void
|
||||
{
|
||||
$this->header = $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getButtons(): ?array
|
||||
{
|
||||
return $this->buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $buttons
|
||||
*/
|
||||
public function setButtons(array $buttons): void
|
||||
{
|
||||
$this->buttons = $buttons;
|
||||
}
|
||||
}
|
88
src/Bot/Model/Entity/Template/TemplateVariables.php
Normal file
88
src/Bot/Model/Entity/Template/TemplateVariables.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\Mg\Bot\Model\Entity\Template;
|
||||
|
||||
use JMS\Serializer\Annotation\Accessor;
|
||||
use JMS\Serializer\Annotation\SkipWhenEmpty;
|
||||
use JMS\Serializer\Annotation\Type;
|
||||
use RetailCrm\Mg\Bot\Model\ModelInterface;
|
||||
|
||||
/**
|
||||
* TemplateVariables class
|
||||
*
|
||||
* @package RetailCrm\Mg\Bot\Model\Entity\Template
|
||||
*/
|
||||
class TemplateVariables implements ModelInterface
|
||||
{
|
||||
/**
|
||||
* @var array $header
|
||||
*
|
||||
* @Type("array")
|
||||
* @Accessor(getter="getHeader",setter="setHeader")
|
||||
*/
|
||||
private $header;
|
||||
|
||||
/**
|
||||
* @var array $body
|
||||
*
|
||||
* @Type("array")
|
||||
* @Accessor(getter="getBody",setter="setBody")
|
||||
*/
|
||||
private $body;
|
||||
|
||||
/**
|
||||
* @var array<array> $buttons
|
||||
*
|
||||
* @Type("array")
|
||||
* @Accessor(getter="getButtons",setter="setButtons")
|
||||
*/
|
||||
private $buttons;
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getHeader(): ?array
|
||||
{
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $header
|
||||
*/
|
||||
public function setHeader(array $header): void
|
||||
{
|
||||
$this->header = $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getBody(): ?array
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $body
|
||||
*/
|
||||
public function setBody(array $body): void
|
||||
{
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]|null
|
||||
*/
|
||||
public function getButtons(): ?array
|
||||
{
|
||||
return $this->buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array[] $buttons
|
||||
*/
|
||||
public function setButtons(array $buttons): void
|
||||
{
|
||||
$this->buttons = $buttons;
|
||||
}
|
||||
}
|
77
src/Bot/Model/Request/TemplateSendRequest.php
Normal file
77
src/Bot/Model/Request/TemplateSendRequest.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* Template send request
|
||||
*
|
||||
* @package RetailCrm\Mg\Bot\Model\Request
|
||||
*/
|
||||
|
||||
namespace RetailCrm\Mg\Bot\Model\Request;
|
||||
|
||||
use JMS\Serializer\Annotation\Accessor;
|
||||
use JMS\Serializer\Annotation\SkipWhenEmpty;
|
||||
use JMS\Serializer\Annotation\Type;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Template\TemplateVariables;
|
||||
use RetailCrm\Mg\Bot\Model\ModelInterface;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* TemplateSendRequest class
|
||||
*
|
||||
* @package RetailCrm\Mg\Bot\Model\Request
|
||||
*/
|
||||
class TemplateSendRequest implements ModelInterface
|
||||
{
|
||||
/**
|
||||
* @var string $phone
|
||||
*
|
||||
* @Type("string")
|
||||
* @Accessor(getter="getPhone",setter="setPhone")
|
||||
*
|
||||
* @Assert\NotBlank
|
||||
*/
|
||||
private $phone;
|
||||
|
||||
/**
|
||||
* @var TemplateVariables $args
|
||||
*
|
||||
* @Type("RetailCrm\Mg\Bot\Model\Entity\Template\TemplateVariables")
|
||||
* @Accessor(getter="getArgs",setter="setArgs")
|
||||
* @SkipWhenEmpty()
|
||||
*/
|
||||
private $args;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPhone(): string
|
||||
{
|
||||
return $this->phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $phone
|
||||
*/
|
||||
public function setPhone(string $phone): void
|
||||
{
|
||||
$this->phone = $phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TemplateVariables|null
|
||||
*/
|
||||
public function getArgs(): ?TemplateVariables
|
||||
{
|
||||
return $this->args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TemplateVariables $args
|
||||
*/
|
||||
public function setArgs(TemplateVariables $args): void
|
||||
{
|
||||
$this->args = $args;
|
||||
}
|
||||
}
|
113
tests/Bot/Tests/TemplatesTest.php
Normal file
113
tests/Bot/Tests/TemplatesTest.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace RetailCrm\Mg\Bot\Tests;
|
||||
|
||||
use RetailCrm\Common\Exception\NotFoundException;
|
||||
use RetailCrm\Mg\Bot\Model\Request\TemplateSendRequest;
|
||||
use RetailCrm\Mg\Bot\Model\Response\MessageSendResponse;
|
||||
use RetailCrm\Mg\Bot\Test\TestCase;
|
||||
use RetailCrm\Mg\Bot\Model\Entity\Template;
|
||||
|
||||
/**
|
||||
* PHP version 7.0
|
||||
*
|
||||
* Class TemplatesTest
|
||||
*
|
||||
* @package RetailCrm\Mg\Bot\Tests
|
||||
*/
|
||||
class TemplatesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @group("templates")
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testTemplatesList()
|
||||
{
|
||||
$client = self::getApiClient(
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
$this->getJsonResponse('templates')
|
||||
);
|
||||
|
||||
$response = $client->templates();
|
||||
|
||||
static::assertCount(2, $response, "Incorrect templates count");
|
||||
static::assertInstanceOf(Template\Template::class, $response[0], "Incorrect template instance");
|
||||
|
||||
$templateType = $response[0]->getHeader()['content']['type'];
|
||||
static::assertStringContainsString("video", $templateType, "Incorrect template type");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group("templates")
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testTemplateSendNotFound()
|
||||
{
|
||||
$this->expectException(NotFoundException::class);
|
||||
|
||||
$client = self::getApiClient(
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
$this->getErrorsResponse(404, "template id=3 was not found")
|
||||
);
|
||||
|
||||
$request = new TemplateSendRequest();
|
||||
$request->setPhone('123');
|
||||
|
||||
$client->templateSend(3, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group("templates")
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testTemplateSendVariablesError()
|
||||
{
|
||||
$this->expectException(NotFoundException::class);
|
||||
|
||||
$client = self::getApiClient(
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
$this->getErrorsResponse(404, "variables number doesn't match template")
|
||||
);
|
||||
|
||||
$request = new TemplateSendRequest();
|
||||
$request->setPhone('123');
|
||||
|
||||
$client->templateSend(2, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group("templates")
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testTemplateSendSuccess()
|
||||
{
|
||||
$client = self::getApiClient(
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
$this->getResponse(
|
||||
'{"message_id":4242,"time":"2019-06-24T06:02:04.434291791Z"}',
|
||||
201
|
||||
)
|
||||
);
|
||||
|
||||
$request = new TemplateSendRequest();
|
||||
$request->setPhone('123');
|
||||
|
||||
$response = $client->templateSend(1, $request);
|
||||
|
||||
self::assertInstanceOf(MessageSendResponse::class, $response);
|
||||
|
||||
if ($response instanceof MessageSendResponse) {
|
||||
self::assertTrue($response->isSuccessful());
|
||||
self::assertCount(0, $response->getErrors());
|
||||
self::assertEquals(4242, $response->getMessageId());
|
||||
}
|
||||
}
|
||||
}
|
56
tests/Resources/templates.json
Normal file
56
tests/Resources/templates.json
Normal file
@ -0,0 +1,56 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"code": "test1#ru",
|
||||
"channel_id": 1,
|
||||
"name": "test1",
|
||||
"enabled": true,
|
||||
"type": "media",
|
||||
"template": [
|
||||
"test1Template"
|
||||
],
|
||||
"body": "test1Template",
|
||||
"lang": "ru",
|
||||
"category": "marketing",
|
||||
"verification_status": "approved",
|
||||
"header": {
|
||||
"content": {
|
||||
"type": "video"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"code": "test2#ru",
|
||||
"channel_id": 5,
|
||||
"name": "test2",
|
||||
"enabled": true,
|
||||
"type": "media",
|
||||
"template": [
|
||||
"Вы не завершили покупку на нашем сайте.\n",
|
||||
{
|
||||
"var": "custom"
|
||||
},
|
||||
"Пройдите по ссылке чтобы оформить заказ."
|
||||
],
|
||||
"body": "Вы не завершили покупку на нашем сайте.\n{{1}}Пройдите по ссылке чтобы оформить заказ.",
|
||||
"lang": "ru",
|
||||
"category": "marketing",
|
||||
"verification_status": "approved",
|
||||
"header": {
|
||||
"content": {
|
||||
"body": "Товары в вашей корзине ждут вас!",
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
"buttons": {
|
||||
"items": [
|
||||
{
|
||||
"label": "Перейти в корзину",
|
||||
"url": "https://test-url/{{1}}",
|
||||
"type": "url"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user