Upgrade to Laravel 11, begining of enabling network join functionality, removed QueryCacheable

This commit is contained in:
Deon George 2024-04-26 16:18:40 +10:00
parent 6e376100a5
commit 79b180f453
16 changed files with 1086 additions and 1018 deletions

View File

@ -36,7 +36,7 @@ class DomainController extends Controller
public function add_edit(DomainRequest $request,Domain $o) public function add_edit(DomainRequest $request,Domain $o)
{ {
if ($request->post()) { if ($request->post()) {
foreach (['name','dnsdomain','active','public','homepage','notes','flatten'] as $key) foreach (['name','dnsdomain','active','public','homepage','notes','flatten','accept_app'] as $key)
$o->{$key} = $request->post($key); $o->{$key} = $request->post($key);
$o->save(); $o->save();

View File

@ -27,6 +27,7 @@ class DomainRequest extends FormRequest
'dnsdomain' => 'nullable|regex:/^(?!:\/\/)(?=.{1,255}$)((.{1,63}\.){1,127}(?![0-9]*$)[a-z0-9-]+\.?)$/i|unique:domains,dnsdomain,'.($o->exists ? $o->id : NULL), 'dnsdomain' => 'nullable|regex:/^(?!:\/\/)(?=.{1,255}$)((.{1,63}\.){1,127}(?![0-9]*$)[a-z0-9-]+\.?)$/i|unique:domains,dnsdomain,'.($o->exists ? $o->id : NULL),
'active' => 'required|boolean', 'active' => 'required|boolean',
'public' => 'required|boolean', 'public' => 'required|boolean',
'accept_app' => 'required|boolean',
'flatten' => 'nullable|boolean', 'flatten' => 'nullable|boolean',
]; ];
} }

View File

