Added filefix %AREA
This commit is contained in:
parent
3e62e3d8e1
commit
ca7ca7e60a
@ -78,7 +78,7 @@ class Area extends Base
|
||||
->whereNotNull('export_at')
|
||||
->whereNull('sent_at')
|
||||
->orderBy('echomails.datetime')
|
||||
->skip($this->mo->fftn->system->pkt_msgs)
|
||||
->skip($this->mo->fftn->system->pkt_msgs) // Might already being sent in this session
|
||||
->delete();
|
||||
|
||||
Log::debug(sprintf('%s:- FTN [%s] UNSUBSCRIBED from [%s] clearing [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$x));
|
||||
|
144
app/Classes/FTN/Process/Netmail/Robot/Filefix/Area.php
Normal file
144
app/Classes/FTN/Process/Netmail/Robot/Filefix/Area.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\FTN\Process\Netmail\Robot\Filefix;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\FTN\Process\Netmail\Robot\Areafix\Base;
|
||||
use App\Jobs\FilefixRescan;
|
||||
|
||||
// Filearea Processing Command
|
||||
class Area extends Base
|
||||
{
|
||||
private const LOGKEY = 'FFA';
|
||||
|
||||
private const command = '%AREA';
|
||||
|
||||
public static function help(): array
|
||||
{
|
||||
return [
|
||||
self::command.' [-|+]<FILEAREA> [R|D=<DAYS>]',
|
||||
' Use the area command to subscribe (+) or unsubscribe (-) to a FILEAREA',
|
||||
' Arguments:',
|
||||
' - FILEAREA (required) name of area to subscribe or unsubscribe',
|
||||
' - D=DAYS (optional) number of days to resend files from this area that you',
|
||||
' havent already received (useful if you are resubscribing to an area and',
|
||||
' have received files in the past)',
|
||||
' - R=DAYS (optional) number of days to resend files from this area (even if',
|
||||
' it was sent to you previously)',
|
||||
' Notes:',
|
||||
' * "+" is optional, and is implied if "-" is not used',
|
||||
' * "R" and "D" options only apply to subscribing',
|
||||
];
|
||||
}
|
||||
|
||||
public function process(): string
|
||||
{
|
||||
$command = self::command.' '.join(' ',$this->arguments);
|
||||
|
||||
// If command starts with '-', its to unsubscribe
|
||||
if (str_starts_with($this->arguments[0],'-')) {
|
||||
$sub = FALSE;
|
||||
$area = substr($this->arguments[0],1);
|
||||
|
||||
} elseif (str_starts_with($this->arguments[0],'+')) {
|
||||
$sub = TRUE;
|
||||
$area = substr($this->arguments[0],1);
|
||||
|
||||
} else {
|
||||
$sub = TRUE;
|
||||
$area = $this->arguments[0];
|
||||
}
|
||||
|
||||
Log::debug(sprintf('%s:- Processing [%s] for [%s]',self::LOGKEY,$sub ? 'ADD' : 'REMOVE',$area));
|
||||
|
||||
// Drop the area from the arguments, the rest are options
|
||||
array_shift($this->arguments);
|
||||
|
||||
// Area exists
|
||||
if ($fa=$this->mo->fftn->domain->fileareas->where('name',$area)->pop()) {
|
||||
// If already subscribed
|
||||
if ($nea=$this->mo->fftn->fileareas->where('name',$area)->pop()) {
|
||||
// requesting to subscribe "You already are since..., arguments ignored
|
||||
if ($sub) {
|
||||
Log::debug(sprintf('%s:- FTN [%s] ALREADY subscribed to [%s] since [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$nea->pivot->subscribed->format('Y-m-d H:i')));
|
||||
|
||||
return sprintf('%-25s <-- ALREADY subscribed since %s',$command,$nea->pivot->subscribed->format('Y-m-d H:i'));
|
||||
|
||||
// requesting to unsubscribe
|
||||
} else {
|
||||
$this->mo->fftn->fileareas()->detach($fa->id);
|
||||
|
||||
// Remove sub, clear queue
|
||||
$x = DB::table('file_seenby')
|
||||
->where('address_id',$this->mo->fftn->id)
|
||||
->join('files',['files.id'=>'file_seenby.file_id'])
|
||||
->where('filearea_id',$nea->id)
|
||||
->whereNotNull('export_at')
|
||||
->whereNull('sent_at')
|
||||
->orderBy('files.datetime')
|
||||
->skip(1) // Might already being sent in this session
|
||||
->delete();
|
||||
|
||||
Log::debug(sprintf('%s:- FTN [%s] UNSUBSCRIBED from [%s] clearing [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area,$x));
|
||||
|
||||
return sprintf('%-25s <-- UNSUBSCRIBED, CLEARED [%d] FILES from queue',$command,$x);
|
||||
}
|
||||
|
||||
// If not subscribed
|
||||
} else {
|
||||
// requesting to subscribe, subsubsribe and rescan if arguments
|
||||
if ($sub) {
|
||||
$this->mo->fftn->fileareas()->attach([$fa->id=>['subscribed'=>Carbon::now()]]);
|
||||
|
||||
// If we have arguments, they are to rescan
|
||||
if (count($this->arguments) === 1) {
|
||||
$m = [];
|
||||
if (preg_match('/^([DR])=([0-9]+)$/',$this->arguments[0],$m)) {
|
||||
switch ($m[1]) {
|
||||
// Scan
|
||||
case 'D':
|
||||
FilefixRescan::dispatch($this->mo->fftn,$fa,$m[2])
|
||||
->onQueue('mail');
|
||||
|
||||
return sprintf('%-25s <-- SUBSCRIBED, RESCAN [%d] DAYS queued',$command,$m[2]);
|
||||
|
||||
// Scan
|
||||
case 'R':
|
||||
FilefixRescan::dispatch($this->mo->fftn,$fa,$m[2],TRUE)
|
||||
->onQueue('mail');
|
||||
|
||||
return sprintf('%-25s <-- SUBSCRIBED, FORCE RESCAN [%d] DAYS queued',$command,$m[2]);
|
||||
}
|
||||
}
|
||||
|
||||
return sprintf('%-25s <-- SUBSCRIBED, INVALID OPTIONS',$command);
|
||||
|
||||
} elseif (count($this->arguments) > 1) {
|
||||
Log::debug(sprintf('%s:- FTN [%s] subscribed to [%s], extra commands [%s] ignored',self::LOGKEY,$this->mo->fftn->ftn,$area,join('|',$this->arguments)));
|
||||
|
||||
return sprintf('%-25s <-- SUBSCRIBED, OPTIONS IGNORED',$command);
|
||||
|
||||
} else {
|
||||
Log::debug(sprintf('%s:- FTN [%s] subscribed to [%s]',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
||||
|
||||
return sprintf('%-25s <-- SUBSCRIBED',$command);
|
||||
}
|
||||
|
||||
// If not subscribed, "you arent subscribed, arguments ignored"
|
||||
} else {
|
||||
Log::debug(sprintf('%s:- FTN [%s] is NOT subscribed to [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
||||
|
||||
return sprintf('%-25s <-- NOT subscribed, NO ACTION taken',$command);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Log::debug(sprintf('%s:- FTN [%s] area UNKNOWN [%s], NO ACTION taken',self::LOGKEY,$this->mo->fftn->ftn,$area));
|
||||
|
||||
return sprintf('%-25s <-- AREA UNKNOWN, NO ACTION TAKEN',$command);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ use Illuminate\Support\Facades\Notification;
|
||||
use App\Classes\FTN\Process\Netmail\Robot\Areafix\Base;
|
||||
use App\Notifications\Netmails\Filefix\AreaList as AreaListNotification;
|
||||
|
||||
// LIST - List echoareas in a domain
|
||||
// LIST - List fileareas in a domain
|
||||
class AreaList extends Base
|
||||
{
|
||||
private const LOGKEY = 'AFS';
|
||||
|
@ -51,6 +51,9 @@ class Rescan extends Command
|
||||
|
||||
$eo = Echoarea::where('name',$this->argument('area'))->sole();
|
||||
|
||||
if ($eo->domain_id !== $ao->zone->domain_id)
|
||||
throw new \Exception(sprintf('Echo area [%s] is not in domain [%s] for FTN [%s]',$eo->name,$ao->zone->domain->name,$ao->ftn));
|
||||
|
||||
if ($this->option('queue'))
|
||||
AreafixRescan::dispatch($ao,$eo,$this->argument('days'))->onQueue($this->option('queuename'));
|
||||
else
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
namespace App\Console\Commands\Filefix;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Models\{Address,Filearea,File};
|
||||
use App\Jobs\FilefixRescan;
|
||||
use App\Models\{Address,Filearea};
|
||||
|
||||
class Rescan extends Command
|
||||
{
|
||||
@ -14,7 +14,13 @@ class Rescan extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'filefix:rescan {ftn} {area} {file?}';
|
||||
protected $signature = 'filefix:rescan'
|
||||
.' {ftn : FTN Address}'
|
||||
.' {area : Echoarea Tag}'
|
||||
.' {days? : Limit to files received days ago}'
|
||||
.' {--j|queue : Queue the Job}'
|
||||
.' {--Q|queuename=default : Queue on queue}'
|
||||
.' {--R|export : Re-export previously sent files}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -31,6 +37,9 @@ class Rescan extends Command
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
if (($this->argument('days')) && (! is_numeric($this->argument('days'))))
|
||||
throw new \Exception('Days must be numeric: '.$this->argument('days'));
|
||||
|
||||
$ao = Address::findFtn($this->argument('ftn'));
|
||||
|
||||
if (! $ao)
|
||||
@ -41,49 +50,14 @@ class Rescan extends Command
|
||||
throw new \Exception('Areaname is required');
|
||||
|
||||
$fao = Filearea::where('name',$this->argument('area'))->sole();
|
||||
|
||||
if ($fao->domain_id !== $ao->zone->domain_id)
|
||||
throw new \Exception(sprintf('File area [%s] is not in domain [%s] for FTN [%s]',$fao->name,$ao->zone->domain->name,$ao->ftn));
|
||||
|
||||
// Check that the user is subscribed
|
||||
if (! $ao->fileareas->contains($fao->id))
|
||||
throw new \Exception(sprintf('FTN [%s] is not subscribed to [%s]',$ao->ftn,$fao->name));
|
||||
|
||||
// Check that an FTN can read the area
|
||||
if (! $fao->can_read($ao->security))
|
||||
throw new \Exception(sprintf('FTN [%s] doesnt have permission to receive [%s]',$ao->ftn,$fao->name));
|
||||
|
||||
foreach (File::select('id')
|
||||
->where('filearea_id',$fao->id)
|
||||
->when($this->argument('file'),function($query) {
|
||||
return $query->where('name','=',$this->argument('file'));
|
||||
})
|
||||
->orderBy('datetime')
|
||||
->cursor() as $fo) {
|
||||
|
||||
// File hasnt been exported before
|
||||
if (! $fo->seenby->count()) {
|
||||
$fo->seenby()->attach($ao->id,['export_at'=>Carbon::now()]);
|
||||
$this->info(sprintf('Exported [%d] to [%s]',$fo->id,$ao->ftn3d));
|
||||
|
||||
} else {
|
||||
$export = $fo->seenby->where('id',$ao->id)->pop();
|
||||
|
||||
// File is pending export
|
||||
if ($export && $export->pivot->export_at && is_null($export->pivot->sent_at) && is_null($export->pivot->sent_pkt)) {
|
||||
$this->warn(sprintf('Not exporting [%d] already queued for [%s]',$fo->id,$ao->ftn3d));
|
||||
|
||||
// File has been exported
|
||||
} elseif ($export) {
|
||||
$fo->seenby()->updateExistingPivot($ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
||||
$this->info(sprintf('Re-exported [%d] to [%s]',$fo->id,$ao->ftn3d));
|
||||
|
||||
// File has not been exported
|
||||
} else {
|
||||
$fo->seenby()->attach($ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
||||
$this->info(sprintf('Exported [%d] to [%s]',$fo->id,$ao->ftn3d));
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->option('queue'))
|
||||
FilefixRescan::dispatch($ao,$fao,$this->argument('days'))->onQueue($this->option('queuename'));
|
||||
else
|
||||
FilefixRescan::dispatchSync($ao,$fao,$this->argument('days'));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
168
app/Jobs/FilefixRescan.php
Normal file
168
app/Jobs/FilefixRescan.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\Middleware\Skip;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
use App\Models\{Address,Filearea,File};
|
||||
use App\Notifications\Netmails\Filefix\Scan;
|
||||
|
||||
class FilefixRescan implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JAR';
|
||||
|
||||
private Address $ao; // System address
|
||||
private Filearea $fao; // Domain we are processing
|
||||
private int $days;
|
||||
private bool $rescan;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(Address $ao,Filearea $fao,int $days=30,bool $rescan=FALSE)
|
||||
{
|
||||
$this->ao = $ao->withoutRelations();
|
||||
$this->fao = $fao->withoutRelations();
|
||||
$this->days = $days;
|
||||
$this->rescan = $rescan;
|
||||
}
|
||||
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
switch ($key) {
|
||||
case 'jobname':
|
||||
return sprintf('%s %s (%d)',$this->ao->ftn,$this->fao->name,$this->days);
|
||||
|
||||
default:
|
||||
$this->fail('Unkown key:'.$key);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public function middleware(): array
|
||||
{
|
||||
return [
|
||||
Skip::when(function(): bool {
|
||||
if ($this->fao->domain_id !== $this->ao->zone->domain_id) {
|
||||
Log::error(sprintf('%s:! File area [%s] is not in domain [%s] for FTN [%s]',self::LOGKEY,$this->fao->name,$this->ao->zone->domain->name,$this->ao->ftn));
|
||||
|
||||
return TRUE;
|
||||
|
||||
// Check that the user is subscribed
|
||||
} elseif (! $this->ao->fileareas->contains($this->fao->id)) {
|
||||
Log::error(sprintf('%s:! FTN [%s] is not subscribed to [%s]',self::LOGKEY,$this->ao->ftn,$this->fao->name));
|
||||
|
||||
return TRUE;
|
||||
|
||||
// Check that an FTN can read the area
|
||||
} elseif (! $this->fao->can_read($this->ao->security)) {
|
||||
Log::error(sprintf('%s:! FTN [%s] doesnt have permission to receive [%s]',self::LOGKEY,$this->ao->ftn,$this->fao->name));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$c = 0;
|
||||
$s = 0;
|
||||
|
||||
$earliest = NULL;
|
||||
$latest = NULL;
|
||||
|
||||
foreach (File::select(['id','datetime'])
|
||||
->where('filearea_id',$this->fao->id)
|
||||
->where('datetime','>=',
|
||||
Carbon::now()
|
||||
->subDays($this->days)
|
||||
->startOfDay()
|
||||
)
|
||||
->orderBy('datetime')
|
||||
->cursor() as $fo) {
|
||||
|
||||
// File hasnt been exported before
|
||||
if (! $fo->seenby->count()) {
|
||||
$fo->seenby()->attach($this->ao->id,['export_at'=>Carbon::now()]);
|
||||
$c++;
|
||||
|
||||
if (($fo->datetime < $earliest) || (! $earliest))
|
||||
$earliest = $fo->datetime;
|
||||
|
||||
if (($latest < $fo->datetime) || (! $latest))
|
||||
$latest = $fo->datetime;
|
||||
|
||||
Log::debug(sprintf('Exported [%d] FILE (%s) dated (%s) to [%s]',$fo->id,$fo->name,$fo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));
|
||||
|
||||
} else {
|
||||
$export = $fo->seenby->where('id',$this->ao->id)->pop();
|
||||
|
||||
if ($export) {
|
||||
// File is pending export
|
||||
if ($export->pivot->export_at && is_null($export->pivot->sent_at) && is_null($export->pivot->sent_pkt)) {
|
||||
$s++;
|
||||
Log::debug(sprintf('Not exporting [%d] FILE (%s) dated (%s) already queued for [%s]',$fo->id,$fo->name,$fo->datetime->format('Y-m-d H:i:s'),$this->ao->ftn3d));
|
||||
|
||||
// File has been exported
|
||||
} elseif ($this->rescan) {
|
||||
$fo->seenby()->updateExistingPivot($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
||||
$c++;
|
||||
|
||||
if (($fo->datetime < $earliest) || (! $earliest))
|
||||
$earliest = $fo->datetime;
|
||||
|
||||
if (($latest < $fo->datetime) || (! $latest))
|
||||
$latest = $fo->datetime;
|
||||
|
||||
Log::debug(sprintf('Re-exported [%d] FILE (%s) dated (%s) to [%s]',$fo->id,$fo->name,$fo->datetime,$this->ao->ftn3d));
|
||||
|
||||
} else {
|
||||
$s++;
|
||||
Log::debug(sprintf('Not resending previously sent message [%d], FILE (%s) - sent on [%s]',
|
||||
$fo->id,
|
||||
$fo->name,
|
||||
$export->pivot->sent_at ?: '-',
|
||||
));
|
||||
}
|
||||
|
||||
// File has not been exported
|
||||
} else {
|
||||
$fo->seenby()->attach($this->ao,['export_at'=>Carbon::now(),'sent_at'=>NULL]);
|
||||
$c++;
|
||||
|
||||
if (($fo->datetime < $earliest) || (! $earliest))
|
||||
$earliest = $fo->datetime;
|
||||
|
||||
if (($latest < $fo->datetime) || (! $latest))
|
||||
$latest = $fo->datetime;
|
||||
|
||||
Log::debug(sprintf('Exported [%d] to [%s]',$fo->id,$this->ao->ftn3d));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Notification::route('netmail',$this->ao)
|
||||
->notify(new Scan(collect([
|
||||
'area'=>$this->fao->name,
|
||||
'queued'=>$c,
|
||||
'skipped'=>$s,
|
||||
'earliest'=>$earliest,
|
||||
'latest'=>$latest,
|
||||
])));
|
||||
|
||||
Log::info(sprintf('%s:= Queued [%d], Skipped [%d] files for [%s] in [%s]',self::LOGKEY,$c,$s,$this->ao->ftn,$this->fao->name));
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ class Scan extends Netmails
|
||||
private const LOGKEY = 'ACS';
|
||||
|
||||
/**
|
||||
* Reply to a areafix, commands unknown.
|
||||
* Notification on a (re)scan request.
|
||||
*
|
||||
* @param Collection $result
|
||||
*/
|
||||
|
68
app/Notifications/Netmails/Filefix/Scan.php
Normal file
68
app/Notifications/Netmails/Filefix/Scan.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications\Netmails\Filefix;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Notifications\Netmails;
|
||||
use App\Models\Netmail;
|
||||
use App\Traits\{MessagePath,PageTemplate};
|
||||
|
||||
class Scan extends Netmails
|
||||
{
|
||||
use MessagePath,PageTemplate;
|
||||
|
||||
private const LOGKEY = 'FCS';
|
||||
|
||||
/**
|
||||
* Notification on a (re)scan request.
|
||||
*
|
||||
* @param Collection $result
|
||||
*/
|
||||
public function __construct(private Collection $result)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return Netmail
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function toNetmail(object $notifiable): Netmail
|
||||
{
|
||||
$o = $this->setupNetmail($notifiable);
|
||||
$ao = $notifiable->routeNotificationFor(static::via);
|
||||
|
||||
Log::info(sprintf('%s:+ Responding to filefix for a node [%s] SCAN processed',self::LOGKEY,$ao->ftn));
|
||||
|
||||
$o->subject = 'Filefix - Scan Results';
|
||||
|
||||
// Message
|
||||
$msg = $this->page(FALSE,'Filefix');
|
||||
|
||||
$msg->addText("A filefix (re)Scan has completed:\r\r");
|
||||
|
||||
$msg->addText(sprintf("Area: %s, Queued: %d, Skipped: %d\r\r",
|
||||
$this->result->get('area'),
|
||||
$this->result->get('queued'),
|
||||
$this->result->get('skipped'),
|
||||
));
|
||||
|
||||
if ($x=$this->result->get('earliest'))
|
||||
$msg->addText(sprintf("The earliest file being sent: %s.\r",$x));
|
||||
|
||||
if (($x=$this->result->get('latest')) && ($this->result->get('earliest') !== $x))
|
||||
$msg->addText(sprintf("The latest file being sent: %s.\r",$x));
|
||||
|
||||
$o->msg = $msg->render();
|
||||
$o->set_tagline = 'Why did the chicken cross the road? The robot programmed it.';
|
||||
|
||||
$o->save();
|
||||
|
||||
return $o;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user