coolify/app/Models/S3Storage.php

155 lines
4.7 KiB
PHP
Raw Permalink Normal View History

2023-08-07 13:31:42 +00:00
<?php
namespace App\Models;
use App\Traits\HasSafeStringAttribute;
use Illuminate\Database\Eloquent\Casts\Attribute;
2023-08-07 13:31:42 +00:00
use Illuminate\Database\Eloquent\Factories\HasFactory;
2023-10-10 11:10:43 +00:00
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Facades\Storage;
2023-08-07 13:31:42 +00:00
class S3Storage extends BaseModel
{
use HasFactory, HasSafeStringAttribute;
2023-08-07 13:31:42 +00:00
protected $guarded = [];
2024-06-10 20:43:34 +00:00
protected $casts = [
'is_usable' => 'boolean',
'key' => 'encrypted',
'secret' => 'encrypted',
];
/**
* Boot the model and register event listeners.
*/
protected static function boot(): void
{
parent::boot();
// Trim whitespace from credentials before saving to prevent
// "Malformed Access Key Id" errors from accidental whitespace in pasted values.
// Note: We use the saving event instead of Attribute mutators because key/secret
// use Laravel's 'encrypted' cast. Attribute mutators fire before casts, which
// would cause issues with the encryption/decryption cycle.
static::saving(function (S3Storage $storage) {
if ($storage->key !== null) {
$storage->key = trim($storage->key);
}
if ($storage->secret !== null) {
$storage->secret = trim($storage->secret);
}
});
}
2024-06-10 20:43:34 +00:00
public static function ownedByCurrentTeam(array $select = ['*'])
2023-08-07 13:31:42 +00:00
{
$selectArray = collect($select)->concat(['id']);
2024-06-10 20:43:34 +00:00
2023-08-22 15:44:49 +00:00
return S3Storage::whereTeamId(currentTeam()->id)->select($selectArray->all())->orderBy('name');
2023-08-07 13:31:42 +00:00
}
2024-06-10 20:43:34 +00:00
2023-10-10 11:10:43 +00:00
public function isUsable()
{
return $this->is_usable;
}
2023-10-10 11:10:43 +00:00
public function team()
{
return $this->belongsTo(Team::class);
}
2024-06-10 20:43:34 +00:00
public function awsUrl()
{
2023-08-07 13:31:42 +00:00
return "{$this->endpoint}/{$this->bucket}";
}
protected function path(): Attribute
{
return Attribute::make(
set: function (?string $value) {
if ($value === null || $value === '') {
return null;
}
return str($value)->trim()->start('/')->value();
}
);
}
/**
* Trim whitespace from endpoint to prevent malformed URLs.
*/
protected function endpoint(): Attribute
{
return Attribute::make(
set: fn (?string $value) => $value ? trim($value) : null,
);
}
/**
* Trim whitespace from bucket name to prevent connection errors.
*/
protected function bucket(): Attribute
{
return Attribute::make(
set: fn (?string $value) => $value ? trim($value) : null,
);
}
/**
* Trim whitespace from region to prevent connection errors.
*/
protected function region(): Attribute
{
return Attribute::make(
set: fn (?string $value) => $value ? trim($value) : null,
);
}
public function testConnection(bool $shouldSave = false)
{
2023-10-10 11:10:43 +00:00
try {
$disk = Storage::build([
'driver' => 's3',
'region' => $this['region'],
'key' => $this['key'],
'secret' => $this['secret'],
'bucket' => $this['bucket'],
'endpoint' => $this['endpoint'],
'use_path_style_endpoint' => true,
]);
// Test the connection by listing files with ListObjectsV2 (S3)
$disk->files();
2023-10-10 11:10:43 +00:00
$this->unusable_email_sent = false;
$this->is_usable = true;
} catch (\Throwable $e) {
2023-10-10 11:10:43 +00:00
$this->is_usable = false;
if ($this->unusable_email_sent === false && is_transactional_emails_enabled()) {
$mail = new MailMessage;
$mail->subject('Coolify: S3 Storage Connection Error');
$mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('storage.show', ['storage_uuid' => $this->uuid])]);
// Load the team with its members and their roles explicitly
$team = $this->team()->with(['members' => function ($query) {
$query->withPivot('role');
}])->first();
// Get admins directly from the pivot relationship for this specific team
$users = $team->members()->wherePivotIn('role', ['admin', 'owner'])->get(['users.id', 'users.email']);
2023-10-10 11:10:43 +00:00
foreach ($users as $user) {
send_user_an_email($mail, $user->email);
2023-10-10 11:10:43 +00:00
}
$this->unusable_email_sent = true;
}
throw $e;
} finally {
if ($shouldSave) {
$this->save();
}
2023-10-10 11:10:43 +00:00
}
2023-08-07 13:31:42 +00:00
}
}