Multiple enhancements to interactive messages, moved messages to Notifications, send netmail back when invalid packet password

This commit is contained in:
Deon George 2023-07-23 17:27:52 +10:00
parent 9f0fa0a8ec
commit 17fe7e910d
28 changed files with 837 additions and 475 deletions

View File

@ -84,8 +84,10 @@ class Message extends FTNBase
public const FLAG_AUDITREQ = 1<<14; // (ARQ)
/** @var int Requesting a file update (filename in subject) */
public const FLAG_FILEUPDATEREQ = 1<<15; // (URQ)
/** Echomail has been scanned out */
/** @var int Echomail has been scanned out */
public const FLAG_ECHOMAIL = 1<<16;
/** @var int Use packet password on the subject line for this message */
public const FLAG_PKTPASSWD = 1<<17;
// FTS-0001.016 Message header 32 bytes node, net, flags, cost, date
public const HEADER_LEN = 0x20; // Length of message header

View File

@ -368,8 +368,9 @@ class Packet extends FTNBase implements \Iterator, \Countable
*
* @param Address $oo
* @param Address $o
* @param string|null $passwd Override the password used in the packet
*/
public function addressHeader(Address $oo,Address $o): void
public function addressHeader(Address $oo,Address $o,string $passwd=NULL): void
{
Log::debug(sprintf('%s:+ Creating packet for [%s]',self::LOGKEY,$o->ftn));
@ -393,7 +394,7 @@ class Packet extends FTNBase implements \Iterator, \Countable
'H' => $date->format('H'), // Hour
'M' => $date->format('i'), // Minute
'S' => $date->format('s'), // Second
'password' => $o->session('pktpass'), // Packet Password
'password' => (! is_null($passwd)) ? $passwd : $o->session('pktpass'), // Packet Password
];
}

View File

@ -2,17 +2,11 @@
namespace App\Classes\FTN;
use Illuminate\Support\Arr;
/**
* Abstract class to hold the common functions for automatic responding to echomail/netmail messages
*/
abstract class Process
{
private const LOGKEY = 'R--';
protected const MSG_WIDTH = 79;
/**
* Return TRUE if the process class handled the message.
*
@ -20,79 +14,4 @@ abstract class Process
* @return bool
*/
abstract public static function handle(Message $msg): bool;
/**
* This function will format text to static::MSG_WIDTH, as well as adding the logo.
*/
public static function format_msg(string $text,array $logo = []): string
{
$msg = utf8_decode(join("\r",static::msg_header()))."\r";
$c = 0;
$offset = 0;
while ($offset < strlen($text)) {
$ll = '';
// Add our logo
if ($c<count($logo)) {
$line = utf8_decode(Arr::get($logo,$c++));
$ll = $line.' ';
}
// Look for a return
$return = strpos($text,"\r",$offset);
if ($return !== FALSE)
$return -= $offset;
if (($return !== FALSE && $return < static::MSG_WIDTH-strlen($ll))) {
$subtext = substr($text,$offset,$return);
} else {
$subtext = substr($text,$offset,static::MSG_WIDTH-strlen($ll));
// Look for a space
$space = strrpos($subtext,' ');
if ($space === FALSE)
$space = strlen($subtext);
else
$subtext = substr($text,$offset,$space);
}
$msg .= $ll.$subtext."\r";
$offset += strlen($subtext)+1;
}
// In case our text is shorter than the loo
for ($c; $c<count($logo);$c++)
$msg .= utf8_decode(Arr::get($logo,$c))."\r";
$msg .= utf8_decode(join("\r",static::msg_footer()))."\r";
return $msg;
}
/**
* Header added to messages
*
* @return string[]
*/
protected static function msg_header(): array
{
return [
' ÜÜÜ Ü ÜÜÜ ÜÜÜ ÜÜÜ Ü ÜÜÜ ÜÜÜ Ü ÜÜÜ Ü Ü ÜÜÜ',
' Û ß Û ÛÜÛ ÜÜÛ Û ß Ü Û Û ÛÜÛ ÛßÛ Û Û Û Û Üß',
' ÛÜÛ ÛÜÛ ÛÜÜ ÛÜÛ Û Û Û Û ÜÜÛ Û Û ÛÜÛ ÛÜÛ ÛÜÜ',
' FTN Mailer and Tosser',
'ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ'
];
}
protected static function msg_footer(): array
{
return [
'ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ'
];
}
}

View File

