diff --git a/app/Classes/Page.php b/app/Classes/Page.php index d89ef01..f655a5d 100644 --- a/app/Classes/Page.php +++ b/app/Classes/Page.php @@ -186,6 +186,8 @@ class Page $this->text .= $text; $this->text_right = $right; + + return $this; } /** diff --git a/app/Classes/Protocol.php b/app/Classes/Protocol.php index 27aa251..f77a83f 100644 --- a/app/Classes/Protocol.php +++ b/app/Classes/Protocol.php @@ -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; diff --git a/app/Classes/Protocol/Binkp.php b/app/Classes/Protocol/Binkp.php index 0616937..508998c 100644 --- a/app/Classes/Protocol/Binkp.php +++ b/app/Classes/Protocol/Binkp.php @@ -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) { diff --git a/app/Console/Commands/AddressIdle.php b/app/Console/Commands/AddressIdle.php new file mode 100644 index 0000000..cd4cce1 --- /dev/null +++ b/app/Console/Commands/AddressIdle.php @@ -0,0 +1,39 @@ +argument('domain'))->singleOrFail(); + + Job::dispatchSync($do,$this->option('ftn') ? Address::findFTN($this->option('ftn')) : NULL); + + return self::SUCCESS; + } +} \ No newline at end of file diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 29042a5..ac083a3 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -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'); } /** diff --git a/app/Http/Controllers/DomainController.php b/app/Http/Controllers/DomainController.php index 904d0f2..ddcc13e 100644 --- a/app/Http/Controllers/DomainController.php +++ b/app/Http/Controllers/DomainController.php @@ -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(); diff --git a/app/Http/Requests/DomainRequest.php b/app/Http/Requests/DomainRequest.php index 26b2c19..8b64fe5 100644 --- a/app/Http/Requests/DomainRequest.php +++ b/app/Http/Requests/DomainRequest.php @@ -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')), + ] ]; } } \ No newline at end of file diff --git a/app/Jobs/AddressIdle.php b/app/Jobs/AddressIdle.php new file mode 100644 index 0000000..9ac3ecd --- /dev/null +++ b/app/Jobs/AddressIdle.php @@ -0,0 +1,189 @@ +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(); + } +} \ No newline at end of file diff --git a/app/Jobs/AddressIdleDomain.php b/app/Jobs/AddressIdleDomain.php new file mode 100644 index 0000000..1e7d5e6 --- /dev/null +++ b/app/Jobs/AddressIdleDomain.php @@ -0,0 +1,32 @@ +cursor() as $do) + AddressIdle::dispatch($do); + } +} \ No newline at end of file diff --git a/app/Models/Domain.php b/app/Models/Domain.php index 87dfb34..19d3334 100644 --- a/app/Models/Domain.php +++ b/app/Models/Domain.php @@ -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); diff --git a/app/Notifications/Echomails.php b/app/Notifications/Echomails.php index c705018..6ee2788 100644 --- a/app/Notifications/Echomails.php +++ b/app/Notifications/Echomails.php @@ -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; } diff --git a/app/Notifications/Echomails/AbsentNodes.php b/app/Notifications/Echomails/AbsentNodes.php new file mode 100644 index 0000000..53517dc --- /dev/null +++ b/app/Notifications/Echomails/AbsentNodes.php @@ -0,0 +1,86 @@ +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; + } +} \ No newline at end of file diff --git a/app/Notifications/Echomails/Test.php b/app/Notifications/Echomails/Test.php index 14e3d63..6aee01d 100644 --- a/app/Notifications/Echomails/Test.php +++ b/app/Notifications/Echomails/Test.php @@ -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; diff --git a/app/Notifications/Emails/NodeDelisted.php b/app/Notifications/Emails/NodeDelisted.php new file mode 100644 index 0000000..216c765 --- /dev/null +++ b/app/Notifications/Emails/NodeDelisted.php @@ -0,0 +1,49 @@ + + */ + 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)); + } +} \ No newline at end of file diff --git a/app/Notifications/Emails/NodeMarkedDown.php b/app/Notifications/Emails/NodeMarkedDown.php new file mode 100644 index 0000000..2686628 --- /dev/null +++ b/app/Notifications/Emails/NodeMarkedDown.php @@ -0,0 +1,54 @@ + + */ + 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.'); + } +} \ No newline at end of file diff --git a/app/Notifications/Emails/NodeMarkedHold.php b/app/Notifications/Emails/NodeMarkedHold.php new file mode 100644 index 0000000..eeffbee --- /dev/null +++ b/app/Notifications/Emails/NodeMarkedHold.php @@ -0,0 +1,54 @@ + + */ + 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.'); + } +} \ No newline at end of file diff --git a/app/Notifications/Netmails.php b/app/Notifications/Netmails.php index 3276680..1a5bc08 100644 --- a/app/Notifications/Netmails.php +++ b/app/Notifications/Netmails.php @@ -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) { diff --git a/app/Notifications/Netmails/NodeDelisted.php b/app/Notifications/Netmails/NodeDelisted.php new file mode 100644 index 0000000..af4b548 --- /dev/null +++ b/app/Notifications/Netmails/NodeDelisted.php @@ -0,0 +1,60 @@ +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; + } +} \ No newline at end of file diff --git a/app/Notifications/Netmails/NodeMarkedDown.php b/app/Notifications/Netmails/NodeMarkedDown.php new file mode 100644 index 0000000..f7b3f8c --- /dev/null +++ b/app/Notifications/Netmails/NodeMarkedDown.php @@ -0,0 +1,65 @@ +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; + } +} \ No newline at end of file diff --git a/app/Notifications/Netmails/NodeMarkedHold.php b/app/Notifications/Netmails/NodeMarkedHold.php new file mode 100644 index 0000000..27e37db --- /dev/null +++ b/app/Notifications/Netmails/NodeMarkedHold.php @@ -0,0 +1,65 @@ +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; + } +} \ No newline at end of file diff --git a/config/fido.php b/config/fido.php index 4afc533..13d02e6 100644 --- a/config/fido.php +++ b/config/fido.php @@ -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, + ], ]; \ No newline at end of file diff --git a/database/migrations/2024_05_25_213358_nodestatus_id_to_domains.php b/database/migrations/2024_05_25_213358_nodestatus_id_to_domains.php new file mode 100644 index 0000000..b4f5346 --- /dev/null +++ b/database/migrations/2024_05_25_213358_nodestatus_id_to_domains.php @@ -0,0 +1,30 @@ +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'); + }); + } +}; diff --git a/resources/views/domain/addedit.blade.php b/resources/views/domain/addedit.blade.php index ea9ae2b..ef37a55 100644 --- a/resources/views/domain/addedit.blade.php +++ b/resources/views/domain/addedit.blade.php @@ -4,6 +4,10 @@ @if($o->exists) Update @else Add @endif Domain @endsection +@php +use App\Models\Echoarea; +@endphp + @section('content')
@csrf @@ -62,7 +66,7 @@ @if ($o->nodelist_filename)
- +
@else @@ -116,10 +120,10 @@ @if ($o->nodelist_filename)
- +
- +
@@ -127,6 +131,29 @@ @endif
+
+
+
+
+ +
+ + + + @error('nodestatus_id') + {{ $message }} + @enderror + + Add a NEW Echoarea. This echoarea is used to send node status messages. +
+
+
+
@@ -167,13 +194,19 @@ @section('page-css') @css('simplemde') + @css('select2') @append @section('page-scripts') @js('simplemde') + @js('select2') @can('admin',$o) @endcan @append \ No newline at end of file