Automatically mark idle nodes HOLD/DOWN/DE-LIST. Automatically validate presented addresses.
This commit is contained in:
parent
0e1d5b3239
commit
35d9e5a5d5
@ -186,6 +186,8 @@ class Page
|
||||
$this->text .= $text;
|
||||
|
||||
$this->text_right = $right;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -426,8 +426,11 @@ abstract class Protocol
|
||||
|
||||
if ($so && $so->exists) {
|
||||
foreach ($this->node->aka_other as $aka)
|
||||
if (! Address::findFTN($aka))
|
||||
if (! Address::findFTN($aka)) {
|
||||
Address::createFTN($aka,$so);
|
||||
$o->validated = TRUE;
|
||||
$o->save();
|
||||
}
|
||||
|
||||
// Log session in DB
|
||||
$slo = new SystemLog;
|
||||
|
@ -711,6 +711,11 @@ final class Binkp extends BaseProtocol
|
||||
|
||||
} else {
|
||||
Log::info(sprintf('%s:- Got AKA [%s]',self::LOGKEY,$rem_aka));
|
||||
|
||||
// We'll update this address status
|
||||
$o->validated = TRUE;
|
||||
$o->role &= ~(Address::NODE_HOLD|Address::NODE_DOWN);
|
||||
$o->save();
|
||||
}
|
||||
|
||||
} catch (InvalidFTNException $e) {
|
||||
|
39
app/Console/Commands/AddressIdle.php
Normal file
39
app/Console/Commands/AddressIdle.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Jobs\AddressIdle as Job;
|
||||
use App\Models\{Address,Domain};
|
||||
|
||||
class AddressIdle extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'address:idle'
|
||||
.' {domain : Domain}'
|
||||
.' {--ftn= : Limit to specific address}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Find and mark nodes as hold/down/delist if idle';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$do = Domain::where('name',$this->argument('domain'))->singleOrFail();
|
||||
|
||||
Job::dispatchSync($do,$this->option('ftn') ? Address::findFTN($this->option('ftn')) : NULL);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ namespace App\Console;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
use App\Jobs\{MailSend,SystemHeartbeat};
|
||||
use App\Jobs\{AddressIdleDomain,MailSend,SystemHeartbeat};
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
@ -28,7 +28,8 @@ class Kernel extends ConsoleKernel
|
||||
{
|
||||
$schedule->job(new MailSend(TRUE))->everyMinute()->withoutOverlapping();
|
||||
$schedule->job(new MailSend(FALSE))->twiceDaily(1,13);
|
||||
$schedule->job(new SystemHeartbeat())->hourly();
|
||||
$schedule->job(new SystemHeartbeat)->hourly();
|
||||
$schedule->job(new AddressIdleDomain)->weeklyOn('Sunday','01:00');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,7 +36,7 @@ class DomainController extends Controller
|
||||
public function add_edit(DomainRequest $request,Domain $o)
|
||||
{
|
||||
if ($request->post()) {
|
||||
foreach (['name','dnsdomain','active','public','homepage','notes','flatten','accept_app'] as $key)
|
||||
foreach (['name','dnsdomain','active','public','homepage','notes','flatten','accept_app','nodestatus_id'] as $key)
|
||||
$o->{$key} = $request->post($key);
|
||||
|
||||
$o->save();
|
||||
|
@ -5,8 +5,9 @@ namespace App\Http\Requests;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
use App\Models\Domain;
|
||||
use App\Models\{Domain,Echoarea};
|
||||
|
||||
class DomainRequest extends FormRequest
|
||||
{
|
||||
@ -29,6 +30,11 @@ class DomainRequest extends FormRequest
|
||||
'public' => 'required|boolean',
|
||||
'accept_app' => 'required|boolean',
|
||||
'flatten' => 'nullable|boolean',
|
||||
'nodestatus_id' => [
|
||||
'nullable',
|
||||
Rule::exists(Echoarea::class,'id'),
|
||||
Rule::in($o->echoareas->pluck('id')),
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
189
app/Jobs/AddressIdle.php
Normal file
189
app/Jobs/AddressIdle.php
Normal file
@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
use App\Models\{Address,Domain,Echoarea};
|
||||
use App\Notifications\Echomails\AbsentNodes;
|
||||
use App\Notifications\Emails\NodeMarkedDown as NodeMarkedDownEmail;
|
||||
use App\Notifications\Netmails\NodeMarkedDown as NodeMarkedDownNetmail;
|
||||
use App\Notifications\Emails\NodeMarkedHold as NodeMarkedHoldEmail;
|
||||
use App\Notifications\Netmails\NodeMarkedHold as NodeMarkedHoldNetmail;
|
||||
use App\Notifications\Emails\NodeDelisted as NodeDelistedEmail;
|
||||
use App\Notifications\Netmails\NodeDelisted as NodeDelistedNetmail;
|
||||
|
||||
class AddressIdle implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JAI';
|
||||
|
||||
private ?Address $ao; // System address
|
||||
private Domain $do; // Domain we are processing
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(Domain $do,Address $ao=NULL)
|
||||
{
|
||||
$this->do = $do;
|
||||
$this->ao = $ao;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$result = collect();
|
||||
|
||||
// Delist DOWN nodes
|
||||
foreach ($this->old($this->do,config('fido.idle.delist'),Address::NODE_DOWN,$this->ao) as $ao) {
|
||||
// Only delist system that has been marked down
|
||||
// Only mark delist them if its been 7 days since they were marked DOWN
|
||||
if ((! $ao->is_down) || ($ao->updated_at->isPast(Carbon::now()->subWeek())))
|
||||
continue;
|
||||
|
||||
Log::info(sprintf('%s:- Delisting [%s], not seen for [%d] days',self::LOGKEY,$ao->ftn,config('fido.idle.delist')));
|
||||
$contact = FALSE;
|
||||
|
||||
// @todo Subscribe from echoareas/fileareas
|
||||
$ao->active = FALSE;
|
||||
$ao->save();
|
||||
|
||||
// Email Alert
|
||||
if ($ao->system->users->count()) {
|
||||
Notification::send($ao->system->users,new NodeDelistedEmail($ao->withoutRelations()));
|
||||
$contact = TRUE;
|
||||
}
|
||||
|
||||
// Netmail Alert (to othernet network address)
|
||||
// Uncommon addresses
|
||||
$uncommon = $ao->system->addresses->map(fn($item)=>$item->parent())->diff(our_address())->first();
|
||||
if ($uncommon) {
|
||||
Notification::route('netmail',$uncommon->withoutRelations())->notify(new NodeDelistedNetmail($ao->withoutRelations()));
|
||||
$contact = TRUE;
|
||||
}
|
||||
|
||||
$ao->contacted = (! $contact);
|
||||
$result->push($ao);
|
||||
}
|
||||
|
||||
// Mark nodes DOWN
|
||||
foreach ($this->old($this->do,config('fido.idle.down'),Address::NODE_HOLD,$this->ao) as $ao) {
|
||||
Log::info(sprintf('%s:- Marking [%s] as DOWN, not seen for [%d] days',self::LOGKEY,$ao->ftn,config('fido.idle.down')));
|
||||
$contact = FALSE;
|
||||
|
||||
// Email Alert
|
||||
if ($ao->system->users->count()) {
|
||||
Notification::send($ao->system->users,new NodeMarkedDownEmail($ao->withoutRelations()));
|
||||
$contact = TRUE;
|
||||
}
|
||||
|
||||
// Netmail Alert (to othernet network address)
|
||||
// Uncommon addresses
|
||||
$uncommon = $ao->system->addresses->map(fn($item)=>$item->parent())->diff(our_address())->first();
|
||||
if ($uncommon) {
|
||||
Notification::route('netmail',$uncommon->withoutRelations())->notify(new NodeMarkedDownNetmail($ao->withoutRelations()));
|
||||
$contact = TRUE;
|
||||
}
|
||||
|
||||
// Mark as DOWN
|
||||
$ao->role &= ~Address::NODE_HOLD;
|
||||
$ao->role |= Address::NODE_DOWN;
|
||||
$ao->save();
|
||||
|
||||
$ao->contacted = (! $contact);
|
||||
$result->push($ao);
|
||||
}
|
||||
|
||||
// Mark nodes as HOLD
|
||||
foreach ($this->old($this->do,config('fido.idle.hold'),0,$this->ao) as $ao) {
|
||||
// Ignore any systems already marked hold or down
|
||||
if ($ao->role & (Address::NODE_DOWN|Address::NODE_HOLD))
|
||||
continue;
|
||||
|
||||
$contact = FALSE;
|
||||
|
||||
Log::info(sprintf('%s:- Marking [%s] as HOLD, not seen for [%d] days',self::LOGKEY,$ao->ftn,config('fido.idle.hold')));
|
||||
|
||||
// Email Alert
|
||||
if ($ao->system->users->count()) {
|
||||
Notification::send($ao->system->users,new NodeMarkedHoldEmail($ao->withoutRelations()));
|
||||
$contact = TRUE;
|
||||
}
|
||||
|
||||
// Netmail Alert (to othernet network address)
|
||||
// Uncommon addresses
|
||||
$uncommon = $ao->system->addresses->map(fn($item)=>$item->parent())->diff(our_address())->first();
|
||||
if ($uncommon) {
|
||||
Notification::route('netmail',$uncommon->withoutRelations())->notify(new NodeMarkedHoldNetmail($ao->withoutRelations()));
|
||||
$contact = TRUE;
|
||||
}
|
||||
|
||||
// Mark as DOWN
|
||||
$ao->role |= Address::NODE_HOLD;
|
||||
$ao->save();
|
||||
|
||||
$ao->contacted = (! $contact);
|
||||
$result->push($ao);
|
||||
}
|
||||
|
||||
if ($result->count())
|
||||
Notification::route('echomail',$this->do->nodestatusarea)->notify(new AbsentNodes($result));
|
||||
}
|
||||
|
||||
private function old(Domain $do,int $days,int $flags=0,Address $ao=NULL): Collection
|
||||
{
|
||||
$age = Carbon::now()->subDays($days)->endOfDay();
|
||||
|
||||
return Address::select([
|
||||
'a.id',
|
||||
'a.system_id',
|
||||
'a.zone_id',
|
||||
'addresses.region_id',
|
||||
'a.host_id',
|
||||
'a.node_id',
|
||||
'a.point_id',
|
||||
'addresses.active',
|
||||
'addresses.hub_id',
|
||||
'addresses.role',
|
||||
'addresses.updated_at',
|
||||
DB::raw('sum(a.uncollected_echomail) as uncollected_echomail'),
|
||||
DB::raw('sum(a.uncollected_netmail) as uncollected_netmail'),
|
||||
DB::raw('sum(a.uncollected_files) as uncollected_files')
|
||||
])
|
||||
->from(
|
||||
Address::UncollectedEchomailTotal()
|
||||
->union(Address::UncollectedNetmailTotal())
|
||||
->union(Address::UncollectedFilesTotal()),'a')
|
||||
->where('systems.active',TRUE)
|
||||
->where('addresses.active',TRUE)
|
||||
->where('zones.active',TRUE)
|
||||
->where('domains.active',TRUE)
|
||||
->whereNotIn('a.id',our_address()->pluck('id'))
|
||||
->when($ao,fn($query)=>$query->where('addresses.id',$ao->id))
|
||||
->where('last_session','<',$age)
|
||||
->where('domains.id',$do->id)
|
||||
->whereRaw(sprintf('((role IS NULL) OR ((role & %d) > 0))',$flags))
|
||||
->join('addresses',['addresses.id'=>'a.id'])
|
||||
->join('systems',['systems.id'=>'a.system_id'])
|
||||
->join('zones',['zones.id'=>'addresses.zone_id'])
|
||||
->join('domains',['domains.id'=>'zones.domain_id'])
|
||||
->ftnOrder()
|
||||
->groupBy('a.system_id','a.id','a.zone_id','addresses.region_id','a.host_id','a.node_id','a.point_id','addresses.hub_id','addresses.role','addresses.active','addresses.updated_at')
|
||||
->with(['system','zone.domain'])
|
||||
->dontCache()
|
||||
->get();
|
||||
}
|
||||
}
|
32
app/Jobs/AddressIdleDomain.php
Normal file
32
app/Jobs/AddressIdleDomain.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
use App\Models\Domain;
|
||||
|
||||
class AddressIdleDomain implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
foreach (Domain::whereNotNull('nodestatus_id')->cursor() as $do)
|
||||
AddressIdle::dispatch($do);
|
||||
}
|
||||
}
|
@ -55,6 +55,11 @@ class Domain extends Model
|
||||
return $this->belongsTo(Filearea::class);
|
||||
}
|
||||
|
||||
public function nodestatusarea()
|
||||
{
|
||||
return $this->belongsTo(Echoarea::class,'nodestatus_id');
|
||||
}
|
||||
|
||||
public function zones()
|
||||
{
|
||||
return $this->hasMany(Zone::class);
|
||||
|
@ -46,24 +46,19 @@ abstract class Echomails extends Notification //implements ShouldQueue
|
||||
*/
|
||||
abstract public function toEchomail(object $notifiable): Echomail;
|
||||
|
||||
protected function setupEchomail(Echomail $mo,object $notifiable): Echomail
|
||||
protected function setupEchomail(Echoarea $eo): Echomail
|
||||
{
|
||||
$echoarea = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
$o = new Echomail;
|
||||
$o->from = Setup::PRODUCT_NAME;
|
||||
$o->replyid = $mo->msgid;
|
||||
$o->echoarea_id = $echoarea->id;
|
||||
|
||||
$o->echoarea_id = $eo->id;
|
||||
|
||||
$o->datetime = Carbon::now();
|
||||
$o->tzoffset = $o->datetime->utcOffset();
|
||||
|
||||
$o->fftn_id = ($x=our_address($mo->fftn))->id;
|
||||
$o->flags = (Message::FLAG_LOCAL);
|
||||
|
||||
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
|
||||
$o->origin = sprintf('%s (%s)',Setup::PRODUCT_NAME,$x->ftn4d);
|
||||
$o->kludges->put('CHRS:',$mo->kludges->get('chrs') ?: 'CP437 2');
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
86
app/Notifications/Echomails/AbsentNodes.php
Normal file
86
app/Notifications/Echomails/AbsentNodes.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Echomails;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\{Fonts\Thick,Page};
|
||||
use App\Models\{Address,Echomail,Setup};
|
||||
use App\Notifications\Echomails;
|
||||
use App\Traits\MessagePath;
|
||||
|
||||
class AbsentNodes extends Echomails
|
||||
{
|
||||
use MessagePath;
|
||||
|
||||
private const LOGKEY = 'NNP';
|
||||
|
||||
private Echomail $mo;
|
||||
|
||||
/**
|
||||
* Reply to a netmail ping request.
|
||||
*
|
||||
* @param Echomail $mo
|
||||
*/
|
||||
public function __construct(private Collection $aos)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return Echomail
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function toEchomail(object $notifiable): Echomail
|
||||
{
|
||||
$echoarea = $notifiable->routeNotificationFor(static::via);
|
||||
$o = $this->setupEchomail($echoarea);
|
||||
$now = Carbon::now();
|
||||
|
||||
Log::info(sprintf('%s:+ Creating NODE ABSENT echomail in [%s]',self::LOGKEY,$echoarea->name));
|
||||
|
||||
$o->to = 'All';
|
||||
$o->subject = 'Status changes for nodes';
|
||||
$o->fftn_id = ($x=our_address($echoarea->domain)->last())->id;
|
||||
$o->kludges->put('CHRS:','CP437 2');
|
||||
$o->origin = sprintf('%s (%s)',Setup::PRODUCT_NAME,$x->ftn4d);
|
||||
|
||||
// Message
|
||||
$msg = new Page;
|
||||
|
||||
$header = new Thick;
|
||||
$header->addText('Clearing Houz');
|
||||
$msg->addHeader($header,'FTN Mailer and Tosser',TRUE,0xc4);
|
||||
|
||||
$msg->addText("The following nodes have had their status changed, because they are absent from the network.\r\r");
|
||||
|
||||
// Nodes marked HOLD - will be marked down ...
|
||||
foreach ($this->aos->filter(fn($item)=>$item->role & Address::NODE_HOLD) as $ao)
|
||||
$msg->addText(sprintf('* %s marked HOLD, last seen %d days ago',$ao->ftn4d,$ao->system->last_session->diffInDays($now)).($ao->contacted ? '': ' ^')."\r");
|
||||
|
||||
// Nodes marked DOWN - will be delisted on...
|
||||
foreach ($this->aos->filter(fn($item)=>$item->role & Address::NODE_DOWN) as $ao)
|
||||
$msg->addText(sprintf('* %s marked DOWN, last seen %d days ago',$ao->ftn4d,$ao->system->last_session->diffInDays($now)).($ao->contacted ? '': ' ^')."\r");
|
||||
|
||||
// Nodes DELISTED
|
||||
foreach ($this->aos->filter(fn($item)=>! $item->active) as $ao)
|
||||
$msg->addText(sprintf('* %s DE-LISTED, last seen %d days ago',$ao->ftn4d,$ao->system->last_session->diffInDays($now)).($ao->contacted ? '': ' ^')."\r");
|
||||
|
||||
if ($this->aos->filter(fn($item)=>(! $item->contacted))->count())
|
||||
$msg->addText("\r^ Unable to contact these nodes.\r");
|
||||
|
||||
$msg->addText("\rEmails and/or Netmails have been sent to these nodes. If you can help let them know that they have outstanding mail on the Hub, that would be helpful :)");
|
||||
|
||||
$o->msg = $msg->render();
|
||||
$o->tagline = 'When life gives you lemons, freeze them and throw them back.';
|
||||
|
||||
$o->save();
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ use Carbon\CarbonInterface;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\{Fonts\Thick,Fonts\Thin,Page};
|
||||
use App\Models\Echomail;
|
||||
use App\Models\{Echomail,Setup};
|
||||
use App\Notifications\Echomails;
|
||||
use App\Traits\MessagePath;
|
||||
|
||||
@ -40,13 +40,17 @@ class Test extends Echomails
|
||||
*/
|
||||
public function toEchomail(object $notifiable): Echomail
|
||||
{
|
||||
$o = $this->setupEchomail($this->mo,$notifiable);
|
||||
$echoarea = $notifiable->routeNotificationFor(static::via);
|
||||
$o = $this->setupEchomail($echoarea);
|
||||
|
||||
Log::info(sprintf('%s:+ Creating TEST echomail in [%s]',self::LOGKEY,$echoarea->name));
|
||||
|
||||
$o->to = $this->mo->from;
|
||||
$o->fftn_id = ($x=our_address($this->mo->fftn))->id;
|
||||
$o->replyid = $this->mo->msgid;
|
||||
$o->subject = 'Test Reply';
|
||||
$o->kludges->put('CHRS:',$this->mo->kludges->get('chrs') ?: 'CP437 2');
|
||||
$o->origin = sprintf('%s (%s)',Setup::PRODUCT_NAME,$x->ftn4d);
|
||||
|
||||
// Message
|
||||
$msg = new Page;
|
||||
|
49
app/Notifications/Emails/NodeDelisted.php
Normal file
49
app/Notifications/Emails/NodeDelisted.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Emails;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
use App\Models\Address;
|
||||
|
||||
class NodeDelisted extends Notification //implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(private Address $ao)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
return (new MailMessage)
|
||||
->cc(our_address($this->ao)->system->users->first()->email)
|
||||
->subject(sprintf('Your system has been DE-LISTED on %s from %s',$now->format('Y-m-d'),$x=$this->ao->zone->domain->name))
|
||||
->line(sprintf('Your system has been DE-LISTED, because it hasnt polled **%s** since **%s** (%d days).',$x,$this->ao->system->last_session->format('Y-m-d'),$this->ao->system->last_session->diffInDays($now)))
|
||||
->line('')
|
||||
->line('If you think this was a mistake, please let me know.')
|
||||
->line(sprintf('If you think about returning to %s, then reach out and we can get you back online pretty quickly.',$x));
|
||||
}
|
||||
}
|
54
app/Notifications/Emails/NodeMarkedDown.php
Normal file
54
app/Notifications/Emails/NodeMarkedDown.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Emails;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
use App\Models\Address;
|
||||
|
||||
class NodeMarkedDown extends Notification //implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(private Address $ao)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
return (new MailMessage)
|
||||
->cc(our_address($this->ao)->system->users->first()->email)
|
||||
->subject(sprintf('ACTION REQUIRED: Your system will be delisted on %s',$now->format('Y-m-d')))
|
||||
->line(sprintf('Your system has been marked **DOWN**, because it hasnt polled **%s** since **%s** (%d days).',$this->ao->zone->domain->name,$this->ao->system->last_session->format('Y-m-d'),$this->ao->system->last_session->diffInDays($now)))
|
||||
->line('')
|
||||
->line('You have (waiting for collection):')
|
||||
->lineIf($this->ao->uncollected_netmail,sprintf('* %s Netmails',number_format($this->ao->uncollected_netmail)))
|
||||
->lineIf($this->ao->uncollected_echomail,sprintf('* %s Echomails',number_format($this->ao->uncollected_echomail)))
|
||||
->lineIf($this->ao->uncollected_files,sprintf('* %s Files',number_format($this->ao->uncollected_files)))
|
||||
->line('')
|
||||
->line(sprintf('Your system will automatically be **DE-LISTED** if your system hasnt polled to collected your mail/file(s) by **%s**',$now->addDays(7)->format('Y-m-d')))
|
||||
->line('If you think you\'ve received this email by mistake or need help, please let me know.');
|
||||
}
|
||||
}
|
54
app/Notifications/Emails/NodeMarkedHold.php
Normal file
54
app/Notifications/Emails/NodeMarkedHold.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Emails;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
use App\Models\Address;
|
||||
|
||||
class NodeMarkedHold extends Notification //implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(private Address $ao)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
return (new MailMessage)
|
||||
->cc(our_address($this->ao)->system->users->first()->email)
|
||||
->subject('Your system has been marked HOLD')
|
||||
->line(sprintf('Your system has been marked **HOLD**, because it hasnt polled **%s** since **%s** (%d days).',$this->ao->zone->domain->name,$this->ao->system->last_session->format('Y-m-d'),$this->ao->system->last_session->diffInDays($now)))
|
||||
->line('')
|
||||
->line('You have (waiting for collection):')
|
||||
->lineIf($this->ao->uncollected_netmail,sprintf('* %s Netmails',number_format($this->ao->uncollected_netmail)))
|
||||
->lineIf($this->ao->uncollected_echomail,sprintf('* %s Echomails',number_format($this->ao->uncollected_echomail)))
|
||||
->lineIf($this->ao->uncollected_files,sprintf('* %s Files',number_format($this->ao->uncollected_files)))
|
||||
->line('')
|
||||
->line(sprintf('To clear this status, all you need to do make sure your system polls and collects mail by **%s**',$this->ao->system->last_session->addDays(config('fido.idle.down'))->format('Y-m-d')))
|
||||
->line('If you think you\'ve received this email by mistake or need help, please let me know.');
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ abstract class Netmails extends Notification //implements ShouldQueue
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
* @todo change to object $notifiable
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
|
60
app/Notifications/Netmails/NodeDelisted.php
Normal file
60
app/Notifications/Netmails/NodeDelisted.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Netmails;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Address,Netmail};
|
||||
use App\Traits\PageTemplate;
|
||||
|
||||
class NodeDelisted extends Netmails //implements ShouldQueue
|
||||
{
|
||||
use Queueable,PageTemplate;
|
||||
|
||||
private const LOGKEY = 'NMD';
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(private Address $ao)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toNetmail(object $notifiable): Netmail
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Sending a NODE MARKED HOLD for address [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->subject = sprintf('Your system has been DE-LISTED from %s',$x=$ao->zone->domain->name);
|
||||
$o->flags = (Message::FLAG_LOCAL|Message::FLAG_PRIVATE|Message::FLAG_CRASH);
|
||||
|
||||
// Message
|
||||
$msg = $this->page(TRUE,'delist');
|
||||
|
||||
$msg->addText(sprintf("Hi %s,\r\r",$this->ao->system->sysop))
|
||||
->addText(sprintf("Your system has been marked **DE-LISTED**, because it hasnt polled **%s** with address %s since **%s** (%d days).\r",$this->ao->zone->domain->name,$this->ao->ftn4d,$this->ao->system->last_session->format('Y-m-d'),$this->ao->system->last_session->diffInDays($now)))
|
||||
->addText("\r")
|
||||
->addText("If you think this was a mistake, please let me know.\r")
|
||||
->addText(sprintf('If you think about returning to %s, then reach out and we can get you back online pretty quickly.',$x));
|
||||
|
||||
$o->msg = $msg->render();
|
||||
$o->tagline = 'You\'ve been DE-LISTED';
|
||||
|
||||
$o->save();
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
65
app/Notifications/Netmails/NodeMarkedDown.php
Normal file
65
app/Notifications/Netmails/NodeMarkedDown.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Netmails;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Address,Netmail};
|
||||
use App\Traits\PageTemplate;
|
||||
|
||||
class NodeMarkedDown extends Netmails //implements ShouldQueue
|
||||
{
|
||||
use Queueable,PageTemplate;
|
||||
|
||||
private const LOGKEY = 'NMD';
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(private Address $ao)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toNetmail(object $notifiable): Netmail
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Sending a NODE MARKED DOWN for address [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->subject = sprintf('ACTION REQUIRED: Your system will be delisted on %s',$now->format('Y-m-d'));
|
||||
$o->flags = (Message::FLAG_LOCAL|Message::FLAG_PRIVATE|Message::FLAG_CRASH);
|
||||
|
||||
// Message
|
||||
$msg = $this->page(TRUE,'down');
|
||||
|
||||
$msg->addText(sprintf("Hi %s,\r\r",$this->ao->system->sysop))
|
||||
->addText(sprintf("Your system has been marked **DOWN**, because it hasnt polled **%s** with address %s since **%s** (%d days).\r",$this->ao->zone->domain->name,$this->ao->ftn4d,$this->ao->system->last_session->format('Y-m-d'),$this->ao->system->last_session->diffInDays($now)))
|
||||
->addText("\r")
|
||||
->addText("You have (waiting for collection):\r")
|
||||
->addText(sprintf("* %s Netmails\r",number_format($this->ao->uncollected_netmail)))
|
||||
->addText(sprintf("* %s Echomails\r",number_format($this->ao->uncollected_echomail)))
|
||||
->addText(sprintf("* %s Files\r",number_format($this->ao->uncollected_files)))
|
||||
->addText("\r")
|
||||
->addText(sprintf("Your system will automatically be **DE-LISTED** if your system hasnt polled to collected your mail/file(s) by **%s**\r\r",$now->addDays(7)->format('Y-m-d')))
|
||||
->addText("If you think you've received this netmail by mistake or need help, please let me know.\r");
|
||||
|
||||
$o->msg = $msg->render();
|
||||
$o->tagline = 'Pending de-list';
|
||||
|
||||
$o->save();
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
65
app/Notifications/Netmails/NodeMarkedHold.php
Normal file
65
app/Notifications/Netmails/NodeMarkedHold.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Netmails;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Message;
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\{Address,Netmail};
|
||||
use App\Traits\PageTemplate;
|
||||
|
||||
class NodeMarkedHold extends Netmails //implements ShouldQueue
|
||||
{
|
||||
use Queueable,PageTemplate;
|
||||
|
||||
private const LOGKEY = 'NMD';
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(private Address $ao)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toNetmail(object $notifiable): Netmail
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Sending a NODE MARKED HOLD for address [%s]',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->subject = 'Your system has been marked HOLD';
|
||||
$o->flags = (Message::FLAG_LOCAL|Message::FLAG_PRIVATE|Message::FLAG_CRASH);
|
||||
|
||||
// Message
|
||||
$msg = $this->page(TRUE,'hold');
|
||||
|
||||
$msg->addText(sprintf("Hi %s,\r\r",$this->ao->system->sysop))
|
||||
->addText(sprintf("Your system has been marked **HOLD**, because it hasnt polled **%s** with address %s since **%s** (%d days).\r",$this->ao->zone->domain->name,$this->ao->ftn4d,$this->ao->system->last_session->format('Y-m-d'),$this->ao->system->last_session->diffInDays($now)))
|
||||
->addText("\r")
|
||||
->addText("You have (waiting for collection):\r")
|
||||
->addText(sprintf("* %s Netmails\r",number_format($this->ao->uncollected_netmail)))
|
||||
->addText(sprintf("* %s Echomails\r",number_format($this->ao->uncollected_echomail)))
|
||||
->addText(sprintf("* %s Files\r",number_format($this->ao->uncollected_files)))
|
||||
->addText("\r")
|
||||
->addText(sprintf("To clear this status, all you need to do make sure your system polls and collects mail by **%s**\r\r",$this->ao->system->last_session->addDays(config('fido.idle.down'))->format('Y-m-d')))
|
||||
->addText("If you think you've received this netmail by mistake or need help, please let me know.\r");
|
||||
|
||||
$o->msg = $msg->render();
|
||||
$o->tagline = 'You\'ve been marked HOLD';
|
||||
|
||||
$o->save();
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
@ -37,4 +37,10 @@ return [
|
||||
// Strict mode enforces what address we present to uplinks, when we carry more than 1 address with different roles
|
||||
// When true, we'll only present a role that is higher than the node we are talking to
|
||||
'strict' => env('FIDO_STRICT',FALSE),
|
||||
|
||||
'idle' => [
|
||||
'hold' => 21,
|
||||
'down' => 35,
|
||||
'delist' => 45,
|
||||
],
|
||||
];
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('domains', function (Blueprint $table) {
|
||||
$table->integer('nodestatus_id')->nullable();
|
||||
$table->foreign(['nodestatus_id'])->references(['id'])->on('echoareas');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('domains', function (Blueprint $table) {
|
||||
$table->dropForeign(['nodestatus_id']);
|
||||
$table->dropColumn('nodestatus_id');
|
||||
});
|
||||
}
|
||||
};
|
@ -4,6 +4,10 @@
|
||||
@if($o->exists) Update @else Add @endif Domain
|
||||
@endsection
|
||||
|
||||
@php
|
||||
use App\Models\Echoarea;
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
<form class="needs-validation" method="post" novalidate>
|
||||
@csrf
|
||||
@ -62,7 +66,7 @@
|
||||
@if ($o->nodelist_filename)
|
||||
<label for="nodelist_filename" class="form-label">Nodelist File</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="bi bi bi-file-earmark-break-fill"></i></span>
|
||||
<span class="input-group-text"><i class="bi bi-file-earmark-break-fill"></i></span>
|
||||
<input type="text" class="form-control" id="nodelist_filename" placeholder="Nodelist" name="nodelist_filename" value="{{ $o->nodelist_filename }}" readonly>
|
||||
</div>
|
||||
@else
|
||||
@ -116,10 +120,10 @@
|
||||
|
||||
@if ($o->nodelist_filename)
|
||||
<div class="col-4">
|
||||
<label for="name" class="form-label">Nodelist File Area</label>
|
||||
<label for="nodelist" class="form-label">Nodelist File Area</label>
|
||||
<a href="{{ url('filearea/addedit',$o->nodelist_filearea_id) }}">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="bi bi bi-collection-fill"></i></span>
|
||||
<span class="input-group-text"><i class="bi bi-collection-fill"></i></span>
|
||||
<input type="text" class="form-control @error('nodelist') is-invalid @enderror" id="nodelist" placeholder="Nodelist" name="nodelist" value="{{ $o->nodelist_filearea->name }}" readonly>
|
||||
</div>
|
||||
</a>
|
||||
@ -127,6 +131,29 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<label for="nodestatus_id" class="form-label">Echoarea Node Status</label>
|
||||
<div class="input-group has-validation">
|
||||
<span class="input-group-text"><i class="bi bi-journal-text"></i></span>
|
||||
<select style="width: 80%;" class="form-select @error('nodestatus_id') is-invalid @enderror" id="nodestatus_id" name="nodestatus_id" @cannot('admin',$o)disabled @endcannot>
|
||||
<option value=""> </option>
|
||||
@foreach (Echoarea::active()->where('domain_id',$o->id)->orderBy('description')->cursor() as $oo)
|
||||
<option value="{{ $oo->id }}" @if(old('nodestatus_id',$o->nodestatus_id)==$oo->id)selected @endif>{{ $oo->description }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<span class="invalid-feedback" role="alert">
|
||||
@error('nodestatus_id')
|
||||
{{ $message }}
|
||||
@enderror
|
||||
</span>
|
||||
<span class="input-helper">Add a <a href="{{ url('echoarea/addedit') }}">NEW Echoarea</a>. This echoarea is used to send node status messages.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label for="notes" class="form-label">Notes</label>
|
||||
@ -167,13 +194,19 @@
|
||||
|
||||
@section('page-css')
|
||||
@css('simplemde')
|
||||
@css('select2')
|
||||
@append
|
||||
@section('page-scripts')
|
||||
@js('simplemde')
|
||||
@js('select2')
|
||||
|
||||
@can('admin',$o)
|
||||
<script type="text/javascript">
|
||||
var simplemde = new SimpleMDE({ element: $("#homepage")[0] });
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#nodestatus_id').select2();
|
||||
});
|
||||
</script>
|
||||
@endcan
|
||||
@append
|
Loading…
Reference in New Issue
Block a user