Compare commits

...

4 Commits

Author SHA1 Message Date
Deon George 6a41536d57 Enable user reseting password
Create Docker Image / Build Docker Image (x86_64) (push) Failing after 24s Details
Create Docker Image / Build Docker Image (arm64) (push) Failing after 54s Details
Create Docker Image / Final Docker Image Manifest (push) Has been skipped Details
2024-04-25 15:45:05 +10:00
Deon George 527cc1d4ab Added passkey for logins 2024-04-25 15:45:05 +10:00
Deon George d90f431925 Changed layout of system/addedit 2024-04-25 15:45:05 +10:00
Deon George ceffc7ff14 Removed unnessary controller functions that just call a view, HTML/CSS consistency updates 2024-04-25 15:44:52 +10:00
58 changed files with 1976 additions and 1586 deletions

View File

@ -2,13 +2,14 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
class LoginController extends Controller
{
/*
@ -38,7 +39,8 @@ class LoginController extends Controller
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->middleware('guest')
->except('logout');
}
public function login(Request $request)
@ -70,6 +72,7 @@ class LoginController extends Controller
if (file_exists('login_note.txt'))
$login_note = file_get_contents('login_note.txt');
return view('auth.login')->with('login_note',$login_note);
return view('auth.login')
->with('login_note',$login_note);
}
}

View File

@ -39,7 +39,7 @@ class HomeController extends Controller
})
->get();
return view('file')
return view('widgets.file')
->with('f',$f);
}
@ -73,20 +73,11 @@ class HomeController extends Controller
->with(['echoarea'])
->get();
return view('packet')
return view('widgets.packet')
->with('nm',$nm)
->with('em',$em);
}
/**
* Render a view that summarises the users permissions
*/
public function permissions()
{
return view('auth.permissions')
->with('user',Auth::user());
}
/**
* Show a packet dump
*

View File

@ -323,7 +323,7 @@ class SystemController extends Controller
// Make sure that no other system has this address active.
if ($o->role === Address::NODE_ACTIVE)
return redirect()->back()->withErrors(['demaddress'=>sprintf('%s cannot be demoted any more',$o->ftn3D)]);
return redirect()->back()->withErrors(['address'=>sprintf('%s cannot be demoted any more',$o->ftn3D)]);
$o->role = ($o->role << 1);
$o->save();
@ -494,7 +494,7 @@ class SystemController extends Controller
// Make sure that no other system has this address active.
if ($o->role === Address::NODE_NC)
return redirect()->back()->withErrors(['proaddress'=>sprintf('%s cannot be promoted any more',$o->ftn3D)]);
return redirect()->back()->withErrors(['address'=>sprintf('%s cannot be promoted any more',$o->ftn3D)]);
$o->role = ($o->role >> 1);
$o->save();
@ -564,7 +564,7 @@ class SystemController extends Controller
'active'=>TRUE,
])->single())) {
return redirect()->back()->withErrors(['susaddress'=>sprintf('%s is already active on system [<a href="%s">%s</a>]',$o->ftn,url('system/addedit',$x->system_id),$x->system->name)]);
return redirect()->back()->withErrors(['address'=>sprintf('%s is already active on system [<a href="%s">%s</a>]',$o->ftn,url('system/addedit',$x->system_id),$x->system->name)]);
}
$o->active = (! $o->active);

View File

@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use App\Http\Requests\UserRequest;
@ -23,13 +24,17 @@ class UserController extends Controller
if (! $o->exists)
$o->password = base64_encode(random_bytes(20));
elseif ($request->password)
$o->password = Hash::make($request->password);
$o->save();
if ($o->wasRecentlyCreated)
event(new Registered($o));
return redirect()->to('user');
return redirect()
->to('user/addedit/'.$o->id)
->with('success','User Updated');
}
return view('user.addedit')
@ -65,9 +70,4 @@ class UserController extends Controller
return view('user.link');
}
public function register()
{
return view('user/system/register');
}
}

View File

@ -14,7 +14,7 @@ class AddressMerge extends FormRequest
public function authorize()
{
return Gate::allows( 'admin');
return Gate::allows('admin');
}
public function rules(Request $request)

View File

@ -12,7 +12,7 @@ class AreafixRequest extends FormRequest
{
public function authorize()
{
return Gate::allows( 'admin');
return Gate::allows('admin');
}
public function rules(Request $request)

View File

@ -12,7 +12,7 @@ class DomainRequest extends FormRequest
{
public function authorize(Domain $o)
{
return Gate::allows( 'admin',$o);
return Gate::allows('admin',$o);
}
public function rules(Request $request)

View File

@ -10,7 +10,7 @@ class SetupRequest extends FormRequest
{
public function authorize()
{
return Gate::allows( 'admin');
return Gate::allows('admin');
}
public function rules(Request $request)

View File

@ -7,13 +7,11 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\Rule;
use App\Models\User;
class UserRequest extends FormRequest
{
public function authorize()
{
return Gate::allows( 'admin');
return Gate::any(['admin','update'],$this->route('o'));
}
public function rules(Request $request)

View File

@ -57,7 +57,8 @@ class User extends Authenticatable implements MustVerifyEmail
*/
protected $casts = [
'email_verified_at' => 'datetime',
'last_on' => 'datetime:Y-m-d H:i:s'
'last_on' => 'datetime:Y-m-d H:i:s',
'passkey' => 'json',
];
/* RELATIONS */

View File

@ -18,6 +18,7 @@
"laravel/sanctum": "^3.2",
"laravel/ui": "^4.0",
"league/flysystem-aws-s3-v3": "^3.0",
"leenooks/passkey": "^0.1.0",
"nunomaduro/laravel-console-summary": "^1.9",
"rennokki/laravel-eloquent-query-cache": "^3.3",
"repat/laravel-job-models": "^0.8",
@ -47,6 +48,10 @@
}
},
"repositories": {
"passkey": {
"type": "vcs",
"url": "https://gitea.dege.au/laravel/passkey.git"
},
"laravel-console-summary": {
"type": "vcs",
"url": "https://github.com/leenooks/laravel-console-summary"

88
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b9697fb5a34c3ed05cea0ce107b63d3f",
"content-hash": "0f0e0e75d37ebcbcbc03996fb1f3e18b",
"packages": [
{
"name": "aglipanci/laravel-eloquent-case",
@ -1700,6 +1700,51 @@
},
"time": "2023-05-09T19:47:28+00:00"
},
{
"name": "lbuchs/webauthn",
"version": "v2.1.1",
"source": {
"type": "git",
"url": "https://github.com/lbuchs/WebAuthn.git",
"reference": "e73ff007e8a1099e72e0dbdd9d0884057409fc54"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lbuchs/WebAuthn/zipball/e73ff007e8a1099e72e0dbdd9d0884057409fc54",
"reference": "e73ff007e8a1099e72e0dbdd9d0884057409fc54",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
},
"type": "library",
"autoload": {
"psr-4": {
"lbuchs\\WebAuthn\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Lukas Buchs",
"role": "Developer"
}
],
"description": "A simple PHP WebAuthn (FIDO2) server library",
"homepage": "https://github.com/lbuchs/webauthn",
"keywords": [
"Authentication",
"webauthn"
],
"support": {
"issues": "https://github.com/lbuchs/WebAuthn/issues",
"source": "https://github.com/lbuchs/WebAuthn/tree/v2.1.1"
},
"time": "2024-01-15T15:46:57+00:00"
},
{
"name": "league/commonmark",
"version": "2.4.1",
@ -2160,6 +2205,47 @@
],
"time": "2023-10-17T14:13:20+00:00"
},
{
"name": "leenooks/passkey",
"version": "0.1.0",
"source": {
"type": "git",
"url": "https://gitea.dege.au/laravel/passkey.git",
"reference": "4872d55ed65863e03102eea1046504e630f80ae2"
},
"require": {
"lbuchs/webauthn": "^2.1"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Leenooks\\Passkey\\PasskeyServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Leenooks\\Passkey\\": "src"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Deon George",
"email": "deon@dege.au"
}
],
"description": "Leenooks Laravel Passkey Implementation",
"keywords": [
"dege",
"laravel",
"passkey"
],
"time": "2024-04-25T05:05:51+00:00"
},
{
"name": "masterminds/html5",
"version": "2.8.1",

35
public/css/fixes.css vendored
View File

@ -98,4 +98,39 @@ ol {
padding: 0;
color: inherit;
background-color: inherit;
}
/* h1 headings reference */
h1>small.float-end {
padding-top: 2rem;
}
h1>small.float-end:before {
color: #acacac;
content: '[';
}
h1>small.float-end:after {
color: #acacac;
content: ']';
}
h1 sup {
text-shadow: none;
font-size: 50%;
top: -1em;
}
h1>small.success {
color: #005300 !important;
}
h1>small.success:before {
color: #00aa00;
content: '[';
}
h1>small.success:after {
color: #00aa00;
content: ']';
}
/* Ensure our greyframe titled boxes are full width */
.titledbox {
margin-right: 0;
margin-left: 0;
}

225
public/passkey/passkey.js vendored Normal file
View File

@ -0,0 +1,225 @@
/*
* Passkey Implementation
*/
let passkey_debug = false;
/**
* Convert a ArrayBuffer to Base64
* @param {ArrayBuffer} buffer
* @returns {String}
*/
function arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa(binary);
}
/**
* convert RFC 1342-like base64 strings to array buffer
* @param {mixed} obj
* @returns {undefined}
*/
function recursiveBase64StrToArrayBuffer(obj) {
let prefix = '=?BINARY?B?';
let suffix = '?=';
if (typeof obj === 'object') {
for (let key in obj) {
if (typeof obj[key] === 'string') {
let str = obj[key];
if (str.substring(0, prefix.length) === prefix && str.substring(str.length - suffix.length) === suffix) {
str = str.substring(prefix.length, str.length - suffix.length);
let binary_string = window.atob(str);
let len = binary_string.length;
let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
obj[key] = bytes.buffer;
}
} else {
recursiveBase64StrToArrayBuffer(obj[key]);
}
}
}
}
function passkey_check_browser()
{
// check browser support
if ((! window.fetch) || (! navigator.credentials) || (! navigator.credentials.create))
throw new Error('Browser not supported.');
/*
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.
// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.
// `isConditionalMediationAvailable` means the feature detection is usable.
if (window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&
PublicKeyCredential.isConditionalMediationAvailable) {
// Check if user verifying platform authenticator is available.
Promise.all([
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(),
PublicKeyCredential.isConditionalMediationAvailable(),
]).then(results => {
if (results.every(r => r === true)) {
// Display "Create a new passkey" button
}
});
}
*/
if (passkey_debug)
console.log('Passkey: Browser OK');
return true;
}
/**
* Register/Create a passkey for a user
*/
async function passkey_register(csrf_token,icon_dom,icon,icon_shell_success,icon_shell_fail)
{
try {
if (! passkey_check_browser())
return;
// Change our icon so that it is obvious we are doing something
icon_dom.find('i').removeClass(icon).addClass('spinner-grow spinner-grow-sm');
// Get our arguments
var createArgs;
$.ajax({
url: '/passkey/register',
type: 'GET',
dataType: 'json',
async: false,
cache: false,
success: function(data) {
if (passkey_debug)
console.log('Passkey: Get Register Success');
recursiveBase64StrToArrayBuffer(data);
createArgs = data;
},
error: function(e,status,error) {
throw new Error(status || 'Unknown error occurred');
}
});
// Create credentials
try {
const cred = await navigator.credentials.create(createArgs);
const authenticatorAttestationResponse = {
id: cred.id,
rawId: arrayBufferToBase64(cred.rawId),
transports: cred.response.getTransports ? cred.response.getTransports() : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
attestationObject: cred.response.attestationObject ? arrayBufferToBase64(cred.response.attestationObject) : null,
authenticatorAttachment: cred.authenticatorAttachment,
_token: csrf_token,
};
$.ajax({
url: '/passkey/check',
type: 'POST',
data: authenticatorAttestationResponse,
cache: false,
success: function(data) {
if (passkey_debug)
console.log('Passkey: Registration Success');
icon_dom.find('i').addClass(icon).removeClass('spinner-grow spinner-grow-sm');
icon_dom.removeClass('btn-outline-primary').addClass('btn-primary');
},
error: function(e,status,error) {
throw new Error(status || 'Unknown error occurred');
}
});
} catch (status) {
if (passkey_debug)
console.log(status || 'Passkey: User Aborted Register');
// Restore the icon
icon_dom.find('i').addClass(icon).removeClass('spinner-grow spinner-grow-sm');
return;
}
} catch (err) {
window.alert(err || 'An UNKNOWN error occurred?');
}
}
/**
* Check a passkey being presented
*/
async function passkey_check(csrf_token,redirect)
{
if (passkey_debug)
console.log('Passkey: Check User Passkey');
try {
if (! passkey_check_browser())
return;
// Get our arguments
var getArgs;
$.ajax({
url: '/passkey/get',
type: 'GET',
dataType: 'json',
async: false,
cache: false,
success: function(data) {
if (passkey_debug)
console.log('Passkey: Get Args Success');
recursiveBase64StrToArrayBuffer(data);
getArgs = data;
},
error: function(e,status,error) {
throw new Error(status || 'Unknown error occurred');
}
});
// check credentials with hardware
const cred = await navigator.credentials.get(getArgs);
// create object for transmission to server
const authenticatorAttestationResponse = {
id: cred.rawId ? arrayBufferToBase64(cred.rawId) : null,
clientDataJSON: cred.response.clientDataJSON ? arrayBufferToBase64(cred.response.clientDataJSON) : null,
authenticatorData: cred.response.authenticatorData ? arrayBufferToBase64(cred.response.authenticatorData) : null,
signature: cred.response.signature ? arrayBufferToBase64(cred.response.signature) : null,
userHandle: cred.response.userHandle ? arrayBufferToBase64(cred.response.userHandle) : null,
_token: csrf_token
};
$.ajax({
url: '/passkey/process',
type: 'POST',
data: authenticatorAttestationResponse,
cache: false,
success: function(data) {
if (passkey_debug)
console.log('Passkey: Process Success');
// Direct to the home page
window.location.href = (redirect !== undefined) ? redirect : '/';
},
error: function(e,status,error) {
throw new Error(status || 'Unknown error occurred');
}
});
} catch (err) {
window.alert(err || 'An UNKNOWN error occurred?');
}
}

View File

