Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,33 @@ $apiClient->setAccessToken($accessToken)
});
```

Отправить пользователя на страницу авторизации можно 2мя способами:
1. Отрисовав кнопку на сайт:
Доступные методы отправки на страницу авторизации пользователя
1. Кнопка установки существующей интеграции по client_id
```php
$apiClient->getOAuthClient()->getOAuthButton(
[
'title' => 'Установить интеграцию',
'compact' => true,
'class_name' => 'className',
'color' => 'default',
'error_callback' => 'handleOauthError',
'state' => $state,
]
);
// data-client-id будет взят из API клиента
$apiClient->getOAuthClient()->getOAuthButton([
'title' => 'Установить интеграцию',
'compact' => true,
'class_name' => 'className',
'color' => 'default',
'error_callback' => 'handleOauthError',
'state' => $state,
]);
```

2. Отправив пользователя на страницу авторизации
2. Кнопка с метаданными для создания внешней интеграции. Для каждой установки создается отдельная интеграция

```php
// redirect_uri будет взят из API клиента
$apiClient->getOAuthClient()->getOAuthButton([
'is_metadata' => true, // указываем, что передаем метаданные в кнопку. По умолчанию - false
'secrets_uri' => 'https://your-domain.com/secrets'
'title' => 'Создать интеграцию',
// ... другие параметры
]);
```

3. Прямой редирект на страницу авторизации
```php
$authorizationUrl = $apiClient->getOAuthClient()->getAuthorizeUrl([
'state' => $state,
Expand Down
52 changes: 52 additions & 0 deletions examples/oauth_button_actions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

require_once __DIR__ . '/../vendor/autoload.php';

use AmoCRM\Client\AmoCRMApiClient;

$clientId = 'client_id';
$clientSecret = 'client_secret';

// Здесь нужны работающие redirect_uri и client_secret
$redirectUri = 'https://example.com/redirect';
$secretsUri = 'https://example.com/secrets';

$apiClient = new AmoCRMApiClient($clientId, $clientSecret, $redirectUri);

echo "=== Генерация обычной OAuth кнопки ===\n";
$buttonByClientId = $apiClient->getOAuthClient()->getOAuthButton(
[
'title' => 'title_tmedvedevv',
'compact' => false,
'is_kommo' => true,
'class_name' => 'classNameTmedvedevv',
'color' => 'red',
'mode' => 'popup',
'error_callback' => 'handleOauthError'
]
);

var_dump($buttonByClientId);

echo "\n=== Генерация кнопки с метаданными, необходимые для создания внешней интеграции ===\n";

// Генерируем кнопку с метаданными для внешней интеграции
// client_id из API клиента будет проигнорирован т.к создается новая интеграция в аккаунте
// После установки приходит 2 хука.

$buttonMetadata = $apiClient->getOAuthClient()->getOAuthButton([
'title' => 'title_tmedvedevv',
'compact' => true,
'is_kommo' => false,
'class_name' => 'classNameTmedvedevv',
'color' => 'red',
'mode' => 'popup',
'error_callback' => 'handleOauthError',
'scopes' => ['crm'],
'is_metadata' => true, // Указываем, поскольку нужна кнопка с передачей метаданных. По умолчанию false
'secrets_uri' => $secretsUri // url куда будут отправлены данные по интеграции
]);

var_dump($buttonMetadata);
10 changes: 10 additions & 0 deletions src/AmoCRM/Exceptions/AmoCRMOAuthButtonConfigurationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace AmoCRM\Exceptions;

/**
* Выбрасывается в случае неверной конфигурации oAuth кнопки
*/
class AmoCRMOAuthButtonConfigurationException extends AmoCRMApiException
{
}
99 changes: 93 additions & 6 deletions src/AmoCRM/OAuth/AmoCRMOAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace AmoCRM\OAuth;

use AmoCRM\Exceptions\AmoCRMOAuthButtonConfigurationException;
use AmoCRM\Exceptions\DisposableTokenExpiredException;
use AmoCRM\Exceptions\DisposableTokenInvalidDestinationException;
use AmoCRM\Exceptions\DisposableTokenVerificationFailedException;
Expand All @@ -15,7 +16,6 @@
use AmoCRM\Exceptions\AmoCRMApiHttpClientException;
use AmoCRM\Exceptions\AmoCRMApiTooManyRedirectsException;
use AmoCRM\Exceptions\AmoCRMoAuthApiException;
use AmoCRM\Exceptions\BadTypeException;
use AmoCRM\OAuth2\Client\Provider\AmoCRM;
use Exception;
use Fig\Http\Message\StatusCodeInterface;
Expand Down Expand Up @@ -67,6 +67,11 @@ class AmoCRMOAuth
'red' => '#D84315',
];

/**
* Доступные scopes для кнопки с метаданными, необходимые для создания внешней интеграции.
*/
public const METADATA_BUTTON_AVAILABLE_SCOPES = ['crm', 'notifications'];

protected const REQUEST_TIMEOUT = 15;

/**
Expand Down Expand Up @@ -333,24 +338,38 @@ public function getResourceOwner(AccessTokenInterface $accessToken): ResourceOwn

/**
* Доступные значения для options:
* string class_name
* string title
* bool compact
* string class_name
* string color
* string state
* string error_callback
* string mode
* bool is_kommo - Использовать Kommo вместо amoCRM
* bool is_metadata - Создать кнопку с передачей метаданных для установки внешней интеграции
*
* Для кнопки с метаданными:
* string name - Название интеграции
* string secrets_uri - Адрес, куда будет отправлен webhook с client_id, state и секретным ключом интеграции
* string description - Описание интеграции
* array scopes - Запрашиваемые права
* string logo - URL логотипа
*
* @param array $options
*
* @return string
* @throws BadTypeException
* @return string HTML код кнопки
* @throws AmoCRMOAuthButtonConfigurationException
*/
public function getOAuthButton(array $options = []): string
{
if (isset($options['color']) && !array_key_exists($options['color'], self::BUTTON_COLORS)) {
throw new BadTypeException('Invalid color selected');
throw new AmoCRMOAuthButtonConfigurationException(
'Cannot create OAuth button: Invalid color selected'
);
}

$isMetadata = $options['is_metadata'] ?? false;
$clientId = $this->oauthProvider->getClientId();
$title = $options['title'] ?? 'Установить интеграцию';
$compact = isset($options['compact']) && $options['compact'] ? 'true' : 'false';
$className = $options['class_name'] ?? 'className';
Expand All @@ -371,7 +390,8 @@ public function getOAuthButton(array $options = []): string
? 'https://www.kommo.com/auth/button.min.js'
: 'https://www.amocrm.ru/auth/button.min.js';

return '<div>
if ($isMetadata === false) {
return '<div>
<script
class="' . $mainClassName . '"
charset="utf-8"
Expand All @@ -386,6 +406,73 @@ class="' . $mainClassName . '"
src="' . $scriptPath . '"
></script>
</div>';
}

$secretsUri = $options['secrets_uri'] ?? '';
$redirectUri = $this->redirectUri;

// Должны быть заполнены т.к при передаче метаданных после установки приходит два хука
// с данными по самой интеграции и с данными для получения токенов.
if (empty($secretsUri) || empty($redirectUri)) {
throw new AmoCRMOAuthButtonConfigurationException(
'Cannot create metadata OAuth button: For metadata OAuth button,
both secrets_uri and redirect_uri must be configured'
);
}

$description = $options['description'] ?? 'Описание интеграции';
$name = $options['name'] ?? 'Название интеграции';
$logo = $options['logo'] ?? 'https://example.com/amocrm_logo.png';

if (!isset($options['scopes'])) {
$scopes = self::METADATA_BUTTON_AVAILABLE_SCOPES;
} else {
if (!is_array($options['scopes'])) {
throw new AmoCRMOAuthButtonConfigurationException(
'scopes parameter must be an array.'
);
}

$scopes = $options['scopes'];
}

$scopes = array_filter($scopes);

if (empty($scopes)) {
$scopes = self::METADATA_BUTTON_AVAILABLE_SCOPES;
}

$invalidScopes = array_diff($scopes, self::METADATA_BUTTON_AVAILABLE_SCOPES);
if (!empty($invalidScopes)) {
throw new AmoCRMOAuthButtonConfigurationException(sprintf(
'Invalid scopes: %s. Available scopes: %s',
implode(', ', $invalidScopes),
implode(', ', self::METADATA_BUTTON_AVAILABLE_SCOPES)
));
}

$scopes = implode(',', $scopes);

return '<div>
<script
class="' . $mainClassName . '"
charset="utf-8"
data-name="' . $name . '"
data-description="' . $description . '"
data-redirect_uri="' . $redirectUri . '"
data-secrets_uri="' . $secretsUri . '"
data-logo="' . $logo . '"
data-scopes="' . $scopes . '"
data-title="' . $title . '"
data-compact="' . $compact . '"
data-class-name="' . $className . '"
data-color="' . $color . '"
data-state="' . $state . '"
data-error-callback="' . $errorCallback . '"
data-mode="' . $mode . '"
src="' . $scriptPath . '"
></script>
</div>';
}

/**
Expand Down
Loading