mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Implemented webhooks database structure and console command register webhooks
This commit is contained in:
		
							
								
								
									
										42
									
								
								common/models/WebHook.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								common/models/WebHook.php
									
									
									
									
									
										Normal 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']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								common/models/WebHookEvent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								common/models/WebHookEvent.php
									
									
									
									
									
										Normal 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']);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								console/controllers/WebhooksController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								console/controllers/WebhooksController.php
									
									
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -25,28 +25,12 @@ class Migration extends YiiMigration {
 | 
				
			|||||||
        parent::createTable($table, $columns, $options);
 | 
					        parent::createTable($table, $columns, $options);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected function primary(...$columns) {
 | 
					    protected function primary(string ...$columns): string {
 | 
				
			||||||
        switch (count($columns)) {
 | 
					        foreach ($columns as &$column) {
 | 
				
			||||||
            case 0:
 | 
					            $column = $this->db->quoteColumnName($column);
 | 
				
			||||||
                $key = '';
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 1:
 | 
					 | 
				
			||||||
                $key = $columns[0];
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                $key = $this->buildKey($columns);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return " PRIMARY KEY ($key) ";
 | 
					        return ' PRIMARY KEY (' . implode(', ', $columns) . ') ';
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private function buildKey(array $columns) {
 | 
					 | 
				
			||||||
        $key = '';
 | 
					 | 
				
			||||||
        foreach ($columns as $i => $column) {
 | 
					 | 
				
			||||||
            $key .= $i === count($columns) ? $column : "$column,";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $key;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								console/migrations/m180706_230451_webhooks.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								console/migrations/m180706_230451_webhooks.php
									
									
									
									
									
										Normal 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}}');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
*
 | 
					 | 
				
			||||||
							
								
								
									
										70
									
								
								console/models/WebHookForm.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								console/models/WebHookForm.php
									
									
									
									
									
										Normal 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',
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user