diff --git a/app/Classes/FTN/Message.php b/app/Classes/FTN/Message.php index c9207cb..7362147 100644 --- a/app/Classes/FTN/Message.php +++ b/app/Classes/FTN/Message.php @@ -12,6 +12,7 @@ use Illuminate\Validation\Validator as ValidatorResult; use App\Classes\FTN as FTNBase; use App\Models\{Address,Domain}; use App\Rules\TwoByteInteger; +use App\Traits\EncodeUTF8; /** * Class Message @@ -21,6 +22,8 @@ use App\Rules\TwoByteInteger; */ class Message extends FTNBase { + use EncodeUTF8; + private const cast_utf8 = [ 'message', 'message_src', @@ -342,43 +345,7 @@ class Message extends FTNBase */ public function __serialize(): array { - $values = []; - - $properties = (new \ReflectionClass($this))->getProperties(); - - $class = get_class($this); - - foreach ($properties as $property) { - // Dont serialize the validation error - if ($property->name == 'errors') - continue; - - if ($property->isStatic()) { - continue; - } - - $property->setAccessible(true); - - if (! $property->isInitialized($this)) { - continue; - } - - $name = $property->getName(); - $encode = in_array($name,self::cast_utf8); - - if ($property->isPrivate()) { - $name = "\0{$class}\0{$name}"; - } elseif ($property->isProtected()) { - $name = "\0*\0{$name}"; - } - - $property->setAccessible(true); - $value = $property->getValue($this); - - $values[$name] = $encode ? utf8_encode($value) : $value; - } - - return $values; + return $this->encode(); } /** diff --git a/app/Http/Controllers/EchoareaController.php b/app/Http/Controllers/EchoareaController.php new file mode 100644 index 0000000..c8863c0 --- /dev/null +++ b/app/Http/Controllers/EchoareaController.php @@ -0,0 +1,49 @@ +middleware('auth'); + } + + /** + * Add or edit a echoarea + */ + public function add_edit(Request $request,Echoarea $o) + { + if ($request->post()) { + $this->authorize('admin',$o); + + $request->validate([ + // http://ftsc.org/docs/old/fsp-1028.002 + 'domain_id' => 'required|exists:domains,id', + 'name' => 'required|max:35|regex:/^[a-zA-Z-_~]{1,8}$/|unique:echoareas,name,'.($o->exists ? $o->id : 0), + 'description' => 'required', + 'active' => 'required|boolean', + 'public' => 'required|boolean', + ]); + + foreach (['name','description','active','public','notes','domain_id'] as $key) + $o->{$key} = $request->post($key); + + $o->save(); + + return redirect()->action([self::class,'home']); + } + + return view('echoarea.addedit') + ->with('o',$o); + } + + public function home() + { + return view('echoarea.home'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/FileareaController.php b/app/Http/Controllers/FileareaController.php new file mode 100644 index 0000000..e06b376 --- /dev/null +++ b/app/Http/Controllers/FileareaController.php @@ -0,0 +1,48 @@ +middleware('auth'); + } + + /** + * Add or edit a echoarea + */ + public function add_edit(Request $request,Filearea $o) + { + if ($request->post()) { + $this->authorize('admin',$o); + + $request->validate([ + // http://ftsc.org/docs/old/fsp-1028.002 + 'domain_id' => 'required|exists:domains,id', + 'name' => 'required|max:35|regex:/^[a-zA-Z-_~]{1,8}$/|unique:echoareas,name,'.($o->exists ? $o->id : 0), + 'description' => 'required', + 'active' => 'required|boolean', + 'public' => 'required|boolean', + ]); + + foreach (['name','description','active','public','notes','domain_id'] as $key) + $o->{$key} = $request->post($key); + + $o->save(); + + return redirect()->action([self::class,'home']); + } + + return view('filearea.addedit') + ->with('o',$o); + } + + public function home() + { + return view('filearea.home'); + } +} \ No newline at end of file diff --git a/app/Jobs/ProcessPacket.php b/app/Jobs/ProcessPacket.php index 7e8caab..bd7239f 100644 --- a/app/Jobs/ProcessPacket.php +++ b/app/Jobs/ProcessPacket.php @@ -10,7 +10,7 @@ use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; use App\Classes\FTN\{Message,Process}; -use App\Models\{Echomail,Netmail,Setup}; +use App\Models\{Echoarea,Echomail,Netmail,Setup}; class ProcessPacket implements ShouldQueue { @@ -141,7 +141,10 @@ class ProcessPacket implements ShouldQueue $this->msg->user_from, )); - // @todo Determine if we know about this echo area + $ea = Echoarea::where('name',$this->msg->echoarea) + ->where('domain_id',$this->msg->fftn_o->zone->domain_id) + ->single(); + // @todo Can the sender create it if it doesnt exist? // - Create it, or // - Else record in bad area @@ -155,7 +158,7 @@ class ProcessPacket implements ShouldQueue $o->tzoffset = $this->msg->date->utcOffset(); $o->fftn_id = ($x=$this->msg->fftn_o) ? $x->id : NULL; - $o->echoarea = $this->msg->echoarea; + $o->echoarea_id = $ea?->id; $o->msgid = $this->msg->msgid; $o->msg = $this->msg->message_src; diff --git a/app/Models/Domain.php b/app/Models/Domain.php index ab16d40..db8f5f2 100644 --- a/app/Models/Domain.php +++ b/app/Models/Domain.php @@ -23,6 +23,16 @@ class Domain extends Model /* RELATIONS */ + public function echoareas() + { + return $this->hasMany(Echoarea::class); + } + + public function fileareas() + { + return $this->hasMany(Filearea::class); + } + public function zones() { return $this->hasMany(Zone::class); diff --git a/app/Models/Echoarea.php b/app/Models/Echoarea.php new file mode 100644 index 0000000..81a732f --- /dev/null +++ b/app/Models/Echoarea.php @@ -0,0 +1,31 @@ +belongsToMany(Address::class); + } + + public function domain() + { + return $this->belongsTo(Domain::class); + } + + public function echomail() + { + return Echomail::select('*') + ->where('echoarea_id',$this->id); + } +} \ No newline at end of file diff --git a/app/Models/Echomail.php b/app/Models/Echomail.php index 247d7b1..857388b 100644 --- a/app/Models/Echomail.php +++ b/app/Models/Echomail.php @@ -2,17 +2,22 @@ namespace App\Models; -use Carbon\Exceptions\Exception; use Jenssegers\Mongodb\Eloquent\Model; use Jenssegers\Mongodb\Eloquent\SoftDeletes; use App\Classes\FTN\Message; use App\Interfaces\Packet; -use App\Traits\{MsgID,UseMongo}; +use App\Traits\{EncodeUTF8,MsgID,UseMongo}; class Echomail extends Model implements Packet { - use SoftDeletes,MsgID,UseMongo; + use SoftDeletes,MsgID,UseMongo,EncodeUTF8; + + protected $collection = FALSE; + + private const cast_utf8 = [ + 'msg' + ]; protected $dates = ['datetime']; @@ -28,6 +33,11 @@ class Echomail extends Model implements Packet /* METHODS */ + public function jsonSerialize(): array + { + return $this->encode(); + } + /** * Return this model as a packet */ diff --git a/app/Models/Filearea.php b/app/Models/Filearea.php new file mode 100644 index 0000000..d96437a --- /dev/null +++ b/app/Models/Filearea.php @@ -0,0 +1,25 @@ +belongsToMany(Address::class); + } + + public function domain() + { + return $this->belongsTo(Domain::class); + } +} \ No newline at end of file diff --git a/app/Models/Netmail.php b/app/Models/Netmail.php index f859670..ddbe44e 100644 --- a/app/Models/Netmail.php +++ b/app/Models/Netmail.php @@ -90,7 +90,6 @@ class Netmail extends Model implements Packet $o->via = $via; - return $o; } } \ No newline at end of file diff --git a/app/Traits/EncodeUTF8.php b/app/Traits/EncodeUTF8.php new file mode 100644 index 0000000..c1affdb --- /dev/null +++ b/app/Traits/EncodeUTF8.php @@ -0,0 +1,50 @@ +getProperties(); + + $class = get_class($this); + + foreach ($properties as $property) { + // Dont serialize the validation error + if ($property->name == 'errors') + continue; + + if ($property->isStatic()) { + continue; + } + + $property->setAccessible(true); + + if (! $property->isInitialized($this)) { + continue; + } + + $name = $property->getName(); + $encode = in_array($name,self::cast_utf8); + + if ($property->isPrivate()) { + $name = "\0{$class}\0{$name}"; + } elseif ($property->isProtected()) { + $name = "\0*\0{$name}"; + } + + $property->setAccessible(true); + $value = $property->getValue($this); + + $values[$name] = $encode ? utf8_encode($value) : $value; + } + + return $values; + } +} \ No newline at end of file diff --git a/database/migrations/2021_08_10_130352_echomail.php b/database/migrations/2021_08_10_130352_echomail.php new file mode 100644 index 0000000..f1b6bc9 --- /dev/null +++ b/database/migrations/2021_08_10_130352_echomail.php @@ -0,0 +1,97 @@ +id(); + $table->timestamps(); + $table->softDeletes(); + $table->string('name'); + $table->string('description'); + $table->boolean('active'); + $table->boolean('public'); + $table->string('notes')->nullable(); + + $table->integer('domain_id'); + $table->foreign('domain_id')->references('id')->on('domains'); + }); + + Schema::create('fileareas', function (Blueprint $table) { + $table->id(); + $table->timestamps(); + $table->softDeletes(); + $table->string('name'); + $table->string('description'); + $table->boolean('active'); + $table->boolean('public'); + $table->string('notes')->nullable(); + + $table->integer('domain_id'); + $table->foreign('domain_id')->references('id')->on('domains'); + }); + + Schema::create('address_echoarea', function (Blueprint $table) { + $table->integer('echoarea_id'); + $table->foreign('echoarea_id')->references('id')->on('echoareas'); + + $table->integer('address_id'); + $table->foreign('address_id')->references('id')->on('addresses'); + + $table->dateTime('subscribed'); + }); + + Schema::create('address_filearea', function (Blueprint $table) { + $table->integer('filearea_id'); + $table->foreign('filearea_id')->references('id')->on('fileareas'); + + $table->integer('address_id'); + $table->foreign('address_id')->references('id')->on('addresses'); + + $table->dateTime('subscribed'); + }); + + Schema::create('address_echomail', function (Blueprint $table) { + $table->integer('echomail_id'); + $table->string('packet'); + + $table->integer('address_id'); + $table->foreign('address_id')->references('id')->on('addresses'); + }); + + Schema::create('address_file', function (Blueprint $table) { + $table->integer('filearea_id'); + $table->boolean('sent'); + + $table->integer('address_id'); + $table->foreign('address_id')->references('id')->on('addresses'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('address_file'); + Schema::dropIfExists('address_echomail'); + + Schema::dropIfExists('address_filearea'); + Schema::dropIfExists('fileareas'); + + Schema::dropIfExists('address_echoarea'); + Schema::dropIfExists('echoareas'); + } +} diff --git a/database/seeders/InitialSetupSeeder.php b/database/seeders/InitialSetupSeeder.php index 77965c6..329fe7b 100644 --- a/database/seeders/InitialSetupSeeder.php +++ b/database/seeders/InitialSetupSeeder.php @@ -78,5 +78,19 @@ class InitialSetupSeeder extends Seeder 'active'=>TRUE, 'password'=>'$2y$10$bJQDLfxnKrh6o5Sa02MZOukXcLTNQiByXSTJ7fTr.kHMpV2wxbG6.', ]); + + DB::table('echoareas')->insert([ + 'name'=>'-BAD_AREA', + 'description'=>'Inbound invalid echomail', + 'active'=>TRUE, + 'domain_id'=>$do->id, + ]); + + DB::table('fileareas')->insert([ + 'name'=>'-BAD_AREA', + 'description'=>'Inbound invalid files', + 'active'=>TRUE, + 'domain_id'=>$do->id, + ]); } } diff --git a/resources/views/domain/view.blade.php b/resources/views/domain/view.blade.php index e5b685a..cae4845 100644 --- a/resources/views/domain/view.blade.php +++ b/resources/views/domain/view.blade.php @@ -26,7 +26,27 @@
- @if(FALSE) + @if($o->echoareas->count()) +

This network provides the following Echomail areas:

+ + + + + + + + + + + @foreach ($o->echoareas->sortBy('name') as $oo) + + + + + + @endforeach + +
EchoareaDescriptionLast Message
{{ $oo->name }}{{ $oo->description }}{{ ($x=$oo->echomail()->orderBy('created_at','DESC')->first()) ? $x->created_at->format('Y-m-d H:i') : '-' }}
@else This network doesnt have any Echomail areas (yet). Perhaps you would like to create one? @endif @@ -40,7 +60,27 @@
- @if(FALSE) + @if($o->fileareas->count()) +

This network provides the following File areas:

+ + + + + + + + + + + @foreach ($o->fileareas->sortBy('name') as $oo) + + + + + + @endforeach + +
FileareaDescriptionLast File Sent
{{ $oo->name }}{{ $oo->description }}-
@else This network doesnt have any File areas (yet). Perhaps you would like to create one? @endif diff --git a/resources/views/echoarea/addedit.blade.php b/resources/views/echoarea/addedit.blade.php new file mode 100644 index 0000000..3b26c64 --- /dev/null +++ b/resources/views/echoarea/addedit.blade.php @@ -0,0 +1,115 @@ +@extends('layouts.app') + +@section('htmlheader_title') + @if($o->exists) Update @else Add @endif Echoarea +@endsection + +@section('content') +
+ @csrf + +
+
+
+

@if($o->exists) Update @else Add @endif Echoarea

+ +
+
+ +
+ + + + @error('domain_id') + {{ $message }} + @else + A domain is required. + @enderror + + Add a NEW Domain +
+
+ +
+ +
+ + + + @error('name') + {{ $message }} + @else + A name is required. + @enderror + +
+
+ +
+ +
+
+ active ?? TRUE))checked @endif> + + + active ?? TRUE))checked @endif> + +
+
+
+ +
+ +
+
+ public ?? TRUE))checked @endif> + + + public ?? TRUE))checked @endif> + +
+
+
+
+ +
+
+ +
+ + + + @error('description') + {{ $message }} + @enderror + +
+
+ +
+ +
+
+ + +
+
+ +
+
+ Cancel + @can('admin',$o) + + @endcan +
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/echoarea/home.blade.php b/resources/views/echoarea/home.blade.php new file mode 100644 index 0000000..d3d0a55 --- /dev/null +++ b/resources/views/echoarea/home.blade.php @@ -0,0 +1,68 @@ +@extends('layouts.app') +@section('htmlheader_title') + Echoareas +@endsection + +@section('content') +
+
+

