Show netmails to admins, record netmail path in the DB

This commit is contained in:
Deon George 2023-06-18 23:33:26 +10:00
parent f147b33b60
commit 58341db0fb
10 changed files with 214 additions and 17 deletions

View File

@ -14,11 +14,11 @@ class CompressedString implements CastsAttributes
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param array $attributes * @param array $attributes
* @return string|null * @return string
*/ */
public function get($model,string $key,$value,array $attributes): ?string public function get($model,string $key,$value,array $attributes): string
{ {
return $value ? zstd_uncompress(base64_decode($value)) : NULL; return $value ? zstd_uncompress(base64_decode($value)) : '';
} }
/** /**
@ -28,10 +28,10 @@ class CompressedString implements CastsAttributes
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param array $attributes * @param array $attributes
* @return string|null * @return string
*/ */
public function set($model,string $key,$value,array $attributes): ?string public function set($model,string $key,$value,array $attributes): string
{ {
return $value ? base64_encode(zstd_compress($value)) : NULL; return $value ? base64_encode(zstd_compress($value)) : '';
} }
} }

View File

@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Validator as ValidatorResult; use Illuminate\Validation\Validator as ValidatorResult;
use App\Classes\FTN as FTNBase; use App\Classes\FTN as FTNBase;
use App\Http\Controllers\DomainController;
use App\Models\{Address,Domain,Zone}; use App\Models\{Address,Domain,Zone};
use App\Rules\{TwoByteInteger,TwoByteIntegerWithZero}; use App\Rules\{TwoByteInteger,TwoByteIntegerWithZero};
use App\Traits\EncodeUTF8; use App\Traits\EncodeUTF8;
@ -632,7 +633,7 @@ class Message extends FTNBase
/** /**
* Parse the Seenby/path lines and return a collection of addresses * Parse the Seenby/path lines and return a collection of addresses
* *
* @param string $type * @param string $type Type of address, ie: seenby/path
* @param Collection $addresses * @param Collection $addresses
* @param Collection $rogue * @param Collection $rogue
* @return Collection * @return Collection
@ -658,7 +659,7 @@ class Message extends FTNBase
$node = (int)$item; $node = (int)$item;
}; };
$ftn = sprintf('%d:%d/%d',$this->fz,$net&0x7fff,$node&0x7fff); $ftn = sprintf('%d:%d/%d',$this->fz,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX);
// @todo This should be enhanced to include the address at the time of the message. // @todo This should be enhanced to include the address at the time of the message.
if ($aos->has($ftn)) if ($aos->has($ftn))
$ao = $aos->get($ftn); $ao = $aos->get($ftn);
@ -712,6 +713,48 @@ class Message extends FTNBase
} }
} }
/**
* Parse the via address and return a collection of addresses
*
* <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone] <Program Name> <Version> [Serial Number]
*
* @param Collection $via
* @param Collection $rogue
* @return Collection
*/
private function parseVia(Collection $via,Collection &$rogue): Collection
{
$nodes = collect();
foreach ($via as $line) {
$m = [];
if (preg_match('/^([0-9]+:[0-9]+\/[0-9]+(\..*)?)\s+@([0-9.a-zA-Z]+)\s+(.*)$/',$line,$m)) {
// Address
$ao = Address::findFTN($m[1]);
// Time
$t = [];
$datetime = '';
if (! preg_match('/^([0-9]+\.[0-9]+)(\.?(.*))?$/',$m[3],$t))
Log::alert(sprintf('%s:! Unable to determine time from [%s]',self::LOGKEY,$m[3]));
else
$datetime = Carbon::createFromFormat('Ymd.His',$t[1],$t[3] ?? '');
if (! $ao) {
Log::alert(sprintf('%s:! Undefined Node [%s] for Netmail.',self::LOGKEY,$m[1]));
//$rogue->push(['node'=>$m[1],'datetime'=>$datetime,'program'=>$m[4]]);
} else {
$nodes->push(['node'=>$ao,'datetime'=>$datetime,'program'=>$m[4]]);
}
}
}
return $nodes;
}
/** /**
* Extract information out of the message text. * Extract information out of the message text.
* *
@ -904,6 +947,10 @@ class Message extends FTNBase
// Parse PATH // Parse PATH
if ($this->path->count()) if ($this->path->count())
$this->pathaddress = $this->parseAddresses('path',$this->path,$this->rogue_path); $this->pathaddress = $this->parseAddresses('path',$this->path,$this->rogue_path);
// Parse VIA
if ($this->via->count())
$this->pathaddress = $this->parseVia($this->via,$this->rogue_path);
} }
/** /**

View File

@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Gate;
use App\Classes\File; use App\Classes\File;
use App\Classes\FTN\Packet; use App\Classes\FTN\Packet;
use App\Models\{Address,Domain,Echomail,Setup}; use App\Models\{Address,Domain,Echomail,Netmail,Setup};
class HomeController extends Controller class HomeController extends Controller
{ {
@ -97,7 +97,7 @@ class HomeController extends Controller
list($zone_id,$host_id,$node_id,$point_id,$domain) = sscanf($request->query('term'),'%d:%d/%d.%d@%s'); list($zone_id,$host_id,$node_id,$point_id,$domain) = sscanf($request->query('term'),'%d:%d/%d.%d@%s');
# Look for Systems // Look for Systems
foreach (Address::select(['systems.name',DB::raw('systems.id AS system_id'),'zones.zone_id','region_id','host_id','node_id','point_id']) foreach (Address::select(['systems.name',DB::raw('systems.id AS system_id'),'zones.zone_id','region_id','host_id','node_id','point_id'])
->join('zones',['zones.id'=>'addresses.zone_id']) ->join('zones',['zones.id'=>'addresses.zone_id'])
->rightjoin('systems',['systems.id'=>'addresses.system_id']) ->rightjoin('systems',['systems.id'=>'addresses.system_id'])
@ -124,7 +124,7 @@ class HomeController extends Controller
$result->push(['id'=>$o->system_id,'name'=>$o->name.($ftn ? ' '.$ftn : ''),'value'=>url('system/view',[$o->system_id]),'category'=>'Systems']); $result->push(['id'=>$o->system_id,'name'=>$o->name.($ftn ? ' '.$ftn : ''),'value'=>url('system/view',[$o->system_id]),'category'=>'Systems']);
} }
# Look for Messages // Look for Echomail
foreach (Echomail::select(['id','fftn_id','from']) foreach (Echomail::select(['id','fftn_id','from'])
->where('msgid','like','%'.$request->query('term').'%') ->where('msgid','like','%'.$request->query('term').'%')
->orWhere('replyid','like','%'.$request->query('term').'%') ->orWhere('replyid','like','%'.$request->query('term').'%')
@ -133,6 +133,16 @@ class HomeController extends Controller
$result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',$o->from,$o->fftn->ftn3d),'value'=>url('echomail/view',[$o->id]),'category'=>'Echomail']); $result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',$o->from,$o->fftn->ftn3d),'value'=>url('echomail/view',[$o->id]),'category'=>'Echomail']);
} }
// Look for Netmail
if (Gate::check('admin'))
foreach (Netmail::select(['id','fftn_id','from'])
->where('msgid','like','%'.$request->query('term').'%')
->orWhere('replyid','like','%'.$request->query('term').'%')
->get() as $o)
{
$result->push(['id'=>$o->id,'name'=>sprintf('%s (%s)',$o->from,$o->fftn->ftn3d),'value'=>url('netmail/view',[$o->id]),'category'=>'Netmail']);
}
return $result->unique(['id'])->take(10)->values(); return $result->unique(['id'])->take(10)->values();
} }

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers;
use App\Models\Netmail;
class NetmailController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function view(Netmail $o)
{
return view('netmail.view')
->with('o',$o);
}
}

View File

@ -54,6 +54,7 @@ class MessageProcess implements ShouldQueue
$o = $this->create_netmail($this->msg); $o = $this->create_netmail($this->msg);
$o->recv_pkt = $this->packet; $o->recv_pkt = $this->packet;
$o->set_path = $this->msg->pathaddress;
// Determine if the message is to this system, or in transit // Determine if the message is to this system, or in transit
if ($ftns->search(function($item) { return $this->msg->tftn == $item->ftn; }) !== FALSE) { if ($ftns->search(function($item) { return $this->msg->tftn == $item->ftn; }) !== FALSE) {

View File

@ -5,8 +5,11 @@ namespace App\Models;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Casts\CompressedString;
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
use App\Interfaces\Packet; use App\Interfaces\Packet;
use App\Traits\{EncodeUTF8,MsgID}; use App\Traits\{EncodeUTF8,MsgID};
@ -17,6 +20,8 @@ final class Netmail extends Model implements Packet
use SoftDeletes,EncodeUTF8,MsgID; use SoftDeletes,EncodeUTF8,MsgID;
private Collection $set_path;
private const cast_utf8 = [ private const cast_utf8 = [
'to', 'to',
'from', 'from',
@ -30,6 +35,44 @@ final class Netmail extends Model implements Packet
protected $dates = ['datetime','sent_at']; protected $dates = ['datetime','sent_at'];
protected $casts = [
'msg' => CompressedString::class,
'msg_src' => CompressedString::class,
];
public function __set($key,$value)
{
switch ($key) {
case 'set_path':
$this->{$key} = $value;
break;
default:
parent::__set($key,$value);
}
}
public static function boot()
{
parent::boot();
static::created(function($model) {
// Save the Path
$ppoid = NULL;
foreach ($model->set_path as $path) {
$po = DB::select('INSERT INTO netmail_path (netmail_id,address_id,parent_id,datetime,program) VALUES (?,?,?,?,?) RETURNING id',[
$model->id,
$path['node']->id,
$ppoid,
(string)$path['datetime'],
$path['program'],
]);
$ppoid = $po[0]->id;
}
});
}
/* RELATIONS */ /* RELATIONS */
public function fftn() public function fftn()
@ -39,6 +82,12 @@ final class Netmail extends Model implements Packet
->withTrashed(); ->withTrashed();
} }
public function path()
{
return $this->belongsToMany(Address::class,'netmail_path')
->withPivot(['id','parent_id','datetime','program']);
}
public function tftn() public function tftn()
{ {
return $this return $this
@ -113,4 +162,16 @@ final class Netmail extends Model implements Packet
return $o; return $o;
} }
public function pathorder(string $display='ftn2d',int $start=NULL): Collection
{
$result = collect();
if ($x=$this->path->firstWhere('pivot.parent_id',$start)) {
$result->push($x->$display);
$result->push($this->pathorder($display,$x->pivot->id));
};
return $result->flatten()->filter();
}
} }

