mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-14 16:52:45 -04:00
- database import: add keep_owners (restore PostgreSQL owners and privileges) and sqlite_database (pick the target SQLite file) to the API, OpenAPI spec, and import form - oauth: require password confirmation and support team selection on OAuth login - remote process: send team broadcast events to the team of the server that ran the process instead of the causer's user id - servers API: handle the legacy build server setting - compose: support parent bind paths and volume driver options - dns: improve record hints and provider management - notifications: fix throttling and missing backup notifications - ui: rework the confirmation modal - add feature and unit tests for the new behavior
137 lines
3.9 KiB
PHP
137 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Contracts\ThrottledNotification;
|
|
use Carbon\CarbonInterface;
|
|
use Closure;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
|
use Throwable;
|
|
|
|
/**
|
|
* Records when a notification was last sent for a resource, so repeated checks
|
|
* (across queue workers) do not send the same notification again.
|
|
*/
|
|
class NotificationThrottle extends Model
|
|
{
|
|
public $timestamps = false;
|
|
|
|
protected $fillable = [
|
|
'notifiable_type',
|
|
'notifiable_id',
|
|
'notification',
|
|
'sent_at',
|
|
];
|
|
|
|
protected function casts(): array
|
|
{
|
|
return [
|
|
'sent_at' => 'datetime',
|
|
];
|
|
}
|
|
|
|
public function notifiable(): MorphTo
|
|
{
|
|
return $this->morphTo();
|
|
}
|
|
|
|
/**
|
|
* Atomically reserve the right to send a notification.
|
|
*
|
|
* Returns true when the notification was never sent, or when it was last sent
|
|
* before $sentBefore. Without $sentBefore, it is sent only once until released.
|
|
*/
|
|
public static function claim(Model $notifiable, string $notification, ?CarbonInterface $sentBefore = null): bool
|
|
{
|
|
if ($sentBefore !== null) {
|
|
$renewed = static::query()
|
|
->whereMorphedTo('notifiable', $notifiable)
|
|
->where('notification', $notification)
|
|
->where('sent_at', '<', $sentBefore)
|
|
->update(['sent_at' => now()]);
|
|
|
|
if ($renewed === 1) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return static::query()->insertOrIgnore([
|
|
'notifiable_type' => $notifiable->getMorphClass(),
|
|
'notifiable_id' => $notifiable->getKey(),
|
|
'notification' => $notification,
|
|
'sent_at' => now(),
|
|
]) === 1;
|
|
}
|
|
|
|
/**
|
|
* Claim the throttle, then run $send. When $send throws, the claim is released so the
|
|
* next attempt is not throttled, and the exception is rethrown.
|
|
*
|
|
* Returns false when the claim failed and $send did not run.
|
|
*/
|
|
public static function sendOnce(Model $notifiable, string $notification, ?CarbonInterface $sentBefore, Closure $send): bool
|
|
{
|
|
if (! static::claim($notifiable, $notification, $sentBefore)) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$send();
|
|
} catch (Throwable $exception) {
|
|
static::release($notifiable, $notification);
|
|
|
|
throw $exception;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Claim the throttle a notification declares. Notifications without a throttle subject are always allowed.
|
|
*/
|
|
public static function claimFor(ThrottledNotification $notification): bool
|
|
{
|
|
$subject = $notification->throttleSubject();
|
|
if ($subject === null) {
|
|
return true;
|
|
}
|
|
|
|
return static::claim($subject, $notification::class, now()->subMinutes($notification->throttleIntervalMinutes()));
|
|
}
|
|
|
|
/**
|
|
* Mark a notification as sent without sending it.
|
|
*/
|
|
public static function record(Model $notifiable, string $notification): void
|
|
{
|
|
static::query()->updateOrInsert(
|
|
[
|
|
'notifiable_type' => $notifiable->getMorphClass(),
|
|
'notifiable_id' => $notifiable->getKey(),
|
|
'notification' => $notification,
|
|
],
|
|
['sent_at' => now()],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Forget a sent notification. Returns true when a record was removed.
|
|
*/
|
|
public static function release(Model $notifiable, string $notification): bool
|
|
{
|
|
return static::query()
|
|
->whereMorphedTo('notifiable', $notifiable)
|
|
->where('notification', $notification)
|
|
->delete() > 0;
|
|
}
|
|
|
|
public static function wasSent(Model $notifiable, string $notification): bool
|
|
{
|
|
return static::query()
|
|
->whereMorphedTo('notifiable', $notifiable)
|
|
->where('notification', $notification)
|
|
->exists();
|
|
}
|
|
}
|