@ -12,11 +12,11 @@ use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use App\Casts\CompressedString; use App\Casts\CompressedString;
use App\Traits\{QueryCacheableConfig,ScopeActive}; use App\Traits\ScopeActive;
class Domain extends Model class Domain extends Model
{ {
use HasFactory,ScopeActive,QueryCacheableConfig; use HasFactory,ScopeActive;
private const CACHE_TIME = 3600; private const CACHE_TIME = 3600;
private const STATS_MONTHS = 6; private const STATS_MONTHS = 6;
@ -62,6 +62,15 @@ class Domain extends Model
/* ATTRIBUTES */ /* ATTRIBUTES */
public function getCanAcceptAppAttribute(): bool
{
return our_address($this)->count()
&& $this->active
&& $this->accept_app
&& Auth::id()
&& $this->userHasSystemsNotInNet(Auth::user())->count();
}
public function getHomePageAttribute(?string $value): string public function getHomePageAttribute(?string $value): string
{ {
//0xFD2FB528 //0xFD2FB528
@ -78,8 +87,7 @@ class Domain extends Model
->whenRaw("datetime >= '?'",$dt->subMonth()->format('Y-m-d'))->thenRaw("'month'") ->whenRaw("datetime >= '?'",$dt->subMonth()->format('Y-m-d'))->thenRaw("'month'")
->elseRaw("'all'"); ->elseRaw("'all'");
return Echoarea::cacheFor(self::CACHE_TIME) return Echoarea::select(['echoareas.id','name','description','active',DB::raw('count(echomails.id) AS count'),DB::raw('max(datetime) as last_message')])
->select(['echoareas.id','name','description','active',DB::raw('count(echomails.id) AS count'),DB::raw('max(datetime) as last_message')])
->selectRaw($case->toRaw().' AS stats') ->selectRaw($case->toRaw().' AS stats')
->join('echomails',['echomails.echoarea_id'=>'echoareas.id'],NULL,NULL,'left outer') ->join('echomails',['echomails.echoarea_id'=>'echoareas.id'],NULL,NULL,'left outer')
->where('domain_id',$this->id) ->where('domain_id',$this->id)
@ -124,4 +132,23 @@ class Domain extends Model
{ {
return our_address($this)->count() > 0; return our_address($this)->count() > 0;
} }
/**
* Work out which of the users systems are not in this domain
*
* @param User $o
* @return Collection
*/
public function userHasSystemsNotInNet(User $o): Collection
{
$o->load('systems.akas.zone');
$result = collect();
foreach ($o->systems->filter(function($item) { return $item->active; }) as $so) {
if (! $so->akas->pluck('zone')->unique('domain_id')->pluck('domain_id')->contains($this->id))
$result->push($so);
}
return $result;
}
} }

View File

@ -4,13 +4,12 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Rennokki\QueryCache\Traits\QueryCacheable;
use App\Casts\CollectionOrNull; use App\Casts\CollectionOrNull;
class Dynamic extends Model class Dynamic extends Model
{ {
use SoftDeletes,QueryCacheable; use SoftDeletes;
protected $casts = [ protected $casts = [
'arguments' => CollectionOrNull::class, 'arguments' => CollectionOrNull::class,

View File

@ -6,7 +6,6 @@ use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Rennokki\QueryCache\Traits\QueryCacheable;
use App\Traits\{AreaSecurity,ScopeActive}; use App\Traits\{AreaSecurity,ScopeActive};
@ -42,7 +41,7 @@ use App\Traits\{AreaSecurity,ScopeActive};
*/ */
class Echoarea extends Model class Echoarea extends Model
{ {
use SoftDeletes,ScopeActive,QueryCacheable,AreaSecurity; use SoftDeletes,ScopeActive,AreaSecurity;
private const CACHE_TIME = 3600; private const CACHE_TIME = 3600;
@ -72,8 +71,7 @@ class Echoarea extends Model
public function messages_count(int $period=NULL): int public function messages_count(int $period=NULL): int
{ {
$eo = Echomail::cacheFor(self::CACHE_TIME) $eo = Echomail::where('echoarea_id',$this->id);
->where('echoarea_id',$this->id);
$dt = Carbon::now()->startOfday(); $dt = Carbon::now()->startOfday();

View File

@ -8,7 +8,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Rennokki\QueryCache\Traits\QueryCacheable;
use App\Casts\{CollectionOrNull,CompressedString}; use App\Casts\{CollectionOrNull,CompressedString};
use App\Classes\FTN\Message; use App\Classes\FTN\Message;
@ -17,7 +16,7 @@ use App\Traits\{EncodeUTF8,MsgID,ParseAddresses};
final class Echomail extends Model implements Packet final class Echomail extends Model implements Packet
{ {
use SoftDeletes,EncodeUTF8,MsgID,QueryCacheable,ParseAddresses; use SoftDeletes,EncodeUTF8,MsgID,ParseAddresses;
private const LOGKEY = 'ME-'; private const LOGKEY = 'ME-';
private Collection $set_seenby; private Collection $set_seenby;

View File

@ -10,14 +10,13 @@ use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Rennokki\QueryCache\Traits\QueryCacheable;
use App\Casts\{CollectionOrNull,CompressedString}; use App\Casts\{CollectionOrNull,CompressedString};
use App\Traits\EncodeUTF8; use App\Traits\EncodeUTF8;
class File extends Model class File extends Model
{ {
use SoftDeletes,EncodeUTF8,QueryCacheable; use SoftDeletes,EncodeUTF8;
private const LOGKEY = 'MF-'; private const LOGKEY = 'MF-';
private bool $no_export = FALSE; private bool $no_export = FALSE;

View File

@ -75,27 +75,21 @@ class User extends Authenticatable implements MustVerifyEmail
/* GENERAL METHODS */ /* GENERAL METHODS */
public function addresses(): Collection public function addresses(Domain $o=NULL): Collection
{ {
return Address::select('addresses.*') return Address::select('addresses.*')
->join('systems',['systems.id'=>'addresses.system_id']) ->join('systems',['systems.id'=>'addresses.system_id'])
->join('system_user',['system_user.system_id'=>'systems.id']) ->join('system_user',['system_user.system_id'=>'systems.id'])
->when(! is_null($o),function($query) use ($o) {
return $query
->join('zones',['zones.id'=>'addresses.zone_id'])
->where('zones.domain_id',$o->id);
})
->where('system_user.user_id',$this->id) ->where('system_user.user_id',$this->id)
->with(['zone.domain']) ->with(['zone.domain'])
->get(); ->get();
} }
/**
* See if the user is already a member of the chosen network
*
* @param Domain $o
* @return bool
*/
public function isMember(Domain $o): bool
{
return FALSE;
}
/** /**
* Is this user a ZC of a domain? * Is this user a ZC of a domain?
* *
@ -128,6 +122,8 @@ class User extends Authenticatable implements MustVerifyEmail
*/ */
public function zc(): Collection public function zc(): Collection
{ {
$this->load('systems.addresses');
return $this->systems->pluck('addresses')->flatten()->where('role',Address::NODE_ZC); return $this->systems->pluck('addresses')->flatten()->where('role',Address::NODE_ZC);
} }
} }

View File

@ -4,7 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use App\Traits\{QueryCacheableConfig,ScopeActive}; use App\Traits\ScopeActive;
class Zone extends Model class Zone extends Model
{ {

View File

@ -1,17 +0,0 @@
<?php
/**
* Set defaults of QueryCacheable
*/
namespace App\Traits;
use Rennokki\QueryCache\Traits\QueryCacheable;
trait QueryCacheableConfig
{
use QueryCacheable;
public $cacheFor = 900; // cache time, in seconds
protected static $flushCacheOnUpdate = TRUE;
public $cacheDriver = 'memcached';
}

View File

@ -5,30 +5,29 @@
"keywords": ["framework","laravel"], "keywords": ["framework","laravel"],
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.1|8.2", "php": "^8.1|8.2|8.3",
"ext-bz2": "*", "ext-bz2": "*",
"ext-pcntl": "*", "ext-pcntl": "*",
"ext-sockets": "*", "ext-sockets": "*",
"ext-zip": "*", "ext-zip": "*",
"ext-zlib": "*", "ext-zlib": "*",
"ext-zstd": "*", "ext-zstd": "*",
"aglipanci/laravel-eloquent-case": "^2.0", "aglipanci/laravel-eloquent-case": "^3.0",
"eduardokum/laravel-mail-auto-embed": "^2.0", "eduardokum/laravel-mail-auto-embed": "^2.11",
"laravel/framework": "^10.0", "laravel/framework": "^11.0",
"laravel/sanctum": "^3.2", "laravel/sanctum": "^4.0",
"laravel/ui": "^4.0", "laravel/ui": "^4.5",
"league/flysystem-aws-s3-v3": "^3.0", "league/flysystem-aws-s3-v3": "^3.27",
"leenooks/passkey": "^0.1.0", "leenooks/passkey": "^0.1.0",
"nunomaduro/laravel-console-summary": "^1.9", "nunomaduro/laravel-console-summary": "^1.12.1",
"rennokki/laravel-eloquent-query-cache": "^3.3", "repat/laravel-job-models": "^0.9",
"repat/laravel-job-models": "^0.8", "romanzipp/laravel-queue-monitor": "^5.0"
"romanzipp/laravel-queue-monitor": "^2.0"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.6", "barryvdh/laravel-debugbar": "^3.6",
"fakerphp/faker": "^1.9.1", "fakerphp/faker": "^1.9.1",
"mockery/mockery": "^1.4.4", "mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^7.0", "nunomaduro/collision": "^8.1",
"phpunit/phpunit": "^10.0", "phpunit/phpunit": "^10.0",
"spatie/laravel-ignition": "^2.1" "spatie/laravel-ignition": "^2.1"
}, },
@ -51,10 +50,6 @@
"passkey": { "passkey": {
"type": "vcs", "type": "vcs",
"url": "https://gitea.dege.au/laravel/passkey.git" "url": "https://gitea.dege.au/laravel/passkey.git"
},
"laravel-console-summary": {
"type": "vcs",
"url": "https://github.com/leenooks/laravel-console-summary"
} }
}, },
"scripts": { "scripts": {

1853
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('domains', function (Blueprint $table) {
$table->boolean('accept_app')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('domains', function (Blueprint $table) {
$table->dropColumn('accept_app');
});
}
};

View File

@ -18,7 +18,7 @@
<label for="name" class="form-label">Name</label> <label for="name" class="form-label">Name</label>
<div class="input-group has-validation"> <div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-tag-fill"></i></span> <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> <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 autocomplete="off">
<span class="invalid-feedback" role="alert"> <span class="invalid-feedback" role="alert">
@error('name') @error('name')
{{ $message }} {{ $message }}
@ -30,7 +30,7 @@
</div> </div>
<div class="col-2"> <div class="col-2">
<label for="active" class="form-label">Active</label> <label class="form-label">Active</label>
<div class="input-group"> <div class="input-group">
<div class="btn-group" role="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> <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>
@ -44,7 +44,7 @@
<div class="col-2"> <div class="col-2">
@if ($o->zones->count() > 1) @if ($o->zones->count() > 1)
<label for="flatten" class="form-label">Flatten Zones <i class="bi bi-info-circle" title="Treat this domain as a 2D domain"></i></label> <label class="form-label">Flatten Zones <i class="bi bi-info-circle" title="Treat this domain as a 2D domain"></i></label>
<div class="input-group"> <div class="input-group">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<input type="radio" class="btn-check" name="flatten" id="flatten_yes" value="1" required @if(old('flatten',$o->flatten))checked @endif> <input type="radio" class="btn-check" name="flatten" id="flatten_yes" value="1" required @if(old('flatten',$o->flatten))checked @endif>
@ -88,8 +88,8 @@
</div> </div>
</div> </div>
<div class="col-4"> <div class="col-2">
<label for="public" class="form-label">Public</label> <label class="form-label">Public</label>
<div class="input-group"> <div class="input-group">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<input type="radio" class="btn-check" name="public" id="public_yes" value="1" required @cannot('admin',$o)disabled @endcannot @if(old('public',$o->public))checked @endif> <input type="radio" class="btn-check" name="public" id="public_yes" value="1" required @cannot('admin',$o)disabled @endcannot @if(old('public',$o->public))checked @endif>
@ -101,6 +101,19 @@
</div> </div>
</div> </div>
<div class="col-2">
<label class="form-label">Applications</label>
<div class="input-group">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="accept_app" id="accept_app_yes" value="1" required @cannot('admin',$o)disabled @endcannot @if(old('accept_app',$o->accept_app))checked @endif>
<label class="btn btn-outline-success" for="accept_app_yes">Yes</label>
<input type="radio" class="btn-check btn-danger" name="accept_app" id="accept_app_no" value="0" required @cannot('admin',$o)disabled @endcannot @if(! old('accept_app',$o->accept_app))checked @endif>
<label class="btn btn-outline-danger" for="accept_app_no">No</label>
</div>
</div>
</div>
@if ($o->nodelist_filename) @if ($o->nodelist_filename)
<div class="col-4"> <div class="col-4">
<label for="name" class="form-label">Nodelist File Area</label> <label for="name" class="form-label">Nodelist File Area</label>
@ -117,7 +130,7 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<label for="notes" class="form-label">Notes</label> <label for="notes" class="form-label">Notes</label>
<textarea class="form-control" rows=3 name="notes" placeholder="Notes..." @cannot('admin',$o)disabled @endcannot>{{ old('notes',$o->notes) }}</textarea> <textarea class="form-control" rows=3 id="notes" name="notes" placeholder="Notes..." @cannot('admin',$o)disabled @endcannot>{{ old('notes',$o->notes) }}</textarea>
</div> </div>
</div> </div>
</div> </div>

View File

@ -156,24 +156,41 @@
</div> </div>
<!-- Sign up --> <!-- Sign up -->
<div class="accordion-item"> @if ($o->can_accept_app)
<h3 class="accordion-header"> <div class="accordion-item">
<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 class="accordion-header">
</h3> <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 id="collapse_signup" class="accordion-collapse collapse" aria-labelledby="signup" data-bs-parent="#accordion_homepage">
<div class="accordion-body"> <div class="accordion-body">
@guest <p>Your system(s) <strong class="highlight">{!! $o->userHasSystemsNotInNet(Auth::user())->pluck('name')->join('</strong>, <strong class="highlight">') !!}</strong> can join this network.</p>
To start an application to join this network please <a href="{{ url('login') }}">login</a>. <p>
@else If you want to join it/them to this network, make sure:
@if($user->isMember($o)) </p>
@else
This website is not ready to take applications yet, check back soon! <ul>
@endif <li>it is online and can accept mailer calls</li>
@endguest <li>you have the <strong class="highlight">BBS Internet Hostname</strong> configured with the correct hostname</li>
<li>you have selected either <strong class="highlight">BINKP</strong> or <strong class="highlight">EMSI</strong> in the mailer settings, with the correct TCP port</li>
</ul>
<p>Here's what will happen next</p>
<ul>
<li>You complete the application form (see the button below)</li>
<li>We'll poll your system to make sure it is connectable</li>
<li>Your applicaiton will then be forwarded to the <strong class="highlight">ZC</strong> of the domain</li>
<li>You'll hear back from your assigned hub to configure your system with your assigned FTN address</li>
<li>Configure your system, subscribe to file and echo areas</li>
<li>Enjoy!</li>
</ul>
<button class="btn btn-success">Lets Do It</button>
</div>
</div> </div>
</div> </div>
</div> @endif
</div> </div>
</div> </div>
</div> </div>
@ -181,15 +198,8 @@
@section('page-css') @section('page-css')
@css('datatables') @css('datatables')
<style>
div#collapse_about {
min-height: 25em;
}
div#collapse_about .collapse{
min-height: 0;
}
</style>
@append @append
@section('page-scripts') @section('page-scripts')
@js('datatables') @js('datatables')
@js('highcharts') @js('highcharts')
@ -253,6 +263,19 @@
} }
} }
}); });
@if ($o->can_accept_app)
$('#join_top').on('click',function(item) {
$('.accordion-collapse').each(function(){
if ($(this).hasClass('show')) {
$(this).toggle();
}
});
$('#collapse_signup').toggle();
return false;
});
@endif
}); });
Highcharts.chart('network_traffic', { Highcharts.chart('network_traffic', {

View File

@ -15,12 +15,10 @@
</ul> </ul>
</div> </div>
</li> </li>
<li><a href="{{ url('status') }}" class="@if(preg_match('#^status#',request()->path()))thispage disabled @endif"><span>Status</span></a></li> @if(preg_match('#^domain/#',request()->path()) && $o->can_accept_app)
{{-- <li><a href="{{ url('join') }}" id="join_top" class="@if(preg_match('#^join#',request()->path()))thispage @endif"><span>Join</span></a></li>
<li><a href="{{ url('help') }}" class="@if(preg_match('#^help#',request()->path()))thispage @endif disabled"><span>Help</span></a></li> @else
--}} <li><a href="{{ url('status') }}" class="@if(preg_match('#^status#',request()->path()))thispage disabled @endif"><span>Status</span></a></li>
@if(preg_match('#^/network/#',request()->path()))
<li><a href="{{ url('join') }}" class="@if(preg_match('#^join#',request()->path()))thispage @endif"><span>Join</span></a></li>
@endif @endif
</ul> </ul>