@ -2,12 +2,11 @@
namespace App\Classes\FTN\Process\Echomail;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\{Message,Process};
use App\Models\{Echoarea,Echomail,Setup};
use App\Notifications\Echomails\Test as TestNotification;
/**
* Process messages to Test
@ -18,12 +17,6 @@ final class Test extends Process
{
private const LOGKEY = 'RT-';
private static array $logo = [
'Ú¿ÚÄ¿ÚÄ¿Ú¿',
' ³ ³ÄÙÀÄ¿ ³ ',
' Á ÀÄÙÀÄÙ Á '
];
private const testing = ['test','testing'];
public static function handle(Message $msg): bool
@ -32,51 +25,8 @@ final class Test extends Process
return FALSE;
Log::info(sprintf('%s:- Processing TEST message from (%s) [%s]',self::LOGKEY,$msg->user_from,$msg->fftn));
$ftns = Setup::findOrFail(config('app.id'))->system->match($msg->fboss_o->zone)->first();
$reply = sprintf("Your test was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r",
Carbon::now()->utc()->toDateTimeString(),
$msg->date->utc()->toDateTimeString(),
$msg->date->diffForHumans(['parts'=>3,'syntax'=>CarbonInterface::DIFF_ABSOLUTE])
);
$reply .= "\r";
$reply .= "\r";
$reply .= "------------------------------ BEGIN MESSAGE ------------------------------\r";
$reply .= sprintf("TO: %s\r",$msg->user_to);
$reply .= sprintf("SUBJECT: %s\r",$msg->subject);
$reply .= str_replace("\r---","\r#--",$msg->message)."\r";
$reply .= "------------------------------ CONTROL LINES ------------------------------\r";
$reply .= sprintf("DATE: %s\r",$msg->date->utc()->format('Y-m-d H:i:s'));
$reply .= sprintf("MSGID: %s\r",$msg->msgid);
foreach ($msg->kludge as $k=>$v)
$reply .= sprintf("@%s: %s\r",strtoupper($k),$v);
foreach ($msg->via as $via)
$reply .= sprintf("VIA: %s\r",$via);
$reply .= "------------------------------ END MESSAGE ------------------------------\r";
$eo = Echoarea::where('name',$msg->echoarea)->single();
$o = new Echomail;
$o->init();
$o->to = $msg->user_from;
$o->from = Setup::PRODUCT_NAME;
$o->subject = 'Test Reply';
$o->datetime = Carbon::now();
$o->tzoffset = $o->datetime->utcOffset();
$o->echoarea_id = $eo?->id;
$o->replyid = $msg->msgid;
$o->fftn_id = $ftns->id;
$o->flags = Message::FLAG_LOCAL;
$o->msg = static::format_msg($reply,self::$logo);
$o->tagline = 'I ate a clock yesterday, it was very time-consuming.';
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
$o->origin = sprintf('%s (%s)',Setup::PRODUCT_NAME,$ftns->ftn4d);
$o->kludges = collect(['chrs'=>$msg->kludge->get('chrs') ?: 'CP437 2']);
$o->save();
Notification::route('echomail',$msg->echoarea)->notify(new TestNotification($msg));
return TRUE;
}

View File

@ -2,12 +2,11 @@
namespace App\Classes\FTN\Process\Netmail;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\{Message,Process};
use App\Models\{Netmail,Setup};
use App\Notifications\Netmails\Ping as PingNotification;
/**
* Process messages to Ping
@ -18,48 +17,14 @@ final class Ping extends Process
{
private const LOGKEY = 'RP-';
private static array $logo = [
'ÚÄ¿þÚÄ¿ÚÄ¿',
'³ ³Â³ ³Àij',
'ÃÄÙÁÁ ÁÄÄÙ'
];
public static function handle(Message $msg): bool
{
if (strtolower($msg->user_to) !== 'ping')
return FALSE;
Log::info(sprintf('%s:- Processing PING message from (%s) [%s]',self::LOGKEY,$msg->user_from,$msg->fftn));
$ftns = Setup::findOrFail(config('app.id'))->system->match($msg->fftn_o->zone)->first();
$reply = sprintf("Your ping was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r",
Carbon::now()->utc()->toDateTimeString(),
$msg->date->utc()->toDateTimeString(),
$msg->date->diffForHumans(['parts'=>3,'syntax'=>CarbonInterface::DIFF_ABSOLUTE])
);
$reply .= "\r";
$reply .= "Your message travelled along this path on the way here:\r";
foreach ($msg->via as $path)
$reply .= sprintf(" * %s\r",$path);
$o = new Netmail;
$o->to = $msg->user_from;
$o->from = Setup::PRODUCT_NAME;
$o->subject = 'Ping Reply';
$o->datetime = Carbon::now();
$o->tzoffset = $o->datetime->utcOffset();
$o->replyid = $msg->msgid;
$o->fftn_id = $ftns->id;
$o->tftn_id = ($x=$msg->fftn_o) ? $x->id : NULL;
$o->flags = Message::FLAG_LOCAL|Message::FLAG_PRIVATE;
$o->cost = 0;
$o->msg = static::format_msg($reply,self::$logo);
$o->tagline = 'My ping pong opponent was not happy with my serve. He kept returning it.';
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
$o->save();
Notification::route('netmail',$msg->fftn_o)->notify(new PingNotification($msg));
return TRUE;
}

View File

@ -3,9 +3,8 @@
namespace App\Classes\File;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Notification;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use App\Classes\{File,Protocol};
@ -13,6 +12,7 @@ use App\Classes\FTN\{InvalidPacketException,Packet};
use App\Exceptions\FileGrewException;
use App\Jobs\{MessageProcess,TicProcess};
use App\Models\Address;
use App\Notifications\Netmails\PacketPasswordInvalid;
/**
* Object representing the files we are receiving
@ -138,10 +138,10 @@ class Receive extends Base
}
// Check the packet password
if ($this->ao->session('pktpass') != $po->password) {
if ($this->ao->session('pktpass') !== $po->password) {
Log::error(sprintf('%s:! Packet from [%s] with password [%s] is invalid.',self::LOGKEY,$this->ao->ftn,$po->password));
// @todo Generate message to system advising invalid password - that message should be sent without a packet password!
Notification::route('netmail',$this->ao)->notify(new PacketPasswordInvalid($po->password,$this->receiving->nameas));
break;
}
@ -158,6 +158,20 @@ class Receive extends Base
// @todo Quick check that the packet should be processed by us.
// @todo validate that the packet's zone is in the domain.
/*
* // @todo generate exception when echomail for an area that doesnt exist
* // @todo generate exception when echomail for an area sender cannot post to
* // @todo generate exception when echomail for an area sender not subscribed to
* // @todo generate exception when echomail comes from a system not defined here
* // @todo generate exception when echomail comes from a system doesnt exist
*
* // @todo generate exception when netmail to system that doesnt exist (node/point)
* // @todo generate exception when netmail from system that doesnt exist (node/point)
* // @todo generate warning when netmail comes from a system not defined here
*
* // @todo generate exception when packet has wrong password
*/
try {
// Dispatch job.
if ($queue)

View File

@ -6,7 +6,7 @@ use Illuminate\Console\Command;
use Illuminate\Support\Facades\Notification;
use App\Models\Address;
use App\Notifications\NetmailTest as NetmailTestNotification;
use App\Notifications\Netmails\Test as NetmailTestNotification;
class NetmailTest extends Command
{
@ -35,6 +35,6 @@ class NetmailTest extends Command
{
$ao = Address::findFTN($this->argument('ftn'));
Notification::route('netmail',$ao)->notify(new NetmailTestNotification($ao));
Notification::route('netmail',$ao)->notify(new NetmailTestNotification());
}
}

View File

@ -6,7 +6,7 @@ use Illuminate\Console\Command;
use Illuminate\Support\Facades\Notification;
use App\Models\{Address,User};
use App\Notifications\AddressLink;
use App\Notifications\Netmails\AddressLink;
class UserCodeSend extends Command
{
@ -27,6 +27,6 @@ class UserCodeSend extends Command
$ao = Address::findFTN($this->argument('ftn'));
$uo = User::where('email',$this->argument('email'))->singleOrFail();
Notification::route('netmail',$ao->parent())->notify(new AddressLink($ao,$uo));
Notification::route('netmail',$ao->parent())->notify(new AddressLink($uo));
}
}

