Implemented echoarea/filearea security

This commit is contained in:
Deon George 2023-07-29 13:17:36 +10:00
parent f1ccca25ea
commit cd140971e2
22 changed files with 548 additions and 58 deletions

View File

@ -96,6 +96,7 @@ class DomainController extends Controller
->where('node_id',0)
->where('point_id',0)
->orderBy('region_id')
->active()
->with(['system'])
->get();

View File

@ -22,11 +22,16 @@ class EchoareaController extends Controller
'description' => 'required',
'active' => 'required|boolean',
'show' => 'required|boolean',
'sec_read' => 'required|integer|min:0|max:7',
'sec_write' => 'required|integer|min:0|max:7',
]);
foreach (['name','description','active','show','notes','domain_id'] as $key)
$o->{$key} = $request->post($key);
$o->setRead($request->post('sec_read'));
$o->setWrite($request->post('sec_write'));
$o->save();
return redirect()->action([self::class,'home']);

View File

@ -21,12 +21,17 @@ class FileareaController extends Controller
'description' => 'required',
'active' => 'required|boolean',
'show' => 'required|boolean',
'nodelist' => 'nullable|string|max:12'
'nodelist' => 'nullable|string|max:12',
'sec_read' => 'required|integer|min:0|max:7',
'sec_write' => 'required|integer|min:0|max:7',
]);
foreach (['name','description','active','show','notes','domain_id'] as $key)
$o->{$key} = $request->post($key);
$o->setRead($request->post('sec_read'));
$o->setWrite($request->post('sec_write'));
$o->save();
if ($request->post('nodelist')) {

View File

@ -35,7 +35,7 @@ class SystemController extends Controller
session()->flash('accordion','address');
$request->validate([
'action' => 'required|in:region,host,node',
'action' => 'required|in:region,host,node,update',
'zone_id' => 'required|exists:zones,id',
]);
@ -166,6 +166,7 @@ class SystemController extends Controller
$o->addresses()->save($oo);
break;
case 'update':
case 'node':
$request->validate([
'region_id' => ['required',new FidoInteger],
@ -181,7 +182,8 @@ class SystemController extends Controller
->where('zone_id',$request->post('zone_id'))
->where('host_id',$request->post('host_id'))
->where('node_id',$value)
->where('point_id',0);
->where('point_id',0)
->where('id','<>',$request->post('submit'));
});
if ($o->count()) {
@ -202,7 +204,8 @@ class SystemController extends Controller
->where('zone_id',$request->post('zone_id'))
->where('host_id',$request->post('host_id'))
->where('node_id',$request->post('node_id'))
->where('point_id',$value);
->where('point_id',$value)
->where('id','<>',$request->post('submit'));
});
if ($o->count()) {
@ -212,16 +215,19 @@ class SystemController extends Controller
],
'hub' => 'required|boolean',
'hub_id' => 'nullable|exists:addresses,id',
'security' => 'required|integer|min:0|max:7',
]);
$oo = new Address;
$oo = Address::findOrNew($request->post('submit'));
$oo->zone_id = $request->post('zone_id');
$oo->region_id = $request->post('region_id');
$oo->host_id = $request->post('host_id');
$oo->node_id = $request->post('node_id');
$oo->point_id = $request->post('point_id');
$oo->hub_id = $request->post('hub_id') > 0 ? $request->post('hub_id') : NULL;
$oo->role = ((! $oo->point_id) && $request->post('hub')) ? Address::NODE_HC : ($request->post('point_id') ? Address::NODE_POINT : Address::NODE_ACTIVE);
if (is_null($oo->role))
$oo->role = ((! $oo->point_id) && $request->post('hub')) ? Address::NODE_HC : ($request->post('point_id') ? Address::NODE_POINT : Address::NODE_ACTIVE);
$oo->security = $request->post('security');
$oo->active = TRUE;
$o->addresses()->save($oo);
@ -317,6 +323,11 @@ class SystemController extends Controller
->map(function($item) { return ['id'=>(string)$item->id,'value'=>$item->ftn4d]; });
}
public function api_address_get(Address $o)
{
return $o;
}
/**
* Systems with no owners
*/

View File

