Added laravel/passport, assign ftn addresses to nodes
This commit is contained in:
parent
84df9ce811
commit
7cab4e288b
@ -2,12 +2,21 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
use App\Models\Domain;
|
use App\Models\{Address,Domain,Zone};
|
||||||
|
|
||||||
class DomainController extends Controller
|
class DomainController extends Controller
|
||||||
{
|
{
|
||||||
|
public const NODE_ZC = 1<<1; // Zone
|
||||||
|
public const NODE_RC = 1<<2; // Region
|
||||||
|
public const NODE_NC = 1<<3; // Host
|
||||||
|
public const NODE_HC = 1<<4; // Hub
|
||||||
|
|
||||||
|
// http://ftsc.org/docs/frl-1002.001
|
||||||
|
public const NUMBER_MAX = 0x7fff;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('auth');
|
$this->middleware('auth');
|
||||||
@ -40,6 +49,69 @@ class DomainController extends Controller
|
|||||||
->with('o',$o);
|
->with('o',$o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the hosts for a zone of a particular region (or not)
|
||||||
|
*
|
||||||
|
* @param Zone $o
|
||||||
|
* @param int $region
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function api_hosts(Zone $o,int $region): Collection
|
||||||
|
{
|
||||||
|
$oo = Address::where('role',self::NODE_NC)
|
||||||
|
->where('zone_id',$o->id)
|
||||||
|
->when($region,function($query,$region) { return $query->where('region_id',$region)->where('node_id','<>',0); })
|
||||||
|
->when((! $region),function($query) use ($region) { return $query->whereNull('region_id'); })
|
||||||
|
->where('point_id',0)
|
||||||
|
->with(['system'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return $oo->map(function($item) {
|
||||||
|
return ['id'=>$item->host_id,'value'=>sprintf('%s %s',$item->ftn,$item->system->name)];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all the hubs for a host
|
||||||
|
*
|
||||||
|
* @param Zone $o
|
||||||
|
* @param int $host
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function api_hubs(Zone $o,int $host): Collection
|
||||||
|
{
|
||||||
|
$oo = Address::where('role',self::NODE_HC)
|
||||||
|
->where('zone_id',$o->id)
|
||||||
|
->when($host,function($query,$host) { return $query->where('host_id',$host)->where('node_id','<>',0); })
|
||||||
|
->with(['system'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return $oo->map(function($item) {
|
||||||
|
return ['id'=>$item->host_id,'value'=>sprintf('%s %s',$item->ftn,$item->system->name)];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the regions for a zone
|
||||||
|
*
|
||||||
|
* @param Zone $o
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function api_regions(Zone $o): Collection
|
||||||
|
{
|
||||||
|
$oo = Address::where('role',self::NODE_RC)
|
||||||
|
->where('zone_id',$o->id)
|
||||||
|
->where('node_id',0)
|
||||||
|
->where('point_id',0)
|
||||||
|
->orderBy('region_id')
|
||||||
|
->with(['system'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return $oo->map(function($item) {
|
||||||
|
return ['id'=>$item->region_id,'value'=>sprintf('%s %s',$item->ftn,$item->system->location)];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public function home()
|
public function home()
|
||||||
{
|
{
|
||||||
return view('domain.home');
|
return view('domain.home');
|
||||||
|
@ -4,7 +4,8 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
use App\Models\System;
|
use App\Models\{Address,System};
|
||||||
|
use App\Rules\TwoByteInteger;
|
||||||
|
|
||||||
class SystemController extends Controller
|
class SystemController extends Controller
|
||||||
{
|
{
|
||||||
@ -13,6 +14,171 @@ class SystemController extends Controller
|
|||||||
$this->middleware('auth');
|
$this->middleware('auth');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an address to a system
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param System $o
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*/
|
||||||
|
public function add_address(Request $request,System $o)
|
||||||
|
{
|
||||||
|
$this->authorize('admin',$o);
|
||||||
|
session()->flash('add_address',TRUE);
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'action' => 'required|in:region,host,node',
|
||||||
|
'zone_id' => 'required|exists:zones,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
switch ($request->post('action')) {
|
||||||
|
case 'region':
|
||||||
|
$request->validate([
|
||||||
|
'region_id_new' => [
|
||||||
|
'required',
|
||||||
|
new TwoByteInteger,
|
||||||
|
function ($attribute,$value,$fail) {
|
||||||
|
// Check that the region doesnt already exist
|
||||||
|
$o = Address::where(function($query) use ($value) {
|
||||||
|
return $query->where('region_id',$value)
|
||||||
|
->whereNULL('host_id')
|
||||||
|
->where('node_id',0)
|
||||||
|
->where('point_id',0)
|
||||||
|
->where('role',DomainController::NODE_RC);
|
||||||
|
})
|
||||||
|
// Check that a host doesnt already exist
|
||||||
|
->orWhere(function($query) use ($value) {
|
||||||
|
return $query->where('host_id',$value)
|
||||||
|
->where('point_id',0)
|
||||||
|
->where('role',DomainController::NODE_NC);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($o->count()) {
|
||||||
|
$fail('Region or host already exists');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$oo = new Address;
|
||||||
|
$oo->zone_id = $request->post('zone_id');
|
||||||
|
$oo->region_id = $request->post('region_id_new');
|
||||||
|
$oo->node_id = 0;
|
||||||
|
$oo->point_id = 0;
|
||||||
|
$oo->role = DomainController::NODE_RC;
|
||||||
|
$oo->active = TRUE;
|
||||||
|
|
||||||
|
$o->addresses()->save($oo);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'host':
|
||||||
|
$request->validate([
|
||||||
|
'region_id' => ['nullable',new TwoByteInteger],
|
||||||
|
'host_id_new' => [
|
||||||
|
'required',
|
||||||
|
new TwoByteInteger,
|
||||||
|
function ($attribute,$value,$fail) {
|
||||||
|
// Check that the region doesnt already exist
|
||||||
|
$o = Address::where(function($query) use ($value) {
|
||||||
|
return $query->where('region_id',$value)
|
||||||
|
->whereNULL('host_id')
|
||||||
|
->where('node_id',0)
|
||||||
|
->where('point_id',0)
|
||||||
|
->where('role',DomainController::NODE_RC);
|
||||||
|
})
|
||||||
|
// Check that a host doesnt already exist
|
||||||
|
->orWhere(function($query) use ($value) {
|
||||||
|
return $query->where('host_id',$value)
|
||||||
|
->where('point_id',0)
|
||||||
|
->where('role',DomainController::NODE_NC);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($o->count()) {
|
||||||
|
$fail('Region or host already exists');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'node_id_new' => [
|
||||||
|
'required',
|
||||||
|
new TwoByteInteger,
|
||||||
|
function ($attribute,$value,$fail) use ($request) {
|
||||||
|
// Check that the region doesnt already exist
|
||||||
|
$o = Address::where(function($query) use ($request,$value) {
|
||||||
|
return $query
|
||||||
|
->where('host_id',$request->post('host_id_new'))
|
||||||
|
->where('node_id',$value)
|
||||||
|
->where('point_id',0)
|
||||||
|
->where('role',DomainController::NODE_RC);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($o->count()) {
|
||||||
|
$fail('Host already exists');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$oo = new Address;
|
||||||
|
$oo->zone_id = $request->post('zone_id');
|
||||||
|
$oo->region_id = ($x=$request->post('region_id')) == 'no' ? NULL : $x;
|
||||||
|
$oo->host_id = $request->post('host_id_new');
|
||||||
|
$oo->node_id = $request->post('node_id_new');
|
||||||
|
$oo->point_id = 0;
|
||||||
|
$oo->role = DomainController::NODE_NC;
|
||||||
|
$oo->active = TRUE;
|
||||||
|
|
||||||
|
$o->addresses()->save($oo);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'node':
|
||||||
|
$request->validate([
|
||||||
|
'region_id' => ['nullable',new TwoByteInteger],
|
||||||
|
'host_id' => ['nullable',new TwoByteInteger],
|
||||||
|
'node_id' => [
|
||||||
|
'required',
|
||||||
|
new TwoByteInteger,
|
||||||
|
function ($attribute,$value,$fail) use ($request) {
|
||||||
|
// Check that the region doesnt already exist
|
||||||
|
$o = Address::where(function($query) use ($request,$value) {
|
||||||
|
return $query
|
||||||
|
->where('host_id',$request->post('host_id_new'))
|
||||||
|
->where('node_id',$value)
|
||||||
|
->where('point_id',0)
|
||||||
|
->where('role',DomainController::NODE_RC);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($o->count()) {
|
||||||
|
$fail('Host already exists');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'point_id' => ['required',function($attribute,$value,$fail) {
|
||||||
|
if (! is_numeric($value) || $value > DomainController::NUMBER_MAX)
|
||||||
|
$fail(sprintf('Point numbers must be between 0 and %d',DomainController::NUMBER_MAX));
|
||||||
|
}],
|
||||||
|
'hub' => 'required|boolean',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$oo = new Address;
|
||||||
|
$oo->zone_id = $request->post('zone_id');
|
||||||
|
$oo->region_id = ($x=$request->post('region_id')) == 'no' ? NULL : $x;
|
||||||
|
$oo->host_id = $request->post('host_id');
|
||||||
|
$oo->node_id = $request->post('node_id');
|
||||||
|
$oo->point_id = $request->post('point_id');
|
||||||
|
$oo->role = (! $oo->point_id) && $request->post('hub') ? DomainController::NODE_HC : NULL;
|
||||||
|
$oo->active = TRUE;
|
||||||
|
|
||||||
|
$o->addresses()->save($oo);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return redirect()->back()->withErrors(['action'=>'Unknown action: '.$request->post('action')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to(sprintf('ftn/system/addedit/%d',$o->id));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add or edit a node
|
* Add or edit a node
|
||||||
*/
|
*/
|
||||||
|
@ -35,6 +35,7 @@ class Kernel extends HttpKernel
|
|||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
|
52
app/Models/Address.php
Normal file
52
app/Models/Address.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
use App\Http\Controllers\DomainController;
|
||||||
|
|
||||||
|
class Address extends Model
|
||||||
|
{
|
||||||
|
/* RELATIONS */
|
||||||
|
|
||||||
|
public function system()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(System::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function zone()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Zone::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ATTRIBUTES */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the node name in full 5D
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFTNAttribute()
|
||||||
|
{
|
||||||
|
return sprintf('%d:%d/%d.%d@%s',$this->zone->zone_id,$this->host_id ?: $this->region_id,$this->node_id,$this->point_id,$this->zone->domain->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoleAttribute($value)
|
||||||
|
{
|
||||||
|
switch ($value) {
|
||||||
|
case DomainController::NODE_ZC;
|
||||||
|
return 'Zone';
|
||||||
|
case DomainController::NODE_RC;
|
||||||
|
return 'Region';
|
||||||
|
case DomainController::NODE_NC;
|
||||||
|
return 'Host';
|
||||||
|
case DomainController::NODE_HC;
|
||||||
|
return 'Hub';
|
||||||
|
case NULL:
|
||||||
|
return 'Node';
|
||||||
|
default:
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,5 +15,14 @@ class System extends Model
|
|||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
|
public function addresses()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Address::class)
|
||||||
|
->orderBy('region_id')
|
||||||
|
->orderBy('host_id')
|
||||||
|
->orderBy('node_id')
|
||||||
|
->orderBy('point_id');
|
||||||
|
}
|
||||||
|
|
||||||
/* CASTS */
|
/* CASTS */
|
||||||
}
|
}
|
@ -6,10 +6,25 @@ use Illuminate\Contracts\Auth\MustVerifyEmail;
|
|||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Laravel\Passport\HasApiTokens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class User
|
||||||
|
*
|
||||||
|
* User Roles:
|
||||||
|
* + Site Admin
|
||||||
|
* + ZC - For Domain/Zone
|
||||||
|
* + RC - For sub portion of a Domain/Zone (aka Region)
|
||||||
|
* + Host Admin - For sub portion of a Region
|
||||||
|
* + Hub Admin - For a sub portion of a Hosts system
|
||||||
|
* + Sysop - Individual system
|
||||||
|
* + Guest
|
||||||
|
*
|
||||||
|
* @package App\Models
|
||||||
|
*/
|
||||||
class User extends Authenticatable implements MustVerifyEmail
|
class User extends Authenticatable implements MustVerifyEmail
|
||||||
{
|
{
|
||||||
use HasFactory, Notifiable;
|
use HasFactory,Notifiable,HasApiTokens;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
@ -42,4 +57,17 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $dates = ['last_on'];
|
protected $dates = ['last_on'];
|
||||||
|
|
||||||
|
/* GENERAL METHODS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if the user is already a member of the chosen network
|
||||||
|
*
|
||||||
|
* @param Domain $o
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isMember(Domain $o): bool
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,11 @@ class Zone extends Model
|
|||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
|
public function addresses()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Address::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function domain()
|
public function domain()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Domain::class);
|
return $this->belongsTo(Domain::class);
|
||||||
|
@ -4,6 +4,7 @@ namespace App\Providers;
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Laravel\Passport\Passport;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@ -14,7 +15,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
//
|
Passport::ignoreMigrations();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
33
app/Rules/TwoByteInteger.php
Normal file
33
app/Rules/TwoByteInteger.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Rules;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\Rule;
|
||||||
|
|
||||||
|
use App\Http\Controllers\DomainController;
|
||||||
|
|
||||||
|
class TwoByteInteger implements Rule
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the validation rule passes.
|
||||||
|
* This will check that a number used for zone, net, host is between 1 and DomainController::NUMBER_MAX.
|
||||||
|
*
|
||||||
|
* @param string $attribute
|
||||||
|
* @param mixed $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function passes($attribute, $value)
|
||||||
|
{
|
||||||
|
return (is_numeric($value) && ($value > 0) && ($value < DomainController::NUMBER_MAX)) || ($value === 'no');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation error message.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function message()
|
||||||
|
{
|
||||||
|
return sprintf('The number must be between 1 and %d.',DomainController::NUMBER_MAX);
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@
|
|||||||
"fideloper/proxy": "^4.4",
|
"fideloper/proxy": "^4.4",
|
||||||
"fruitcake/laravel-cors": "^2.0",
|
"fruitcake/laravel-cors": "^2.0",
|
||||||
"laravel/framework": "^8.0",
|
"laravel/framework": "^8.0",
|
||||||
|
"laravel/passport": "^10.1",
|
||||||
"laravel/ui": "^3.2",
|
"laravel/ui": "^3.2",
|
||||||
"repat/laravel-job-models": "^0.5.1"
|
"repat/laravel-job-models": "^0.5.1"
|
||||||
},
|
},
|
||||||
|
@ -74,7 +74,6 @@ class CreateNodes extends Migration
|
|||||||
$table->integer('software_id')->nullable();
|
$table->integer('software_id')->nullable();
|
||||||
$table->foreign('software_id')->references('id')->on('software');
|
$table->foreign('software_id')->references('id')->on('software');
|
||||||
|
|
||||||
|
|
||||||
// $table->unique(['zone_id','host_id','id']);
|
// $table->unique(['zone_id','host_id','id']);
|
||||||
// $table->index(['zone_id','host_id']);
|
// $table->index(['zone_id','host_id']);
|
||||||
// $table->index(['zone_id','id']);
|
// $table->index(['zone_id','id']);
|
||||||
|
49
database/migrations/2021_06_19_045817_create_addresses.php
Normal file
49
database/migrations/2021_06_19_045817_create_addresses.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class CreateAddresses extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('addresses', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->boolean('active');
|
||||||
|
|
||||||
|
$table->integer('zone_id');
|
||||||
|
$table->foreign('zone_id')->references('id')->on('zones');
|
||||||
|
|
||||||
|
$table->integer('region_id')->nullable();
|
||||||
|
$table->integer('host_id')->nullable();
|
||||||
|
$table->integer('node_id');
|
||||||
|
$table->integer('point_id');
|
||||||
|
$table->integer('status')->nullable(); // @note Used to record Down/Private/Pending, etc
|
||||||
|
|
||||||
|
$table->integer('role')->nullable();
|
||||||
|
|
||||||
|
$table->integer('system_id');
|
||||||
|
$table->foreign('system_id')->references('id')->on('systems');
|
||||||
|
|
||||||
|
$table->unique(['zone_id','region_id','host_id','node_id']);
|
||||||
|
$table->unique(['zone_id','host_id','node_id','point_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('addresses');
|
||||||
|
}
|
||||||
|
}
|
50
database/migrations/2021_06_20_124638_unique_relations.php
Normal file
50
database/migrations/2021_06_20_124638_unique_relations.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class UniqueRelations extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('node_setup', function (Blueprint $table) {
|
||||||
|
$table->unique(['node_id','setup_id']);
|
||||||
|
});
|
||||||
|
Schema::table('domain_user', function (Blueprint $table) {
|
||||||
|
$table->unique(['domain_id','user_id']);
|
||||||
|
});
|
||||||
|
Schema::table('node_system', function (Blueprint $table) {
|
||||||
|
$table->unique(['node_id','system_id']);
|
||||||
|
});
|
||||||
|
Schema::table('system_user', function (Blueprint $table) {
|
||||||
|
$table->unique(['system_id','user_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('node_setup', function (Blueprint $table) {
|
||||||
|
$table->dropUnique(['node_id','setup_id']);
|
||||||
|
});
|
||||||
|
Schema::table('domain_user', function (Blueprint $table) {
|
||||||
|
$table->dropUnique(['domain_id','user_id']);
|
||||||
|
});
|
||||||
|
Schema::table('node_system', function (Blueprint $table) {
|
||||||
|
$table->dropUnique(['node_id','system_id']);
|
||||||
|
});
|
||||||
|
Schema::table('system_user', function (Blueprint $table) {
|
||||||
|
$table->dropUnique(['system_id','user_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
13
public/oldschool/css/main.css
vendored
13
public/oldschool/css/main.css
vendored
@ -590,19 +590,6 @@ tbody {
|
|||||||
border-bottom:1px solid #666
|
border-bottom:1px solid #666
|
||||||
}
|
}
|
||||||
|
|
||||||
.push-right {
|
|
||||||
float:right;
|
|
||||||
}
|
|
||||||
.text-center {
|
|
||||||
text-align:center;
|
|
||||||
}
|
|
||||||
.text-left {
|
|
||||||
text-align:left;
|
|
||||||
}
|
|
||||||
.text-right {
|
|
||||||
text-align:right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.titledbox {
|
.titledbox {
|
||||||
margin:1.5em auto 2.5em auto
|
margin:1.5em auto 2.5em auto
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h2>About FTN Domains</h2>
|
<h2>About FTN Domains</h2>
|
||||||
<p>In FTN network addresses, a domain is the 5th dimension and used when a system supports 5D addressing, ie: zone:hub/host.point@<strong class="highlight">domain</strong>.</p>
|
<p>In FTN network addresses, a domain is the 5th dimension and used when a system supports 5D addressing, ie: zone:net/node.point@<strong class="highlight">domain</strong>.</p>
|
||||||
<p>Domains are used with zones to uniquely identify a FTN network.</p>
|
<p>Domains are used with zones to uniquely identify a FTN network.</p>
|
||||||
<p><small>Some legacy Fidonet software is not 5D aware and may behave unexpectedly when a domain is used</small></p>
|
<p><small>Some legacy Fidonet software is not 5D aware and may behave unexpectedly when a domain is used</small></p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
@section('content')
|
@section('content')
|
||||||
<h1>{{ $o->name }} <small class="push-right">Last Update: {{ $o->updated_at }}</small></h1>
|
<h1>{{ $o->name }} <small class="push-right">Last Update: {{ $o->updated_at }}</small></h1>
|
||||||
|
|
||||||
<div class="accordion accordion-flush" id="accordion_homepage">
|
<div class="accordion" id="accordion_homepage">
|
||||||
<!-- About -->
|
<!-- About -->
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
<h3 class="accordion-header" id="about" data-bs-toggle="collapse" data-bs-target="#collapse_about" aria-expanded="true" aria-controls="collapse_about">About</h3>
|
<h3 class="accordion-header" id="about" data-bs-toggle="collapse" data-bs-target="#collapse_about" aria-expanded="true" aria-controls="collapse_about">About</h3>
|
||||||
@ -19,8 +19,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Echomail -->
|
<!-- Echomail -->
|
||||||
<div class="accordion-item">
|
<div class="accordion-item open">
|
||||||
<h3 class="accordion-header" id="echoareas" data-bs-toggle="collapse" data-bs-target="#collapse_echoareas" aria-expanded="true" aria-controls="collapse_echoareas">Echo Areas</h3>
|
<h3 class="accordion-header" id="echoareas" data-bs-toggle="collapse" data-bs-target="#collapse_echoareas" aria-expanded="false" aria-controls="collapse_echoareas">Echo Areas</h3>
|
||||||
|
|
||||||
<div id="collapse_echoareas" class="accordion-collapse collapse" aria-labelledby="echoareas" data-bs-parent="#accordion_homepage">
|
<div id="collapse_echoareas" class="accordion-collapse collapse" aria-labelledby="echoareas" data-bs-parent="#accordion_homepage">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<!-- File areas -->
|
<!-- File areas -->
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
<h3 class="accordion-header" id="fileareas" data-bs-toggle="collapse" data-bs-target="#collapse_fileareas" aria-expanded="true" aria-controls="collapse_fileareas">File Areas</h3>
|
<h3 class="accordion-header" id="fileareas" data-bs-toggle="collapse" data-bs-target="#collapse_fileareas" aria-expanded="false" aria-controls="collapse_fileareas">File Areas</h3>
|
||||||
|
|
||||||
<div id="collapse_fileareas" class="accordion-collapse collapse" aria-labelledby="fileareas" data-bs-parent="#accordion_homepage">
|
<div id="collapse_fileareas" class="accordion-collapse collapse" aria-labelledby="fileareas" data-bs-parent="#accordion_homepage">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<!-- Systems -->
|
<!-- Systems -->
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
<h3 class="accordion-header" id="systems" data-bs-toggle="collapse" data-bs-target="#collapse_systems" aria-expanded="true" aria-controls="collapse_systems">Systems</h3>
|
<h3 class="accordion-header" id="systems" data-bs-toggle="collapse" data-bs-target="#collapse_systems" aria-expanded="false" aria-controls="collapse_systems">Systems</h3>
|
||||||
|
|
||||||
<div id="collapse_systems" class="accordion-collapse collapse" aria-labelledby="systems" data-bs-parent="#accordion_homepage">
|
<div id="collapse_systems" class="accordion-collapse collapse" aria-labelledby="systems" data-bs-parent="#accordion_homepage">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
@ -59,8 +59,9 @@
|
|||||||
<th>System</th>
|
<th>System</th>
|
||||||
<th>Sysop</th>
|
<th>Sysop</th>
|
||||||
<th>Location</th>
|
<th>Location</th>
|
||||||
|
<th>Role</th>
|
||||||
<th>Address</th>
|
<th>Address</th>
|
||||||
<th>Last Connect</th>
|
<th>Last Seen</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@ -71,11 +72,22 @@
|
|||||||
<td>{{ $oz->system->name }}</td>
|
<td>{{ $oz->system->name }}</td>
|
||||||
<td>{{ $oz->system->sysop }}</td>
|
<td>{{ $oz->system->sysop }}</td>
|
||||||
<td>{{ $oz->system->location }}</td>
|
<td>{{ $oz->system->location }}</td>
|
||||||
<td>{{ $oz->zone_id }}:1/0<span>@</span>{{ $oz->domain->name }}</td>
|
<td>Zone</td>
|
||||||
|
<td>{{ $oz->zone_id }}:0/0.0<span>@</span>{{ $oz->domain->name }}</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<!-- Other Nodes -->
|
<!-- Other Nodes -->
|
||||||
|
@foreach ($oz->addresses()->orderBy('region_id')->orderBy('host_id','desc')->orderBy('node_id')->orderBy('point_id')->with(['system','zone.domain'])->get() as $ao)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $ao->system->name }}</td>
|
||||||
|
<td>{{ $ao->system->sysop }}</td>
|
||||||
|
<td>{{ $ao->system->location }}</td>
|
||||||
|
<td>{{ $ao->role }}</td>
|
||||||
|
<td>{{ $ao->ftn }}</td>
|
||||||
|
<td>-</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -85,7 +97,7 @@
|
|||||||
|
|
||||||
<!-- Sign up -->
|
<!-- Sign up -->
|
||||||
<div class="accordion-item">
|
<div class="accordion-item">
|
||||||
<h3 class="accordion-header" id="signup" data-bs-toggle="collapse" data-bs-target="#collapse_signup" aria-expanded="true" aria-controls="collapse_signup">Join Network</h3>
|
<h3 class="accordion-header" id="signup" data-bs-toggle="collapse" data-bs-target="#collapse_signup" aria-expanded="false" aria-controls="collapse_signup">Join Network</h3>
|
||||||
|
|
||||||
<div id="collapse_signup" class="accordion-collapse collapse" aria-labelledby="signup" data-bs-parent="#accordion_homepage">
|
<div id="collapse_signup" class="accordion-collapse collapse" aria-labelledby="signup" data-bs-parent="#accordion_homepage">
|
||||||
<div class="accordion-body">
|
<div class="accordion-body">
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
<meta name="description" content="{{ $decription ?? '' }}">
|
<meta name="description" content="{{ $decription ?? '' }}">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
<!-- CSS only -->
|
<!-- CSS only -->
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
|
||||||
|
@ -10,6 +10,13 @@
|
|||||||
(function () {
|
(function () {
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
// Our CSRF token to each interaction
|
||||||
|
$.ajaxSetup({
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Fetch all the forms we want to apply custom Bootstrap validation styles to
|
// Fetch all the forms we want to apply custom Bootstrap validation styles to
|
||||||
var forms = document.querySelectorAll('.needs-validation')
|
var forms = document.querySelectorAll('.needs-validation')
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
<dd><a href="{{ url('ftn/domain') }}">Domains</a></dd>
|
<dd><a href="{{ url('ftn/domain') }}">Domains</a></dd>
|
||||||
<dd><a href="{{ url('ftn/system') }}">Systems</a></dd>
|
<dd><a href="{{ url('ftn/system') }}">Systems</a></dd>
|
||||||
<dd><a href="{{ url('ftn/zone') }}" >Zones</a></dd>
|
<dd><a href="{{ url('ftn/zone') }}" >Zones</a></dd>
|
||||||
<dd><a href="{{ url('ftn/node') }}" >Nodes</a></dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
@can('admin')
|
@can('admin')
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
@endif
|
@endif
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="push-right">
|
<ul class="float-end">
|
||||||
@auth
|
@auth
|
||||||
<li><a href="{{ url('settings') }}"><span>{{ Auth::user()->name }}</span></a></li>
|
<li><a href="{{ url('settings') }}"><span>{{ Auth::user()->name }}</span></a></li>
|
||||||
<li><a href="{{ url('logout') }}"><span>Logout</span></a></li>
|
<li><a href="{{ url('logout') }}"><span>Logout</span></a></li>
|
||||||
|
@ -5,6 +5,16 @@
|
|||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
<div class="accordion accordion-flush" id="accordion_homepage">
|
||||||
|
|
||||||
|
@if ($o->exists)
|
||||||
|
<!-- System -->
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h3 class="accordion-header" id="system" data-bs-toggle="collapse" data-bs-target="#collapse_system" aria-expanded="true" aria-controls="collapse_system">System</h3>
|
||||||
|
|
||||||
|
<div id="collapse_system" class="accordion-collapse collapse {{ ! session()->has('add_address') ? 'show' : '' }}" aria-labelledby="system" data-bs-parent="#accordion_homepage">
|
||||||
|
<div class="accordion-body">
|
||||||
|
@endif
|
||||||
<form class="row g-0 needs-validation" method="post" novalidate>
|
<form class="row g-0 needs-validation" method="post" novalidate>
|
||||||
@csrf
|
@csrf
|
||||||
|
|
||||||
@ -91,12 +101,10 @@
|
|||||||
|
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
<label for="address" class="form-label">Address</label>
|
<label for="address" class="form-label">Address</label>
|
||||||
<div class="input-group">
|
<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="form-control @error('address') is-invalid @enderror" id="address" placeholder="FQDN" name="address" value="{{ old('address',$o->address) }}" @cannot('admin',$o)disabled @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('admin',$o)disabled @endcannot>
|
||||||
<span class="m-0 p-0 input-group-text" style="background-color: #ffffff;">
|
<input type="text" class="form-control @error('port') is-invalid @enderror" id="port" placeholder="Port" name="port" value="{{ old('port',$o->port) }}" @cannot('admin',$o)disabled @endcannot>
|
||||||
<input type="text" class="form-control @error('port') is-invalid @enderror" id="port" placeholder="port" name="port" value="{{ old('port',$o->port) }}" @cannot('admin',$o)disabled @endcannot>
|
|
||||||
</span>
|
|
||||||
<span class="invalid-feedback" role="alert">
|
<span class="invalid-feedback" role="alert">
|
||||||
@error('address')
|
@error('address')
|
||||||
{{ $message }}
|
{{ $message }}
|
||||||
@ -128,4 +136,504 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@if ($o->exists)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($o->exists)
|
||||||
|
<!-- Authentication -->
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h3 class="accordion-header" id="authentication" data-bs-toggle="collapse" data-bs-target="#collapse_auth" aria-expanded="false" aria-controls="collapse_auth">System Authentication</h3>
|
||||||
|
|
||||||
|
<div id="collapse_auth" class="accordion-collapse collapse" aria-labelledby="authentication" data-bs-parent="#accordion_homepage">
|
||||||
|
<div class="accordion-body">
|
||||||
|
TBA
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Addresses -->
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h3 class="accordion-header" id="addresses" data-bs-toggle="collapse" data-bs-target="#collapse_addresses" aria-expanded="false" aria-controls="collapse_addresses">System AKAs</h3>
|
||||||
|
|
||||||
|
<div id="collapse_addresses" class="accordion-collapse collapse {{ session()->has('add_address') ? 'show' : '' }}" aria-labelledby="addresses" data-bs-parent="#accordion_homepage">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<p>FidoNet addresses are constructed in the format <strong class="highlight">zone</strong>:<strong class="highlight">net</strong>/<strong class="highlight">node</strong>.<strong class="highlight">point</strong><span>@</span><strong class="highlight">domain</strong>.</p>
|
||||||
|
|
||||||
|
<div class="accordion accordion-flush" id="accordion_ftnaddress">
|
||||||
|
<h4 class="accordion-header" id="ftnaddress" data-bs-toggle="collapse" data-bs-target="#collapse_ftnaddresses" aria-expanded="false" aria-controls="collapse_addresses">Fidonet Addressing</h4>
|
||||||
|
|
||||||
|
<div id="collapse_ftnaddresses" class="accordion-collapse collapse" aria-labelledby="ftnaddress" data-bs-parent="#accordion_ftnaddress">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<p>FidoNet system are also assigned some roles, and in some cases, those roles have a paritcular address format:</p>
|
||||||
|
<table class="table monotable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Address Format</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Zone <small>(optional)</small></td>
|
||||||
|
<td>
|
||||||
|
<strong class="highlight">ZONE</strong>:0/0.0, where the net, node and point values are zero. Zones normally have 1 or more Regions and/or Hosts.<br><br>
|
||||||
|
<small>(Systems that do not configure other systems with a zone, assume that that other system is in the same zone as the system being configured.)</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Region <small>(optional)</small></td>
|
||||||
|
<td>
|
||||||
|
zone:<strong class="highlight">REGION</strong>/0.0, where the zone indicates which zone the region is in. The node and point values are zero. Regions normally have 1 or more Hosts.<br><br>
|
||||||
|
<small>Fidonet software normally doesnt configure the region address per-se. It is used by the mailer to receive packets destined to it by routing, in transition to the final destination. The region number must be unique with a zone.</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Host <small>(mandatory)</small></td>
|
||||||
|
<td>
|
||||||
|
zone:<strong class="highlight">HOST</strong>/0.0, where the zone indicates which zone the host is in. The node and point values are zero. The Host system is normally configured with an additional address, where the NET address is the same and the NODE number that is greater than zero. Hosts may may zero or more Hubs and 1 or more Nodes.<br><br>
|
||||||
|
<small>The host number must be unique within a zone, which implies that it cannot be the same as a region, if regions are used.</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Hub <small>(optional)</small></td>
|
||||||
|
<td>
|
||||||
|
zone:net/<strong class="highlight">NODE</strong>.0, where the zone/net indicates which zone/net the hub is in. The system(s) in the nodelist below a Hub are fed from that hub from a routing perspective.<br><br>
|
||||||
|
<small>The node is unique within the net and point is zero.</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Node <small>(required)</small></td>
|
||||||
|
<td>
|
||||||
|
zone:net/<strong class="highlight">NODE</strong>.0, where the zone/net indicates which zone/net the node is in.<br><br>
|
||||||
|
<small>The node is unique within the net and point is zero.</small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($o->addresses->count())
|
||||||
|
<p>This system has the following addresses assigned to it:</p>
|
||||||
|
|
||||||
|
<table class="table monotable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Address</th>
|
||||||
|
<th>Active</th>
|
||||||
|
<th>Role</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
@foreach ($o->addresses->sortBy(['region_id','host_id']) as $oo)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $oo->ftn }}</td>
|
||||||
|
<td>{{ $oo->active ? 'YES' : 'NO' }}</td>
|
||||||
|
<td>{{ $oo->role }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@can('admin',$o)
|
||||||
|
<form class="row g-0 needs-validation" method="post" action="{{ url('ftn/system/addaddress',$o->id) }}" novalidate>
|
||||||
|
<input type="hidden" id="action" name="action" value="">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row pt-0">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="greyframe titledbox shadow0xb0">
|
||||||
|
<h2 class="cap">Assign New address</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Select Zone -->
|
||||||
|
<div class="col-3">
|
||||||
|
<label for="zone_id" class="form-label">Zone</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-hash"></i></span>
|
||||||
|
<select class="form-select @error('zone_id') is-invalid @enderror" id="zone_id" name="zone_id" required>
|
||||||
|
<option></option>
|
||||||
|
@foreach(\App\Models\Zone::active()->with(['domain'])->get() as $zo)
|
||||||
|
<option value="{{ $zo->id }}">{{ $zo->zone_id }} <small>({{ $zo->domain->name }})</small></option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('zone_id')
|
||||||
|
{{ $message }}
|
||||||
|
@else
|
||||||
|
Please select the Zone for the node's address.
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Select Region -->
|
||||||
|
<div class="col-3 d-none" id="region-select">
|
||||||
|
<label for="region_id" class="form-label">Region</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-geo"></i></span>
|
||||||
|
<select class="form-select @error('region_id') is-invalid @enderror" id="region_id" name="region_id" required>
|
||||||
|
</select>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('region_id')
|
||||||
|
{{ $message }}
|
||||||
|
@else
|
||||||
|
Please make a choice.
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Select Host -->
|
||||||
|
<div class="col-3 d-none" id="host-select">
|
||||||
|
<label for="host_id" class="form-label">Host</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-diagram-3-fill"></i></span>
|
||||||
|
<select class="form-select @error('host_id') is-invalid @enderror" id="host_id" name="host_id">
|
||||||
|
</select>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('host_id')
|
||||||
|
{{ $message }}
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Select Hub -->
|
||||||
|
<div class="col-3 d-none" id="hub-select">
|
||||||
|
<label for="hub_id" class="form-label">Hub</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-diagram-2-fill"></i></span>
|
||||||
|
<select class="form-select @error('hub_id') is-invalid @enderror" id="hub_id" name="hub_id">
|
||||||
|
|
||||||
|
</select>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('hub_id')
|
||||||
|
{{ $message }}
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Node/Point address -->
|
||||||
|
<div class="col-3 d-none" id="node-address">
|
||||||
|
<label for="node_id" class="form-label">Node/Point Address</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-hash"></i></span>
|
||||||
|
<input type="text" style="width: 35%;" class="form-control @error('node_id') is-invalid @enderror" id="node_id" placeholder="Node" name="node_id" value="{{ old('node_id',$o->node_id) }}" @cannot('admin',$o)disabled @endcannot>
|
||||||
|
<span class="input-group-text ml-1 mr-1 p-0">.</span>
|
||||||
|
<input type="text" class="form-control @error('point_id') is-invalid @enderror" id="point_id" placeholder="0" name="point_id" value="{{ old('point_id',$o->point_id) ?: 0 }}" @cannot('admin',$o)disabled @endcannot style="padding-left: 0;">
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('node_id')
|
||||||
|
{{ $message }}
|
||||||
|
@enderror
|
||||||
|
@error('point_id')
|
||||||
|
{{ $message }}
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Region Address -->
|
||||||
|
<div class="pl-0 col-3 d-none" id="region-address" >
|
||||||
|
<label for="region" class="form-label">Region Address</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-hash"></i></span>
|
||||||
|
<input type="text" style="width: 35%;" class="form-control @error('region_id_new') is-invalid @enderror" id="region_id_new" placeholder="Region #" name="region_id_new" value="{{ old('region_id_new') }}" @cannot('admin',$o)disabled @endcannot>
|
||||||
|
<span class="input-group-text">/0.0</span>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('region_id_new')
|
||||||
|
{{ $message }}
|
||||||
|
@else
|
||||||
|
The region number is required.
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Host Address -->
|
||||||
|
<div class="pl-0 col-3 d-none" id="host-address">
|
||||||
|
<label for="host" class="form-label">Host Address</label>
|
||||||
|
<div class="input-group has-validation">
|
||||||
|
<span class="input-group-text"><i class="bi bi-hash"></i></span>
|
||||||
|
<input type="text" class="form-control @error('host_id_new') is-invalid @enderror" id="host_id_new" placeholder="Host #" name="host_id_new" value="{{ old('host_id_new') }}" @cannot('admin',$o)disabled @endcannot>
|
||||||
|
<span class="input-group-text ml-1 mr-1 p-0">/</span>
|
||||||
|
<input type="text" class="form-control @error('node_id_new') is-invalid @enderror" id="node_id_new" placeholder="Node #" name="node_id_new" value="{{ old('node_id_new') }}" @cannot('admin',$o)disabled @endcannot>
|
||||||
|
<span class="input-group-text">.0</span>
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
@error('host_id_new')
|
||||||
|
{{ $message }}
|
||||||
|
@else
|
||||||
|
The host address is required.
|
||||||
|
@enderror
|
||||||
|
@error('node_id_new')
|
||||||
|
{{ $message }}
|
||||||
|
@else
|
||||||
|
The node address is required.
|
||||||
|
@enderror
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hub Checkbox -->
|
||||||
|
<div class="col-2 d-none" id="hub-checkbox">
|
||||||
|
<label for="hub" class="form-label">Hub</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<input type="radio" class="btn-check" name="hub" id="hub_yes" value="1" required @cannot('admin',$o)disabled @endcannot @if(old('hub',$o->hub))checked @endif>
|
||||||
|
<label class="btn btn-outline-success" for="hub_yes">Yes</label>
|
||||||
|
|
||||||
|
<input type="radio" class="btn-check btn-danger" name="hub" id="hub_no" value="0" required @cannot('admin',$o)disabled @endcannot @if(! old('hub',$o->hub))checked @endif>
|
||||||
|
<label class="btn btn-outline-danger" for="hub_no">No</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-2">
|
||||||
|
<a href="{{ url('ftn/system') }}" class="btn btn-danger">Cancel</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="col-6 mt-auto mx-auto text-center align-bottom">
|
||||||
|
@if($errors->count())
|
||||||
|
<span class="pl-5 btn btn-sm btn-danger" role="alert">
|
||||||
|
There were errors with the submission.
|
||||||
|
@dump($errors)
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
|
||||||
|
@can('admin',$o)
|
||||||
|
<div class="col-2">
|
||||||
|
<button type="submit" name="submit" class="btn btn-success mr-0 float-end">Add</button>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
This system does not currently belong to any Fido networks. You'll need to ask an admin to assign addresses.
|
||||||
|
@endcan
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@section('page-scripts')
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
/*
|
||||||
|
// Disable enter for form submission.
|
||||||
|
$('input').on('keydown', function(event) {
|
||||||
|
var x = event.which;
|
||||||
|
if (x === 13) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
$('#zone_id').on('change',function() {
|
||||||
|
$(this).parent().find('i').addClass('spinner-grow spinner-grow-sm');
|
||||||
|
$('#region_id').prop('disabled',true);
|
||||||
|
$('#region_id').children().remove();
|
||||||
|
|
||||||
|
if (! $('#region-address').hasClass('d-none'))
|
||||||
|
$('#region-address').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#host-address').hasClass('d-none'))
|
||||||
|
$('#host-address').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#host-select').hasClass('d-none'))
|
||||||
|
$('#host-select').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#hub-select').hasClass('d-none'))
|
||||||
|
$('#hub-select').addClass('d-none')
|
||||||
|
|
||||||
|
if (! $('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#node-address').hasClass('d-none'))
|
||||||
|
$('#node-address').addClass('d-none');
|
||||||
|
|
||||||
|
$.get('{{ url('api/regions') }}'+'/'+this.value,function(data) {
|
||||||
|
$('#region_id').append('<option value=""></option>');
|
||||||
|
$('#region_id').append('<option value="no">No Region</option>');
|
||||||
|
$('#region_id').append('<option value="new">New Region</option>');
|
||||||
|
|
||||||
|
data.forEach(function(item) {
|
||||||
|
$('#region_id').append('<option value="'+item.id+'">'+item.id+':'+item.value+'</option>');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#region_id').prop('disabled',false);
|
||||||
|
$('#region_id').show();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#region-select').removeClass('d-none');
|
||||||
|
$(this).parent().find('i').removeClass('spinner-grow spinner-grow-sm');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#region_id').on('change',function() {
|
||||||
|
switch(this.value) {
|
||||||
|
case 'new':
|
||||||
|
if (! $('#host-select').hasClass('d-none'))
|
||||||
|
$('#host-select').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#host-address').hasClass('d-none'))
|
||||||
|
$('#host-address').addClass('d-none');
|
||||||
|
|
||||||
|
if ($('#region-address').hasClass('d-none'))
|
||||||
|
$('#region-address').removeClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#hub-select').hasClass('d-none'))
|
||||||
|
$('#hub-select').addClass('d-none')
|
||||||
|
|
||||||
|
if (! $('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#node-address').hasClass('d-none'))
|
||||||
|
$('#node-address').addClass('d-none');
|
||||||
|
|
||||||
|
$('#action').val('region');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'no':
|
||||||
|
default:
|
||||||
|
// Find Hosts
|
||||||
|
if ($('#host-select').hasClass('d-none'))
|
||||||
|
$('#host-select').removeClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#region-address').hasClass('d-none'))
|
||||||
|
$('#region-address').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#hub-select').hasClass('d-none'))
|
||||||
|
$('#hub-select').addClass('d-none')
|
||||||
|
|
||||||
|
if (! $('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#host-address').hasClass('d-none'))
|
||||||
|
$('#host-address').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#node-address').hasClass('d-none'))
|
||||||
|
$('#node-address').addClass('d-none');
|
||||||
|
|
||||||
|
$(this).parent().find('i').addClass('spinner-grow spinner-grow-sm');
|
||||||
|
$('#host_id').prop('disabled',true);
|
||||||
|
$('#host_id').children().remove();
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
$.get('{{ url('api/hosts') }}'+'/'+$('#zone_id').val()+'/'+((this.value === 'no') ? 0 : this.value),function(data) {
|
||||||
|
$('#host_id').append('<option value=""></option>');
|
||||||
|
if (that.value !== 'no')
|
||||||
|
$('#host_id').append('<option value="no">No Host</option>');
|
||||||
|
$('#host_id').append('<option value="new">New Host</option>');
|
||||||
|
|
||||||
|
data.forEach(function(item) {
|
||||||
|
$('#host_id').append('<option value="'+item.id+'">'+item.id+':'+item.value+'</option>');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#host_id').prop('disabled',false);
|
||||||
|
$('#host_id').show();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#host-select').removeClass('d-none');
|
||||||
|
$(this).parent().find('i').removeClass('spinner-grow spinner-grow-sm');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#host_id').on('change',function() {
|
||||||
|
switch(this.value) {
|
||||||
|
case 'new':
|
||||||
|
if ($('#host-address').hasClass('d-none'))
|
||||||
|
$('#host-address').removeClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#hub-select').hasClass('d-none'))
|
||||||
|
$('#hub-select').addClass('d-none')
|
||||||
|
|
||||||
|
if (! $('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').addClass('d-none');
|
||||||
|
|
||||||
|
if (! $('#node-address').hasClass('d-none'))
|
||||||
|
$('#node-address').addClass('d-none');
|
||||||
|
|
||||||
|
$('#action').val('host');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'no':
|
||||||
|
default:
|
||||||
|
if (! $('#host-address').hasClass('d-none'))
|
||||||
|
$('#host-address').addClass('d-none');
|
||||||
|
|
||||||
|
if ($('#hub-select').hasClass('d-none'))
|
||||||
|
$('#hub-select').removeClass('d-none');
|
||||||
|
|
||||||
|
if ($('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').removeClass('d-none');
|
||||||
|
|
||||||
|
if ($('#node-address').hasClass('d-none'))
|
||||||
|
$('#node-address').removeClass('d-none');
|
||||||
|
|
||||||
|
$(this).parent().find('i').addClass('spinner-grow spinner-grow-sm');
|
||||||
|
$('#hub_id').prop('disabled',true);
|
||||||
|
$('#hub_id').children().remove();
|
||||||
|
|
||||||
|
$.get('{{ url('api/hubs') }}'+'/'+$('#zone_id').val()+'/'+((this.value === 'no') ? 0 : this.value),function(data) {
|
||||||
|
$('#hub_id').append('<option value="no">No Hub</option>');
|
||||||
|
|
||||||
|
data.forEach(function(item) {
|
||||||
|
$('#hub_id').append('<option value="'+item.id+'">'+item.id+':'+item.value+'</option>');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#hub_id').prop('disabled',false);
|
||||||
|
$('#hub_id').show();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#hub-select').removeClass('d-none');
|
||||||
|
$(this).parent().find('i').removeClass('spinner-grow spinner-grow-sm');
|
||||||
|
$('#action').val('node');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#hub_id').on('change',function() {
|
||||||
|
switch(this.value) {
|
||||||
|
case 'no':
|
||||||
|
if ($('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').removeClass('d-none');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (! $('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').addClass('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#point_id').on('change',function() {
|
||||||
|
switch(this.value) {
|
||||||
|
case '0':
|
||||||
|
if ($('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').removeClass('d-none');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (! $('#hub-checkbox').hasClass('d-none'))
|
||||||
|
$('#hub-checkbox').addClass('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@append
|
@ -7,7 +7,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h2>About FTN Zones</h2>
|
<h2>About FTN Zones</h2>
|
||||||
<p>In FTN network addresses, a zone is the 3rd dimension and used when a system supports 3D (or better) addressing, ie: <strong class="highlight">zone</strong>:hub/host.point@domain.</p>
|
<p>In FTN network addresses, a zone is the 3rd dimension and used when a system supports 3D (or better) addressing, ie: <strong class="highlight">zone</strong>:net/node.point@domain.</p>
|
||||||
<p>Zones are used with domains to uniquely identify a FTN network. Within an FTN network there can be multiple zones with the same domain.</p>
|
<p>Zones are used with domains to uniquely identify a FTN network. Within an FTN network there can be multiple zones with the same domain.</p>
|
||||||
<p>It is rare that a domain has multiple zones - unless it grows quite large. Zones can also be used to group systems into a common boundary.</p>
|
<p>It is rare that a domain has multiple zones - unless it grows quite large. Zones can also be used to group systems into a common boundary.</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use App\Http\Controllers\{DomainController};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@ -13,6 +14,8 @@ use Illuminate\Http\Request;
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#Route::middleware('auth:api')->get('/user', function (Request $request) {
|
Route::middleware(['auth:api'])->group(function () {
|
||||||
# return $request->user();
|
Route::get('regions/{o}',[DomainController::class,'api_regions']);
|
||||||
#});
|
Route::get('hosts/{o}/{region}',[DomainController::class,'api_hosts']);
|
||||||
|
Route::get('hubs/{o}/{host}',[DomainController::class,'api_hubs']);
|
||||||
|
});
|
||||||
|
@ -42,6 +42,8 @@ Route::middleware(['verified','activeuser'])->group(function () {
|
|||||||
Route::get('ftn/system',[SystemController::class,'home']);
|
Route::get('ftn/system',[SystemController::class,'home']);
|
||||||
Route::match(['get','post'],'ftn/system/addedit/{o?}',[SystemController::class,'add_edit'])
|
Route::match(['get','post'],'ftn/system/addedit/{o?}',[SystemController::class,'add_edit'])
|
||||||
->where('o','[0-9]+');
|
->where('o','[0-9]+');
|
||||||
|
Route::post('ftn/system/addaddress/{o?}',[SystemController::class,'add_address'])
|
||||||
|
->where('o','[0-9]+');
|
||||||
|
|
||||||
Route::get('ftn/zone',[ZoneController::class,'home']);
|
Route::get('ftn/zone',[ZoneController::class,'home']);
|
||||||
Route::match(['get','post'],'ftn/zone/addedit/{o?}',[ZoneController::class,'add_edit'])
|
Route::match(['get','post'],'ftn/zone/addedit/{o?}',[ZoneController::class,'add_edit'])
|
||||||
|
Loading…
Reference in New Issue
Block a user