View File

@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('netmail_path', function (Blueprint $table) {
$table->id();
$table->bigInteger('address_id');
$table->foreign('address_id')->references('id')->on('addresses');
$table->unique(['id','netmail_id']);
$table->unique(['netmail_id','address_id','parent_id']);
$table->bigInteger('parent_id')->nullable();
$table->foreign(['parent_id','netmail_id'])->references(['id','netmail_id'])->on('netmail_path');
$table->bigInteger('netmail_id');
$table->foreign('netmail_id')->references('id')->on('netmails');
$table->dateTime('datetime');
$table->string('program');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('netmail_path');
}
};

View File

@ -0,0 +1,10 @@
@extends('layouts.app')
@section('htmlheader_title')
Message View
@endsection
@section('content')
<h3>Netmail</h3>
@include('widgets.message',['msg'=>$o])
@endsection

View File

@ -1,6 +1,6 @@
<div class="row"> <div class="row">
<div class="col-4"> <div class="col-4">
TO: <strong class="highlight">{!! \App\Classes\FTN\Message::tr($msg->to) !!}</strong> TO: <strong class="highlight">{!! \App\Classes\FTN\Message::tr($msg->to) !!}</strong>@if ($msg instanceof \App\Models\Netmail)(<strong class="highlight">{{ $msg->tftn->ftn }}</strong>)@endif
</div> </div>
<div class="col-4"> <div class="col-4">
DATE: <strong class="highlight">{{ $msg->datetime->format('Y-m-d H:i:s') }}</strong> DATE: <strong class="highlight">{{ $msg->datetime->format('Y-m-d H:i:s') }}</strong>
@ -35,11 +35,13 @@
</div> </div>
</div> </div>
<div class="row pb-2"> @if ($msg instanceof \App\Models\Echomail)
<div class="row pb-2">
<div class="col-8"> <div class="col-8">
SEENBY: <br><strong class="highlight">{!! optimize_path($msg->seenby->pluck('ftn2d'))->join('</strong>, <strong class="highlight">') !!}</strong> SEENBY: <br><strong class="highlight">{!! optimize_path($msg->seenby->pluck('ftn2d'))->join('</strong>, <strong class="highlight">') !!}</strong>
</div> </div>
</div> </div>
@endif
<div class="row pb-2"> <div class="row pb-2">
<div class="col-8"> <div class="col-8">

View File

@ -8,6 +8,7 @@ use App\Http\Controllers\{HomeController,
EchoareaController, EchoareaController,
EchomailController, EchomailController,
FileareaController, FileareaController,
NetmailController,
SystemController, SystemController,
UserController, UserController,
UserSwitchController, UserSwitchController,
@ -106,6 +107,7 @@ Route::middleware(['auth','can:admin'])->group(function () {
Route::match(['get','post'],'setup',[HomeController::class,'setup']); Route::match(['get','post'],'setup',[HomeController::class,'setup']);
Route::get('echomail/view/{o}',[EchomailController::class,'view']); Route::get('echomail/view/{o}',[EchomailController::class,'view']);
Route::get('netmail/view/{o}',[NetmailController::class,'view']);
Route::get('user/list',[UserController::class,'home']); Route::get('user/list',[UserController::class,'home']);
Route::match(['get','post'],'user/addedit/{o?}',[UserController::class,'add_edit']) Route::match(['get','post'],'user/addedit/{o?}',[UserController::class,'add_edit'])
->where('o','[0-9]+'); ->where('o','[0-9]+');