@ -5,7 +5,7 @@
@endsection
@section('content')
@if(isset($login_note) AND $login_note)
@if(isset($login_note) && $login_note)
<div class="row">
<div class="col-8 m-auto">
<div class="alert alert-info alert-dismissible" role="alert">
@ -20,20 +20,21 @@
</div>
@endisset
<div class="row">
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Login</h2>
<form class="needs-validation" method="post" novalidate>
@csrf
<form class="row g-0 needs-validation" method="post" novalidate>
@csrf
<div class="row">
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Login</h2>
<div class="row">
<div class="col-12">
<label for="email" class="form-label">Email</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-person-badge"></i></span>
<input type="text" class="form-control @error('email') is-invalid @enderror" id="email" placeholder="Email" name="email" required autocomplete="email" autofocus>
<!-- Conditionally display passkeys in autofill -->
<input type="text" class="form-control @error('email') is-invalid @enderror" id="email" placeholder="Email" name="email" required autocomplete="email webauthn" autofocus>
<span class="invalid-feedback" role="alert">
@error('email')
{{ $message }}
@ -50,7 +51,7 @@
<label for="password" class="form-label">Password</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-key-fill"></i></span>
<input type="password" class="form-control" id="password" placeholder="Password" name="password" required>
<input type="password" class="form-control" id="password" placeholder="Password" name="password" autocomplete="new-password" required>
<span class="invalid-feedback" role="alert">
Your password is required.
</span>
@ -70,20 +71,29 @@
<button type="submit" name="submit" class="btn btn-success float-end">Sign In</button>
</div>
</div>
</form>
<div class="row">
<div class="col-12">
<a class="link-danger" href="{{ url('password/reset') }}">Forgot Password</a>
<div class="row">
<div class="col-12">
<a class="link-danger" href="{{ url('password/reset') }}">Forgot Password</a>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<a class="link-danger" href="{{ url('register') }}">Register</a>
<div class="row">
<div class="col-12">
<a class="link-danger" href="{{ url('register') }}">Register</a>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
</form>
@endsection
@section('page-scripts')
<!-- Passkeys -->
<script type='text/javascript' src='{{ asset('/passkey/passkey.js') }}'></script>
<script type="text/javascript">
passkey_check('{{ csrf_token() }}','{{ back()->getTargetUrl() }}');
</script>
@append

View File

@ -5,23 +5,15 @@
@endsection
@section('content')
@if (Session('status'))
@includeWhen(session()->has('success'),'widgets.success-row',['msg'=>session()->get('success')])
<form class="needs-validation" method="post" action="{{ route('password.email') }}" novalidate>
@csrf
<div class="row">
<div class="col-8 m-auto">
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
</div>
</div>
@endif
<div class="row">
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Forgot Password</h2>
<form class="row g-0 needs-validation" method="post" action="{{ route('password.email') }}" novalidate>
@csrf
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Forgot Password</h2>
<div class="row">
<div class="col-12">
@ -52,8 +44,8 @@
<a class="link-danger" href="{{ url('login') }}">Login</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</form>
@endsection

View File

@ -5,23 +5,16 @@
@endsection
@section('content')
@if (Session('status'))
@includeWhen(session()->has('status') || true,'widgets.success-row',['msg'=>session()->get('status')])
<form class="needs-validation" method="post" action="{{ route('password.update') }}" novalidate>
@csrf
<div class="row">
<div class="col-8 m-auto">
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
</div>
</div>
@endif
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Reset Password</h2>
<div class="row">
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Reset Password</h2>
<form class="row g-0 needs-validation" method="post" action="{{ route('password.update') }}" novalidate>
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<div class="row">
@ -77,8 +70,8 @@
<button type="submit" name="submit" class="btn btn-success float-end">Sign In</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
@endsection

View File

@ -4,91 +4,95 @@
@endsection
@section('content')
<h2>{{ auth()->check() ? auth()->user()->name : 'Guest' }}</h2>
<div class="row">
<div class="col-12">
<h2>{{ auth()->check() ? auth()->user()->name : 'Guest' }}</h2>
<table class="table monotable">
<thead>
<tr>
<th>Test</th>
<th>Result</th>
</tr>
</thead>
<table class="table monotable">
<thead>
<tr>
<th>Test</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>isAdmin</td>
<td>@can('admin')YES @else NO @endcan</td>
</tr>
<tr>
<td>Domains</td>
<td>
<table class="table table-sm" id="domains">
<thead>
<tr>
<th class="w-75">Domain</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>isAdmin</td>
<td>@can('admin')YES @else NO @endcan</td>
</tr>
<tr>
<td>Domains</td>
<td>
<table class="table table-sm" id="domains">
<thead>
<tr>
<th class="w-75">Domain</th>
<th>Result</th>
</tr>
</thead>
<tbody>
@foreach (\App\Models\Domain::orderBy('name')->get() as $o)
<tr>
<td>{{ $o->name }}</td>
<td>@can('admin',$o)YES @else NO @endcan</td>
</tr>
@endforeach
</tbody>
</table>
</td>
</tr>
<tbody>
@foreach (\App\Models\Domain::orderBy('name')->get() as $o)
<tr>
<td>{{ $o->name }}</td>
<td>@can('admin',$o)YES @else NO @endcan</td>
</tr>
@endforeach
</tbody>
</table>
</td>
</tr>
<tr>
<td>System</td>
<td>
<table class="table table-sm" id="systems">
<thead>
<tr>
<th class="w-75">System</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td>System</td>
<td>
<table class="table table-sm" id="systems">
<thead>
<tr>
<th class="w-75">System</th>
<th>Result</th>
</tr>
</thead>
<tbody>
@foreach (\App\Models\System::orderBy('name')->with(['users'])->get() as $o)
<tr>
<td>{{ $o->name }}</td>
<td>@can('update',$o)YES @else NO @endcan</td>
</tr>
@endforeach
</tbody>
</table>
</td>
</tr>
<tbody>
@foreach (\App\Models\System::orderBy('name')->with(['users'])->get() as $o)
<tr>
<td>{{ $o->name }}</td>
<td>@can('update',$o)YES @else NO @endcan</td>
</tr>
@endforeach
</tbody>
</table>
</td>
</tr>
<tr>
<td>Zone</td>
<td>
<table class="table table-sm" id="zones">
<thead>
<tr>
<th class="w-75">Zone</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td>Zone</td>
<td>
<table class="table table-sm" id="zones">
<thead>
<tr>
<th class="w-75">Zone</th>
<th>Result</th>
</tr>
</thead>
<tbody>
@foreach (\App\Models\Zone::orderBy('zone_id')->get() as $o)
<tr>
<td>{{ $o->zone_id }}</td>
<td>@can('admin',$o)YES @else NO @endcan</td>
</tr>
@endforeach
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<tbody>
@foreach (\App\Models\Zone::orderBy('zone_id')->get() as $o)
<tr>
<td>{{ $o->zone_id }}</td>
<td>@can('admin',$o)YES @else NO @endcan</td>
</tr>
@endforeach
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
@endsection
@section('page-css')

View File

@ -5,13 +5,13 @@
@endsection
@section('content')
<div class="row">
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Register</h2>
<form class="needs-validation" method="post" novalidate>
@csrf
<form class="row g-0 needs-validation" method="post" novalidate>
@csrf
<div class="row">
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Register</h2>
<div class="row">
<div class="col-12">
@ -82,14 +82,14 @@
<button type="submit" name="submit" class="btn btn-success float-end">Sign In</button>
</div>
</div>
</form>
<div class="row">
<div class="col-12">
<a class="link-danger" href="{{ url('login') }}">Login</a>
<div class="row">
<div class="col-12">
<a class="link-danger" href="{{ url('login') }}">Login</a>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
@endsection

View File

@ -5,23 +5,13 @@
@endsection
@section('content')
@if (Session('resent'))
<form class="needs-validation" method="post" action="{{ route('verification.resend') }}" novalidate>
@csrf
<div class="row">
<div class="col-8 m-auto">
<div class="alert alert-success alert-dismissible" role="alert">
{{ __('A fresh verification link has been sent to your email address.') }}
</div>
</div>
</div>
@endif
<div class="row">
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Verify</h2>
<form class="row" method="post" action="{{ route('verification.resend') }}" novalidate>
@csrf
<div class="col-6 m-auto">
<div class="greyframe titledbox shadow0xb0 text-center">
<h2 class="cap">Verify</h2>
<div class="row">
<div class="col-12">
@ -30,8 +20,8 @@
<button type="submit" class="btn btn-link p-0" style="text-decoration: none;line-height: 1.0;">{{ __('click here to request another') }}</button>.
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</form>
@endsection

View File

@ -5,7 +5,7 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" novalidate>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row">

View File

@ -4,14 +4,12 @@
@endsection
@section('content')
<div class="row pt-0">
<div class="row">
<div class="col-12">
<h2>List of known FTN Networks</h2>
<p>Here is a list of known <strong class="highlight">FTN Networks</strong>.</p>
</div>
<div class="col-12 pt-2">
<table class="table monotable" id="ftnlist">
<thead>
<tr>

View File

@ -5,170 +5,174 @@
@endsection
@section('content')
<h1>{{ $o->name }} <small class="float-end pt-4">Last Update: {{ $o->updated_at->format('Y-m-d H:i') }}</small></h1>
<div class="row">
<div class="col-12">
<h1>{{ $o->name }} <small class="float-end">Last Update: {{ $o->updated_at->format('Y-m-d H:i') }}</small></h1>
<div class="accordion" id="accordion_homepage">
<!-- About -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button" id="about" data-bs-toggle="collapse" data-bs-target="#collapse_about" aria-expanded="true" aria-controls="collapse_about">About</span>
</h3>
<div class="accordion" id="accordion_homepage">
<!-- About -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button" id="about" data-bs-toggle="collapse" data-bs-target="#collapse_about" aria-expanded="true" aria-controls="collapse_about">About</span>
</h3>
<div id="collapse_about" class="accordion-collapse collapse show" aria-labelledby="about" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
<div class="float-end" style="max-height: 25em;" id="network_traffic"></div>
{!! \Illuminate\Mail\Markdown::parse($o->homepage) !!}
<div id="collapse_about" class="accordion-collapse collapse show" aria-labelledby="about" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
<div class="float-end" style="max-height: 25em;" id="network_traffic"></div>
{!! \Illuminate\Mail\Markdown::parse($o->homepage) !!}
</div>
</div>
</div>
</div>
</div>
<!-- Echomail -->
<div class="accordion-item open">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="echoareas" data-bs-toggle="collapse" data-bs-target="#collapse_echoareas" aria-expanded="false" aria-controls="collapse_echoareas">Echo Areas</span>
</h3>
<!-- Echomail -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="echoareas" data-bs-toggle="collapse" data-bs-target="#collapse_echoareas" aria-expanded="false" aria-controls="collapse_echoareas">Echo Areas</span>
</h3>
<div id="collapse_echoareas" class="accordion-collapse collapse" aria-labelledby="echoareas" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
@if($o->echoareas->count())
<p>This network provides the following Echomail areas:</p>
<table class="table monotable w-100" id="echoarea">
<thead>
<tr>
<th class="w-75" colspan="4"></th>
<th colspan="4" class="text-center">Messages</th>
</tr>
<tr>
<th>Echoarea</th>
<th>Description</th>
<th>Last Message</th>
<th>Area Active</th>
<th class="text-end">Day</th>
<th class="text-end">Week</th>
<th class="text-end">Month</th>
<th class="text-end">Total</th>
</tr>
</thead>
<div id="collapse_echoareas" class="accordion-collapse collapse" aria-labelledby="echoareas" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
@if($o->echoareas->count())
<p>This network provides the following Echomail areas:</p>
<table class="table monotable w-100" id="echoarea">
<thead>
<tr>
<th class="w-75" colspan="4"></th>
<th colspan="4" class="text-center">Messages</th>
</tr>
<tr>
<th>Echoarea</th>
<th>Description</th>
<th>Last Message</th>
<th>Area Active</th>
<th class="text-end">Day</th>
<th class="text-end">Week</th>
<th class="text-end">Month</th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody>
@foreach ($o->echoarea_stats()->groupBy('id') as $oo)
<tbody>
@foreach ($o->echoarea_stats()->groupBy('id') as $oo)
<tr>
<td style="width: 15%;"><a href="{{ url('echoarea/addedit',[($x=$oo->first())->id]) }}">{{ $x->name }}</a></td>
<td>{{ $x->description }}</td>
<td style="width: 15%;">{{ $x->last_message ? $x->last_message->format('Y-m-d H:i') : '-' }}</td>
<td>{{ $x->active ? 'Active' : 'Archive' }}</td>
<td class="text-end">{{ number_format($oo->where('stats','day')->pop()?->count) }}</td>
<td class="text-end">{{ number_format($oo->where('stats','week')->pop()?->count) }}</td>
<td class="text-end">{{ number_format($oo->where('stats','month')->pop()?->count) }}</td>
<td class="text-end">{{ number_format($oo->sum('count')) }}</td>
</tr>
@endforeach
</tbody>
</table>
@else
This network doesnt have any Echomail areas (yet). Perhaps you would like to create one?
@endif
</div>
</div>
</div>
<!-- File areas -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="fileareas" data-bs-toggle="collapse" data-bs-target="#collapse_fileareas" aria-expanded="false" aria-controls="collapse_fileareas">File Areas</span>
</h3>
<div id="collapse_fileareas" class="accordion-collapse collapse" aria-labelledby="fileareas" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
@if($o->fileareas->count())
<p>This network provides the following File areas:</p>
<table class="table monotable" id="filearea">
<thead>
<tr>
<th>Filearea</th>
<th>Description</th>
<th>Last File Sent</th>
</tr>
</thead>
<tbody>
@foreach ($o->fileareas->sortBy('name') as $oo)
<tr>
<td style="width: 15%;"><a href="{{ url('filearea/addedit',[$oo->id]) }}">{{ $oo->name }}</a></td>
<td>{{ $oo->description }}</td>
<td style="width: 15%;">-</td>
</tr>
@endforeach
</tbody>
</table>
@else
This network doesnt have any File areas (yet). Perhaps you would like to create one?
@endif
</div>
</div>
</div>
<!-- Systems -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="systems" data-bs-toggle="collapse" data-bs-target="#collapse_systems" aria-expanded="false" aria-controls="collapse_systems">Systems</span>
</h3>
<div id="collapse_systems" class="accordion-collapse collapse" aria-labelledby="systems" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
<p>The following systems are members of this network.</p>
<table class="table monotable" id="system">
<thead>
<tr>
<td style="width: 15%;"><a href="{{ url('echoarea/addedit',[($x=$oo->first())->id]) }}">{{ $x->name }}</a></td>
<td>{{ $x->description }}</td>
<td style="width: 15%;">{{ $x->last_message ? $x->last_message->format('Y-m-d H:i') : '-' }}</td>
<td>{{ $x->active ? 'Active' : 'Archive' }}</td>
<td class="text-end">{{ number_format($oo->where('stats','day')->pop()?->count) }}</td>
<td class="text-end">{{ number_format($oo->where('stats','week')->pop()?->count) }}</td>
<td class="text-end">{{ number_format($oo->where('stats','month')->pop()?->count) }}</td>
<td class="text-end">{{ number_format($oo->sum('count')) }}</td>
<th>System</th>
<th>Sysop</th>
<th>Location</th>
<th>Address</th>
<th>Last Seen</th>
</tr>
@endforeach
</tbody>
</table>
@else
This network doesnt have any Echomail areas (yet). Perhaps you would like to create one?
@endif
</thead>
<tbody>
@foreach ($o->zones->sortBy('zone_id') as $oz)
@foreach ($oz->addresses as $ao)
<tr>
<td><a href="{{ url('system/addedit',[$ao->system_id]) }}">{{ $ao->system->full_name($ao) }}</a> @auth<span class="float-end"><small>@if($ao->session('sespass'))<sup>{{ $ao->session('default') ? '**' : '*' }}</sup>@elseif($ao->system->setup)<sup class="success">+</sup>@endif[{{ $ao->system_id }}]</small></span>@endauth</td>
<td>{{ $ao->system->sysop }}</td>
<td>{{ $ao->system->location }}</td>
<td>{{ $ao->ftn4d }}</td>
<td>{{ $ao->system->last_session ? $ao->system->last_session->format('Y-m-d H:i') : '-' }}</td>
</tr>
@endforeach
@endforeach
</tbody>
@auth
<tfoot>
<tr>
<td colspan="5"><sup>**</sup>Default route <sup>*</sup>System defined here <sup class="success">+</sup>This system</td>
</tr>
</tfoot>
@endauth
</table>
</div>
</div>
</div>
</div>
</div>
<!-- File areas -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="fileareas" data-bs-toggle="collapse" data-bs-target="#collapse_fileareas" aria-expanded="false" aria-controls="collapse_fileareas">File Areas</span>
</h3>
<!-- Sign up -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="signup" data-bs-toggle="collapse" data-bs-target="#collapse_signup" aria-expanded="false" aria-controls="collapse_signup">Join Network</span>
</h3>
<div id="collapse_fileareas" class="accordion-collapse collapse" aria-labelledby="fileareas" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
@if($o->fileareas->count())
<p>This network provides the following File areas:</p>
<table class="table monotable" id="filearea">
<thead>
<tr>
<th>Filearea</th>
<th>Description</th>
<th>Last File Sent</th>
</tr>
</thead>
<tbody>
@foreach ($o->fileareas->sortBy('name') as $oo)
<tr>
<td style="width: 15%;"><a href="{{ url('filearea/addedit',[$oo->id]) }}">{{ $oo->name }}</a></td>
<td>{{ $oo->description }}</td>
<td style="width: 15%;">-</td>
</tr>
@endforeach
</tbody>
</table>
@else
This network doesnt have any File areas (yet). Perhaps you would like to create one?
@endif
</div>
</div>
</div>
<!-- Systems -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="systems" data-bs-toggle="collapse" data-bs-target="#collapse_systems" aria-expanded="false" aria-controls="collapse_systems">Systems</span>
</h3>
<div id="collapse_systems" class="accordion-collapse collapse" aria-labelledby="systems" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
<p>The following systems are members of this network.</p>
<table class="table monotable" id="system">
<thead>
<tr>
<th>System</th>
<th>Sysop</th>
<th>Location</th>
<th>Address</th>
<th>Last Seen</th>
</tr>
</thead>
<tbody>
@foreach ($o->zones->sortBy('zone_id') as $oz)
@foreach ($oz->addresses as $ao)
<tr>
<td><a href="{{ url('system/addedit',[$ao->system_id]) }}">{{ $ao->system->full_name($ao) }}</a> @auth<span class="float-end"><small>@if($ao->session('sespass'))<sup>{{ $ao->session('default') ? '**' : '*' }}</sup>@elseif($ao->system->setup)<sup class="success">+</sup>@endif[{{ $ao->system_id }}]</small></span>@endauth</td>
<td>{{ $ao->system->sysop }}</td>
<td>{{ $ao->system->location }}</td>
<td>{{ $ao->ftn4d }}</td>
<td>{{ $ao->system->last_session ? $ao->system->last_session->format('Y-m-d H:i') : '-' }}</td>
</tr>
@endforeach
@endforeach
</tbody>
@auth
<tfoot>
<tr>
<td colspan="5"><sup>**</sup>Default route <sup>*</sup>System defined here <sup class="success">+</sup>This system</td>
</tr>
</tfoot>
@endauth
</table>
</div>
</div>
</div>
<!-- Sign up -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="signup" data-bs-toggle="collapse" data-bs-target="#collapse_signup" aria-expanded="false" aria-controls="collapse_signup">Join Network</span>
</h3>
<div id="collapse_signup" class="accordion-collapse collapse" aria-labelledby="signup" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
@guest
To start an application to join this network please <a href="{{ url('login') }}">login</a>.
@else
@if($user->isMember($o))
@else
This website is not ready to take applications yet, check back soon!
@endif
@endguest
<div id="collapse_signup" class="accordion-collapse collapse" aria-labelledby="signup" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
@guest
To start an application to join this network please <a href="{{ url('login') }}">login</a>.
@else
@if($user->isMember($o))
@else
This website is not ready to take applications yet, check back soon!
@endif
@endguest
</div>
</div>
</div>
</div>
</div>

