clrghouz/app/Models/File.php
Deon George 81f59dcbb8
All checks were successful
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 42s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 1m50s
Create Docker Image / Final Docker Image Manifest (push) Successful in 11s
Remove EncodeUTF8 infavour of using attribute casting only. The implementation of EncodeUTF8 was not correct, essentially removing any previous casting causing issues when saving a record.
2024-06-01 10:46:02 +10:00

218 lines
5.8 KiB
PHP

<?php
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use App\Casts\{CollectionOrNull,CompressedStringOrNull};
class File extends Model
{
use SoftDeletes;
private const LOGKEY = 'MF-';
private bool $no_export = FALSE;
public Collection $set_path;
public Collection $set_seenby;
public string $src_file = '';
protected $casts = [
'kludges' => CollectionOrNull::class,
'datetime' => 'datetime:Y-m-d H:i:s',
'desc' => CompressedStringOrNull::class,
'ldesc' => CompressedStringOrNull::class,
'rogue_seenby' => CollectionOrNull::class,
'rogue_path' => CollectionOrNull::class,
'size' => 'int',
];
public static function boot()
{
parent::boot();
static::creating(function($model) {
if (! $model->filearea_id) {
Log::alert(sprintf('%s:- File has no filearea, not processing creating [%s]',self::LOGKEY,$model->name));
return;
}
Log::info(sprintf('%s:- Storing file [%s] in [%s]',self::LOGKEY,$model->src_file,$model->rel_name));
$srcfs = Storage::disk(config('fido.local_disk'));
$tgtfs = Storage::disk(config('fido.file_disk'));
// Delete anything being replaced
foreach (self::where('name',$model->name)->where('filearea_id',$model->filearea_id)->get() as $fo) {
Log::info(sprintf('%s:%% Deleting old file record [%d] for file [%s]',self::LOGKEY,$fo->id,$fo->rel_name));
$tgtfs->move($fo->rel_name,$fo->relname.'.'.$fo->id);
$fo->delete();
}
// Store file
if ($tgtfs->put($model->rel_name,$srcfs->get($model->src_file),'public')) {
$srcfs->delete($model->src_file);
} else {
throw new \Exception(sprintf('Unable to move file [%s] to [%s]',$model->src_file,$model->rel_name));
}
});
// @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 [%d]',self::LOGKEY,$model->id));
return;
}
$rogue = collect();
$seenby = collect();
$path = collect();
$zone = $model->fftn->zone;
// Parse PATH
/**
* Path 21:4/106.0 @231005001126 PST+7 Foobar
* Path 21:1/100 1696489954 Thu Oct 05 07:12:34 2023 UTC htick/lnx 1.9 2022-07-03
*/
foreach ($model->set_path as $line) {
$matches = [];
preg_match(sprintf('#^(%s)\ ((@?)(\d+)(\ ([A-Z]{3}([\+\-][0-9]+)))?)\ ?(.*)$#',Address::ftn_regex),$line,$matches);
if ($x=Arr::get($matches,1)) {
$ftn = Address::parseFTN($x);
// If domain should be flattened, look for node regardless of zone (within the list of zones for the domain)
$ao = ($zone->domain->flatten)
? Address::findZone($zone->domain,$ftn['n'],$ftn['f'],0)
: Address::findFTN($x);
if (! $ao)
$ao = Address::createFTN($x,System::createUnknownSystem());
$datetime = ($matches[8] === '@')
? Carbon::createFromFormat('ymdHis',$matches[9],$matches[12])
: Carbon::createFromTimestamp($matches[7]);
$path->push(['address'=>$ao,'datetime'=>$datetime,'extra'=>$matches[13]]);
}
}
// Save the Path
$ppoid = NULL;
foreach ($path as $item) {
$po = DB::select('INSERT INTO file_path (file_id,address_id,parent_id,datetime,extra) VALUES (?,?,?,?,?) RETURNING id',[
$model->id,
$item['address']->id,
$ppoid,
$item['datetime'],
$item['extra'],
]);
$ppoid = $po[0]->id;
}
// Make sure all the path is in the seenby
// Add zone to seenby
$model->set_seenby = $model->set_seenby->merge($path->pluck('address.ftn3d'))->unique()->filter();
foreach ($model->set_seenby as $sb) {
$ftn = Address::parseFTN($sb);
$ao = ($zone->domain->flatten)
? Address::findZone($zone->domain,$ftn['n'],$ftn['f'],0)
: Address::findFTN($sb);
if ($ao)
$seenby->push($ao->id);
else
$rogue->push($sb);
}
$model->rogue_seenby = $rogue;
$model->seenby()->sync($seenby);
$model->save();
// See if we need to export this file.
if ($model->filearea->sec_read) {
$exportto = $model
->filearea
->addresses
->filter(function($item) use ($model) { return $model->filearea->can_read($item->security); })
->pluck('id')
->diff($seenby);
if ($exportto->count()) {
if ($model->no_export) {
Log::alert(sprintf('%s:- NOT processing exporting of message by configuration [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
return;
}
Log::info(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 getOriginAttribute(): Address
{
return $this->path->where('pivot.parent_id','=',NULL)->pop();
}
/**
* Return the relative path to Storage::disk() in the store
*
* @return string
*/
public function getRelNameAttribute(): string
{
return sprintf('%04X/%s',$this->filearea_id,$this->name);
}
/* METHODS */
public function jsonSerialize(): array
{
return $this->encode();
}
}