Implemented webhooks database structure and console command register webhooks

This commit is contained in:
ErickSkrauch 2018-07-07 15:01:18 +03:00
parent 03bd5ec144
commit 6751eb6591
7 changed files with 228 additions and 21 deletions

42
common/models/WebHook.php Normal file
View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace common\models;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveQueryInterface;
use yii\db\ActiveRecord;
/**
* Fields:
* @property int $id
* @property string $url
* @property string|null $secret
* @property int $created_at
*
* Relations:
* @property WebHookEvent[] $events
*
* Behaviors:
* @mixin TimestampBehavior
*/
class WebHook extends ActiveRecord {
public static function tableName(): string {
return '{{%webhooks}}';
}
public function behaviors(): array {
return [
[
'class' => TimestampBehavior::class,
'updatedAtAttribute' => false,
],
];
}
public function getEvents(): ActiveQueryInterface {
return $this->hasMany(WebHookEvent::class, ['webhook_id' => 'id']);
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace common\models;
use yii\db\ActiveQueryInterface;
use yii\db\ActiveRecord;
/**
* Fields:
* @property int $webhook_id
* @property string $event_type
*
* Relations:
* @property WebHook $webhook
*/
class WebHookEvent extends ActiveRecord {
public static function tableName(): string {
return '{{%webhooks_events}}';
}
public function getWebhook(): ActiveQueryInterface {
return $this->hasOne(WebHook::class, ['id' => 'webhook_id']);
}
}

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace console\controllers;
use common\models\WebHook;
use console\models\WebHookForm;
use yii\console\Controller;
use yii\console\ExitCode;
use yii\helpers\Console;
class WebhooksController extends Controller {
public function actionCreate(): int {
$form = new WebHookForm(new WebHook());
$url = Console::prompt('Enter webhook url:', [
'required' => true,
'validator' => function(string $input, ?string &$error) use ($form): bool {
$form->url = $input;
if (!$form->validate('url')) {
$error = $form->getFirstError('url');
return false;
}
return true;
},
]);
$secret = Console::prompt('Enter webhook secret (empty to no secret):');
$options = $form::getEvents();
$options[''] = 'Finish input'; // It's needed to allow finish input cycle
$events = [];
do {
$availableOptions = array_diff($options, $events);
$eventIndex = Console::select('Choose wanted events (submit no input to finish):', $availableOptions);
if ($eventIndex !== '') {
$events[] = $options[$eventIndex];
}
} while($eventIndex !== '' || empty($events)); // User must choose at least one event
$form->url = $url;
$form->events = $events;
if ($secret !== '') {
$form->secret = $secret;
}
if (!$form->save()) {
Console::error('Unable to create new webhook. Check errors list below' . PHP_EOL . Console::errorSummary($form));
return ExitCode::UNSPECIFIED_ERROR;
}
return ExitCode::OK;
}
}

View File

@ -25,28 +25,12 @@ class Migration extends YiiMigration {
parent::createTable($table, $columns, $options);
}
protected function primary(...$columns) {
switch (count($columns)) {
case 0:
$key = '';
break;
case 1:
$key = $columns[0];
break;
default:
$key = $this->buildKey($columns);
protected function primary(string ...$columns): string {
foreach ($columns as &$column) {
$column = $this->db->quoteColumnName($column);
}
return " PRIMARY KEY ($key) ";
}
private function buildKey(array $columns) {
$key = '';
foreach ($columns as $i => $column) {
$key .= $i === count($columns) ? $column : "$column,";
}
return $key;
return ' PRIMARY KEY (' . implode(', ', $columns) . ') ';
}
}

View File

@ -0,0 +1,28 @@
<?php
use console\db\Migration;
class m180706_230451_webhooks extends Migration {
public function safeUp() {
$this->createTable('{{%webhooks}}', [
'id' => $this->primaryKey(11)->unsigned(),
'url' => $this->string()->notNull(),
'secret' => $this->string(),
'created_at' => $this->integer(11)->unsigned()->notNull(),
]);
$this->createTable('{{%webhooks_events}}', [
'webhook_id' => $this->db->getTableSchema('{{%webhooks}}')->getColumn('id')->dbType . ' NOT NULL',
'event_type' => $this->string()->notNull(),
$this->primary('webhook_id', 'event_type'),
]);
$this->addForeignKey('FK_webhook_event_to_webhook', '{{%webhooks_events}}', 'webhook_id', 'webhooks', 'id', 'CASCADE', 'CASCADE');
}
public function safeDown() {
$this->dropTable('{{%webhooks_events}}');
$this->dropTable('{{%webhooks}}');
}
}

View File

@ -1 +0,0 @@
*

View File

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace console\models;
use api\exceptions\ThisShouldNotHappenException;
use common\models\WebHook;
use common\models\WebHookEvent;
use Yii;
use yii\base\Model;
class WebHookForm extends Model {
public $url;
public $secret;
public $events = [];
private $webHook;
public function __construct(WebHook $webHook, array $config = []) {
parent::__construct($config);
$this->webHook = $webHook;
}
public function rules(): array {
return [
[['url'], 'required'],
[['url'], 'url'],
[['secret'], 'string'],
[['events'], 'in', 'range' => static::getEvents(), 'allowArray' => true],
];
}
public function save(): bool {
if (!$this->validate()) {
return false;
}
$transaction = Yii::$app->db->beginTransaction();
$webHook = $this->webHook;
$webHook->url = $this->url;
$webHook->secret = $this->secret;
if (!$webHook->save()) {
throw new ThisShouldNotHappenException('Cannot save webhook.');
}
foreach ($this->events as $event) {
$eventModel = new WebHookEvent();
$eventModel->webhook_id = $webHook->id;
$eventModel->event_type = $event;
if (!$eventModel->save()) {
throw new ThisShouldNotHappenException('Cannot save webhook event.');
}
}
$transaction->commit();
return true;
}
public static function getEvents(): array {
return [
'account.edit',
];
}
}