@ -13,7 +13,7 @@ use Illuminate\Support\Facades\Notification;
use App\Classes\FTN\Message;
use App\Models\{Address,Echoarea,Echomail,Netmail,Setup};
use App\Notifications\Netmails\Reject;
use App\Notifications\Netmails\{EchoareaNotExist,EchoareaNotSubscribed,EchoareaNoWrite,Reject};
class MessageProcess implements ShouldQueue
{
@ -195,6 +195,8 @@ class MessageProcess implements ShouldQueue
if (! $ea) {
Log::alert(sprintf('%s:! Echoarea [%s] doesnt exist for zone [%d]',self::LOGKEY,$this->msg->echoarea,$this->msg->fboss_o->zone->zone_id));
Notification::route('netmail',$this->msg->fftn_o)->notify(new EchoareaNotExist($this->msg));
return;
}
@ -251,9 +253,17 @@ class MessageProcess implements ShouldQueue
}
// @todo Can the sender create it if it doesnt exist?
// @todo Can the sender send messages to this area?
// - Create it, or
// - Else record in bad area
// Can the system send messages to this area?
if (! $ea->sec_write || ($this->msg->fftn_o->security < $ea->sec_write)) {
Notification::route('netmail',$this->msg->fftn_o)->notify(new EchoareaNoWrite($this->msg));
return;
}
// If the node is not subsccribed
if ($this->msg->fftn_o->echoareas->search(function($item) use ($ea) { return $item->id === $ea->id; }) === FALSE) {
Notification::route('netmail',$this->msg->fftn_o)->notify(new EchoareaNotSubscribed($this->msg));
}
// We know about this area, store it
$o = new Echomail;

View File