View File

@ -3,9 +3,9 @@
namespace App\Http\Controllers;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;
@ -13,7 +13,7 @@ use Illuminate\Support\ViewErrorBag;
use App\Http\Requests\SystemRegister;
use App\Models\{Address,Echoarea,Filearea,Setup,System,SystemZone,Zone};
use App\Notifications\AddressLink;
use App\Notifications\Netmails\AddressLink;
use App\Rules\{FidoInteger,TwoByteInteger};
class SystemController extends Controller
@ -654,7 +654,7 @@ class SystemController extends Controller
}
if ($ca->count() && $la=$ca->pop())
Notification::route('netmail',$la)->notify(new AddressLink($la,Auth::user()));
Notification::route('netmail',$la)->notify(new AddressLink(Auth::user()));
return view('user.system.register_send')
->with('la',$la)
@ -682,7 +682,7 @@ class SystemController extends Controller
// If we have addresses, we'll trigger the routed netmail
if ($validate->count())
Notification::route('netmail',$x=$validate->first())->notify(new AddressLink($x,Auth::user()));
Notification::route('netmail',$validate->first())->notify(new AddressLink(Auth::user()));
return view('user.system.widget.register_send')
->with('validate',$validate)

View File

@ -9,9 +9,11 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use App\Classes\FTN\{Message,Process};
use App\Classes\FTN\Message;
use App\Models\{Address,Echoarea,Echomail,Netmail,Setup};
use App\Notifications\Netmails\Reject;
class MessageProcess implements ShouldQueue
{
@ -83,7 +85,29 @@ class MessageProcess implements ShouldQueue
// @todo Enable checks to see if this is a file request or file send
$o = $this->create_netmail($this->msg);
$o = new Netmail;
$o->to = $this->msg->user_to;
$o->from = $this->msg->user_from;
$o->fftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL;
$o->tftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL;
$o->datetime = $this->msg->date;
$o->tzoffset = $this->msg->date->utcOffset();
$o->flags = $this->msg->flags;
$o->cost = $this->msg->cost;
$o->msgid = $this->msg->msgid;
$o->subject = $this->msg->subject;
$o->msg = $this->msg->message;
foreach ($this->msg->via as $v)
$o->msg .= sprintf("\01Via %s\r",$v);
$o->msg_src = $this->msg->message_src;
$o->msg_crc = md5($this->msg->message);
$o->set_pkt = $this->packet;
$o->set_sender = $this->sender;
$o->set_path = $this->msg->pathaddress;
@ -133,52 +157,9 @@ class MessageProcess implements ShouldQueue
// If not processed, no users here!
if (! $processed) {
$reject = [
'ÚÄ¿ÚÄ¿ ÂÚÄ¿ÚÄ¿Ú¿',
'³ ³ÄÙ ³³ÄÙ³ ³ ',
'Á ÀÄÙÀÄÙÀÄÙÀÄÙ Á '
];
Log::alert(sprintf('%s:! Netmail to the Hub from (%s) [%s] but no users here.',self::LOGKEY,$this->msg->user_from,$this->msg->fftn));
$reply = "Your Netmail was not processed by the hub and cannot be delivered to anybody (as there are no users here).\r";
$reply .= "\r";
$reply .= "\r";
$reply .= "This is your original message:\r";
$reply .= "------------------------------ BEGIN MESSAGE ------------------------------\r";
$reply .= sprintf("TO: %s\r",$this->msg->user_to);
$reply .= sprintf("SUBJECT: %s\r",$this->msg->subject);
$reply .= str_replace("\r---","\r#--",$this->msg->message)."\r";
$reply .= "------------------------------ CONTROL LINES ------------------------------\r";
$reply .= sprintf("DATE: %s\r",$this->msg->date->format('Y-m-d H:i:s'));
$reply .= sprintf("MSGID: %s\r",$this->msg->msgid);
foreach ($this->msg->kludge as $k=>$v)
$reply .= sprintf("@%s: %s\r",strtoupper($k),$v);
foreach ($this->msg->via as $via)
$reply .= sprintf("VIA: %s\r",$via);
$reply .= "------------------------------ END MESSAGE ------------------------------\r";
$o = new Netmail;
$o->to = $this->msg->user_from;
$o->from = Setup::PRODUCT_NAME;
$o->subject = 'Message Undeliverable - '.$this->msg->msgid;
$o->datetime = $this->msg->date;
$o->tzoffset = $this->msg->date->utcOffset();
$o->cost = 0;
$o->flags = Message::FLAG_LOCAL|Message::FLAG_PRIVATE;
$o->fftn_id = ($x=$this->msg->tftn_o) ? $x->id : NULL;
$o->tftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL;
$o->replyid = $this->msg->msgid;
$o->msg = Process::format_msg($reply,$reject);
$o->tagline = 'Do you think it was fate which brought us together? Nah, bad luck :(';
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
$o->save();
Notification::route('netmail',$this->msg->fftn_o)->notify(new Reject($this->msg));
}
// If in transit, store for collection
@ -319,32 +300,4 @@ class MessageProcess implements ShouldQueue
}
}
}
private function create_netmail(Message $msg): Netmail
{
$o = new Netmail;
$o->to = $msg->user_to;
$o->from = $msg->user_from;
$o->fftn_id = ($x=$msg->fftn_o) ? $x->id : NULL;
$o->tftn_id = ($x=$msg->tftn_o) ? $x->id : NULL;
$o->datetime = $msg->date;
$o->tzoffset = $msg->date->utcOffset();
$o->flags = $msg->flags;
$o->cost = $msg->cost;
$o->msgid = $msg->msgid;
$o->subject = $msg->subject;
$o->msg = $msg->message;
foreach ($msg->via as $v)
$o->msg .= sprintf("\01Via %s\r",$v);
$o->msg_src = $msg->message_src;
$o->msg_crc = md5($msg->message); // @todo DB schema needs to handle this
return $o;
}
}