View File

@ -5,7 +5,7 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" novalidate>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row">

View File

@ -4,9 +4,9 @@
@endsection
@section('content')
<div class="row pt-3">
<div class="row">
<div class="col-12">
<h3>Echomail</h3>
<h1>Echomail [{{ $o->msgid ?: '-' }}] <small class="float-end">#{{ $o->id }}</small></h1>
@include('widgets.message',['msg'=>$o])
</div>

View File

@ -6,7 +6,7 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" novalidate>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row">

View File

@ -1,6 +1,6 @@
<!-- Bootstrap & Jquery App -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https:///cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous"></script>
<!-- JavaScript Bundle with Popper -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

View File

@ -43,7 +43,7 @@
<dl>
<dt>Users</dt>
<dd><a href="{{ url('user/addedit') }}">Create</a></dd>
<dd><a href="{{ url('user') }}">List</a></dd>
<dd><a href="{{ url('user/list') }}">List</a></dd>
</dl>
@endcan
@endauth

View File

@ -32,6 +32,7 @@
</a>
<div class="collapse navbar-collapse" id="user-menu-list">
<ul class="dropdown-menu dropdown-menu-dark">
<li><a class="dropdown-item" href="{{ url('user/addedit',$user->id) }}">Account Settings</a></li>
<li><a class="dropdown-item" href="{{ url('user/system/register') }}">Register/Link System</a></li>
@can('admin')
<li><a class="dropdown-item @if(preg_match('#^setup#',request()->path()))thispage @endif" href="{{ url('setup') }}">Setup</a></li>

View File

@ -4,9 +4,9 @@
@endsection
@section('content')
<div class="row pt-3">
<div class="row">
<div class="col-12">
<h3>Netmail</h3>
<h1>Netmail [{{ $o->msgid ?: '-' }}] <small class="float-end">#{{ $o->id }}</small></h1>
@include('widgets.message',['msg'=>$o])
</div>

View File

@ -4,7 +4,7 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" enctype="multipart/form-data" novalidate>
<form class="needs-validation" method="post" enctype="multipart/form-data" novalidate>
@csrf
<div class="row">

View File

@ -10,19 +10,15 @@ use App\Classes\Protocol\{Binkp,EMSI,DNS};
@endsection
@section('content')
<div class="row">
<div class="col-12">
<h2>Site Setup</h2>
</div>
</div>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row pt-0">
<div class="col-12">
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">@if($o->exists) Update @else Initial @endif Setup</h2>
<div class="row">
<div class="col-12">
<h2>Site Setup</h2>
<form class="row g-0 needs-validation" method="post" novalidate>
@csrf
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">@if($o->exists) Update @else Initial @endif Setup</h2>
<div class="row">
<!-- System -->
@ -275,7 +271,7 @@ use App\Classes\Protocol\{Binkp,EMSI,DNS};
<div class="row pt-5">
<div class="col-2">
<a href="{{ url('domain') }}" class="btn btn-danger">Cancel</a>
<a href="{{ back()->getTargetUrl() }}" class="btn btn-danger">Cancel</a>
</div>
<span class="col-6 mt-auto mx-auto text-center align-bottom">
@ -298,10 +294,10 @@ use App\Classes\Protocol\{Binkp,EMSI,DNS};
</div>
@endcan
</div>
</form>
</div>
</div>
</div>
</div>
</form>
@endsection
@section('page-css')

View File