@ -47,6 +47,8 @@ class Address extends Model
});
}
protected $visible = ['zone_id','region_id','host_id','node_id','point_id','security'];
/* SCOPES */
public function scopeActiveFTN($query)
@ -308,7 +310,12 @@ class Address extends Model
*/
public function getActiveAttribute(bool $value): bool
{
return $value && $this->zone->active && $this->zone->domain->active;
return $value && $this->getActiveDomainAttribute();
}
public function getActiveDomainAttribute(): bool
{
return $this->zone->active && $this->zone->domain->active;
}
/**

View File

@ -8,11 +8,41 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Rennokki\QueryCache\Traits\QueryCacheable;
use App\Traits\ScopeActive;
use App\Traits\{AreaSecurity,ScopeActive};
/**
* Echomail echoareas
*
* Security thoughts:
* + ZCs/RCs/NCs/HUBs carry all echos
* + echos for HUBs only (not NODES/POINTs, thus Hub/NC/RC/ZC)
* + echos for NCs only (NC/RC/ZC)
* + echos for RCs only (RC/ZC)
* YYRRRWWW
*
* Thus YY:
* + 0 - not exported
* + 1 - Sent to RCs (RW)
* + 2 - Sent to NCs as well (RW)
* + 3 - Sent to Hubs as well (RW)
*
* Thus RRR: (Read)
* + 0-7
* = 0 no read access
* = 1-7 minimum access required to perform
* Thus WWW: (Write)
* + 0-7
* = 0 no write access
* = 1-7 minimum access required to perform
*
* - If a node has 0, or an echoarea has 0, then no access to the function
* - So if node has 1, and echoarea has 2, no access to function
*
* @note change "public" to "bot posts"?
*/
class Echoarea extends Model
{
use SoftDeletes,ScopeActive,QueryCacheable;
use SoftDeletes,ScopeActive,QueryCacheable,AreaSecurity;
private const CACHE_TIME = 3600;

View File

@ -96,18 +96,25 @@ final class Echomail extends Model implements Packet
}
// See if we need to export this message.
$exportto = $model->echoarea->addresses->pluck('id')->diff($model->set_seenby);
if ($model->echoarea->sec_read) {
$exportto = ($x=$model
->echoarea
->addresses
->filter(function($item) use ($model) { return $item->security >= $model->echoarea->sec_read; }))
->pluck('id')
->diff($model->set_seenby);
if ($exportto->count()) {
if ($model->no_export) {
Log::debug(sprintf('%s:- NOT processing exporting of message by configuration [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
return;
if ($exportto->count()) {
if ($model->no_export) {
Log::debug(sprintf('%s:- NOT processing exporting of message by configuration [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
return;
}
Log::debug(sprintf('%s:- Exporting message [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
// Save the seenby for the exported systems
$model->seenby()->syncWithPivotValues($exportto,['export_at'=>Carbon::now()],FALSE);
}
Log::debug(sprintf('%s:- Exporting message [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
// Save the seenby for the exported systems
$model->seenby()->syncWithPivotValues($exportto,['export_at'=>Carbon::now()],FALSE);
}
});
}

View File

@ -112,18 +112,25 @@ class File extends Model
}
// See if we need to export this message.
$exportto = $model->filearea->addresses->pluck('id')->diff($model->set_seenby);
if ($model->filearea->sec_read) {
$exportto = $model
->filearea
->addresses
->filter(function($item) use ($model) { return $item->security >= $model->echoarea->sec_read; })
->pluck('id')
->diff($model->set_seenby);
if ($exportto->count()) {
if ($model->no_export) {
Log::debug(sprintf('%s:- NOT processing exporting of message by configuration [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
return;
if ($exportto->count()) {
if ($model->no_export) {
Log::debug(sprintf('%s:- NOT processing exporting of message by configuration [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
return;
}
Log::debug(sprintf('%s:- Exporting file [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
// Save the seenby for the exported systems
$model->seenby()->syncWithPivotValues($exportto,['export_at'=>Carbon::now()],FALSE);
}
Log::debug(sprintf('%s:- Exporting file [%s] to [%s]',self::LOGKEY,$model->id,$exportto->join(',')));
// Save the seenby for the exported systems
$model->seenby()->syncWithPivotValues($exportto,['export_at'=>Carbon::now()],FALSE);
}
});
}

View File

@ -5,11 +5,11 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Traits\ScopeActive;
use App\Traits\{AreaSecurity,ScopeActive};
class Filearea extends Model
{
use SoftDeletes,ScopeActive;
use SoftDeletes,ScopeActive,AreaSecurity;
protected $fillable = [
'name',

View File

@ -0,0 +1,74 @@
<?php
namespace App\Notifications\Netmails;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\Message;
use App\Notifications\Netmails;
use App\Models\{Netmail,System};
use App\Traits\{MessagePath,PageTemplate};
class EchoareaNoWrite extends Netmails
{
use MessagePath,PageTemplate;
private const LOGKEY = 'NNW';
private Message $mo;
/**
* Send a sysop a message if they attempt to write to an area that they dont have permission.
*
* @param Message $mo
*/
public function __construct(Message $mo)
{
parent::__construct();
$this->mo = $mo;
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating ECHOMAIL NO WRITE netmail to [%s]',self::LOGKEY,$ao->ftn));
$o->subject = 'Echomail rejected - '.$this->mo->msgid;
// Message
$msg = $this->page(FALSE,'nowrite');
$msg->addText(
sprintf("Your echomail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
$this->mo->msgid,
$this->mo->user_to,
Carbon::now()->utc()->toDateTimeString(),
$this->mo->date->utc()->toDateTimeString(),
)
);
$msg->addText("It appears that you do not have permission to post in this echoarea, so the message from your system was rejected.\r\r");
$msg->addText("Please contact the ZC if you think this is a mistake.\r\r");
$msg->addText($this->message_path($this->mo));
$o->msg = $msg->render();
$o->tagline = 'See something wrong? Do something right.';
$o->save();
return $o;
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace App\Notifications\Netmails;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\Message;
use App\Notifications\Netmails;
use App\Models\{Netmail,System};
use App\Traits\{MessagePath,PageTemplate};
class EchoareaNotExist extends Netmails
{
use MessagePath,PageTemplate;
private const LOGKEY = 'NNW';
private Message $mo;
/**
* Send a sysop a message if they attempt to write to an area that doesnt exist.
*
* @param Message $mo
*/
public function __construct(Message $mo)
{
parent::__construct();
$this->mo = $mo;
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating ECHOMAIL NOT EXIST netmail to [%s]',self::LOGKEY,$ao->ftn));
$o->subject = 'Echoarea doesnt exist - '.$this->mo->echoarea;
// Message
$msg = $this->page(FALSE,'nothere');
$msg->addText(
sprintf("Your echomail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
$this->mo->msgid,
$this->mo->user_to,
Carbon::now()->utc()->toDateTimeString(),
$this->mo->date->utc()->toDateTimeString(),
)
);
$msg->addText("It appears that the echoarea that this message is for doesnt exist, so the message from your system was rejected.\r\r");
$msg->addText("Please contact the ZC if you think this is a mistake.\r\r");
$msg->addText($this->message_path($this->mo));
$o->msg = $msg->render();
$o->tagline = 'Don\'t let your trash become someone else\'s treasure. Feed your shredder often.';
$o->save();
return $o;
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace App\Notifications\Netmails;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use App\Classes\FTN\Message;
use App\Notifications\Netmails;
use App\Models\{Netmail,System};
use App\Traits\{MessagePath,PageTemplate};
class EchoareaNotSubscribed extends Netmails
{
use MessagePath,PageTemplate;
private const LOGKEY = 'NNW';
private Message $mo;
/**
* Send a sysop a message if they write to an area that they hadnt previously subscribed to.
*
* @param Message $mo
*/
public function __construct(Message $mo)
{
parent::__construct();
$this->mo = $mo;
}
/**
* Get the mail representation of the notification.
*
* @param System $so
* @param mixed $notifiable
* @return Netmail
* @throws \Exception
*/
public function toNetmail(System $so,object $notifiable): Netmail
{
$o = $this->setupNetmail($so,$notifiable);
$ao = $notifiable->routeNotificationFor(static::via);
Log::info(sprintf('%s:+ Creating ECHOMAIL NOT SUBSCRIBED netmail to [%s]',self::LOGKEY,$ao->ftn));
$o->subject = 'Echoarea not subscribed - '.$this->mo->echoarea;
// Message
$msg = $this->page(FALSE,'nothere');
$msg->addText(
sprintf("Your echomail with ID [%s] to [%s] here was received here on [%s] and it looks like you sent it on [%s].\r\r",
$this->mo->msgid,
$this->mo->user_to,
Carbon::now()->utc()->toDateTimeString(),
$this->mo->date->utc()->toDateTimeString(),
)
);
$msg->addText("It appears that you havent been previously subscribed to this echoarea.\r\r");
$msg->addText("Even though your post was accepted, I'm not configured to export any posts to you when others respond, you might like to log in to the web interface and do that.\r\r");
$msg->addText($this->message_path($this->mo));
$o->msg = $msg->render();
$o->tagline = 'Don\'t let your trash become someone else\'s treasure. Feed your shredder.';
$o->save();
return $o;
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Return the area security information
*/
namespace App\Traits;
trait AreaSecurity
{
public function getSecReadAttribute(): int
{
return ($this->security>>3) & 0x7;
}
public function getSecWriteAttribute(): int
{
return $this->security & 0x7;
}
public function setRead(int $security): void
{
$this->security = ($this->security & ~(0x7<<3)) | (($security & 0x7) << 3);
}
public function setWrite(int $security): void
{
$this->security = ($this->security & ~(0x7)) | ($security & 0x7);
}
}

View File

@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
DB::statement('ALTER TABLE echoareas RENAME COLUMN public TO show');
DB::statement('ALTER TABLE fileareas RENAME COLUMN public TO show');
Schema::table('echoareas',function (Blueprint $table) {
$table->smallInteger('security')->unsigned()->nullable();
});
Schema::table('fileareas',function (Blueprint $table) {
$table->smallInteger('security')->unsigned()->nullable();
});
Schema::table('addresses',function (Blueprint $table) {
$table->smallInteger('security')->unsigned()->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
DB::statement('ALTER TABLE echoareas RENAME COLUMN show TO public');
DB::statement('ALTER TABLE fileareas RENAME COLUMN show TO public');
Schema::table('echoareas',function (Blueprint $table) {
$table->dropColumn(['security']);
});
Schema::table('fileareas',function (Blueprint $table) {
$table->dropColumn(['security']);
});
Schema::table('addresses',function (Blueprint $table) {
$table->dropColumn(['security']);
});
}
};

View File

@ -91,6 +91,31 @@
</div>
</div>
<div class="col-2">
<label for="sec_read" class="form-label">Read <i class="bi bi-info-circle" title="Min security level required for read access"></i></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-eyeglasses"></i></span>
<input type="text" class="form-control text-end @error('sec_read') is-invalid @enderror" id="sec_read" placeholder="#" name="sec_read" value="{{ old('sec_read',$o->sec_read) }}" required @cannot('admin',$o)disabled @endcannot autofocus>
<span class="invalid-feedback" role="alert">
@error('sec_read')
{{ $message }}
@enderror
</span>
</div>
</div>
<div class="col-2">
<label for="sec_write" class="form-label">Write <i class="bi bi-info-circle" title="Min security level required for write access"></i></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-pencil"></i></span>
<input type="text" class="form-control text-end @error('sec_write') is-invalid @enderror" id="sec_write" placeholder="#" name="sec_write" value="{{ old('sec_write',$o->sec_write) }}" required @cannot('admin',$o)disabled @endcannot autofocus>
<span class="invalid-feedback" role="alert">
@error('sec_write')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
<div class="row">

View File

@ -31,6 +31,8 @@
<th>Description</th>
<th>Active</th>
<th>Domain</th>
<th>Read</th>
<th>Write</th>
</tr>
</thead>
@ -42,6 +44,8 @@
<td>{{ $oo->description }}</td>
<td>{{ $oo->active ? 'YES' : 'NO' }}</td>
<td>{{ $oo->domain->name }}</td>
<td>{{ $oo->sec_read }}</td>
<td>{{ $oo->sec_write }}</td>
</tr>
@endforeach
</tbody>

View File

@ -51,7 +51,7 @@
</div>
</div>
<div class="col-2">
<div class="offset-1 col-2" style="padding-left: 20px;">
<label for="active" class="form-label">Active</label>
<div class="input-group">
<div class="btn-group" role="group">
@ -79,7 +79,7 @@
</div>
<div class="row">
<div class="col-7">
<div class="col-5">
<label for="description" class="form-label">Description</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-file-text-fill"></i></span>
@ -92,7 +92,7 @@
</div>
</div>
<div class="col-5">
<div class="col-3">
<label for="nodelist" class="form-label">Nodelist File Name</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-file-earmark-break-fill"></i></span>
@ -104,6 +104,32 @@
</span>
</div>
</div>
<div class="col-2">
<label for="sec_read" class="form-label">Read <i class="bi bi-info-circle" title="Min security level required for read access"></i></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-eyeglasses"></i></span>
<input type="text" class="form-control text-end @error('sec_read') is-invalid @enderror" id="sec_read" placeholder="#" name="sec_read" value="{{ old('sec_read',$o->sec_read) }}" required @cannot('admin',$o)disabled @endcannot autofocus>
<span class="invalid-feedback" role="alert">
@error('sec_read')
{{ $message }}
@enderror
</span>
</div>
</div>
<div class="col-2">
<label for="sec_write" class="form-label">Write <i class="bi bi-info-circle" title="Min security level required for write access"></i></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-pencil"></i></span>
<input type="text" class="form-control text-end @error('sec_write') is-invalid @enderror" id="sec_write" placeholder="#" name="sec_write" value="{{ old('sec_write',$o->sec_write) }}" required @cannot('admin',$o)disabled @endcannot autofocus>
<span class="invalid-feedback" role="alert">
@error('sec_write')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
<div class="row">

View File

@ -31,6 +31,8 @@
<th>Description</th>
<th>Active</th>
<th>Domain</th>
<th>Read</th>
<th>Write</th>
</tr>
</thead>
@ -42,6 +44,8 @@
<td>{{ $oo->description }}</td>
<td>{{ $oo->active ? 'YES' : 'NO' }}</td>
<td>{{ $oo->domain->name }}</td>
<td>{{ $oo->sec_read }}</td>
<td>{{ $oo->sec_write }}</td>
</tr>
@endforeach
</tbody>

View File

@ -100,6 +100,7 @@
<tr>
<th>Address</th>
<th>Active</th>
<th>Security</th>
<th colspan="2">Role</th>
</tr>
</thead>
@ -109,29 +110,26 @@
<tr>
<td @if($oo->trashed()) class="trashed" @elseif (! $oo->active) class="inactive" @endif>{{ $oo->ftn }}</td>
<td>{{ $oo->active ? 'YES' : 'NO' }}</td>
<td class="text-end">{{ $oo->security }}</td>
<td>{{ $oo->role_name }}</td>
<td class="nowrap actions">
@can('admin',$oo)
{{--
@if (! $oo->role & (Address::NODE_ZC|Address::NODE_RC|Address::NODE_NC))
<a href="{{ url('ftn/system/modaddress',[$oo->id]) }}" title="Modify Address" class="modify"><i class="bi bi-pen-fill"></i></a>
@endif
--}}
@if($oo->trashed())
<a href="{{ url('ftn/system/recaddress',[$oo->id]) }}" title="Restore Address"><i class="bi bi-bandaid-fill"></i></a>
<a href="{{ url('ftn/system/puraddress',[$oo->id]) }}" title="Purge Address" class="purge"><i class="bi bi-scissors"></i></a>
@elseif(! $oo->active)
@if(! $oo->active_domain)
<!-- No options -->
<a href="javascript:;" title="Net Disabled"><i class="bi bi-slash-square"></i></a>
@elseif($oo->trashed())
<a href="{{ url('ftn/system/recaddress',[$oo->id]) }}" title="Restore Address"><i class="bi bi-bandaid"></i></a>
<a href="{{ url('ftn/system/puraddress',[$oo->id]) }}" title="Purge Address" class="purge"><i class="bi bi-scissors"></i></a>
@else
<a href="{{ url('ftn/system/susaddress',[$oo->id]) }}" title="@if($oo->active)Pause @else Activate @endif Address"><i class="bi @if($oo->active)bi-pause-circle-fill @else bi-play-circle-fill @endif"></i></a>
<a href="{{ url('ftn/system/movaddress',[$o->id,$oo->id]) }}" title="Move Address to another System"><i class="bi bi-arrow-right-square-fill"></i></a>
<a href="{{ url('ftn/system/deladdress',[$oo->id]) }}" title="Delete Address"><i class="bi bi-trash-fill"></i></a>
<a href="{{ url('ftn/system/modaddress',[$oo->id]) }}" data-id="{{ $oo->id }}" title="Modify Address" class="modaddress" aria-readonly="true"><i class="bi bi-pencil-square"></i></a>
<a href="{{ url('ftn/system/susaddress',[$oo->id]) }}" title="@if($oo->active)Pause @else Activate @endif Address"><i class="bi @if($oo->active)bi-pause-circle @else bi-play-circle @endif"></i></a>
<a href="{{ url('ftn/system/movaddress',[$o->id,$oo->id]) }}" title="Move Address to another System"><i class="bi bi-arrow-right-square"></i></a>
<a href="{{ url('ftn/system/deladdress',[$oo->id]) }}" title="Delete Address"><i class="bi bi-trash"></i></a>
@if ((\App\Models\Address::NODE_HC|\App\Models\Address::NODE_ACTIVE) & $oo->role)
<a href="{{ url('ftn/system/proaddress',[$oo->id]) }}" title="Promote Address"><i class="bi bi-arrow-up-square-fill"></i></a>
<a href="{{ url('ftn/system/proaddress',[$oo->id]) }}" title="Promote Address"><i class="bi bi-arrow-up-square"></i></a>
@endif
@if ((\App\Models\Address::NODE_NC|\App\Models\Address::NODE_HC) & $oo->role)
<a href="{{ url('ftn/system/demaddress',[$oo->id]) }}" title="Demote Address"><i class="bi bi-arrow-down-square-fill"></i></a>
<a href="{{ url('ftn/system/demaddress',[$oo->id]) }}" title="Demote Address"><i class="bi bi-arrow-down-square"></i></a>
@endif
@endif
@endcan

View File

@ -5,7 +5,7 @@
<div class="row pt-0">
<div class="col-12">
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">Assign New address</h2>
<h2 class="cap">Assign New/Update Existing Address</h2>
<div class="row">
<!-- Select Zone -->
@ -83,7 +83,7 @@
<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>
<input type="text" style="width: 35%;" class="form-control text-end @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 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">
@ -119,7 +119,7 @@
<label for="host_id_new" 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>
<input type="text" class="form-control text-end @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 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>
@ -151,6 +151,20 @@
</div>
</div>
</div>
<!-- Security -->
<div class="col-2 d-none" id="sec-level">
<label for="security" class="form-label">Security Level</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-file-lock"></i></span>
<input type="text" class="form-control text-end @error('security') is-invalid @enderror" id="security" placeholder="#" name="security" value="{{ old('security') }}" @cannot('admin',$o)disabled @endcannot>
<span class="invalid-feedback" role="alert">
@error('security')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
<div class="row">
@ -168,7 +182,7 @@
@can('admin',$o)
<div class="col-2">
<button type="submit" name="submit" class="btn btn-success float-end">Add</button>
<button type="submit" id="submit" name="submit" class="btn btn-success float-end">Add/Update</button>
</div>
@endcan
</div>
@ -180,6 +194,9 @@
@section('page-scripts')
<script type="text/javascript">
$(document).ready(function() {
var modify;
var id;
/*
// Disable enter for form submission.
$('input').on('keydown', function(event) {
@ -190,6 +207,21 @@
});
*/
$('.modaddress').on('click',function(event) {
id = $(this).attr('data-id');
event.stopPropagation();
modify = $.get('{{ url('address/get') }}'+'/'+id,function(data) {
console.log(data.security);
$('#zone_id').val(data.zone_id).change();
$('#node_id').val(data.node_id).change();
$('#point_id').val(data.point_id).change();
$('#security').val(data.security).change();
});
return false;
});
$('#zone_id').on('change',function() {
$(this).parent().find('i').addClass('spinner-grow spinner-grow-sm');
$('#region_id').prop('disabled',true);
@ -224,6 +256,9 @@
$('#region_id').prop('disabled',false);
$('#region_id').show();
if (modify.responseJSON.region_id)
$('#region_id').val(modify.responseJSON.region_id).change();
});
$('#region-select').removeClass('d-none');
@ -312,6 +347,9 @@
$('#host_id').prop('disabled',false);
$('#host_id').show();
if (modify.responseJSON.host_id)
$('#host_id').val(modify.responseJSON.host_id).change();
});
$('#host-select').removeClass('d-none');
@ -378,11 +416,22 @@
$('#hub_id').prop('disabled',false);
$('#hub_id').show();
if (modify.responseJSON.hub_id)
$('#host_id').val(modify.responseJSON.hub_id).change();
});
$('#hub-select').removeClass('d-none');
$('#sec-level').removeClass('d-none');
$(this).parent().find('i').removeClass('spinner-grow spinner-grow-sm');
$('#action').val('node');
if (modify.responseJSON) {
$('#submit').val(id);
$('#action').val('update');
} else {
$('#action').val('node');
}
}
});

View File

@ -51,6 +51,8 @@ Route::get('system/view/{o}',[SystemController::class,'view'])
Route::get('search',[HomeController::class,'search']);
Route::middleware(['auth','verified','activeuser'])->group(function () {
Route::get('address/get/{o}',[SystemController::class,'api_address_get'])
->where('o','[0-9]+');
Route::get('addresses/orphan',[SystemController::class,'api_orphan_address']);
Route::get('dashboard',[UserController::class,'dashboard']);
Route::post('default/{o}',[ZoneController::class,'api_default'])
@ -105,7 +107,8 @@ Route::middleware(['auth','verified','activeuser'])->group(function () {
->where('o','[0-9]+');
Route::get('hosts/{o}/{region}',[DomainController::class,'api_hosts'])
->where('o','[0-9]+');
->where('o','[0-9]+')
->where('region','[0-9]+');
Route::get('hubs/{o}/{host}',[DomainController::class,'api_hubs'])
->where('o','[0-9]+');
Route::match(['get','post'],'link',[UserController::class,'link']);