About Echoareas

+

BBS Systems exchange public messages called echomail. Echomail is grouped into echoareas normally around a theme or a topic.

+

Each echoarea has a unique areatag which helps a receiving BBS to know where to file the message when it is received.

+
+
+ +
+
+

This system is aware of the following echoareas:

+ + @if (\App\Models\Echoarea::count() == 0) + @can('admin',(new \App\Models\Echoarea)) +

There are no echoareas setup, to set up your first.

+ @else +

There are no echoareas - you need to ask an admin to create one for you.

+ @endcan + @else + + + + + + + + + + + + + @can('admin',(new \App\Models\Echoarea)) + + + + @endcan + @foreach (\App\Models\Echoarea::orderBy('name')->with(['domain'])->get() as $oo) + + + + + + + + @endforeach + +
IDAreatagDescriptionActiveDomain
Add New Echoarea
{{ $oo->id }}{{ $oo->name }}{{ $oo->description }}{{ $oo->active ? 'YES' : 'NO' }}{{ $oo->domain->name }}
+ @endif +
+
+@endsection + +@section('page-scripts') + +@append diff --git a/resources/views/filearea/addedit.blade.php b/resources/views/filearea/addedit.blade.php new file mode 100644 index 0000000..7296942 --- /dev/null +++ b/resources/views/filearea/addedit.blade.php @@ -0,0 +1,115 @@ +@extends('layouts.app') + +@section('htmlheader_title') + @if($o->exists) Update @else Add @endif Filearea +@endsection + +@section('content') +
+ @csrf + +
+
+
+