View File

@ -619,6 +619,23 @@ class Address extends Model
$s = Setup::findOrFail(config('app.id'));
if (($x=$this->netmailAlertWaiting())->count()) {
Log::debug(sprintf('%s:= Packaging [%d] netmail alerts to [%s]',self::LOGKEY,$x->count(),$this->ftn));
$passpos = strpos($x->last()->subject,':');
if ($passpos > 8)
Log::alert(sprintf('%s:! Password would be greater than 8 chars? [%d]',self::LOGKEY,$passpos));
$pkt = $this->getPacket($x,substr($x->last()->subject,0,$passpos));
if ($pkt && $pkt->count() && $update)
DB::table('netmails')
->whereIn('id',$x->pluck('id'))
->update(['sent_pkt'=>$pkt->name]);
return $pkt;
}
if (($x=$this->netmailWaiting())
->count())
{
@ -644,9 +661,10 @@ class Address extends Model
* Return a packet of mail
*
* @param Collection $msgs of message models (Echomail/Netmail)
* @param string|null $passwd Override password used in packet
* @return Packet|null
*/
public function getPacket(Collection $msgs): ?Packet
public function getPacket(Collection $msgs,string $passwd=NULL): ?Packet
{
$s = Setup::findOrFail(config('app.id'));
$ao = $s->system->match($this->zone)->first();
@ -658,7 +676,7 @@ class Address extends Model
// Get packet type
$type = collect(Packet::PACKET_TYPES)->get($this->system->pkt_type ?: config('app.default_pkt'));
$o = new $type;
$o->addressHeader($ao,$this);
$o->addressHeader($ao,$this,$passwd);
// $oo = Netmail/Echomail Model
$c = 0;
@ -667,7 +685,7 @@ class Address extends Model
if (++$c > $s->msgs_pkt)
break;
$o->addMail($oo->packet($this));
$o->addMail($oo->packet($this,$passwd));
}
return $o;
@ -690,6 +708,21 @@ class Address extends Model
->get();
}
/**
* Netmail alerts waiting to be sent to this system
*
* @return Collection
*/
public function netmailAlertWaiting(): Collection
{
return Netmail::where('tftn_id',$this->id)
->whereRaw(sprintf('(flags & %d) > 0',Message::FLAG_LOCAL))
->whereRaw(sprintf('(flags & %d) > 0',Message::FLAG_PKTPASSWD))
->whereRaw(sprintf('(flags & %d) = 0',Message::FLAG_SENT))
->whereNull('sent_at')
->get();
}
/**
*
* Parse a string and split it out as an FTN array

View File

@ -130,7 +130,7 @@ final class Netmail extends Model implements Packet
/**
* Return this model as a packet
*/
public function packet(Address $ao): Message
public function packet(Address $ao,string $strippass=NULL): Message
{
Log::debug(sprintf('%s:+ Bundling [%s]',self::LOGKEY,$this->id));
@ -153,7 +153,7 @@ final class Netmail extends Model implements Packet
$o->tzutc = $this->datetime->utcOffset($this->tzoffset)->getOffsetString('');
$o->user_to = $this->to;
$o->user_from = $this->from;
$o->subject = $this->subject;
$o->subject = (! is_null($strippass)) ? preg_replace('/^'.$strippass.':/','',$this->subject) : $this->subject;
// INTL kludge
$o->intl = sprintf('%s %s',$this->tftn->ftn3d,$this->fftn->ftn3d);

View File

@ -1,104 +0,0 @@
<?php
namespace App\Notifications;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use App\Classes\{ANSI,Fonts\Thin,Page};
use App\Classes\Fonts\Thick;
use App\Classes\FTN\Message;
use App\Models\{Address,Netmail,Setup,User};
class AddressLink extends Notification //implements ShouldQueue
{
private const LOGKEY = 'NAL';
use Queueable;
private Address $ao;
private User $uo;
/**
* Create a netmail to enable a sysop to activate an address.
*
* @param Address $ao
* @param User $uo
*/
public function __construct(Address $ao,User $uo)
{
$this->queue = 'netmail';
$this->ao = $ao;
$this->uo = $uo;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['netmail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail($notifiable): Netmail
{
Log::info(sprintf('%s:Sending a link code for address [%s]',self::LOGKEY,$this->ao->ftn));
$so = Setup::findOrFail(config('app.id'))->system;
$o = new Netmail;
$o->to = $this->ao->system->sysop;
$o->from = Setup::PRODUCT_NAME;
$o->subject = 'Address Link Code';
$o->datetime = Carbon::now();
$o->tzoffset = $o->datetime->utcOffset();
$o->fftn_id = $so->match($this->ao->zone)->first()->id;
$o->tftn_id = $this->ao->id;
$o->flags = Message::FLAG_LOCAL|Message::FLAG_PRIVATE|Message::FLAG_CRASH;
$o->cost = 0;
$o->tagline = 'Address Linking...';
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
// Message
$msg = new Page;
$msg->addLogo(new ANSI(base_path('public/logo/netmail.bin')));
$header = new Thick;
$header->addText(ANSI::ansi_code([1,37]).'Clearing Houz');
$msg->addHeader($header,'FTN Mailer and Tosser',TRUE,0xc4);
$lbc = new Thin;
$lbc->addText('#link');
$msg->addLeftBoxContent($lbc);
$msg->addText(sprintf(
"Hi %s,\r\r".
"This message is to link your address [%s] to your user ID in the Clearing Houz web site.\r\r".
"If you didnt start this process, then you can safely ignore this netmail. But if you wanted to link this address, please head over to [%s] and paste in the following:\r\r%s\r",
$this->ao->system->sysop,
$this->ao->ftn3d,
url('/link'),
$this->ao->set_activation($this->uo)
));
$o->msg = $msg->render();
$o->save();
return $o;
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Notifications\Channels;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use App\Models\Echomail;
use App\Models\Setup;
class EchomailChannel
{
private const LOGKEY = 'CN-';
/**
* @var Echomail
*/
protected Echomail $echomail;
/**
* Create a new Netmail channel instance.
*
* @param Echomail $o
*/
public function __construct(Echomail $o)
{
$this->echomail = $o;
}
/**
* Send the given notification.
*
* @param mixed $notifiable
* @param \Illuminate\Notifications\Notification $notification
* @return \Psr\Http\Message\ResponseInterface|void
*/
public function send($notifiable,Notification $notification)
{
if (! $echoarea = $notifiable->routeNotificationFor('echomail',$notification))
return;
$so = Setup::findOrFail(config('app.id'))->system;
$o = $notification->toEchomail($so,$notifiable);
Log::info(sprintf('%s:= Posted echomail [%s] to [%s]',self::LOGKEY,$o->msgid,$echoarea));
}
}

View File

@ -5,22 +5,21 @@ namespace App\Notifications\Channels;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use App\Models\Netmail;
use App\Jobs\AddressPoll as Job;
use App\Models\Netmail;
use App\Models\Setup;
class NetmailChannel
{
private const LOGKEY = 'CN-';
/**
* The HTTP client instance.
*
* @var Netmail
*/
protected Netmail $netmail;
/**
* Create a new Slack channel instance.
* Create a new Netmail channel instance.
*
* @param Netmail $o
*/
@ -41,9 +40,10 @@ class NetmailChannel
if (! $ao = $notifiable->routeNotificationFor('netmail',$notification))
return;
$o = $notification->toNetmail($notifiable);
$so = Setup::findOrFail(config('app.id'))->system;
$o = $notification->toNetmail($so,$notifiable);
Job::dispatch($ao);
Log::info(sprintf('%s:Sent netmail [%s] via [%s]',self::LOGKEY,$o->msgid,$ao->ftn));
Log::info(sprintf('%s:= Sent netmail [%s] to [%s]',self::LOGKEY,$o->msgid,$ao->ftn));
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Notifications;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use App\Classes\FTN\Message;
use App\Models\{Echoarea, Echomail, Setup, System};
abstract class Echomails extends Notification //implements ShouldQueue
{
use Queueable;
protected const via = 'echomail';
private const LOGKEY = 'NN-';
/**
* Create a new notification instance.
*/
public function __construct()
{
$this->queue = 'echomail';
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return [ self::via ];
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Echomail
* @throws \Exception
*/
abstract public function toEchomail(System $so,object $notifiable): Echomail;
protected function setupEchomail(Message $mo,System $so,object $notifiable): Echomail
{
$echoarea = $notifiable->routeNotificationFor(static::via);
$eo = Echoarea::where('name',$echoarea)->singleOrFail();
$o = new Echomail;
$o->init();
$o->from = Setup::PRODUCT_NAME;
$o->replyid = $mo->msgid;
$o->echoarea_id = $eo->id;
$o->datetime = Carbon::now();
$o->tzoffset = $o->datetime->utcOffset();
$o->fftn_id = ($x=$so->match($mo->fftn_o->zone)->first())->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 = collect(['chrs'=>$mo->kludge->get('chrs') ?: 'CP437 2']);
return $o;
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Notifications\Echomails;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\Log;
use App\Classes\{Fonts\Thick,Fonts\Thin,FTN\Message,Page};
use App\Models\{Echomail,System};
use App\Notifications\Echomails;
use App\Traits\MessagePath;
class Test extends Echomails
{
use MessagePath;
private const LOGKEY = 'NNP';
private Message $mo;
/**
* Reply to a netmail ping request.
*
* @param Message $mo
*/
public function __construct(Message $mo)
{
parent::__construct();
$this->mo = $mo;
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Echomail
* @throws \Exception
*/
public function toEchomail(System $so,object $notifiable): Echomail
{
$o = $this->setupEchomail($this->mo,$so,$notifiable);
$echoarea = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating test echomail to [%s]',self::LOGKEY,$echoarea));
$o->to = $this->mo->user_from;
$o->subject = 'Test Reply';
// Message
$msg = new Page;
$header = new Thick;
$header->addText('Clearing Houz');
$msg->addHeader($header,'FTN Mailer and Tosser',TRUE,0xc4);
$lbc = new Thin;
$lbc->addText('Test');
$msg->addLeftBoxContent($lbc,TRUE);
$msg->addText(
sprintf("Your test was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r\r",
Carbon::now()->utc()->toDateTimeString(),
$this->mo->date->utc()->toDateTimeString(),
$this->mo->date->diffForHumans(['parts'=>3,'syntax'=>CarbonInterface::DIFF_ABSOLUTE])
)
);
$msg->addText($this->message_path($this->mo));
$o->msg = $msg->render();
$o->tagline = 'I ate a clock yesterday, it was very time-consuming.';
$o->save();
return $o;
}
}

View File

@ -1,97 +0,0 @@
<?php
namespace App\Notifications;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use App\Classes\{ANSI,Fonts\Thin,Fonts\Thick,Page};
use App\Classes\FTN\Message;
use App\Models\{Address,Netmail,Setup,User};
class NetmailTest extends Notification //implements ShouldQueue
{
private const LOGKEY = 'NNT';
use Queueable;
private Address $ao;
/**
* Create a new notification instance.
*
* @param Address $ao
* @param User $uo
*/
public function __construct(Address $ao)
{
$this->queue = 'netmail';
$this->ao = $ao;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['netmail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail($notifiable): Netmail
{
Log::info(sprintf('%s:Creating test netmail to [%s]',self::LOGKEY,$this->ao->ftn));
$so = Setup::findOrFail(config('app.id'))->system;
$o = new Netmail;
$o->to = $this->ao->system->sysop;
$o->from = Setup::PRODUCT_NAME;
$o->subject = 'Testing 1, 2, 3...';
$o->datetime = Carbon::now();
$o->tzoffset = $o->datetime->utcOffset();
$o->fftn_id = $so->match($this->ao->zone)->first()->id;
$o->tftn_id = $this->ao->id;
$o->flags = Message::FLAG_LOCAL|Message::FLAG_PRIVATE;
$o->cost = 0;
$o->tagline = 'Testing, testing, 1 2 3.';
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
// Message
$msg = new Page;
$msg->addLogo(new ANSI('public/logo/netmail.bin'));
$header = new Thick;
$header->addText(ANSI::ansi_code([1,37]).'Clearing Houz');
$msg->addHeader($header,'FTN Mailer and Tosser',TRUE,0xc4);
$lbc = new Thin;
$lbc->addText('Test');
$msg->addLeftBoxContent($lbc);
$msg->addText(
"Hi there,\r\r".
"This is just a test netmail to make sure we can send a message to your system.\r\r".
"There is no need to reply, but if you do, it'll boost my spirits :)\r"
);
$o->msg = $msg->render();
$o->save();
return $o;
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace App\Notifications;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use App\Classes\FTN\Message;
use App\Models\{Netmail,Setup,System};
abstract class Netmails extends Notification //implements ShouldQueue
{
use Queueable;
protected const via = 'netmail';
private const LOGKEY = 'NN-';
/**
* Create a new notification instance.
*/
public function __construct()
{
$this->queue = 'netmail';
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return [ self::via ];
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
abstract public function toNetmail(System $so,object $notifiable): Netmail;
protected function setupNetmail(System $so,object $notifiable): Netmail
{
$ao = $notifiable->routeNotificationFor(static::via);
$o = new Netmail;
$o->to = $ao->system->sysop;
$o->from = Setup::PRODUCT_NAME;
$o->datetime = Carbon::now();
$o->tzoffset = $o->datetime->utcOffset();
$o->fftn_id = $so->match($ao->zone)->first()->id;
$o->tftn_id = $ao->id;
$o->flags = (Message::FLAG_LOCAL|Message::FLAG_PRIVATE);
$o->cost = 0;
$o->tearline = sprintf('%s (%04X)',Setup::PRODUCT_NAME,Setup::PRODUCT_ID);
return $o;
}
}

View File

@ -0,0 +1,69 @@
<?php
namespace App\Notifications\Netmails;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\Message;
use App\Notifications\Netmails;
use App\Models\{Netmail,System,User};
use App\Traits\PageTemplate;
class AddressLink extends Netmails
{
use PageTemplate;
private const LOGKEY = 'NAL';
private User $uo;
/**
* Create a netmail to enable a sysop to activate an address.
*
* @param User $uo
*/
public function __construct(User $uo)
{
parent::__construct();
$this->uo = $uo;
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Sending a link code for address [%s]',self::LOGKEY,$ao->ftn));
$o->subject = 'Address Link Code';
$o->flags = (Message::FLAG_LOCAL|Message::FLAG_PRIVATE|Message::FLAG_CRASH);
// Message
$msg = $this->page(TRUE,'#link');
$msg->addText(sprintf(
"Hi %s,\r\r".
"This message is to link your address [%s] to your user ID in the Clearing Houz web site.\r\r".
"If you didnt start this process, then you can safely ignore this netmail. But if you wanted to link this address, please head over to [%s] and paste in the following:\r\r%s\r",
$ao->system->sysop,
$ao->ftn3d,
url('/link'),
$ao->set_activation($this->uo)
));
$o->msg = $msg->render();
$o->tagline = 'Address Linking...';
$o->save();
return $o;
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Notifications\Netmails;
use Illuminate\Support\Facades\Log;
use App\Notifications\Netmails;
use App\Classes\FTN\Message;
use App\Models\{Netmail,System};
use App\Traits\PageTemplate;
class PacketPasswordInvalid extends Netmails
{
use PageTemplate;
private const LOGKEY = 'NPP';
private string $packet;
private string $invalidpass;
/**
* Create a new notification instance.
*/
public function __construct(string $invalidpass,string $packet)
{
parent::__construct();
$this->invalidpass = $invalidpass;
$this->packet = $packet;
}
/**
* Get the mail representation of the notification.
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating netmail to [%s] - system using invalid packet password',self::LOGKEY,$ao->ftn));
$o->subject = $this->invalidpass.':Incorrect Packet Password';
$o->flags = (Message::FLAG_LOCAL|Message::FLAG_PRIVATE|Message::FLAG_PKTPASSWD|Message::FLAG_CRASH);
// Message
$msg = $this->page(TRUE,'badpass');
if ($this->invalidpass)
$msg->addText(
sprintf("Hi there,\r\r".
"You sent me a mail packet (%s) with the incorrect password \"%s\". It wasnt processed.\r\r"
,$this->packet,$this->invalidpass));
else
$msg->addText(
sprintf("Hi there,\r\r".
"You sent me a mail packet (%s) with no password? It wasnt processed.\r\r"
,$this->packet));
$msg->addText("Head over to the website if you dont know what your packet password should be :)\r");
$o->msg = $msg->render();
$o->tagline = 'Safety first, password second.';
$o->save();
return $o;
}
/**
* Get the array representation of the notification.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
//
];
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Notifications\Netmails;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\Message;
use App\Notifications\Netmails;
use App\Models\{Netmail,System};
use App\Traits\{MessagePath,PageTemplate};
class Ping extends Netmails
{
use MessagePath,PageTemplate;
private const LOGKEY = 'NNP';
private Message $mo;
/**
* Reply to a netmail ping request.
*
* @param Message $mo
*/
public function __construct(Message $mo)
{
parent::__construct();
$this->mo = $mo;
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating test netmail to [%s]',self::LOGKEY,$ao->ftn));
$o->to = $this->mo->user_from;
$o->replyid = $this->mo->msgid;
$o->subject = 'Ping Reply';
// Message
$msg = $this->page(FALSE,'Ping');
$msg->addText(
sprintf("Your ping was received here on %s and it looks like you sent it on %s. If that is correct, then it took %s to get here.\r\r",
Carbon::now()->utc()->toDateTimeString(),
$this->mo->date->utc()->toDateTimeString(),
$this->mo->date->diffForHumans(['parts'=>3,'syntax'=>CarbonInterface::DIFF_ABSOLUTE])
)
);
$msg->addText($this->message_path($this->mo));
$o->msg = $msg->render();
$o->tagline = 'My ping pong opponent was not happy with my serve. He kept returning it.';
$o->save();
return $o;
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace App\Notifications\Netmails;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\Message;
use App\Notifications\Netmails;
use App\Models\{Netmail,System};
use App\Traits\{MessagePath,PageTemplate};
class Reject extends Netmails
{
use MessagePath,PageTemplate;
private const LOGKEY = 'NNP';
private Message $mo;
/**
* Reply to a netmail ping request.
*
* @param Message $mo
*/
public function __construct(Message $mo)
{
parent::__construct();
$this->mo = $mo;
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating reject netmail to [%s]',self::LOGKEY,$ao->ftn));
$o->to = $this->mo->user_from;
$o->replyid = $this->mo->msgid;
$o->subject = 'Message Undeliverable - '.$this->mo->msgid;
// Message
$msg = $this->page(FALSE,'Reject');
$msg->addText(
sprintf("Your netmail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
$this->mo->msgid,
$this->mo->user_to,
Carbon::now()->utc()->toDateTimeString(),
$this->mo->date->utc()->toDateTimeString(),
)
);
$msg->addText("This hub is not attended, so no user will be able to read your message (the hub is unattended). You may like to try and contact them another way.\r\r");
$msg->addText($this->message_path($this->mo));
$o->msg = $msg->render();
$o->tagline = 'Do you think it was fate which brought us together? Nah, bad luck :(';
$o->save();
return $o;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Notifications\Netmails;
use Illuminate\Support\Facades\Log;
use App\Notifications\Netmails;
use App\Models\{Netmail,System};
use App\Traits\PageTemplate;
class Test extends Netmails
{
use PageTemplate;
private const LOGKEY = 'NNT';
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating test netmail to [%s]',self::LOGKEY,$ao->ftn));
$o->subject = 'Testing 1, 2, 3...';
// Message
$msg = $this->page(TRUE,'Test');
$msg->addText(
"Hi there,\r\r".
"This is just a test netmail to make sure we can send a message to your system.\r\r".
"There is no need to reply, but if you do, it'll boost my spirits :)\r"
);
$o->msg = $msg->render();
$o->tagline = 'Testing, testing, 1 2 3.';
$o->save();
return $o;
}
}

View File

@ -6,8 +6,8 @@ use Illuminate\Notifications\ChannelManager;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\ServiceProvider;
use App\Notifications\Channels\NetmailChannel;
use App\Models\Netmail;
use App\Notifications\Channels\{EchomailChannel,NetmailChannel};
use App\Models\{Echomail,Netmail};
use App\Traits\SingleOrFail;
class AppServiceProvider extends ServiceProvider
@ -22,6 +22,10 @@ class AppServiceProvider extends ServiceProvider
public function register()
{
Notification::resolved(function (ChannelManager $service) {
$service->extend('echomail', function ($app) {
return new EchomailChannel($app->make(Echomail::class));
});
$service->extend('netmail', function ($app) {
return new NetmailChannel($app->make(Netmail::class));
});

View File

@ -0,0 +1,49 @@
<?php
/**
* Add show the message detail
*/
namespace App\Traits;
use App\Classes\FTN\Message;
trait MessagePath
{
protected function message_path(Message $mo): string
{
$reply = "This is your original message:\r\r";
$reply .= "+--[ BEGIN MESSAGE ]----------------------------------+\r";
$reply .= sprintf("TO: %s\r",$mo->user_to);
$reply .= sprintf("SUBJECT: %s\r",$mo->subject);
$reply .= str_replace("\r---","\r#--",$mo->message)."\r";
$reply .= "+--[ CONTROL LINES ]----------------------------------+\r";
$reply .= sprintf("DATE: %s\r",$mo->date->format('Y-m-d H:i:s'));
$reply .= sprintf("MSGID: %s\r",$mo->msgid);
foreach ($mo->kludge as $k=>$v)
$reply .= sprintf("@%s: %s\r",strtoupper($k),$v);
$reply .= "+--[ PATH ]-------------------------------------------+\r";
if ($mo->isNetmail()) {
if ($mo->via->count())
foreach ($mo->via as $via)
$reply .= sprintf("VIA: %s\r",$via);
else
$reply .= "No path information? This would be normal if this message came directly to the hub\r";
} else {
if ($mo->path->count())
foreach ($mo->path as $via)
$reply .= sprintf("VIA: %s\r",$via);
else
$reply .= "No path information? This would be normal if this message came directly to the hub\r";
}
$reply .= "+--[ END MESSAGE ]------------------------------------+\r";
return $reply;
}
}

View File

@ -0,0 +1,31 @@
<?php
/**
* Template for starting a message
*/
namespace App\Traits;
use App\Classes\{ANSI,Page};
use App\Classes\Fonts\{Thick,Thin};
trait PageTemplate
{
protected function page(bool $addlogo=FALSE,string $leftbox=''): Page
{
$page = new Page;
if ($addlogo)
$page->addLogo(new ANSI('public/logo/netmail.bin'));
$header = new Thick;
$header->addText('Clearing Houz');
$page->addHeader($header,'FTN Mailer and Tosser',TRUE,0xc4);
if ($leftbox) {
$lbc = new Thin;
$lbc->addText($leftbox);
$page->addLeftBoxContent($lbc);
}
return $page;
}
}

View File

@ -0,0 +1,25 @@
<?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
{
DB::statement('ALTER TABLE netmails ALTER COLUMN flags TYPE integer');
DB::statement('ALTER TABLE echomails ALTER COLUMN flags TYPE integer');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Noop
}
};