Compare commits

...

5 Commits

Author SHA1 Message Date
Deon George d6e23b9a90 Optimise queries for rendering the about page
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 33s Details
Create Docker Image / Build Docker Image (arm64) (push) Successful in 1m38s Details
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s Details
2024-04-13 22:41:58 +10:00
Deon George 2edc41b11e Support merging addresses when both src/dst addresses are in the seenby 2024-04-13 20:54:05 +10:00
Deon George 03ca4c10b1 Only add items to the queue when the queue is empty 2024-04-12 21:22:27 +10:00
Deon George 1923eb429f Change wording for Internet Address for a System 2024-04-12 20:06:58 +10:00
Deon George 1e08c2f6f7 Move Domain_Controller::NUMBER_MAX to Address::ADDRESS_FIELD_MAX 2024-04-12 15:29:11 +10:00
16 changed files with 101 additions and 39 deletions

View File

@ -1333,7 +1333,8 @@ final class Binkp extends BaseProtocol
&& (! $this->sessionGet(self::SE_NOFILES)) && (! $this->sessionGet(self::SE_NOFILES))
&& (! $this->send->fd)) && (! $this->send->fd))
{ {
$this->getFiles($this->node); if (! $this->send->togo_count)
$this->getFiles($this->node);
// Open our next file to send // Open our next file to send
if ($this->send->togo_count && ! $this->send->fd) { if ($this->send->togo_count && ! $this->send->fd) {

View File

@ -7,7 +7,6 @@ use Illuminate\Support\Str;
use App\Classes\Protocol as BaseProtocol; use App\Classes\Protocol as BaseProtocol;
use App\Classes\Sock\SocketClient; use App\Classes\Sock\SocketClient;
use App\Http\Controllers\DomainController;
use App\Models\{Address,Domain,Mailer}; use App\Models\{Address,Domain,Mailer};
/** /**
@ -328,7 +327,7 @@ final class DNS extends BaseProtocol
{ {
$m = []; $m = [];
return (preg_match('/^'.$prefix.'([0-9]+)+/',$label,$m) && ($m[1] <= DomainController::NUMBER_MAX)) return (preg_match('/^'.$prefix.'([0-9]+)+/',$label,$m) && ($m[1] <= Address::ADDRESS_FIELD_MAX))
? $m[1] ? $m[1]
: NULL; : NULL;
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Gate;
@ -10,8 +11,17 @@ use App\Models\{Address,Domain,Zone};
class DomainController extends Controller class DomainController extends Controller
{ {
// http://ftsc.org/docs/frl-1002.001 /**
public const NUMBER_MAX = 0x7fff; * Daily stats as shown on the about page
*
* @param Domain $o
* @return Collection
*/
public function api_daily_stats(Request $request): Collection
{
$do = Domain::where('name',$request->name)->firstOrFail();
return $do->daily_area_stats();
}
/** /**
* Add or edit a domain * Add or edit a domain

View File

@ -16,7 +16,7 @@ use Illuminate\Support\ViewErrorBag;
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
use App\Http\Requests\{AddressMerge,AreafixRequest,SystemRegister}; use App\Http\Requests\{AddressMerge,AreafixRequest,SystemRegister};
use App\Jobs\AddressPoll; use App\Jobs\AddressPoll;
use App\Models\{Address,Echoarea,Filearea,Netmail,Setup,System,Zone}; use App\Models\{Address,Echoarea,Echomail,Filearea,Netmail,Setup,System,Zone};
use App\Notifications\Netmails\AddressLink; use App\Notifications\Netmails\AddressLink;
use App\Rules\{FidoInteger,TwoByteInteger}; use App\Rules\{FidoInteger,TwoByteInteger};
@ -242,8 +242,8 @@ class SystemController extends Controller
'point_id' => [ 'point_id' => [
'required', 'required',
function($attribute,$value,$fail) use ($request) { function($attribute,$value,$fail) use ($request) {
if (! is_numeric($value) || $value > DomainController::NUMBER_MAX) if (! is_numeric($value) || $value > Address::ADDRESS_FIELD_MAX)
$fail(sprintf('Point numbers must be between 0 and %d',DomainController::NUMBER_MAX)); $fail(sprintf('Point numbers must be between 0 and %d',Address::ADDRESS_FIELD_MAX));
// Check that the host doesnt already exist // Check that the host doesnt already exist
$o = Address::where(function($query) use ($request,$value) { $o = Address::where(function($query) use ($request,$value) {
@ -336,6 +336,24 @@ class SystemController extends Controller
if ($request->validated()) { if ($request->validated()) {
DB::beginTransaction(); DB::beginTransaction();
// Find all the echomails that have both seenby's
$x = Echomail::select(['id'])
->join('echomail_seenby',['echomail_seenby.echomail_id'=>'echomails.id'])
->whereIn('address_id',[$request->src])
->distinct()
->with(['seenby:id'])
->get()
->filter(function($item) use ($request) {
return $item->seenby->contains($request->dst) && $item->seenby->contains($request->src);
});
// If the Echomail has both source and dest, delete the src
if ($x->count())
DB::table('echomail_seenby')
->where('address_id',$request->src)
->whereIn('echomail_id',$x->pluck('id'))
->delete();
// Find all echomail seenbys // Find all echomail seenbys
$x = DB::update('update echomail_seenby set address_id=? where address_id=?',[$request->dst,$request->src]); $x = DB::update('update echomail_seenby set address_id=? where address_id=?',[$request->dst,$request->src]);

View File

@ -12,7 +12,6 @@ use Illuminate\Support\Facades\Log;
use App\Classes\FTN\{Message,Packet}; use App\Classes\FTN\{Message,Packet};
use App\Exceptions\InvalidFTNException; use App\Exceptions\InvalidFTNException;
use App\Http\Controllers\DomainController;
use App\Traits\ScopeActive; use App\Traits\ScopeActive;
class Address extends Model class Address extends Model
@ -38,6 +37,9 @@ class Address extends Model
public const NODE_UNKNOWN = 1<<15; // Unknown public const NODE_UNKNOWN = 1<<15; // Unknown
public const NODE_ALL = 0xFFF; // Mask to catch all nodes public const NODE_ALL = 0xFFF; // Mask to catch all nodes
// http://ftsc.org/docs/frl-1002.001
public const ADDRESS_FIELD_MAX = 0x7fff; // Maximum value for a field in the address
public static function boot() public static function boot()
{ {
parent::boot(); parent::boot();
@ -968,10 +970,10 @@ class Address extends Model
// Check our numbers are correct. // Check our numbers are correct.
foreach ([1,2,3] as $i) foreach ([1,2,3] as $i)
if ((! is_numeric($matches[$i])) || ($matches[$i] > DomainController::NUMBER_MAX)) if ((! is_numeric($matches[$i])) || ($matches[$i] > self::ADDRESS_FIELD_MAX))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - zone, host, or node address invalid [%d]',$ftn,$matches[$i])); throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - zone, host, or node address invalid [%d]',$ftn,$matches[$i]));
if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > DomainController::NUMBER_MAX))) if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > self::ADDRESS_FIELD_MAX)))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4])); throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4]));
return [ return [

View File

@ -139,10 +139,16 @@ class Domain extends Model
->get(); ->get();
} }
public function isManaged(): bool
{
return our_address()->pluck('zone.domain')->pluck('id')->contains($this->id);
}
/** /**
* Determine if this zone is managed by this host * Determine if this zone is managed by this host
* *
* @return bool * @return bool
* @deprecated use self::isManaged();
*/ */
public function managed(): bool public function managed(): bool
{ {

View File

@ -84,7 +84,6 @@ class User extends Authenticatable implements MustVerifyEmail
->get(); ->get();
} }
/** /**
* See if the user is already a member of the chosen network * See if the user is already a member of the chosen network
* *
@ -103,6 +102,7 @@ class User extends Authenticatable implements MustVerifyEmail
*/ */
public function isZC(): bool public function isZC(): bool
{ {
$this->load(['systems.addresses']);
return $this->zc()->count() > 0; return $this->zc()->count() > 0;
} }

View File

@ -4,13 +4,13 @@ namespace App\Rules;
use Illuminate\Contracts\Validation\Rule; use Illuminate\Contracts\Validation\Rule;
use App\Http\Controllers\DomainController; use App\Models\Address;
class FidoInteger implements Rule class FidoInteger implements Rule
{ {
/** /**
* Determine if the validation rule passes. * Determine if the validation rule passes.
* This will check that a number used for zone, net, host is between 1 and DomainController::NUMBER_MAX. * This will check that a number used for zone, net, host is between 1 and Address::ADDRESS_FIELD_MAX.
* *
* @param string $attribute * @param string $attribute
* @param mixed $value * @param mixed $value
@ -18,7 +18,7 @@ class FidoInteger implements Rule
*/ */
public function passes($attribute,$value) public function passes($attribute,$value)
{ {
return (is_numeric($value) && ($value >= 0) && ($value < DomainController::NUMBER_MAX)); return (is_numeric($value) && ($value >= 0) && ($value < Address::ADDRESS_FIELD_MAX));
} }
/** /**
@ -28,6 +28,6 @@ class FidoInteger implements Rule
*/ */
public function message() public function message()
{ {
return sprintf('The number must be between 0 and %d.',DomainController::NUMBER_MAX); return sprintf('The number must be between 0 and %d.',Address::ADDRESS_FIELD_MAX);
} }
} }

View File

@ -4,13 +4,13 @@ namespace App\Rules;
use Illuminate\Contracts\Validation\Rule; use Illuminate\Contracts\Validation\Rule;
use App\Http\Controllers\DomainController; use App\Models\Address;
class TwoByteInteger implements Rule class TwoByteInteger implements Rule
{ {
/** /**
* Determine if the validation rule passes. * Determine if the validation rule passes.
* This will check that a number used for zone, net, host is between 1 and DomainController::NUMBER_MAX. * This will check that a number used for zone, net, host is between 1 and Address::ADDRESS_FIELD_MAX.
* *
* @param string $attribute * @param string $attribute
* @param mixed $value * @param mixed $value
@ -18,7 +18,7 @@ class TwoByteInteger implements Rule
*/ */
public function passes($attribute,$value) public function passes($attribute,$value)
{ {
return (is_numeric($value) && ($value > 0) && ($value < DomainController::NUMBER_MAX)); return (is_numeric($value) && ($value > 0) && ($value < Address::ADDRESS_FIELD_MAX));
} }
/** /**
@ -28,6 +28,6 @@ class TwoByteInteger implements Rule
*/ */
public function message() public function message()
{ {
return sprintf('The number must be between 1 and %d.',DomainController::NUMBER_MAX); return sprintf('The number must be between 1 and %d.',Address::ADDRESS_FIELD_MAX);
} }
} }

View File

@ -4,13 +4,13 @@ namespace App\Rules;
use Illuminate\Contracts\Validation\Rule; use Illuminate\Contracts\Validation\Rule;
use App\Http\Controllers\DomainController; use App\Models\Address;
class TwoByteIntegerWithZero implements Rule class TwoByteIntegerWithZero implements Rule
{ {
/** /**
* Determine if the validation rule passes. * Determine if the validation rule passes.
* This will check that a number used for zone, net, host is between 1 and DomainController::NUMBER_MAX. * This will check that a number used for zone, net, host is between 1 and Address::ADDRESS_FIELD_MAX.
* *
* @param string $attribute * @param string $attribute
* @param mixed $value * @param mixed $value
@ -18,7 +18,7 @@ class TwoByteIntegerWithZero implements Rule
*/ */
public function passes($attribute,$value) public function passes($attribute,$value)
{ {
return (is_numeric($value) && ($value >= 0) && ($value < DomainController::NUMBER_MAX)); return (is_numeric($value) && ($value >= 0) && ($value < Address::ADDRESS_FIELD_MAX));
} }
/** /**
@ -28,6 +28,6 @@ class TwoByteIntegerWithZero implements Rule
*/ */
public function message() public function message()
{ {
return sprintf('The number must be between 1 and %d.',DomainController::NUMBER_MAX); return sprintf('The number must be between 1 and %d.',Address::ADDRESS_FIELD_MAX);
} }
} }

View File

@ -5,7 +5,6 @@ namespace App\Traits;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Http\Controllers\DomainController;
use App\Models\{Address,System,Zone}; use App\Models\{Address,System,Zone};
trait ParseAddresses trait ParseAddresses
@ -37,13 +36,13 @@ trait ParseAddresses
// If domain should be flattened, look for node regardless of zone (within the list of zones for the domain) // If domain should be flattened, look for node regardless of zone (within the list of zones for the domain)
$ao = ($zone->domain->flatten) $ao = ($zone->domain->flatten)
? Address::findZone($zone->domain,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,0) ? Address::findZone($zone->domain,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX,0)
: Address::findFTN(sprintf('%d:%d/%d@%s',$zone->zone_id,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$zone->domain->name)); : Address::findFTN(sprintf('%d:%d/%d@%s',$zone->zone_id,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX,$zone->domain->name));
switch ($type) { switch ($type) {
case 'seenby': case 'seenby':
if (! $ao) if (! $ao)
$rogue->push(sprintf('%d:%d/%d',$zone->domain->flatten ? 0 : $zone->zone_id,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX)); $rogue->push(sprintf('%d:%d/%d',$zone->domain->flatten ? 0 : $zone->zone_id,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX));
else else
$nodes->push($ao->id); $nodes->push($ao->id);
@ -51,7 +50,7 @@ trait ParseAddresses
case 'path': case 'path':
if (! $ao) { if (! $ao) {
$ftn = sprintf('%d:%d/%d@%s',$zone->zone_id,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$zone->domain->name); $ftn = sprintf('%d:%d/%d@%s',$zone->zone_id,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX,$zone->domain->name);
Log::info(sprintf('%s:- Creating address [%s] for path',self::LOGKEY,$ftn)); Log::info(sprintf('%s:- Creating address [%s] for path',self::LOGKEY,$ftn));
$ao = Address::createFTN($ftn,System::createUnknownSystem()); $ao = Address::createFTN($ftn,System::createUnknownSystem());

View File

@ -91,16 +91,26 @@ if (! function_exists('hexstr')) {
*/ */
function our_address(Domain $do=NULL,Address $ao=NULL): Collection|Address|NULL function our_address(Domain $do=NULL,Address $ao=NULL): Collection|Address|NULL
{ {
$our = Setup::findOrFail(config('app.id'))->system->akas; static $so = NULL;
static $our = NULL;
if (! $so)
$so = Setup::findOrFail(config('app.id'));
if (! $our) {
$so->load(['system.akas.zone.domain']);
$our = $so->system->akas;
}
$filter = $our;
if ($do) if ($do)
$our = $our->filter(function($item) use ($do) { return $item->zone->domain_id === $do->id; })->sortBy('role'); $filter = $our->filter(function($item) use ($do) { return $item->zone->domain_id === $do->id; })->sortBy('role');
// If we are looking for a specific address, and there is only 1 result, return it, otherwise return what we have // If we are looking for a specific address, and there is only 1 result, return it, otherwise return what we have
if ($ao && config('fido.strict') && ($x=$our->filter(function($item) use ($ao) { return $item->role <= $ao->role; })->sortBy('role'))->count()) if ($ao && config('fido.strict') && ($x=$filter->filter(function($item) use ($ao) { return $item->role <= $ao->role; })->sortBy('role'))->count())
$our = $x; $our = $x;
return $ao ? $our->last() : $our; return $ao ? $our->last() : ($do ? $filter : $our);
} }
/** /**

View File

@ -125,7 +125,7 @@
@js('highcharts') @js('highcharts')
<script> <script>
Highcharts.chart('network_traffic', { var chart = Highcharts.chart('network_traffic', {
chart: { chart: {
type: 'spline', type: 'spline',
zoomType: 'x', zoomType: 'x',
@ -176,16 +176,30 @@
@foreach (\App\Models\Domain::active() @foreach (\App\Models\Domain::active()
->when(((! $user) || (! $user->isAdmin())),function($query) { return $query->public()->active(); }) ->when(((! $user) || (! $user->isAdmin())),function($query) { return $query->public()->active(); })
->orderBy('name') ->orderBy('name')
->with(['echoareas'])->get() as $o) ->with(['echoareas'])
->get() as $o)
@if ($o->managed()) @if ($o->managed())
{ {
name: '{{ $o->name }}', name: '{{ $o->name }}',
data: {!! $o->daily_area_stats() !!}, data: [],
dashStyle: 'ShortDot', dashStyle: 'ShortDot',
}, },
@endif @endif
@endforeach @endforeach
], ],
}); });
chart.series.forEach(function(item) {
$.ajax({
url: '/api/domain/daily',
type: 'GET',
dataType: 'json',
data : {name: item.name},
success: function(data) {
item.setData(data);
},
cache: false
});
});
</script> </script>
@append @append

View File

@ -14,8 +14,9 @@
<dt>Explore Networks</dt> <dt>Explore Networks</dt>
@foreach (\App\Models\Domain::select(['id','name']) @foreach (\App\Models\Domain::select(['id','name'])
->when(((! $user) || (! $user->isAdmin())),function($query) { return $query->public()->active(); }) ->when(((! $user) || (! $user->isAdmin())),function($query) { return $query->public()->active(); })
->orderBy('name')->get() as $o) ->orderBy('name')
@if ($o->managed()) ->get() as $o)
@if ($o->isManaged())
<dd><a href="{{ url('domain/view',['id'=>$o->id]) }}">{{ $o->name }}</a></dd> <dd><a href="{{ url('domain/view',['id'=>$o->id]) }}">{{ $o->name }}</a></dd>
@endif @endif
@endforeach @endforeach

View File

@ -134,7 +134,7 @@
<div class="row"> <div class="row">
<!-- Address --> <!-- Address -->
<div class="col-5"> <div class="col-5">
<label for="address" class="form-label">Internet Address</label> <label for="address" class="form-label">BBS Internet Hostname</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-globe"></i></span> <span class="input-group-text"><i class="bi bi-globe"></i></span>
<input type="text" class="w-75 form-control @error('address') is-invalid @enderror" id="address" placeholder="FQDN" name="address" value="{{ old('address',$o->address) }}" @cannot($action,$o)readonly @endcannot> <input type="text" class="w-75 form-control @error('address') is-invalid @enderror" id="address" placeholder="FQDN" name="address" value="{{ old('address',$o->address) }}" @cannot($action,$o)readonly @endcannot>

View File

@ -14,3 +14,5 @@ use App\Http\Controllers\{DomainController,SystemController,ZoneController};
| is assigned the "api" middleware group. Enjoy building your API! | is assigned the "api" middleware group. Enjoy building your API!
| |
*/ */
Route::get('/domain/daily',[DomainController::class,'api_daily_stats']);