| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- <?php
- namespace App\Module\OpenAPI\Models;
- use UCore\ModelCore;
- /**
- * OpenAPI Webhook配置模型
- *
- * @property int $id
- * @property string $app_id 应用ID
- * @property string $name Webhook名称
- * @property string $url 回调URL
- * @property array $events 监听的事件类型
- * @property string $secret 签名密钥
- * @property string $status 状态
- * @property int $timeout 超时时间(秒)
- * @property int $retry_count 重试次数
- * @property int $current_retry_count 当前重试次数
- * @property int $total_deliveries 总投递次数
- * @property int $successful_deliveries 成功投递次数
- * @property int $failed_deliveries 失败投递次数
- * @property \Carbon\Carbon|null $last_success_at 最后成功时间
- * @property \Carbon\Carbon|null $last_failure_at 最后失败时间
- * @property \Carbon\Carbon $created_at
- * @property \Carbon\Carbon $updated_at
- */
- class OpenApiWebhook extends ModelCore
- {
- // field start
- protected $fillable = [
- 'app_id',
- 'name',
- 'url',
- 'events',
- 'secret',
- 'status',
- 'timeout',
- 'retry_count',
- 'current_retry_count',
- 'total_deliveries',
- 'successful_deliveries',
- 'failed_deliveries',
- 'last_success_at',
- 'last_failure_at',
- ];
- // field end
- /**
- * 数据类型转换
- *
- * @var array
- */
- protected $casts = [
- 'events' => 'array',
- 'timeout' => 'integer',
- 'retry_count' => 'integer',
- 'current_retry_count' => 'integer',
- 'total_deliveries' => 'integer',
- 'successful_deliveries' => 'integer',
- 'failed_deliveries' => 'integer',
- 'last_success_at' => 'datetime',
- 'last_failure_at' => 'datetime',
- ];
- /**
- * 默认值
- *
- * @var array
- */
- protected $attributes = [
- 'status' => 'ACTIVE',
- 'timeout' => 30,
- 'retry_count' => 3,
- 'current_retry_count' => 0,
- 'total_deliveries' => 0,
- 'successful_deliveries' => 0,
- 'failed_deliveries' => 0,
- ];
- /**
- * 关联应用模型
- *
- * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
- */
- public function app()
- {
- return $this->belongsTo(OpenApiApp::class, 'app_id', 'app_id');
- }
- /**
- * 获取状态标签
- *
- * @return string
- */
- public function getStatusLabelAttribute(): string
- {
- return match ($this->status) {
- 'ACTIVE' => '激活',
- 'INACTIVE' => '停用',
- 'FAILED' => '失败',
- default => $this->status,
- };
- }
- /**
- * 获取状态颜色
- *
- * @return string
- */
- public function getStatusColorAttribute(): string
- {
- return match ($this->status) {
- 'ACTIVE' => 'success',
- 'INACTIVE' => 'warning',
- 'FAILED' => 'danger',
- default => 'secondary',
- };
- }
- /**
- * 获取成功率
- *
- * @return float
- */
- public function getSuccessRateAttribute(): float
- {
- if ($this->total_deliveries === 0) {
- return 0;
- }
- return round(($this->successful_deliveries / $this->total_deliveries) * 100, 2);
- }
- /**
- * 获取失败率
- *
- * @return float
- */
- public function getFailureRateAttribute(): float
- {
- if ($this->total_deliveries === 0) {
- return 0;
- }
- return round(($this->failed_deliveries / $this->total_deliveries) * 100, 2);
- }
- /**
- * 获取事件列表的字符串表示
- *
- * @return string
- */
- public function getEventsStringAttribute(): string
- {
- if (empty($this->events)) {
- return '无';
- }
- if (in_array('*', $this->events)) {
- return '全部事件';
- }
- return implode(', ', $this->events);
- }
- /**
- * 检查是否监听指定事件
- *
- * @param string $event
- * @return bool
- */
- public function listensToEvent(string $event): bool
- {
- if (empty($this->events)) {
- return false;
- }
- return in_array('*', $this->events) || in_array($event, $this->events);
- }
- /**
- * 重置重试计数
- *
- * @return void
- */
- public function resetRetryCount(): void
- {
- $this->update(['current_retry_count' => 0]);
- }
- /**
- * 检查是否可以重试
- *
- * @return bool
- */
- public function canRetry(): bool
- {
- return $this->current_retry_count < $this->retry_count;
- }
- /**
- * 按应用ID查询
- *
- * @param \Illuminate\Database\Eloquent\Builder $query
- * @param string $appId
- * @return \Illuminate\Database\Eloquent\Builder
- */
- public function scopeByApp($query, string $appId)
- {
- return $query->where('app_id', $appId);
- }
- /**
- * 查询激活状态的Webhook
- *
- * @param \Illuminate\Database\Eloquent\Builder $query
- * @return \Illuminate\Database\Eloquent\Builder
- */
- public function scopeActive($query)
- {
- return $query->where('status', 'ACTIVE');
- }
- /**
- * 按事件类型查询
- *
- * @param \Illuminate\Database\Eloquent\Builder $query
- * @param string $event
- * @return \Illuminate\Database\Eloquent\Builder
- */
- public function scopeForEvent($query, string $event)
- {
- return $query->where(function ($q) use ($event) {
- $q->whereJsonContains('events', $event)
- ->orWhereJsonContains('events', '*');
- });
- }
- /**
- * 查询最近失败的Webhook
- *
- * @param \Illuminate\Database\Eloquent\Builder $query
- * @param int $hours
- * @return \Illuminate\Database\Eloquent\Builder
- */
- public function scopeRecentlyFailed($query, int $hours = 24)
- {
- return $query->where('last_failure_at', '>=', now()->subHours($hours));
- }
- /**
- * 查询需要重试的Webhook
- *
- * @param \Illuminate\Database\Eloquent\Builder $query
- * @return \Illuminate\Database\Eloquent\Builder
- */
- public function scopeNeedsRetry($query)
- {
- return $query->whereColumn('current_retry_count', '<', 'retry_count')
- ->where('status', 'ACTIVE');
- }
- /**
- * 生成新的密钥
- *
- * @return string
- */
- public function regenerateSecret(): string
- {
- $secret = bin2hex(random_bytes(32));
- $this->update(['secret' => $secret]);
- return $secret;
- }
- /**
- * 获取掩码后的密钥(用于显示)
- *
- * @return string
- */
- public function getMaskedSecretAttribute(): string
- {
- if (empty($this->secret)) {
- return '';
- }
- return substr($this->secret, 0, 8) . str_repeat('*', 48) . substr($this->secret, -8);
- }
- }
|