@if($o->exists) Update @else Add @endif Filearea

+ +
+
+ +
+ + + + @error('domain_id') + {{ $message }} + @else + A domain is required. + @enderror + + Add a NEW Domain +
+
+ +
+ +
+ + + + @error('name') + {{ $message }} + @else + A name is required. + @enderror + +
+
+ +
+ +
+
+ active ?? TRUE))checked @endif> + + + active ?? TRUE))checked @endif> + +
+
+
+ +
+ +
+
+ public ?? TRUE))checked @endif> + + + public ?? TRUE))checked @endif> + +
+
+
+
+ +
+
+ +
+ + + + @error('description') + {{ $message }} + @enderror + +
+
+ +
+ +
+
+ + +
+
+ +
+
+ Cancel + @can('admin',$o) + + @endcan +
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/filearea/home.blade.php b/resources/views/filearea/home.blade.php new file mode 100644 index 0000000..34589f2 --- /dev/null +++ b/resources/views/filearea/home.blade.php @@ -0,0 +1,68 @@ +@extends('layouts.app') +@section('htmlheader_title') + Fileareas +@endsection + +@section('content') +
+
+

About Fileareas

+

BBS Systems exchange area able to exchange and distribute files. Files are grouped into fileareas normally around a theme or type.

+

Each filerea has a unique filetag which helps a receiving BBS to know where to store the file when it is received.

