<?php namespace App\Models; use Carbon\Carbon; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\File as FileFacade; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; use Rennokki\QueryCache\Traits\QueryCacheable; use App\Casts\{CollectionOrNull,CompressedString}; use App\Traits\EncodeUTF8; class File extends Model { use SoftDeletes,EncodeUTF8,QueryCacheable; private const LOGKEY = 'MF-'; private bool $no_export = FALSE; protected $casts = [ 'kludges' => CollectionOrNull::class, 'rogue_seenby' => CollectionOrNull::class, 'rogue_path' => CollectionOrNull::class, 'desc' => CompressedString::class, 'ldesc' => CompressedString::class, 'size' => 'int', ]; private const cast_utf8 = [ 'desc', 'ldesc', ]; protected $dates = ['datetime']; public function __set($key,$value) { switch ($key) { case 'fullname': case 'replaces': case 'no_export': case 'set_path': case 'set_packet': case 'set_seenby': $this->{$key} = $value; break; default: parent::__set($key,$value); } } public static function boot() { parent::boot(); static::creating(function($model) { Log::debug(sprintf('%s:- Storing file [%s] in [%s]',self::LOGKEY,$model->fullname,$model->full_storage_path)); // Store file if (Storage::put($model->full_storage_path,Storage::disk('local')->get($model->fullname),'public')) { unlink(Storage::disk('local')->path($model->fullname)); } else { throw new \Exception(sprintf('Unable to move file [%s] to [%s]',$model->fullname,$model->full_storage_path)); }; // Delete anything being replaced // @todo implement replace }); // @todo if the file is updated with new SEEN-BY's from another route, we'll delete the pending export for systems (if there is one) static::created(function($model) { if (! $model->filearea_id) { Log::alert(sprintf('%s:- File has no filearea, not exporting',self::LOGKEY,$model->id)); return; } $so = Setup::findOrFail(config('app.id')); // Our address $ftns = $so ->system ->match($model->fftn->zone,Address::NODE_ACTIVE|Address::NODE_PVT|Address::NODE_HOLD); // Add our address to the seenby; $model->set_seenby = $model->set_seenby->merge($ftns->pluck('id'))->unique(); $model->set_path = $model->set_path->merge([[ 'address'=>$ftns->first(), 'datetime'=>($x=Carbon::now())->timestamp, 'extra'=>sprintf('%s %s (%s)',$x->toRfc7231String(),$so::PRODUCT_NAME,$so->version), ]]); // Make sure all the path is in the seenby $model->set_seenby = $model->set_seenby->merge($model->set_path->pluck('address.id'))->unique(); // Save the seenby $model->seenby()->sync($model->set_seenby); // Save the Path $ppoid = NULL; foreach ($model->set_path as $path) { $po = DB::select('INSERT INTO file_path (file_id,address_id,parent_id,datetime,extra) VALUES (?,?,?,?,?) RETURNING id',[ $model->id, $path['address']->id, $ppoid, Carbon::createFromTimestamp($path['datetime']), $path['extra'], ]); $ppoid = $po[0]->id; } // See if we need to export this message. $exportto = $model->filearea->addresses->pluck('id')->diff($model->set_seenby); if ($exportto->count()) { if ($model->no_export) { Log::debug(sprintf('%s:- NOT processing exporting of message by configuration [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(','))); return; } Log::debug(sprintf('%s:- Exporting file [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(','))); // Save the seenby for the exported systems $model->seenby()->syncWithPivotValues($exportto,['export_at'=>Carbon::now()],FALSE); } }); } /* RELATIONS */ public function filearea() { return $this->belongsTo(Filearea::class); } public function fftn() { return $this->belongsTo(Address::class) ->withTrashed(); } public function seenby() { return $this->belongsToMany(Address::class,'file_seenby') ->ftnOrder(); } public function path() { return $this->belongsToMany(Address::class,'file_path') ->withPivot(['id','parent_id','datetime','extra']); } /* ATTRIBUTES */ public function getFullStoragePathAttribute(): string { return sprintf('%04X/%s',$this->filearea_id,$this->file); } /* METHODS */ public function jsonSerialize(): array { return $this->encode(); } }