@ -7,193 +7,193 @@
<div class="row">
<div class="col-12">
<h2>System Status</h2>
</div>
</div>
<div class="accordion" id="accordion_status">
<!-- Totals -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button" id="totals" data-bs-toggle="collapse" data-bs-target="#collapse_totals" aria-expanded="false" aria-controls="collapse_totals">Totals</span>
</h3>
<div class="accordion" id="accordion_status">
<!-- Totals -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button" id="totals" data-bs-toggle="collapse" data-bs-target="#collapse_totals" aria-expanded="false" aria-controls="collapse_totals">Totals</span>
</h3>
<div id="collapse_totals" class="accordion-collapse collapse {{ (! $flash=session()->pull('accordion')) ? 'show' : '' }}" aria-labelledby="totals" data-bs-parent="#accordion_status">
<div class="accordion-body">
<p>This system has processed the following so far in the last 7 days:</p>
<div id="collapse_totals" class="accordion-collapse collapse {{ (! $flash=session()->pull('accordion')) ? 'show' : '' }}" aria-labelledby="totals" data-bs-parent="#accordion_status">
<div class="accordion-body">
<p>This system has processed the following so far in the last 7 days:</p>
<div class="row">
<!-- Netmail -->
<div class="col-3">
<div class="card bg-success">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-envelope-at"></i> Netmail
<button type="button" class="btn float-end me-0" style="background-color: darkgreen; color: white;">{{ number_format(($x=\App\Models\Netmail::where('netmails.created_at','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())
->join('addresses',['addresses.id'=>'netmails.fftn_id'])
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->orderBy('domains.name')
->with('fftn.zone.domain')
->get())
->count()) }}
</button>
</span>
</div>
@if($x->count())
<div class="card-body text-dark">
<p class="card-text">Networks:</p>
<ul class="p-0 m-0">
@foreach($x->groupBy('fftn.zone_id') as $oo)
<li class="m-0">{{ $oo->first()->fftn->zone->domain->name }}: {{ number_format($oo->count()) }}</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
<!-- Echomail -->
<div class="col-3">
<div class="card bg-primary">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-envelope"></i> Echomail
<button type="button" class="btn float-end me-0" style="background-color: darkblue; color: white;">{{ number_format(($x=\App\Models\Echomail::where('echomails.created_at','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())
->join('addresses',['addresses.id'=>'echomails.fftn_id'])
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->orderBy('domains.name')
->orderBy('zones.zone_id')
->with('fftn.zone.domain')
->get())
->count()) }}
</button>
</span>
</div>
@if($x->count())
<div class="card-body text-dark">
<p class="card-text">Networks:</p>
<ul class="p-0 m-0">
@foreach($x->groupBy('fftn.zone_id') as $oo)
<li class="m-0">{{ sprintf('Z%d (%s)',$oo->first()->fftn->zone->zone_id,$oo->first()->fftn->zone->domain->name) }}: {{ number_format($oo->count()) }}</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
<!-- File -->
<div class="col-3">
<div class="card bg-danger">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-folder"></i> Files
<button type="button" class="btn float-end me-0" style="background-color: darkred; color: white;">{{ number_format(($x=\App\Models\File::where('files.created_at','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())
->join('addresses',['addresses.id'=>'files.fftn_id'])
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->orderBy('domains.name')
->with('fftn.zone.domain')
->get())
->count()) }}
</button>
</span>
</div>
@if($x->count())
<div class="card-body text-dark">
<p class="card-text">Networks:</p>
<ul class="p-0 m-0">
@foreach($x->groupBy('fftn.zone_id') as $oo)
<li class="m-0">{{ sprintf('Z%d (%s)',$oo->first()->fftn->zone->zone_id,$oo->first()->fftn->zone->domain->name) }}: {{ number_format($oo->count()) }}</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
<!-- DNS -->
<div class="col-3">
<div class="row">
<div class="col-12">
<div class="card bg-light">
<!-- Netmail -->
<div class="col-3">
<div class="card bg-success">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-pc-display"></i> Systems
<button type="button" class="btn float-end me-0" style="background-color: black; color: white;">
{{ number_format(\App\Models\System::where('last_session','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())->count()) }}
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-envelope-at"></i> Netmail
<button type="button" class="btn float-end me-0" style="background-color: darkgreen; color: white;">{{ number_format(($x=\App\Models\Netmail::where('netmails.created_at','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())
->join('addresses',['addresses.id'=>'netmails.fftn_id'])
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->orderBy('domains.name')
->with('fftn.zone.domain')
->get())
->count()) }}
</button>
</span>
</div>
@if($x->count())
<div class="card-body text-dark">
<p class="card-text">Networks:</p>
<ul class="p-0 m-0">
@foreach($x->groupBy('fftn.zone_id') as $oo)
<li class="m-0">{{ $oo->first()->fftn->zone->domain->name }}: {{ number_format($oo->count()) }}</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
</div>
<div class="row pt-3">
<div class="col-12">
<div class="card bg-secondary">
<!-- Echomail -->
<div class="col-3">
<div class="card bg-primary">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-globe"></i> DNS Queries
<button type="button" class="btn float-end me-0" style="background-color: black; color: white;">N/A</button>
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-envelope"></i> Echomail
<button type="button" class="btn float-end me-0" style="background-color: darkblue; color: white;">{{ number_format(($x=\App\Models\Echomail::where('echomails.created_at','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())
->join('addresses',['addresses.id'=>'echomails.fftn_id'])
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->orderBy('domains.name')
->orderBy('zones.zone_id')
->with('fftn.zone.domain')
->get())
->count()) }}
</button>
</span>
</div>
@if($x->count())
<div class="card-body text-dark">
<p class="card-text">Networks:</p>
<ul class="p-0 m-0">
@foreach($x->groupBy('fftn.zone_id') as $oo)
<li class="m-0">{{ sprintf('Z%d (%s)',$oo->first()->fftn->zone->zone_id,$oo->first()->fftn->zone->domain->name) }}: {{ number_format($oo->count()) }}</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
<!-- File -->
<div class="col-3">
<div class="card bg-danger">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-folder"></i> Files
<button type="button" class="btn float-end me-0" style="background-color: darkred; color: white;">{{ number_format(($x=\App\Models\File::where('files.created_at','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())
->join('addresses',['addresses.id'=>'files.fftn_id'])
->join('zones',['zones.id'=>'addresses.zone_id'])
->join('domains',['domains.id'=>'zones.domain_id'])
->orderBy('domains.name')
->with('fftn.zone.domain')
->get())
->count()) }}
</button>
</span>
</div>
@if($x->count())
<div class="card-body text-dark">
<p class="card-text">Networks:</p>
<ul class="p-0 m-0">
@foreach($x->groupBy('fftn.zone_id') as $oo)
<li class="m-0">{{ sprintf('Z%d (%s)',$oo->first()->fftn->zone->zone_id,$oo->first()->fftn->zone->domain->name) }}: {{ number_format($oo->count()) }}</li>
@endforeach
</ul>
</div>
@endif
</div>
</div>
<!-- DNS -->
<div class="col-3">
<div class="row">
<div class="col-12">
<div class="card bg-light">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-pc-display"></i> Systems
<button type="button" class="btn float-end me-0" style="background-color: black; color: white;">
{{ number_format(\App\Models\System::where('last_session','>=',\Carbon\Carbon::now()->subWeek()->startOfDay())->count()) }}
</button>
</span>
</div>
</div>
</div>
</div>
<div class="row pt-3">
<div class="col-12">
<div class="card bg-secondary">
<div class="card-header p-2">
<span class="card-title w-100 text-dark" style="font-size: 125%;"><i class="bi bi-globe"></i> DNS Queries
<button type="button" class="btn float-end me-0" style="background-color: black; color: white;">N/A</button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Uncollected Mail -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="uncollected" data-bs-toggle="collapse" data-bs-target="#collapse_uncollected" aria-expanded="true" aria-controls="collapse_uncollected">Uncollected Mail</span>
</h3>
<!-- Uncollected Mail -->
<div class="accordion-item">
<h3 class="accordion-header">
<span class="accordion-button collapsed" id="uncollected" data-bs-toggle="collapse" data-bs-target="#collapse_uncollected" aria-expanded="true" aria-controls="collapse_uncollected">Uncollected Mail</span>
</h3>
<div id="collapse_uncollected" class="accordion-collapse collapse {{ ($flash==='uncollected') ? 'show' : '' }}" aria-labelledby="uncollected" data-bs-parent="#accordion_status">
<div class="accordion-body">
<div class="row">
<div class="col-12">
<p>Nodes with uncollected mail as at <strong class="highlight">{{ $date }}</strong>:</p>
<div id="collapse_uncollected" class="accordion-collapse collapse {{ ($flash==='uncollected') ? 'show' : '' }}" aria-labelledby="uncollected" data-bs-parent="#accordion_status">
<div class="accordion-body">
<div class="row">
<div class="col-12">
<p>Nodes with uncollected mail as at <strong class="highlight">{{ $date }}</strong>:</p>
<table class="table monotable w-100" id="mailfiles">
<thead>
<tr>
<th>Network</th>
<th>System</th>
<th>Address</th>
<th class="text-end">Echomails</th>
<th class="text-end">Netmails</th>
<th class="text-end">Files</th>
<th>Last Session</th>
<th>Poll Mode</th>
<th>Auto Hold</th>
</tr>
</thead>
<table class="table monotable w-100" id="mailfiles">
<thead>
<tr>
<th>Network</th>
<th>System</th>
<th>Address</th>
<th class="text-end">Echomails</th>
<th class="text-end">Netmails</th>
<th class="text-end">Files</th>
<th>Last Session</th>
<th>Poll Mode</th>
<th>Auto Hold</th>
</tr>
</thead>
<tbody>
@foreach($uncollected as $o)
<tr>
<td>{{ $o->zone->domain->name }}</td>
<td>
<a href="{{ url('system/addedit',$o->system_id) }}">{{ $o->system->name }}</a>
@if (($x=$o->parent()) && ($x->id !== $o->id))
<br><small>[via <a href="{{ url('system/addedit',$x->system_id) }}">{{ $x->ftn4d }}</a>]</small>
@endif
</td>
<td>{{ $o->ftn4d }}</td>
<td class="text-end">{{ number_format($o->uncollected_echomail ?? 0) }}</td>
<td class="text-end">{{ number_format($o->uncollected_netmail ?? 0) }}</td>
<td class="text-end">{{ number_format($o->uncollected_files ?? 0) }}</td>
<td>{{ $o->system->last_session?->format('Y-m-d H:i') }}</td>
<td>{{ is_null($o->system->pollmode) ? 'HOLD' : ($o->system->pollmode ? 'CRASH' : 'DAILY') }}</td>
<td>{{ $o->system->autohold ? 'YES' : 'NO' }}</td>
</tr>
@endforeach
</tbody>
</table>
<tbody>
@foreach($uncollected as $o)
<tr>
<td>{{ $o->zone->domain->name }}</td>
<td>
<a href="{{ url('system/addedit',$o->system_id) }}">{{ $o->system->name }}</a>
@if (($x=$o->parent()) && ($x->id !== $o->id))
<br><small>[via <a href="{{ url('system/addedit',$x->system_id) }}">{{ $x->ftn4d }}</a>]</small>
@endif
</td>
<td>{{ $o->ftn4d }}</td>
<td class="text-end">{{ number_format($o->uncollected_echomail ?? 0) }}</td>
<td class="text-end">{{ number_format($o->uncollected_netmail ?? 0) }}</td>
<td class="text-end">{{ number_format($o->uncollected_files ?? 0) }}</td>
<td>{{ $o->system->last_session?->format('Y-m-d H:i') }}</td>
<td>{{ is_null($o->system->pollmode) ? 'HOLD' : ($o->system->pollmode ? 'CRASH' : 'DAILY') }}</td>
<td>{{ $o->system->autohold ? 'YES' : 'NO' }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>

View File

@ -7,8 +7,10 @@
@section('content')
@if($o->exists)
<h1>{{ $o->name }}@if($o->setup)<sup class="success" style="text-shadow: 0 0; font-size: 50%; top: -1em;">*</sup>@endif</h1>
@if($o->setup)<sup class="success" style="float:right;top:-2em;">* This Host</sup>@endif
<h1>
{{ $o->name }}@if($o->setup)<sup class="success">*</sup>@endif
@if($o->setup)<small class="success float-end">* This Host</small>@endif
</h1>
@endif
@if($o->zcs->count())
@ -25,7 +27,7 @@
<div id="collapse_system" class="accordion-collapse collapse {{ (! $flash=session()->pull('accordion')) ? 'show' : '' }}" aria-labelledby="system" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
@include('system.form-system')
@include('system.widget.form-system')
</div>
</div>
</div>
@ -38,134 +40,135 @@
<div id="collapse_addresses" class="accordion-collapse collapse {{ ($flash=='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="row">
<div class="col-12">
<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">
<span class="accordion-button collapsed" id="ftnaddress" data-bs-toggle="collapse" data-bs-target="#collapse_ftnaddresses" aria-expanded="false" aria-controls="collapse_addresses">Fidonet Addressing</span>
</h4>
<div class="accordion accordion-flush" id="accordion_ftnaddress">
<h4 class="accordion-header">
<span class="accordion-button collapsed" id="ftnaddress" data-bs-toggle="collapse" data-bs-target="#collapse_ftnaddresses" aria-expanded="false" aria-controls="collapse_addresses">Fidonet Addressing</span>
</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 particular 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>
<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 particular address format:</p>
<table class="table monotable">
<thead>
<tr>
<th>Role</th>
<th>Address Format</th>
<th>Address</th>
<th>Active</th>
<th>Security</th>
<th colspan="2">Role</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>
@foreach ($o->addresses->sortBy(function($item) { return sprintf('%04x%04x%04x%04x%04x',$item->zone->zone_id,$item->region_id,$item->host_id,$item->node_id,$item->point_id); }) as $oo)
<tr>
<td @if($oo->trashed()) class="trashed" @elseif (! $oo->active) class="inactive" @endif>{{ $oo->ftn }}<span class="float-end"><i title="@if($oo->validated)Mail flowing @else Mail held @endif" class="bi @if($oo->validated)bi-activity @else bi-radioactive @endif"></i></span></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->active_domain)
<!-- No options -->
<a href="javascript:;" title="Net Disabled"><i class="bi bi-slash-square"></i></a>
@elseif($oo->trashed())
<a href="{{ url('system/address/rec',[$oo->id]) }}" title="Restore Address"><i class="bi bi-bandaid"></i></a>
<a href="{{ url('system/address/pur',[$oo->id]) }}" title="Purge Address" class="purge"><i class="bi bi-scissors"></i></a>
@else
<a href="{{ url('system/address/mod',[$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('system/address/sus',[$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('system/address/mov',[$o->id,$oo->id]) }}" title="Move Address to another System"><i class="bi bi-arrow-right-square"></i></a>
<a href="{{ url('system/address/del',[$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('system/address/pro',[$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('system/address/dem',[$oo->id]) }}" title="Demote Address"><i class="bi bi-arrow-down-square"></i></a>
@endif
@endif
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</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>Security</th>
<th colspan="2">Role</th>
</tr>
</thead>
<tbody>
@foreach ($o->addresses->sortBy(function($item) { return sprintf('%04x%04x%04x%04x%04x',$item->zone->zone_id,$item->region_id,$item->host_id,$item->node_id,$item->point_id); }) as $oo)
<tr>
<td @if($oo->trashed()) class="trashed" @elseif (! $oo->active) class="inactive" @endif>{{ $oo->ftn }} <span class="float-end"><i title="@if($oo->validated)Mail flowing @else Mail held @endif" class="bi @if($oo->validated)bi-activity @else bi-radioactive @endif"></i></span></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->active_domain)
<!-- No options -->
<a href="javascript:;" title="Net Disabled"><i class="bi bi-slash-square"></i></a>
@elseif($oo->trashed())
<a href="{{ url('system/address/rec',[$oo->id]) }}" title="Restore Address"><i class="bi bi-bandaid"></i></a>
<a href="{{ url('system/address/pur',[$oo->id]) }}" title="Purge Address" class="purge"><i class="bi bi-scissors"></i></a>
@else
<a href="{{ url('system/address/mod',[$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('system/address/sus',[$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('system/address/mov',[$o->id,$oo->id]) }}" title="Move Address to another System"><i class="bi bi-arrow-right-square"></i></a>
<a href="{{ url('system/address/del',[$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('system/address/pro',[$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('system/address/dem',[$oo->id]) }}" title="Demote Address"><i class="bi bi-arrow-down-square"></i></a>
@endif
@endif
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
@error('susaddress')
<span class="btn btn-sm btn-danger" role="alert" style="text-align: left;">
{!! $message !!}
</span>
@enderror
@error('demaddress')
<span class="btn btn-sm btn-danger" role="alert" style="text-align: left;">
{!! $message !!}
</span>
@enderror
@error('proaddress')
<span class="btn btn-sm btn-danger" role="alert" style="text-align: left;">
{!! $message !!}
</span>
@enderror
@endif
@error('address')
<div class="row pb-5">
<div class="col-12">
<span class="btn btn-sm btn-danger" role="alert" style="text-align: left;">
{!! $message !!}
</span>
</div>
</div>
@enderror
@can('admin',$o)
@include('system.form-address')
<div class="row pb-2">
<div class="col-12">
@include('system.widget.form-address')
</div>
</div>
@else
You'll need to ask an admin to assign addresses.
@ -204,27 +207,27 @@
<tbody>
@foreach ($o->sessions->sortBy('zone_id') as $oo)
<tr>
<td>{{ $oo->zone_id }}<span>@</span>{{ $oo->domain->name }}</td>
<td style="text-align: center;">
@if(($x=$oo->systems->where('pivot.default',TRUE))->count() && ($x->first()->id !== $o->id))
<i class="bi bi-dash-square"></i>
@else
<span class="default" itemid="{{ $oo->id }}"><i class="bi bi-{{ $x->count() ? 'check-square' : 'square' }}"></i></span>
@endif
</td>
<td>{{ $oo->pivot->sespass }}</td>
<td>{{ $oo->pivot->pktpass }}</td>
<td>{{ $oo->pivot->ticpass }}</td>
<td>{{ $oo->pivot->fixpass }}</td>
<td style="width: 70px;">
{{--
<a href="{{ url('system/session/mod',[$oo->id]) }}" title="Modify Details" class="modify"><i class="bi bi-pen"></i></a>
--}}
<a href="{{ url('system/session/del',[$o->id,$oo->id]) }}" title="Delete Details" class="purge"><i class="bi bi-trash"></i></a>
<a href="{{ url('system/areafix',[$o->id,$oo->id]) }}" title="Areafix/Filefix"><i class="bi bi-envelope-paper"></i></a>
</td>
</tr>
<tr>
<td>{{ $oo->zone_id }}<span>@</span>{{ $oo->domain->name }}</td>
<td style="text-align: center;">
@if(($x=$oo->systems->where('pivot.default',TRUE))->count() && ($x->first()->id !== $o->id))
<i class="bi bi-dash-square"></i>
@else
<span class="default" itemid="{{ $oo->id }}"><i class="bi bi-{{ $x->count() ? 'check-square' : 'square' }}"></i></span>
@endif
</td>
<td>{{ $oo->pivot->sespass }}</td>
<td>{{ $oo->pivot->pktpass }}</td>
<td>{{ $oo->pivot->ticpass }}</td>
<td>{{ $oo->pivot->fixpass }}</td>
<td style="width: 70px;">
{{--
<a href="{{ url('system/session/mod',[$oo->id]) }}" title="Modify Details" class="modify"><i class="bi bi-pen"></i></a>
--}}
<a href="{{ url('system/session/del',[$o->id,$oo->id]) }}" title="Delete Details" class="purge"><i class="bi bi-trash"></i></a>
<a href="{{ url('system/areafix',[$o->id,$oo->id]) }}" title="Areafix/Filefix"><i class="bi bi-envelope-paper"></i></a>
</td>
</tr>
@endforeach
</tbody>
</table>
@ -232,7 +235,7 @@
<p>No session details exist</p>
@endif
@include('system.form-session')
@include('system.widget.form-session')
</div>
</div>
</div>
@ -246,7 +249,7 @@
<div id="collapse_echoarea" class="accordion-collapse collapse {{ ($flash=='echoarea') ? 'show' : '' }}" aria-labelledby="echoarea" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
<p>This system can subscribe to the following echoareas:</p>
@include('system.form-echoarea')
@include('system.widget.form-echoarea')
</div>
</div>
</div>
@ -260,7 +263,7 @@
<div id="collapse_filearea" class="accordion-collapse collapse {{ ($flash=='filearea') ? 'show' : '' }}" aria-labelledby="filearea" data-bs-parent="#accordion_homepage">
<div class="accordion-body">
<p>This system can subscribe to the following fileareas:</p>
@include('system.form-filearea')
@include('system.widget.form-filearea')
</div>
</div>
</div>
@ -638,8 +641,9 @@
</div>
</div>
@endif
@else
@include('system.form-system')
@include('system.widget.form-system')
@endif
</div>
@ -657,18 +661,18 @@
@endsection
@section('page-scripts')
<script type="text/javascript">
$(document).ready(function() {
$('.default').click(function() {
$(document).ready(function () {
$('.default').click(function () {
var item = this;
icon = $(item).find('i');
$.ajax({
type: 'POST',
data: {sid: {{$o->id}},_token: '{{csrf_token()}}',set:(icon.hasClass('bi-square') ? 1 : 0)},
beforeSend: function() {
data: {sid: {{$o->id}}, _token: '{{csrf_token()}}', set: (icon.hasClass('bi-square') ? 1 : 0)},
beforeSend: function () {
$(item).find('i').addClass('spinner-grow spinner-grow-sm');
},
success: function() {
success: function () {
if (icon.hasClass('bi-square')) {
icon.removeClass('bi-square');
icon.addClass('bi-check-square');
@ -679,13 +683,13 @@
$(item).find('i').removeClass('spinner-grow spinner-grow-sm');
},
error: function(e) {
error: function (e) {
$(item).find('i').removeClass('spinner-grow spinner-grow-sm');
if (e.status != 412)
alert('That didnt work? Please try again....');
},
url: '{{ url('zone/api/default') }}/'+item.attributes.itemid.nodeValue,
url: '{{ url('zone/api/default') }}/' + item.attributes.itemid.nodeValue,
cache: false
})
});

View File

@ -6,66 +6,66 @@
@endsection
@section('content')
<div class="row pt-0">
<div class="col-12">
<h2>Merge Address {{ $o->ftn }}</h2>
<p>{{ $o->system->sysop }} : {{ $o->system->name }}</p>
</div>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="col-12">
<form method="POST">
@csrf
<div class="row">
<div class="col-12">
<h2>Merge Address {{ $o->ftn }}</h2>
<p>{{ $o->system->sysop }} : {{ $o->system->name }}</p>
</div>
<div class="col-12">
<table class="table monotable">
<thead>
<tr>
<th>F</th>
<th>T</th>
<th>ID</th>
<th>FTN</th>
<th>ACTIVE</th>
<th>Messages</th>
<th>F</th>
<th>T</th>
<th>ID</th>
<th>FTN</th>
<th>ACTIVE</th>
<th>Messages</th>
</tr>
</thead>
<tbody>
@foreach ($oo as $ao)
<tr>
<td><input type="radio" name="src" value="{{ $ao->id }}"></td>
<td><input type="radio" name="dst" value="{{ $ao->id }}"></td>
<th>{{ $ao->id }} {{ $ao->system_id }}:<a href="{{ url('system/addedit',$ao->system_id) }}">{{ $ao->system->name }}</a></th>
<th>{{ $ao->ftn }}</th>
<td>
@if($ao->trashed())
<a href="{{ url('system/address/rec',[$ao->id]) }}" title="Restore Address"><i class="bi bi-bandaid"></i></a>
<a href="{{ url('system/address/pur',[$ao->id]) }}" title="Purge Address" class="purge"><i class="bi bi-scissors"></i></a>
@else
<a href="{{ url('system/address/sus',[$ao->id]) }}" title="@if($ao->active)Pause @else Activate @endif Address"><i class="bi @if($ao->active)bi-pause-circle @else bi-play-circle @endif"></i></a>
<a href="{{ url('system/address/mov',[$ao->system_id,$ao->id]) }}" title="Move Address to another System"><i class="bi bi-arrow-right-square"></i></a>
<a href="{{ url('system/address/del',[$ao->id]) }}" title="Delete Address"><i class="bi bi-trash"></i></a>
@endif
</td>
<td>
<ul>
@foreach(\App\Models\Echomail::select(['id','msgid','from','msg','echoarea_id'])
->where('fftn_id',$ao->id)
->orderBy('created_at','DESC')
->with('echoarea')
->limit(5)
->get() as $eo)
<li class="pb-4">{{ sprintf('%s-%04d: %s (%s) %s',$eo->echoarea->name,$eo->id,$eo->from,$eo->msgid,$eo->msg) }}</li>
@endforeach
</ul>
</td>
</tr>
<tr>
<td><input type="radio" name="src" value="{{ $ao->id }}"></td>
<td><input type="radio" name="dst" value="{{ $ao->id }}"></td>
<th>{{ $ao->id }} {{ $ao->system_id }}:<a href="{{ url('system/addedit',$ao->system_id) }}">{{ $ao->system->name }}</a></th>
<th>{{ $ao->ftn }}</th>
<td>
@if($ao->trashed())
<a href="{{ url('system/address/rec',[$ao->id]) }}" title="Restore Address"><i class="bi bi-bandaid"></i></a>
<a href="{{ url('system/address/pur',[$ao->id]) }}" title="Purge Address" class="purge"><i class="bi bi-scissors"></i></a>
@else
<a href="{{ url('system/address/sus',[$ao->id]) }}" title="@if($ao->active)Pause @else Activate @endif Address"><i class="bi @if($ao->active)bi-pause-circle @else bi-play-circle @endif"></i></a>
<a href="{{ url('system/address/mov',[$ao->system_id,$ao->id]) }}" title="Move Address to another System"><i class="bi bi-arrow-right-square"></i></a>
<a href="{{ url('system/address/del',[$ao->id]) }}" title="Delete Address"><i class="bi bi-trash"></i></a>
@endif
</td>
<td>
<ul>
@foreach(\App\Models\Echomail::select(['id','msgid','from','msg','echoarea_id'])
->where('fftn_id',$ao->id)
->orderBy('created_at','DESC')
->with('echoarea')
->limit(5)
->get() as $eo)
<li class="pb-4">{{ sprintf('%s-%04d: %s (%s) %s',$eo->echoarea->name,$eo->id,$eo->from,$eo->msgid,$eo->msg) }}</li>
@endforeach
</ul>
</td>
</tr>
@endforeach
</tbody>
</table>
<button type="submit" name="submit" class="btn btn-success float-end">Merge</button>
</form>
</div>
</div>
</form>
@include('error')
</div>
@endsection
@include('widgets.error')
@endsection

View File

@ -11,9 +11,9 @@
</div>
</div>
@include('widgets.success')
@includeWhen(session()->has('success'),'widgets.success',['msg'=>session()->get('success')])
<form class="row g-0 needs-validation" method="post" novalidate>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row pt-0">

View File

@ -1,14 +0,0 @@
<form class="row g-0 needs-validation" method="post" novalidate>
@csrf
<input type="hidden" name="system_id" value="{{ $o->id }}">
<div class="row">
<div class="col-12">
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">@can('update',$o) @if($o->exists) Update @else Add @endif @endif System</h2>
@include('system.widget.form-system')
</div>
</div>
</div>
</form>

View File

@ -6,7 +6,7 @@
@section('content')
<div class="row">
<div class="col-12">
<h2>BBS Systems</h2>
<h2>About BBS Systems</h2>
<p>BBS Systems Send and Receive Echomail and Files.</p>
</div>
</div>

View File

@ -4,7 +4,7 @@
@endsection
@section('content')
<div class="row pt-0">
<div class="row">
<div class="col-12">
<h2>List of Connectable Systems</h2>

View File

@ -5,21 +5,19 @@ Move Address
@endsection
@section('content')
<div class="row">
<div class="col-12">
<h1>{{ $o->system->name }} - {{ $o->ftn }}@if($o->system->setup)<sup class="success" style="text-shadow: 0 0; font-size: 50%; top: -1em;">*</sup>@endif</h1>
@if($o->system->setup)<sup class="success" style="float:right;top:-2em;">* This Host</sup>@endif
</div>
</div>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row pt-0">
<div class="col-12">
<!-- @todo The list of presented system should only be those that the user can see -->
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">Move Address</h2>
<div class="row">
<div class="col-12">
<h1>
{{ $o->system->name }} - {{ $o->ftn }}@if($o->system->setup)<sup class="success">*</sup>@endif
@if($o->system->setup)<small class="success float-end">* This Host</small>@endif
</h1>
<form class="row g-0 needs-validation" method="post" novalidate>
@csrf
<!-- @todo The list of presented system should only be those that the user can see -->
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">Move Address</h2>
<div class="row">
<!-- Choose System -->
@ -105,10 +103,10 @@ Move Address
</div>
@endcan
</div>
</form>
</div>
</div>
</div>
</div>
</form>
@endsection
@section('page-css')

View File

@ -1,199 +1,196 @@
<form class="row g-0 needs-validation" method="post" action="{{ url('system/address/add',$o->id) }}" novalidate>
<input type="hidden" id="action" name="action" value="">
<form class="needs-validation" method="post" action="{{ url('system/address/add',$o->id) }}" novalidate>
@csrf
<input type="hidden" id="action" name="action" value="">
<div class="row pt-0">
<div class="col-12">
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">Assign New/Update Existing Address</h2>
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">Assign New/Update Existing 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()->domainZoneOrder()->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 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">
@error('node_id')
{{ $message }}
@enderror
@error('point_id')
{{ $message }}
@enderror
</span>
</div>
</div>
<!-- Region Address -->
<div class="col-3 ps-0 d-none" id="region-address">
<label for="region_id_new" 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="col-3 ps-0 d-none" id="host-address">
<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 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>
<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>
<!-- 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">
<div class="col-2">
<a href="{{ url('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="btn btn-sm btn-danger" role="alert">
There were errors with the submission.
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</span>
@endif
<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()->domainZoneOrder()->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>
@can('admin',$o)
<div class="col-2">
<button type="submit" id="submit" name="submit" class="btn btn-success float-end">Add/Update</button>
</div>
@endcan
<!-- 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 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">
@error('node_id')
{{ $message }}
@enderror
@error('point_id')
{{ $message }}
@enderror
</span>
</div>
</div>
<!-- Region Address -->
<div class="col-3 ps-0 d-none" id="region-address">
<label for="region_id_new" 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="col-3 ps-0 d-none" id="host-address">
<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 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>
<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>
<!-- 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">
<div class="col-2">
<a href="{{ url('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="btn btn-sm btn-danger" role="alert">
There were errors with the submission.
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</span>
@endif
</span>
@can('admin',$o)
<div class="col-2">
<button type="submit" id="submit" name="submit" class="btn btn-success float-end">Add/Update</button>
</div>
@endcan
</div>
</div>
</form>
@section('page-scripts')

View File

@ -3,7 +3,7 @@
->orderBy('zone_id')
->get())->count())
<form class="row g-0 needs-validation" method="post" action="{{ url('system/echoarea',$o->id) }}" novalidate>
<form class="needs-validation" method="post" action="{{ url('system/echoarea',$o->id) }}" novalidate>
@csrf
<div class="row pt-0">

View File

@ -3,7 +3,7 @@
->orderBy('zone_id')
->get())->count())
<form class="row g-0 needs-validation" method="post" action="{{ url('system/filearea',$o->id) }}" novalidate>
<form class="needs-validation" method="post" action="{{ url('system/filearea',$o->id) }}" novalidate>
@csrf
<div class="row pt-0">

View File

@ -4,9 +4,7 @@
->whereNotIn('id',$o->sessions->pluck('id'))
->get())->count())
<hr>
<form class="row g-0 needs-validation" method="post" action="{{ url('system/session/add',$o->id) }}" novalidate>
<form class="needs-validation" method="post" action="{{ url('system/session/add',$o->id) }}" novalidate>
@csrf
<div class="row pt-0">

View File

@ -1,452 +1,14 @@
<!-- $o = System::class -->
<div class="row pt-0">
<div class="col-12">
<h4 class="mb-0 pb-2">System Users</h4>
<form class="needs-validation" method="post" novalidate>
@csrf
<input type="hidden" name="system_id" value="{{ $o->id }}">
<div class="row pt-0">
<!-- Users -->
<div class="col-4">
<label for="users" class="form-label">Owners</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-people-fill"></i></span>
<select style="width: 80%;" class="form-select @error('users') is-invalid @enderror" id="users" name="users[]">
<option value="">&nbsp;</option>
@foreach (\App\Models\User::orderBy('name')->active()->get() as $uo)
<option value="{{ $uo->id }}" @if(in_array($uo->id,old('users',$o->users->pluck('id')->toArray())))selected @endif>{{ $uo->name }} <small>({{ $uo->email }})</small></option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('users')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<h4 class="mb-0 pb-2">System Details</h4>
<div class="row pt-0">
<!-- Name -->
<div class="col-4">
<label for="name" class="form-label">BBS Name</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-pc"></i></span>
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" placeholder="Name" name="name" value="{{ old('name',$o->name) }}" required @cannot('update',$o)readonly @endcannot autofocus>
<span id="search-icon" style="width: 0;"><i style="border-radius: 50%;" class="spinner-border spinner-border-sm text-dark d-none"></i></span>
<div id="system_search_results"></div>
<span class="invalid-feedback" role="alert">
@error('name')
{{ $message }}
@else
A name is required.
@enderror
</span>
</div>
</div>
<!-- ZeroTier ID -->
<div class="col-3">
<label for="zt_id" class="form-label">ZeroTier ID</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-shield-lock-fill"></i></span>
<input type="text" class="form-control @error('zt_id') is-invalid @enderror" id="zt_id" placeholder="ZeroTier" name="zt_id" value="{{ old('zt_id',$o->zt_id) }}" @cannot($action,$o)readonly @endcannot>
<span class="invalid-feedback" role="alert">
@error('zt_id')
{{ $message }}
@enderror
</span>
</div>
</div>
<!-- Active -->
<div class="offset-2 col-2">
@can('update',$o)
<label for="active" class="form-label">Active</label>
<div class="input-group">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="active" id="active_yes" value="1" required @if(old('active',$o->active))checked @endif>
<label class="btn btn-outline-success" for="active_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="active" id="active_no" value="0" required @if(! old('active',$o->active))checked @endif>
<label class="btn btn-outline-danger" for="active_no">No</label>
</div>
</div>
@endcan
</div>
</div>
<div class="row">
<!-- Sysop -->
<div class="col-4">
<label for="sysop" class="form-label">Sysop</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-person-fill"></i></span>
<input type="text" class="form-control @error('sysop') is-invalid @enderror" id="sysop" placeholder="Sysop" name="sysop" value="{{ old('sysop',$o->sysop) }}" required @cannot('admin',$o)readonly @endcannot autocomplete="name">
<span class="invalid-feedback" role="alert">
@error('sysop')
{{ $message }}
@else
A Sysop's name is required.
@enderror
</span>
</div>
</div>
<!-- Location -->
<div class="col-4">
<label for="location" class="form-label">Location</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-globe"></i></span>
<input type="text" class="form-control @error('location') is-invalid @enderror" id="location" placeholder="Location" name="location" value="{{ old('location',$o->location) }}" required @cannot($action,$o)readonly @endcannot>
<span class="invalid-feedback" role="alert">
@error('location')
{{ $message }}
@else
System location is required.
@enderror
</span>
</div>
</div>
<!-- Hold -->
<div class="offset-1 col-2">
@can('update',$o)
<label for="hold" class="form-label">Hold Mail <i class="bi bi-info-circle" title="Dont give the node any mail regardless of poll mode"></i></label>
<div class="input-group">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="hold" id="hold_yes" value="1" required @if(old('hold',$o->hold))checked @endif>
<label class="btn btn-outline-warning" for="hold_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="hold" id="hold_no" value="0" required @if(! old('hold',$o->hold))checked @endif>
<label class="btn btn-outline-success" for="hold_no">No</label>
</div>
</div>
@endcan
</div>
</div>
<div class="row">
<!-- Address -->
<div class="col-5">
<label for="address" class="form-label">BBS Internet Hostname</label>
<div class="input-group has-validation">
<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>
<span class="invalid-feedback" role="alert">
@error('address')
{{ $message }}
@enderror
</span>
</div>
</div>
<!-- Phone -->
<div class="col-3">
<label for="phone" class="form-label">Phone</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-telephone-fill"></i></span>
<input type="text" class="form-control @error('phone') is-invalid @enderror" id="phone" placeholder="Phone" name="phone" value="{{ old('phone',$o->phone) }}" @cannot($action,$o)readonly @endcannot>
<span class="invalid-feedback" role="alert">
@error('phone')
{{ $message }}
@enderror
</span>
</div>
</div>
<!-- Poll Mode -->
<div class="offset-1 col-3">
@can('update',$o)
<label for="pollmode" class="form-label">Poll Mode <i class="bi bi-info-circle" title="Poll node when mail available, poll on a schedule or hold mail for collection"></i></label>
<div class="input-group has-validation">
<div class="btn-group @error('pollmode') is-invalid @enderror" role="group">
<input type="radio" class="btn-check" name="pollmode" id="poll_crash" value="2" @if((int)old('pollmode',($o->pollmode === TRUE) ? 2 : 0) === 2)checked @endif>
<label class="btn btn-outline-success" for="poll_crash">Crash</label>
<input type="radio" class="btn-check btn-danger" name="pollmode" id="poll_normal" value="1" @if((int)old('pollmode',($o->pollmode === FALSE) ? 1 : 0) === 1)checked @endif>
<label class="btn btn-outline-secondary" for="poll_normal">Normal</label>
<input type="radio" class="btn-check btn-danger" name="pollmode" id="poll_hold" value="0" @if((int)old('pollmode',is_null($o->pollmode) ? 0 : 1) === 0)checked @endif>
<label class="btn btn-outline-warning" for="poll_hold">Hold</label>
</div>
<span class="invalid-feedback" role="alert">
@error('pollmode')
{{ $message }}
@enderror
</span>
</div>
@endcan
</div>
</div>
</div>
</div>
<div class="row">
<!-- Mailer Details -->
<div class="col-12">
<h4 class="pt-4 mb-0 pb-2">Mailer Details</h4>
<!-- Mailer Ports -->
<div class="pt-0 row">
<div class="col-3">
@foreach (\App\Models\Mailer::all() as $mo)
@php($x=$o->mailers->find($mo))
<div class="pt-0 row">
<div class="col-12">
<label for="mailer_port_{{ $mo->id }}" class="form-label w-100">{{ $mo->name }} <span class="float-end text-warning">{{ $x?->pivot->last_poll }}</span></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-modem-fill"></i></span>
<input type="text" class="form-control text-end @error('mailer_details.'.$mo->id.'.port') is-invalid @enderror" id="mailer_port_{{ $mo->id }}" placeholder="Port" name="mailer_details[{{ $mo->id }}][port]" value="{{ old('mailer_details.'.$mo->id.'.port',$x?->pivot->port) }}" @cannot($action,$o)readonly @endcannot>
<div class="input-group-text">
<input type="checkbox" class="form-control-input" name="mailer_details[{{ $mo->id }}][active]" value="1" title="Active" @if(old('mailer_details.'.$mo->id.'.active',$x?->pivot->active))checked @endif>
</div>
<span class="invalid-feedback" role="alert">
@error('mailer_details.'.$mo->id.'.port')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
@endforeach
</div>
<!-- Mail Packet -->
<div class="col-2">
<label for="pkt_type" class="form-label">Mail Packet</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-ui-radios"></i></span>
<select class="form-select @error('pkt_type') is-invalid @enderror" id="pkt_type" name="pkt_type" @cannot($action,$o)readonly @endcannot>
@foreach (\App\Classes\FTN\Packet::PACKET_TYPES as $type => $class)
<option value="{{ $type }}" @if(old('pkt_type',$o->pkt_type ?: config('fido.packet_default')) === $type)selected @endif>{{ $type }}</option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('pkt_type')
{{ $message }}
@enderror
</span>
</div>
</div>
<div class="offset-3 col-4 @if((old('pollmode') === "0") || is_null($o->pollmode))d-none @endif" id="heartbeat_option">
@can('admin',$o)
<div class="row p-0">
<div class="offset-3 col-6">
<label for="method" class="form-label">Heartbeat <i class="bi bi-info-circle" title="Attempt contact after last seen"></i></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-hourglass-bottom"></i></span>
<input type="text" class="form-control text-end @error('heartbeat') is-invalid @enderror" id="heartbeat" placeholder="Hours" name="heartbeat" value="{{ old('heartbeat',$o->heartbeat) }}">
<span class="invalid-feedback" role="alert">
@error('heartbeat')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
@endcan
@if (! is_null($o->pollmode))
<div class="row">
<div class="offset-3 col-9 bg-secondary rounded p-2 small">
@if($job = $o->poll())
<div class="row p-0">
<div class="col-4 text-dark">
@if($job->attempts)Last: @else Scheduled: @endif
</div>
<div class="col-8">
<strong class="highlight">{{ $job->created_at }}</strong>
</div>
</div>
<div class="row">
<div class="col-4 text-dark">
Attempts:
</div>
<div class="col-8">
<strong class="highlight">{{ $job->attempts ?: 0 }}</strong>
</div>
</div>
@if ($job->attempts)
<div class="row">
<div class="col-4 text-dark">
Next:
</div>
<div class="col-8">
<strong class="highlight">{{ $job->available_at->diffForHumans(now(),$job->available_at->isFuture() ? \Carbon\CarbonInterface::DIFF_ABSOLUTE : \Carbon\CarbonInterface::DIFF_RELATIVE_TO_NOW) }}</strong>
</div>
</div>
@endif
@else
<div class="row p-0">
<div class="col-4 text-dark">
Last Poll:
</div>
<div class="col-8">
<strong class="highlight">{{ ($x=$o->logs->where('originate',TRUE)->last())?->created_at ?: 'Never' }}</strong>
</div>
</div>
<div class="row">
<div class="col-4 text-dark">
Method:
</div>
<div class="col-8">
<strong class="highlight">{{ $x ? $x->mailer->name : '-' }}</strong>
</div>
</div>
@if ($o->heartbeat)
<div class="row">
<div class="col-4 text-dark">
Next Heartbeat:
</div>
<div class="col-8">
<strong class="highlight">{{ $x ? $x->created_at->addHours($o->heartbeat) : Carbon::now() }}</strong>
</div>
</div>
@endif
@endif
<div class="row">
<div class="col-4 text-dark">
Status:
</div>
<div class="col-8">
<strong class="highlight">
@if ($job) Queued
@elseif ($o->autohold)Auto Hold
@else
@switch($o->pollmode)
@case(TRUE) Crash @break;
@case(FALSE) Normal @break;
@default Hold
@endswitch
@endif
</strong>
</div>
</div>
</div>
</div>
{{--
<div class="col-12">
<table class="table monotable m-0 p-0 small noborder">
<tbody xstyle="border-style:dotted;">
<tr>
<td class="cap text-end">Status :</td>
<td>
@if ($job) Queued
@elseif ($o->autohold)Auto Hold
@else
@switch($o->pollmode)
@case(TRUE) Crash @break;
@case(FALSE) Normal @break;
@default Hold
@endswitch
@endif
</td>
</tr>
</tbody>
</table>
</div>
--}}
@endif
</div>
</div>
</div>
</div>
<div class="row">
<!-- BBS Details -->
<div class="col-12">
<h4 class="pt-4 mb-0 pb-2">BBS Details</h4>
<div class="pt-0 row">
<div class="col-2">
<label for="method" class="form-label">Connection Method</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-wifi"></i></span>
<select class="form-select @error('method') is-invalid @enderror" id="method" name="method" @cannot($action,$o)readonly @endcannot>
<option></option>
<option value="23" @if(old('method',$o->method) == 23)selected @endif>Telnet</option>
<option value="22" @if(old('method',$o->method) == 22)selected @endif>SSH</option>
<option value="519" @if(old('method',$o->method) == 519)selected @endif>Rlogin</option>
</select>
</div>
</div>
<div class="col-2">
<label for="method" class="form-label">Port</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-wifi"></i></span>
<input type="text" class="form-control text-end @error('port') is-invalid @enderror" id="port" placeholder="Port" name="port" value="{{ old('port',$o->port) }}" @cannot($action,$o)readonly @endcannot>
</div>
</div>
</div>
</div>
</div>
@can('admin',$o)
<div class="row">
<!-- Notes -->
<div class="row pt-0">
<div class="col-12">
<label for="notes" class="form-label">Notes</label>
<textarea class="form-control" rows=3 name="notes" placeholder="Notes...">{{ old('notes',$o->notes) }}</textarea>
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">@can('update',$o) @if($o->exists) Update @else Add @endif @endif System</h2>
@include('system.widget.system')
</div>
</div>
</div>
@endcan
<div class="row">
<div class="col-12">
@if($o->exists)
@can($action,$o)
<a href="{{ url('system') }}" class="btn btn-danger">Cancel</a>
<button type="submit" name="submit" class="btn btn-success float-end">@if ($o->exists)Save @else Add @endif</button>
@else
<input type="hidden" name="system_id" value="{{ $o->id }}">
<span><small><strong>NOTE:</strong> You'll be able to update these details after registration is completed.</small></span>
<button type="submit" class="btn btn-success float-end" name="submit" value="register">Register</button>
@endcan
@else
<button type="submit" class="btn btn-success float-end" name="submit" value="create">Register</button>
@endif
</div>
</div>
@section('page-css')
@css('select2')
@append
@section('page-scripts')
@js('select2')
<script type="text/javascript">
$(document).ready(function() {
$('#users').select2({
@cannot('admin')disabled: true @endcannot
/*multiple: true*/
});
$('#poll_normal').on('click',function() {
$('#heartbeat_option').removeClass('d-none');
})
$('#poll_crash').on('click',function() {
$('#heartbeat_option').removeClass('d-none');
})
$('#poll_hold').on('click',function() {
$('#heartbeat_option').addClass('d-none');
console.log('hold');
})
})
</script>
@append
</form>

View File

@ -0,0 +1,441 @@
<!-- $o = System::class -->
<div class="row">
<div class="col-xl-9 col-12">
<div class="row pt-0">
<div class="col-12">
<h4 class="mb-0 pb-2">System Users</h4>
<div class="row pt-0">
<!-- Users -->
<div class="col-6">
<label for="users" class="form-label">Owners</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-people-fill"></i></span>
<select style="width: 80%;" class="form-select @error('users') is-invalid @enderror" id="users" name="users[]">
<option value="">&nbsp;</option>
@foreach (\App\Models\User::orderBy('name')->active()->get() as $uo)
<option value="{{ $uo->id }}" @if(in_array($uo->id,old('users',$o->users->pluck('id')->toArray())))selected @endif>{{ $uo->name }} <small>({{ $uo->email }})</small></option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('users')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
</div>
</div>
<div class="row pt-4">
<div class="col-12">
<h4 class="mb-0 pb-2">System Details</h4>
<div class="row pt-0">
<!-- Name -->
<div class="col-7">
<label for="name" class="form-label">BBS Name</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-pc"></i></span>
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" placeholder="Name" name="name" value="{{ old('name',$o->name) }}" required @cannot('update',$o)readonly @endcannot autofocus>
<span id="search-icon" style="width: 0;"><i style="border-radius: 50%;" class="spinner-border spinner-border-sm text-dark d-none"></i></span>
<div id="system_search_results"></div>
<span class="invalid-feedback" role="alert">
@error('name')
{{ $message }}
@else
A name is required.
@enderror
</span>
</div>
</div>
<!-- ZeroTier ID -->
<div class="col-5">
<label for="zt_id" class="form-label">ZeroTier ID</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-shield-lock-fill"></i></span>
<input type="text" class="form-control @error('zt_id') is-invalid @enderror" id="zt_id" placeholder="ZeroTier" name="zt_id" value="{{ old('zt_id',$o->zt_id) }}" @cannot($action,$o)readonly @endcannot>
<span class="invalid-feedback" role="alert">
@error('zt_id')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
<div class="row">
<!-- Sysop -->
<div class="col-6">
<label for="sysop" class="form-label">Sysop</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-person-fill"></i></span>
<input type="text" class="form-control @error('sysop') is-invalid @enderror" id="sysop" placeholder="Sysop" name="sysop" value="{{ old('sysop',$o->sysop) }}" required @cannot('admin',$o)readonly @endcannot autocomplete="name">
<span class="invalid-feedback" role="alert">
@error('sysop')
{{ $message }}
@else
A Sysop's name is required.
@enderror
</span>
</div>
</div>
<!-- Location -->
<div class="col-6">
<label for="location" class="form-label">Location</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-globe"></i></span>
<input type="text" class="form-control @error('location') is-invalid @enderror" id="location" placeholder="Location" name="location" value="{{ old('location',$o->location) }}" required @cannot($action,$o)readonly @endcannot>
<span class="invalid-feedback" role="alert">
@error('location')
{{ $message }}
@else
System location is required.
@enderror
</span>
</div>
</div>
</div>
<div class="row">
<!-- Address -->
<div class="col-6">
<label for="address" class="form-label">BBS Internet Hostname</label>
<div class="input-group has-validation">
<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>
<span class="invalid-feedback" role="alert">
@error('address')
{{ $message }}
@enderror
</span>
</div>
</div>
<!-- Phone -->
<div class="col-4">
<label for="phone" class="form-label">Phone</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-telephone-fill"></i></span>
<input type="text" class="form-control @error('phone') is-invalid @enderror" id="phone" placeholder="Phone" name="phone" value="{{ old('phone',$o->phone) }}" @cannot($action,$o)readonly @endcannot>
<span class="invalid-feedback" role="alert">
@error('phone')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
</div>
</div>
<div class="row pt-4">
<!-- Mailer Details -->
<div class="col-12">
<h4 class="mb-0 pb-2">Mailer Details</h4>
<!-- Mailer Ports -->
<div class="row pt-0">
<div class="col-3">
@foreach (\App\Models\Mailer::all() as $mo)
@php($x=$o->mailers->find($mo))
<div class="row pt-0">
<div class="col-12">
<label for="mailer_port_{{ $mo->id }}" class="form-label w-100">{{ $mo->name }} <span class="float-end text-warning">{{ $x?->pivot->last_poll }}</span></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-modem-fill"></i></span>
<input type="text" class="form-control text-end @error('mailer_details.'.$mo->id.'.port') is-invalid @enderror" id="mailer_port_{{ $mo->id }}" placeholder="Port" name="mailer_details[{{ $mo->id }}][port]" value="{{ old('mailer_details.'.$mo->id.'.port',$x?->pivot->port) }}" @cannot($action,$o)readonly @endcannot>
<div class="input-group-text">
<input type="checkbox" class="form-control-input" name="mailer_details[{{ $mo->id }}][active]" value="1" title="Active" @if(old('mailer_details.'.$mo->id.'.active',$x?->pivot->active))checked @endif>
</div>
<span class="invalid-feedback" role="alert">
@error('mailer_details.'.$mo->id.'.port')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
@endforeach
</div>
<!-- Mail Packet -->
<div class="col-4">
<label for="pkt_type" class="form-label">Mail Packet</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-ui-radios"></i></span>
<select class="form-select @error('pkt_type') is-invalid @enderror" id="pkt_type" name="pkt_type" @cannot($action,$o)readonly @endcannot>
@foreach (\App\Classes\FTN\Packet::PACKET_TYPES as $type => $class)
<option value="{{ $type }}" @if(old('pkt_type',$o->pkt_type ?: config('fido.packet_default')) === $type)selected @endif>{{ $type }}</option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('pkt_type')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
</div>
</div>
<div class="row pt-4">
<!-- BBS Details -->
<div class="col-12">
<h4 class="mb-0 pb-2">BBS Details</h4>
<div class="row pt-0">
<div class="col-4">
<label for="method" class="form-label">Connection Method</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-wifi"></i></span>
<select class="form-select @error('method') is-invalid @enderror" id="method" name="method" @cannot($action,$o)readonly @endcannot>
<option></option>
<option value="23" @if(old('method',$o->method) == 23)selected @endif>Telnet</option>
<option value="22" @if(old('method',$o->method) == 22)selected @endif>SSH</option>
<option value="519" @if(old('method',$o->method) == 519)selected @endif>Rlogin</option>
</select>
</div>
</div>
<div class="col-3">
<label for="method" class="form-label">Port</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-wifi"></i></span>
<input type="text" class="form-control text-end @error('port') is-invalid @enderror" id="port" placeholder="Port" name="port" value="{{ old('port',$o->port) }}" @cannot($action,$o)readonly @endcannot>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-12">
<div class="row">
<!-- Active -->
<div class="col-6">
@can('update',$o)
<label for="active" class="form-label">Active</label>
<div class="input-group">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="active" id="active_yes" value="1" required @if(old('active',$o->active))checked @endif>
<label class="btn btn-outline-success" for="active_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="active" id="active_no" value="0" required @if(! old('active',$o->active))checked @endif>
<label class="btn btn-outline-danger" for="active_no">No</label>
</div>
</div>
@endcan
</div>
</div>
<div class="row">
<!-- Hold -->
<div class="col-6">
@can('update',$o)
<label for="hold" class="form-label">Hold Mail <i class="bi bi-info-circle" title="Dont give the node any mail regardless of poll mode"></i></label>
<div class="input-group">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="hold" id="hold_yes" value="1" required @if(old('hold',$o->hold))checked @endif>
<label class="btn btn-outline-warning" for="hold_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="hold" id="hold_no" value="0" required @if(! old('hold',$o->hold))checked @endif>
<label class="btn btn-outline-success" for="hold_no">No</label>
</div>
</div>
@endcan
</div>
</div>
<div class="row">
<!-- Poll Mode -->
<div class="col-12">
@can('update',$o)
<label for="pollmode" class="form-label">Poll Mode <i class="bi bi-info-circle" title="Poll node when mail available, poll on a schedule or hold mail for collection"></i></label>
<div class="input-group has-validation">
<div class="btn-group @error('pollmode') is-invalid @enderror" role="group">
<input type="radio" class="btn-check" name="pollmode" id="poll_crash" value="2" @if((int)old('pollmode',($o->pollmode === TRUE) ? 2 : 0) === 2)checked @endif>
<label class="btn btn-outline-success" for="poll_crash">Crash</label>
<input type="radio" class="btn-check btn-danger" name="pollmode" id="poll_normal" value="1" @if((int)old('pollmode',($o->pollmode === FALSE) ? 1 : 0) === 1)checked @endif>
<label class="btn btn-outline-secondary" for="poll_normal">Normal</label>
<input type="radio" class="btn-check btn-danger" name="pollmode" id="poll_hold" value="0" @if((int)old('pollmode',is_null($o->pollmode) ? 0 : 1) === 0)checked @endif>
<label class="btn btn-outline-warning" for="poll_hold">Hold</label>
</div>
<span class="invalid-feedback" role="alert">
@error('pollmode')
{{ $message }}
@enderror
</span>
</div>
@endcan
</div>
</div>
<div class="row">
<div class="col-12 @if((old('pollmode') === "0") || is_null($o->pollmode))d-none @endif" id="heartbeat_option">
@can('admin',$o)
<div class="row p-0">
<div class="col-6">
<label for="heartbeat" class="form-label">Heartbeat <i class="bi bi-info-circle" title="Attempt contact after last seen"></i></label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-hourglass-bottom"></i></span>
<input type="text" class="form-control text-end @error('heartbeat') is-invalid @enderror" id="heartbeat" placeholder="Hrs" name="heartbeat" value="{{ old('heartbeat',$o->heartbeat) }}">
<span class="invalid-feedback" role="alert">
@error('heartbeat')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
@endcan
@if (! is_null($o->pollmode))
<div class="row">
<div class="col-12 bg-secondary rounded p-2 small">
@if($job = $o->poll())
<div class="row p-0">
<div class="col-4 text-dark">
@if($job->attempts)Last: @else Scheduled: @endif
</div>
<div class="col-8">
<strong class="highlight">{{ $job->created_at }}</strong>
</div>
</div>
<div class="row">
<div class="col-4 text-dark">
Attempts:
</div>
<div class="col-8">
<strong class="highlight">{{ $job->attempts ?: 0 }}</strong>
</div>
</div>
@if ($job->attempts)
<div class="row">
<div class="col-4 text-dark">
Next:
</div>
<div class="col-8">
<strong class="highlight">{{ $job->available_at->diffForHumans(now(),$job->available_at->isFuture() ? \Carbon\CarbonInterface::DIFF_ABSOLUTE : \Carbon\CarbonInterface::DIFF_RELATIVE_TO_NOW) }}</strong>
</div>
</div>
@endif
@else
<div class="row p-0">
<div class="col-4 text-dark">
Last Poll:
</div>
<div class="col-8">
<strong class="highlight">{{ ($x=$o->logs->where('originate',TRUE)->last())?->created_at ?: 'Never' }}</strong>
</div>
</div>
<div class="row">
<div class="col-4 text-dark">
Method:
</div>
<div class="col-8">
<strong class="highlight">{{ $x ? $x->mailer->name : '-' }}</strong>
</div>
</div>
@if ($o->heartbeat)
<div class="row">
<div class="col-4 text-dark">
Next Heartbeat:
</div>
<div class="col-8">
<strong class="highlight">{{ $x ? $x->created_at->addHours($o->heartbeat) : Carbon::now() }}</strong>
</div>
</div>
@endif
@endif
<div class="row">
<div class="col-4 text-dark">
Status:
</div>
<div class="col-8">
<strong class="highlight">
@if ($job) Queued
@elseif ($o->autohold)Auto Hold
@else
@switch($o->pollmode)
@case(TRUE) Crash @break;
@case(FALSE) Normal @break;
@default Hold
@endswitch
@endif
</strong>
</div>
</div>
</div>
</div>
@endif
</div>
</div>
</div>
</div>
@can('admin',$o)
<div class="row">
<!-- Notes -->
<div class="col-12">
<label for="notes" class="form-label">Notes</label>
<textarea class="form-control" rows=3 name="notes" placeholder="Notes...">{{ old('notes',$o->notes) }}</textarea>
</div>
</div>
@endcan
<div class="row">
<div class="col-12">
@if($o->exists)
@can($action,$o)
<a href="{{ url('system') }}" class="btn btn-danger">Cancel</a>
<button type="submit" name="submit" class="btn btn-success float-end">@if ($o->exists)Save @else Add @endif</button>
@else
<input type="hidden" name="system_id" value="{{ $o->id }}">
<span><small><strong>NOTE:</strong> You'll be able to update these details after registration is completed.</small></span>
<button type="submit" class="btn btn-success float-end" name="submit" value="register">Register</button>
@endcan
@else
<button type="submit" class="btn btn-success float-end" name="submit" value="create">Register</button>
@endif
</div>
</div>
@section('page-css')
@css('select2')
@append
@section('page-scripts')
@js('select2')
<script type="text/javascript">
$(document).ready(function() {
$('#users').select2({
@cannot('admin')disabled: true @endcannot
/*multiple: true*/
});
$('#poll_normal').on('click',function() {
$('#heartbeat_option').removeClass('d-none');
})
$('#poll_crash').on('click',function() {
$('#heartbeat_option').removeClass('d-none');
})
$('#poll_hold').on('click',function() {
$('#heartbeat_option').addClass('d-none');
console.log('hold');
})
})
</script>
@append

View File

@ -1,3 +1,4 @@
<!-- $o=User::class -->
@extends('layouts.app')
@section('htmlheader_title')
@ -5,135 +6,170 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" novalidate>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row">
<div class="col-12">
@includeWhen(session()->has('success'),'widgets.success-row',['msg'=>session()->get('success')])
<div class="greyframe titledbox shadow0xb0">
<div class="row pt-0">
<div class="col-12">
<h2 class="cap">@if($o->exists) Update @else Add @endif User</h2>
<h2 class="cap">@if($o->exists) Update @else Add @endif User</h2>
<div class="row">
<div class="col-4">
<label for="name" class="form-label">Name</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-tag-fill"></i></span>
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" placeholder="Name" name="name" value="{{ old('name',$o->name) }}" required @cannot('admin',$o)disabled @endcannot autofocus>
<span class="invalid-feedback" role="alert">
@error('name')
{{ $message }}
@else
A name is required.
@enderror
</span>
</div>
</div>
<div class="col-3">
<label for="alias" class="form-label">BBS Alias</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-tag-fill"></i></span>
<input type="text" class="form-control @error('alias') is-invalid @enderror" id="alias" placeholder="alias" name="alias" value="{{ old('alias',$o->alias) }}" @cannot('admin',$o)disabled @endcannot>
<span class="invalid-feedback" role="alert">
@error('alias')
{{ $message }}
@enderror
</span>
</div>
</div>
<!-- Forward Netmail -->
<div class="col-4">
<label for="system_id" class="form-label">Forward Netmails</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-envelope-at-fill"></i></span>
<select style="width: 80%;" class="form-select @error('system_id') is-invalid @enderror" id="system_id" name="system_id" required @cannot('admin',$o)disabled @endcannot>
<option value="">&nbsp;</option>
@foreach ($o->systems as $oo)
<option value="{{ $oo->id }}" @if(old('system_id',$o->system_id)==$oo->id)selected @endif>{{ $oo->name }}</option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('system_id')
{{ $message }}
@enderror
</span>
</div>
</div>
<div class="row">
<div class="col-4">
<label for="name" class="form-label">Name</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-tag-fill"></i></span>
<input type="text" class="form-control @error('name') is-invalid @enderror" id="name" placeholder="Name" name="name" value="{{ old('name',$o->name) }}" autocomplete="name" required @cannot('admin',$o)disabled @endcannot autofocus>
<span class="invalid-feedback" role="alert">
@error('name')
{{ $message }}
@else
A name is required.
@enderror
</span>
</div>
</div>
<div class="row">
<div class="col-4">
<label for="email" class="form-label">Email</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-person-badge"></i></span>
<input type="text" class="form-control @error('email') is-invalid @enderror" id="email" placeholder="Email" name="email" value="{{ old('email',$o->email) }}" required @cannot('admin',$o)disabled @endcannot>
<span class="invalid-feedback" role="alert">
@error('email')
{{ $message }}
@else
Email required for login.
@enderror
</span>
</div>
</div>
<div class="col-1">
<label for="active" class="form-label">Active</label>
<div class="input-group">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="active" id="active_yes" value="1" required @cannot('admin',$o)disabled @endcannot @if(old('active',$o->active))checked @endif>
<label class="btn btn-outline-success" for="active_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="active" id="active_no" value="0" required @cannot('admin',$o)disabled @endcannot @if(! old('active',$o->active))checked @endif>
<label class="btn btn-outline-danger" for="active_no">No</label>
</div>
</div>
</div>
<div class="offset-1 col-1">
<label for="admin" class="form-label">Site Admin</label>
<div class="input-group">
<div class="btn-group" role="group" @if($user->id === $o->id)data-bs-toggle="tooltip" title="You cannot demote yourself" @endif>
<input type="radio" class="btn-check" name="admin" id="admin_yes" value="1" required @cannot('admin',$o)disabled @endcannot @if(old('admin',$o->admin))checked @endif>
<label class="btn btn-outline-success" for="admin_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="admin" id="admin_no" value="0" required @if(($user->id === $o->id) || $user->cannot('admin',$o)) disabled @endif @if(! old('admin',$o->admin))checked @endif>
<label class="btn btn-outline-danger" for="admin_no">No</label>
</div>
</div>
</div>
<div class="col-3">
<label for="alias" class="form-label">BBS Alias</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-tag-fill"></i></span>
<input type="text" class="form-control @error('alias') is-invalid @enderror" id="alias" placeholder="alias" name="alias" value="{{ old('alias',$o->alias) }}" @cannot('update',$o)disabled @endcannot>
<span class="invalid-feedback" role="alert">
@error('alias')
{{ $message }}
@enderror
</span>
</div>
</div>
<div class="row">
<div class="col-12">
<label for="pgp_pubkey" class="form-label">PGP Public Key</label>
<textarea class="form-control @error('pgp_pubkey')is-invalid @enderror" rows=3 name="pgp_pubkey" placeholder="PGP Public Key..." @cannot('admin',$o)disabled @endcannot>{{ old('pgp_pubkey',$o->pgp_pubkey) }}</textarea>
<!-- Forward Netmail -->
@can('admin',$o)
<div class="col-4">
<label for="system_id" class="form-label">Forward Netmails</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-envelope-at-fill"></i></span>
<select style="width: 80%;" class="form-select @error('system_id') is-invalid @enderror" id="system_id" name="system_id" required>
<option value="">&nbsp;</option>
@foreach ($o->systems as $oo)
<option value="{{ $oo->id }}" @if(old('system_id',$o->system_id)==$oo->id)selected @endif>{{ $oo->name }}</option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('pgp_pubkey')
@error('system_id')
{{ $message }}
@enderror
</span>
</div>
</div>
@endcan
</div>
<div class="row">
<div class="col-12">
<a href="{{ url('user') }}" class="btn btn-danger">Cancel</a>
@can('admin',$o)
<button type="submit" name="submit" class="btn btn-success float-end">@if ($o->exists)Save @else Add @endif</button>
@endcan
<div class="row">
<div class="col-4">
<label for="email" class="form-label">Email</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-person-badge"></i></span>
<input type="text" class="form-control @error('email') is-invalid @enderror" id="email" placeholder="Email" name="email" value="{{ old('email',$o->email) }}" autocomplete="email" required @cannot('update',$o)disabled @endcannot>
<span class="invalid-feedback" role="alert">
@error('email')
{{ $message }}
@else
Email required for login.
@enderror
</span>
</div>
</div>
<div class="col-4">
<label for="password" class="form-label">Password</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-person-badge"></i></span>
<input type="password" class="form-control @error('password') is-invalid @enderror" id="password" placeholder="{{ old('password',$o->password) ? 'Password Unchanged' : 'Password' }}" name="password" value="" @cannot('update',$o)disabled @endcannot>
<span class="invalid-feedback" role="alert">
@error('password')
{{ $message }}
@else
Password required for login.
@enderror
</span>
</div>
</div>
<div class="col-1">
@can('ownes',$o)
<label for="passkey" class="form-label">Passkey</label>
<div class="input-group has-validation">
<button class="btn {{ $o->passkey ? 'btn-primary' : 'btn-outline-primary' }}" id="passkey"><i class="bi bi-key"></i></button>
<span class="invalid-feedback" role="alert">
@error('passkey')
{{ $message }}
@enderror
</span>
</div>
@endcan
</div>
@can('admin',$o)
<div class="col-3">
<div class="row p-0">
<div class="col-xl-6 col-12">
<span class="form-label" style="font-size: 75%; margin-bottom: 1px;">Active</span>
<div class="input-group">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="active" id="active_yes" value="1" required @if(old('active',$o->active))checked @endif>
<label class="btn btn-outline-success" for="active_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="active" id="active_no" value="0" required @if(! old('active',$o->active))checked @endif>
<label class="btn btn-outline-danger" for="active_no">No</label>
</div>
</div>
</div>
<div class="col-xl-6 col-12">
<span class="form-label" style="font-size: 75%; margin-bottom: 1px;">Site Admin</span>
<div class="input-group">
<div class="btn-group" role="group" @if($user->id === $o->id)data-bs-toggle="tooltip" title="You cannot demote yourself" @endif>
<input type="radio" class="btn-check" name="admin" id="admin_yes" value="1" required @if(old('admin',$o->admin))checked @endif>
<label class="btn btn-outline-success" for="admin_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="admin" id="admin_no" value="0" required @if(($user->id === $o->id) || $user->cannot('admin',$o)) disabled @endif @if(! old('admin',$o->admin))checked @endif>
<label class="btn btn-outline-danger" for="admin_no">No</label>
</div>
</div>
</div>
</div>
</div>
@endcan
</div>
<div class="row">
<div class="col-12">
<label for="pgp_pubkey" class="form-label">PGP Public Key</label>
<textarea class="form-control @error('pgp_pubkey')is-invalid @enderror" rows=3 id="pgp_pubkey" name="pgp_pubkey" placeholder="PGP Public Key..." @cannot('update',$o)disabled @endcannot>{{ old('pgp_pubkey',$o->pgp_pubkey) }}</textarea>
<span class="invalid-feedback" role="alert">
@error('pgp_pubkey')
{{ $message }}
@enderror
</span>
</div>
</div>
<div class="row">
<div class="col-12">
<a href="{{ back()->getTargetUrl() }}" class="btn btn-danger">Cancel</a>
@canany(['admin','update'],$o)
<button type="submit" name="submit" class="btn btn-success float-end">@if ($o->exists)Save @else Add @endif</button>
@endcan
</div>
</div>
</div>
</div>
</div>
<div class="row pt-5">
<div class="row">
<div class="col-12">
<h3>Systems</h3>
@ -174,8 +210,11 @@
@section('page-scripts')
@js('select2')
<!-- Passkeys -->
<script type='text/javascript' src='{{ asset('/passkey/passkey.js') }}'></script>
@if($user->id === $o->id)
<script>
<script type="text/javascript">
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
@ -186,6 +225,37 @@
<script type="text/javascript">
$(document).ready(function() {
$('#system_id').select2();
$('#passkey').on('click',function(item) {
if (passkey_debug)
console.log('Passkey: Create Click');
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.
// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.
// `sConditionalMediationAvailable` means the feature detection is usable.
if (window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&
PublicKeyCredential.isConditionalMediationAvailable) {
// Check if user verifying platform authenticator is available.
Promise.all([
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(),
PublicKeyCredential.isConditionalMediationAvailable(),
]).then(results => {
if (passkey_debug)
console.log('Passkey: Browser Supported');
if (results.every(r => r === true)) {
passkey_register('{{ csrf_token() }}',$(this),'bi-key','btn-primary','{{ $o->passkey ? 'btn-primary' : 'btn-outline-primary' }}');
} else {
alert('It seems that passkey is NOT supported by your browse (B)');
}
});
} else {
alert('It seems that passkey is NOT supported by your browser (A)');
}
return false;
});
});
</script>
@append

View File

@ -4,66 +4,70 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" novalidate>
<form class="needs-validation" method="post" novalidate>
@csrf
<input type="hidden" id="address_id" name="address_id">
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">Enter your Link code</h2>
<div class="row">
<div class="col-12">
<div class="greyframe titledbox shadow0xb0">
<h2 class="cap">Enter your Link code</h2>
<!-- SYSTEM -->
<div class="row">
<!-- Name -->
<div class="col-5">
<label for="system" class="form-label">BBS Name</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-laptop-fill"></i></span>
<select style="width: 80%;" class="form-select @error('system_id') is-invalid @enderror" id="system" name="address_id" required>
<option value="">&nbsp;</option>
@foreach (\App\Models\Address::select(['addresses.id','addresses.host_id','addresses.node_id','addresses.point_id','addresses.zone_id','systems.name'])
->active()
->join('systems',['systems.id'=>'addresses.system_id'])
->whereRaw('systems.id NOT IN (SELECT system_id FROM system_user)')
->with(['zone'])
->orderBy('systems.name')
->get() as $oo)
<option value="{{ $oo->id }}" @if(old('id')===$oo->id)selected @endif>{{ $oo->name }} ({{ $oo->ftn3d }})</option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('system_id')
{{ $message }}
@else
BBS Name is required.
@enderror
</span>
<!-- SYSTEM -->
<div class="row">
<!-- Name -->
<div class="col-5">
<label for="system" class="form-label">BBS Name</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-laptop-fill"></i></span>
<select style="width: 80%;" class="form-select @error('system_id') is-invalid @enderror" id="system" name="address_id" required>
<option value="">&nbsp;</option>
@foreach (\App\Models\Address::select(['addresses.id','addresses.host_id','addresses.node_id','addresses.point_id','addresses.zone_id','systems.name'])
->active()
->join('systems',['systems.id'=>'addresses.system_id'])
->whereRaw('systems.id NOT IN (SELECT system_id FROM system_user)')
->with(['zone'])
->orderBy('systems.name')
->get() as $oo)
<option value="{{ $oo->id }}" @if(old('id')===$oo->id)selected @endif>{{ $oo->name }} ({{ $oo->ftn3d }})</option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('system_id')
{{ $message }}
@else
BBS Name is required.
@enderror
</span>
</div>
</div>
</div>
</div>
</div>
<!-- CODE -->
<div class="row">
<div class="col-4">
<label for="code" class="form-label">Code</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-fingerprint"></i></span>
<input type="text" class="form-control @error('code') is-invalid @enderror" id="code" placeholder="Code" name="code" value="{{ old('code') }}" required>
<span class="invalid-feedback" role="alert">
@error('code')
{{ $message }}
@else
A code is required.
@enderror
</span>
<!-- CODE -->
<div class="row">
<div class="col-4">
<label for="code" class="form-label">Code</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-fingerprint"></i></span>
<input type="text" class="form-control @error('code') is-invalid @enderror" id="code" placeholder="Code" name="code" value="{{ old('code') }}" required>
<span class="invalid-feedback" role="alert">
@error('code')
{{ $message }}
@else
A code is required.
@enderror
</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<a href="{{ url('home') }}" class="btn btn-danger">Cancel</a>
<button type="submit" name="submit" class="btn btn-success float-end">Validate</button>
<div class="row">
<div class="col-12">
<a href="{{ url('home') }}" class="btn btn-danger">Cancel</a>
<button type="submit" name="submit" class="btn btn-success float-end">Validate</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -5,14 +5,10 @@
@section('content')
<div class="row">
<div class="row">
<div class="col-12">
<h2>System Users</h2>
</div>
</div>
<div class="col-12">
<p>This system is aware of the following users @can('admin',(new \App\Models\User))(you can <a href="{{ url('user/addedit') }}">add</a> more)@endcan:</p>
<h2>System Users</h2>
<p>This system is aware of the following users (you can <a href="{{ url('user/addedit') }}">add</a> more):</p>
<table class="table monotable" id="user">
<thead>
<tr>

View File

@ -5,7 +5,7 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" autocomplete="off" novalidate>
<form class="needs-validation" method="post" autocomplete="off" novalidate>
@csrf
<div class="row">

View File

@ -27,14 +27,14 @@
<p>Otherwise, if all is good, we'll send a netmail to <strong class="highlight">{{ $o->sysop }}</strong> at <strong class="highlight">{{ $o->access_mailer }}</strong></p> with further details.
<form class="row g-0 needs-validation" method="post" autocomplete="off" action="{{ url('user/system/link') }}" novalidate>
<form class="needs-validation" method="post" autocomplete="off" action="{{ url('user/system/link') }}" novalidate>
@csrf
<input type="hidden" name="system_id" value="{{ $o->id }}">
<input type="hidden" name="name" value="{{ $o->name }}">
<div class="row">
<div class="col-12 pb-2">
<div class="row pb-2">
<div class="col-12">
<input type="submit" name="action" class="btn btn-success" value="Link">
</div>
</div>

View File

@ -0,0 +1,5 @@
<div class="row">
<div class="col-8 m-auto">
@include('widgets.success')
</div>
</div>

View File

@ -1,10 +1,5 @@
<!-- Success -->
@if(session()->has('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
<h4 class="text-success"><i class="bi bi-hand-thumbs-up"></i> Success!</h4>
<ul>
<li>{{ session()->get('success') }}</li>
</ul>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="bi bi-hand-thumbs-up"></i> {{ $msg }}
<button type="button" class="btn btn-sm btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>

View File

@ -5,7 +5,7 @@
@endsection
@section('content')
<form class="row g-0 needs-validation" method="post" novalidate>
<form class="needs-validation" method="post" novalidate>
@csrf
<div class="row">

View File

@ -50,10 +50,15 @@ Route::view('system/list','system.list');
Route::get('system/view/{o}',[SystemController::class,'view'])
->where('o','[0-9]+');
Route::get('search',[HomeController::class,'search']);
Route::view('user/permissions','auth.permissions');
Route::middleware(['auth','verified','activeuser'])->group(function () {
Route::view('dashboard','dashboard');
/* ACCOUNT PATHS */
Route::match(['get','post'],'user/addedit/{o?}',[UserController::class,'add_edit'])
->where('o','[0-9]+');
/* DOMAIN PATHS */
Route::view('domain','domain.home');
Route::get('domain/api/hosts/{o}/{region}',[DomainController::class,'api_hosts'])
@ -121,7 +126,6 @@ Route::middleware(['auth','verified','activeuser'])->group(function () {
Route::post('packet/contents/{o}/{packet}',[HomeController::class,'packet_contents'])
->where('o','[0-9]+')
->where('packet','[[:xdigit:]]+');
Route::get('permissions',[HomeController::class,'permissions']);
Route::match(['get','post'],'user/system/register',[SystemController::class,'register']);
Route::match(['post'],'user/system/link',[SystemController::class,'system_link']);
@ -143,7 +147,5 @@ Route::middleware(['auth','can:admin'])->group(function () {
Route::match(['get','post'],'address/merge/{id}',[SystemController::class,'address_merge']);
Route::match(['get','post'],'setup',[HomeController::class,'setup']);
Route::view('user','user.home');
Route::match(['get','post'],'user/addedit/{o?}',[UserController::class,'add_edit'])
->where('o','[0-9]+');
Route::view('user/list','user.list');
});