+
+
+ +
+
+

This system is aware of the following fileareas:

+ + @if (\App\Models\Filearea::count() == 0) + @can('admin',(new \App\Models\Filearea)) +

There are no fileareas setup, to set up your first.

+ @else +

There are no fileareas - you need to ask an admin to create one for you.

+ @endcan + @else + + + + + + + + + + + + + @can('admin',(new \App\Models\Filearea)) + + + + @endcan + @foreach (\App\Models\Filearea::orderBy('name')->with(['domain'])->get() as $oo) + + + + + + + + @endforeach + +
IDFiletagDescriptionActiveDomain
Add New Filearea
{{ $oo->id }}{{ $oo->name }}{{ $oo->description }}{{ $oo->active ? 'YES' : 'NO' }}{{ $oo->domain->name }}
+ @endif +
+
+@endsection + +@section('page-scripts') + +@append diff --git a/resources/views/layouts/partials/sidebar.blade.php b/resources/views/layouts/partials/sidebar.blade.php index e752665..879df69 100644 --- a/resources/views/layouts/partials/sidebar.blade.php +++ b/resources/views/layouts/partials/sidebar.blade.php @@ -5,7 +5,9 @@
Network Admin
Domains
Systems
-
Zones
+
Zones
+
Echoareas
+
Fileareas
diff --git a/routes/web.php b/routes/web.php index b94a304..8f6520a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,7 +3,13 @@ use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Route; -use App\Http\Controllers\{HomeController,DomainController,NodeController,SystemController,UserController,ZoneController}; +use App\Http\Controllers\{HomeController, + DomainController, + EchoareaController, + FileareaController, + SystemController, + UserController, + ZoneController}; use App\Http\Controllers\Auth\LoginController; /* @@ -35,6 +41,14 @@ Route::middleware(['verified','activeuser'])->group(function () { Route::match(['get','post'],'ftn/domain/addedit/{o?}',[DomainController::class,'add_edit']) ->where('o','[0-9]+'); + Route::get('ftn/echoarea',[EchoareaController::class,'home']); + Route::match(['get','post'],'ftn/echoarea/addedit/{o?}',[EchoareaController::class,'add_edit']) + ->where('o','[0-9]+'); + + Route::get('ftn/filearea',[FileareaController::class,'home']); + Route::match(['get','post'],'ftn/filearea/addedit/{o?}',[FileareaController::class,'add_edit']) + ->where('o','[0-9]+'); + Route::get('ftn/system',[SystemController::class,'home']); Route::match(['get','post'],'ftn/system/addedit/{o?}',[SystemController::class,'add_edit']) ->where('o','[0-9]+');