Enabled user registration

This commit is contained in:
Deon George 2018-12-25 12:48:57 +11:00
parent cb2d7936d0
commit 128002f434
26 changed files with 854 additions and 149 deletions

48
app/Classes/Control.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace App\Classes;
use App\Classes\Control\Register;
use App\Classes\Control\Telnet;
abstract class Control
{
protected $complete = FALSE;
protected $so = NULL;
public $state = [];
public function __construct(Server $so) {
$this->so = $so;
$this->boot();
}
// Default boot method if a child class doesnt have one.
protected function boot() {
$this->state['mode'] = FALSE;
}
/**
* Has control completed?
*/
public function complete()
{
return $this->complete;
}
// @todo Change to Dynamic Calls by the existence of files in App\Classes\Control
public static function factory(string $name, Server $so) {
switch ($name) {
case 'register':
return new Register($so);
case 'telnet':
return new Telnet($so);
default:
throw new \Exception('Unknown control method: '.$name);
}
}
abstract public function handle(string $char);
}

View File

@ -0,0 +1,190 @@
<?php
namespace App\Classes\Control;
use App\Classes\Control;
use App\Mail\SendToken;
use App\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
/**
* Class Register handles registration
*
* @todo REMOVE the force .WHITE at the end of each sendBaseline()
*
* @package App\Classes\Control
*/
class Register extends Control
{
private $data = [];
protected function boot()
{
$this->so->sendBaseline($this->so->client(),GREEN.'Select User Name'.WHITE);
}
/**
* Handle Registration Form Input
*
* This function assumes the form has 7 fields in a specific order.
*
* @todo Make this form more dynamic, or put some configuration in a config file, so that there is flexibility
* in field placement.
* @param string $read
* @param array $current
* @return string
*/
public function handle(string $read,array $current=[])
{
// Ignore CR
if ($read == CR)
return '';
// If we got a # we'll be completing field input.
if ($read == HASH OR $read == LF) {
// Our registration page
// @todo get this from the DB
if ($current['page']['frame'] == '981') {
// Does our field have data...
if (array_get($current['fielddata'],$current['fieldnum'])) {
switch ($current['fieldnum']) {
// Username
case 0:
// See if the requested username already exists
if (User::where('login', $current['fielddata'][$current['fieldnum']])->exists()) {
$this->so->sendBaseline($this->so->client(), RED . 'USER ALREADY EXISTS'.WHITE);
return '';
}
$this->data['user'] = $current['fielddata'][$current['fieldnum']];
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Real Name'.WHITE);
break;
// Real Name
case 1:
$this->data['name'] = $current['fielddata'][$current['fieldnum']];
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Email Address'.WHITE);
break;
// Email Address
case 2:
if (Validator::make(['email'=>$current['fielddata'][$current['fieldnum']]],[
'email'=>'email',
])->fails()) {
$this->so->sendBaseline($this->so->client(), RED . 'INVALID EMAIL ADDRESS'.WHITE);
return '';
};
// See if the requested email already exists
if (User::where('email', $current['fielddata'][$current['fieldnum']])->exists()) {
$this->so->sendBaseline($this->so->client(), RED . 'USER ALREADY EXISTS'.WHITE);
return '';
}
$this->data['email'] = $current['fielddata'][$current['fieldnum']];
$this->data['token'] = sprintf('%06.0f',rand(0,999999));
$this->so->sendBaseline($this->so->client(), YELLOW . 'PROCESSING...'.WHITE);
Mail::to($this->data['email'])->sendNow(new SendToken($this->data['token']));
if (Mail::failures()) {
dump('Failure?');
dump(Mail::failures());
}
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Password'.WHITE);
break;
// Enter Password
case 3:
$this->data['password'] = $current['fielddata'][$current['fieldnum']];
$this->so->sendBaseline($this->so->client(), GREEN . 'Confirm Password'.WHITE);
break;
// Confirm Password
case 4:
if ($this->data['password'] !== $current['fielddata'][$current['fieldnum']]) {
$this->so->sendBaseline($this->so->client(), RED . 'PASSWORD DOESNT MATCH, *09 TO START AGAIN'.WHITE);
return '';
}
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter Location'.WHITE);
break;
// Enter Location
case 5:
$this->data['location'] = $current['fielddata'][$current['fieldnum']];
$this->so->sendBaseline($this->so->client(), GREEN . 'Enter TOKEN emailed to you'.WHITE);
break;
// Enter Token
case 6:
if ($this->data['token'] !== $current['fielddata'][$current['fieldnum']]) {
$this->so->sendBaseline($this->so->client(), RED . 'TOKEN DOESNT MATCH, *09 TO START AGAIN'.WHITE);
return '';
}
break;
default:
$this->so->sendBaseline($this->so->client(), RED . 'HUH?');
}
} else {
// If we are MODE_BL, we need to return the HASH, otherwise nothing.
if (in_array($this->state['mode'],[MODE_BL,MODE_SUBMITRF,MODE_RFNOTSENT])) {
return $read;
} else {
$this->so->sendBaseline($this->so->client(), RED . 'FIELD REQUIRED...'.WHITE);
return '';
}
}
}
}
return $read;
}
public function process()
{
$o = new User;
$o->login = $this->data['user'];
$o->email = $this->data['email'];
$o->password = $this->data['password'];
$o->name = $this->data['name'];
$o->location = $this->data['location'];
try {
$o->save();
$this->so->sendBaseline($this->so->client(), GREEN . 'ACCOUNT CREATED, PRESS '.HASH.' TO CONTINUE...'.WHITE);
$this->state['action'] = ACTION_NEXT;
// Add to CUG 0
$o->cugs()->attach(0);
} catch (\Exception $e) {
$this->so->sendBaseline($this->so->client(), RED . 'SOMETHING WENT WRONG...'.WHITE);
$this->so->log('error',$e->getMessage());
$this->state['action'] = ACTION_RELOAD;
}
$this->complete = TRUE;
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace App\Classes\Control;
use App\Classes\Control;
/**
* Class Telnet
*
* This class looks after any telnet session commands
*
* TELNET http://pcmicro.com/netfoss/telnet.html
*
* @package App\Classes\Control
*/
class Telnet extends Control
{
private $option = FALSE;
private $note = '';
private $terminal = '';
public function handle(string $read)
{
$this->state['mode'] = FALSE;
$this->so->log('debug',sprintf('Session Char (%s)',ord($read)),['complete'=>$this->complete,'option'=>$this->option]);
switch ($read) {
// Command being sent.
case TCP_IAC:
$this->complete = FALSE;
$this->note = 'IAC ';
break;
case TCP_SB:
$this->option = TRUE;
break;
case TCP_SE:
$this->option = FALSE;
$this->complete = TRUE;
$this->so->log('debug',sprintf('Session Terminal: %s',$this->terminal));
break;
case TCP_DO:
$this->note .= 'DO ';
break;
case TCP_WILL:
$this->note .= 'WILL ';
break;
case TCP_WONT:
$this->note .= 'WONT ';
break;
case TCP_OPT_TERMTYPE:
break;
case TCP_OPT_ECHO:
$this->note .= 'ECHO';
$this->complete = TRUE;
$this->so->log('debug',sprintf('Session Note: %s',$this->note));
break;
case TCP_OPT_SUP_GOAHEAD:
$this->note .= 'SUPPRESS GO AHEAD';
$this->complete = TRUE;
$this->so->log('debug',sprintf('Session Note: %s',$this->note));
break;
case TCP_OPT_WINDOWSIZE:
$this->note .= 'WINDOWSIZE';
$this->complete = TRUE;
$this->so->log('debug',sprintf('Session Note: %s',$this->note));
break;
default:
if ($this->option AND $read) {
$this->terminal .= $read;
} else {
$this->so->log('debug',sprintf('Unhandled char in session_init: %s (%s)',$read,ord($read)));
}
}
return '';
}
}

View File

@ -280,7 +280,7 @@ abstract class Frame
*/ */
public function isFramePublic(): bool public function isFramePublic(): bool
{ {
return $this->frame->closed ? FALSE : TRUE; return $this->frame->public ? TRUE : FALSE;
} }
// @todo To implement // @todo To implement
@ -401,7 +401,7 @@ abstract class Frame
$o->frame = 999; $o->frame = 999;
$o->index = 'a'; $o->index = 'a';
$o->access = 1; $o->access = 1;
$o->closed = 0; $o->public = 1;
$o->cls = 1; $o->cls = 1;
// Header // Header

View File

@ -2,6 +2,6 @@
namespace App\Classes; namespace App\Classes;
class Parser abstract class Parser
{ {
} }

View File

@ -16,6 +16,7 @@ abstract class Server {
private $mo = NULL; // Our Mode object private $mo = NULL; // Our Mode object
private $co = NULL; private $co = NULL;
protected $blp = 0; // Size of Bottom Line Pollution protected $blp = 0; // Size of Bottom Line Pollution
protected $baseline = ''; // Whats on the baseline currently
protected $pid = NULL; // Client PID protected $pid = NULL; // Client PID
public function __construct(Mode $o) public function __construct(Mode $o)
@ -40,6 +41,9 @@ abstract class Server {
define('ACTION_SUBMITRF', 7); // Offer to submit a response frame define('ACTION_SUBMITRF', 7); // Offer to submit a response frame
define('ACTION_STAR', 8); define('ACTION_STAR', 8);
define('CONTROL_TELNET', 1); // Telnet session control
define('CONTROL_METHOD', 2); // Send input to an external method
// Keyboard presses // Keyboard presses
define('KEY_DELETE', chr(8)); define('KEY_DELETE', chr(8));
define('KEY_LEFT', chr(136)); define('KEY_LEFT', chr(136));
@ -114,9 +118,7 @@ abstract class Server {
// We are now the child. // We are now the child.
try { try {
$session_init = $session_option = FALSE; $session = NULL; // TCP Session Details
$session_note = ''; // TCP Session Notice
$session_term = ''; // TCP Terminal Type
$client->send(TCP_IAC . TCP_DO . TCP_OPT_SUP_GOAHEAD); // DO SUPPRES GO AHEAD $client->send(TCP_IAC . TCP_DO . TCP_OPT_SUP_GOAHEAD); // DO SUPPRES GO AHEAD
$client->send(TCP_IAC . TCP_WONT . TCP_OPT_LINEMODE); // WONT LINEMODE $client->send(TCP_IAC . TCP_WONT . TCP_OPT_LINEMODE); // WONT LINEMODE
@ -134,6 +136,8 @@ abstract class Server {
$cmd = ''; // Current *command being typed in $cmd = ''; // Current *command being typed in
$mode = FALSE; // Current mode. $mode = FALSE; // Current mode.
$user = new User; // The logged in user $user = new User; // The logged in user
$control = FALSE; // Logic in control
$method = collect(); // Method in control for CONTROL_METHOD
$current = []; // Attributes about the current page $current = []; // Attributes about the current page
// field/fieldnum indexes are for fields on the active page // field/fieldnum indexes are for fields on the active page
@ -161,85 +165,52 @@ abstract class Server {
$read = NULL; $read = NULL;
if ($read != '') { if ($read != '') {
// Client initiation input if ($read == TCP_IAC) {
// TELNET http://pcmicro.com/netfoss/telnet.html
if ($read == TCP_IAC OR $session_init OR $session_option) {
$this->log('debug',sprintf('Session Char (%s)',ord($read)),['init'=>$session_init,'option'=>$session_option]);
switch ($read) { // If we are not already in a TELNET LOOP
// Command being sent. if ($control !== CONTROL_TELNET) {
case TCP_IAC: $control = CONTROL_TELNET;
$session_init = TRUE;
$session_note = 'IAC ';
continue 2; // Remember our Telnet Session Object
// @todo We might need to clear out the old mode/action states
if (! $session) {
$session = Control::factory('telnet',$this);
}
case TCP_SB: $method->push($session);
$session_option = TRUE; }
}
continue 2; if ($control AND $method->count()) {
printf("= Control going to method: %s\n", get_class($method->last()));
case TCP_SE: // Capture our state when we enter this method.
$session_option = $session_init = FALSE; if (! array_key_exists('control',$method->last()->state)) {
$this->log('debug',sprintf('Session Terminal: %s',$session_term)); $method->last()->state['control'] = $control;
$read = ''; $method->last()->state['action'] = $action;
}
break; $method->last()->state['mode'] = $mode;
$action = FALSE;
case TCP_DO: // Pass Control to Method
$session_note .= 'DO '; $read = $method->last()->handle($read,$current);
$mode = $method->last()->state['mode'];
continue 2; if ($method->last()->complete()) {
printf("- Control complete: %s\n",get_class($method->last()));
$save = $method->pop();
case TCP_WILL: if ($method->count()) {
$session_note .= 'WILL '; $control = $method->last()->state['control'];
continue 2;
case TCP_WONT:
$session_note .= 'WONT ';
continue 2;
case TCP_OPT_TERMTYPE:
continue 2;
case TCP_OPT_ECHO:
$session_note .= 'ECHO';
$session_init = FALSE;
$read = '';
$this->log('debug',sprintf('Session Note: %s',$session_note));
continue;
case TCP_OPT_SUP_GOAHEAD:
$session_note .= 'SUPPRESS GO AHEAD';
$session_init = FALSE;
$read = '';
$this->log('debug',sprintf('Session Note: %s',$session_note));
continue;
case TCP_OPT_WINDOWSIZE:
$session_note .= 'WINDOWSIZE';
$session_init = FALSE;
$read = '';
$this->log('debug',sprintf('Session Note: %s',$session_note));
continue;
default:
if ($session_option AND $read) {
$session_term .= $read;
$read = '';
} else { } else {
$this->log('debug',sprintf('Unhandled char in session_init: %s (%s)',$read,ord($read))); $mode = $save->state['mode'];
$action = $save->state['action'];
$control = FALSE;
} }
dump(sprintf('End: Control is now: %s: Method Count: %s',is_object($control) ? get_class($control) : serialize($control),$method->count()));
} }
} }
@ -261,6 +232,8 @@ abstract class Server {
{ {
$action = ACTION_GOTO; $action = ACTION_GOTO;
$page = ['frame'=>'981']; // @todo This should be in the DB. $page = ['frame'=>'981']; // @todo This should be in the DB.
break 2;
} }
} }
@ -303,6 +276,7 @@ abstract class Server {
$action = ACTION_STAR; $action = ACTION_STAR;
$current['fieldpos'] = 0; $current['fieldpos'] = 0;
$fielddata[$current['fieldnum']] = ''; $fielddata[$current['fieldnum']] = '';
$current['fielddata'][$current['fieldnum']] = '';
break; break;
@ -312,6 +286,7 @@ abstract class Server {
$current['fieldpos']--; $current['fieldpos']--;
$client->send(LEFT.$fo::$if_filler.LEFT); $client->send(LEFT.$fo::$if_filler.LEFT);
$fielddata[$current['fieldnum']] = substr($fielddata[$current['fieldnum']],0,-1); $fielddata[$current['fieldnum']] = substr($fielddata[$current['fieldnum']],0,-1);
$current['fielddata'][$current['fieldnum']] = substr($current['fielddata'][$current['fieldnum']],0,-1);
} }
break; break;
@ -360,15 +335,19 @@ abstract class Server {
break; break;
case ESC: case ESC:
break;; break;
// Record Data Entry // Record Data Entry
default: default:
if (ord($read) > 31 && $current['fieldpos'] < $current['field']->length) { if (ord($read) > 31 && $current['fieldpos'] < $current['field']->length) {
if (! array_get($fielddata,$current['fieldnum'])) if (! array_key_exists($current['fieldnum'],$current['fielddata'])) {
$current['fielddata'][$current['fieldnum']] = '';
$fielddata[$current['fieldnum']] = ''; $fielddata[$current['fieldnum']] = '';
}
$fielddata[$current['fieldnum']]{$current['fieldpos']} = $read; // @todo delete
$current['fielddata'][$current['fieldnum']]{$current['fieldpos']} = $read;
$fielddata[$current['fieldnum']]{$current['fieldpos']} = $read;
$current['fieldpos']++; $current['fieldpos']++;
$client->send($fo->isFieldMasked($current['field']->type) ?: $read); $client->send($fo->isFieldMasked($current['field']->type) ?: $read);
@ -393,7 +372,11 @@ abstract class Server {
case '1': case '1':
$route = $fo->route(1); $route = $fo->route(1);
if ($route == '*' OR is_numeric($route)) { // If we are in a control method, complete it
if ($control AND $method->count()) {
$method->last()->process();
} elseif ($route == '*' OR is_numeric($route)) {
$this->sendBaseline($client,RED.'NO ACTION PERFORMED'); $this->sendBaseline($client,RED.'NO ACTION PERFORMED');
$mode = MODE_RFSENT; $mode = MODE_RFSENT;
@ -415,9 +398,13 @@ abstract class Server {
break; break;
case '2': case '2':
$this->sendBaseline($client,MSG_NOTSENT);; $this->sendBaseline($client,MSG_NOTSENT);
$mode = MODE_RFNOTSENT; $mode = MODE_RFNOTSENT;
// If a Control method was rejected, we can clear it
if ($control AND $method->count())
$method->pop();
break; break;
case STAR: case STAR:
@ -564,6 +551,7 @@ abstract class Server {
} }
// Toggle Timewarp Mode // Toggle Timewarp Mode
// @todo in forms, the cursor is in the wrong location for ANSI
if ($cmd === '01') { if ($cmd === '01') {
$client->send(COFF); $client->send(COFF);
$timewarp = !$timewarp; $timewarp = !$timewarp;
@ -575,6 +563,7 @@ abstract class Server {
} }
// Present Timewarp Frames // Present Timewarp Frames
// @todo in forms, the cursor is in the wrong location for ANSI
if ($cmd === '02') { if ($cmd === '02') {
$client->send(COFF); $client->send(COFF);
$action = ACTION_INFO; $action = ACTION_INFO;
@ -583,6 +572,14 @@ abstract class Server {
break; break;
} }
// Report a problem
if ($cmd === '08') {
$this->sendBaseline($client, RED.'NOT IMPLEMENTED YET?');
$read = STAR;
break;
}
// Reload page // Reload page
if ($cmd === '09') { if ($cmd === '09') {
$client->send(COFF); $client->send(COFF);
@ -595,12 +592,14 @@ abstract class Server {
// Another star aborts the command. // Another star aborts the command.
if ($read === STAR) { if ($read === STAR) {
$action = FALSE; $action = FALSE;
$this->sendBaseline($client,''); $this->sendBaseline($client,array_get($current,'baseline',''));
$cmd = ''; $cmd = '';
if ($current['prevmode'] == MODE_FIELD) { if ($current['prevmode'] == MODE_FIELD) {
$mode = $current['prevmode']; $mode = $current['prevmode'];
$current['prevmode'] = FALSE; $current['prevmode'] = FALSE;
// @todo The cursor color could be wrong
$client->send($this->outputPosition($current['field']->x,$current['field']->y).CON); $client->send($this->outputPosition($current['field']->x,$current['field']->y).CON);
$client->send(str_repeat($fo::$if_filler, $current['field']->length)); $client->send(str_repeat($fo::$if_filler, $current['field']->length));
$current['fieldreset'] = TRUE; $current['fieldreset'] = TRUE;
@ -654,6 +653,10 @@ abstract class Server {
case ACTION_STAR: case ACTION_STAR:
echo "+ Star command...\n"; echo "+ Star command...\n";
// If there is something on the baseline, lets preserve it
if ($this->blp)
$current['baseline'] = $this->baseline;
$this->sendBaseline($client,GREEN.STAR,TRUE); $this->sendBaseline($client,GREEN.STAR,TRUE);
$client->send(CON); $client->send(CON);
$action = FALSE; $action = FALSE;
@ -773,6 +776,8 @@ abstract class Server {
$history->push($page); $history->push($page);
} }
printf("+ Mode is: %s\n",$mode);
// drop into // drop into
case ACTION_RELOAD: case ACTION_RELOAD:
$this->sendBaseline($client,''); $this->sendBaseline($client,'');
@ -793,11 +798,25 @@ abstract class Server {
// Login Frame. // Login Frame.
case Frame::FRAMETYPE_LOGIN: case Frame::FRAMETYPE_LOGIN:
$client->send($output);
$output = '';
// If this is the registration page
// @todo Should be evaluated out of the DB
if ($fo->page() == '981a') {
$control = CONTROL_METHOD;
$method->push(Control::factory('register',$this));
$method->last()->state['control'] = $control;
$method->last()->state['action'] = $action;
$method->last()->state['mode'] = MODE_FIELD;
}
// Active Frame. Prestel uses this for a Response Frame. // Active Frame. Prestel uses this for a Response Frame.
case Frame::FRAMETYPE_ACTION: case Frame::FRAMETYPE_ACTION:
$client->send($output); $client->send($output);
// holds data entered by user. // holds data entered by user.
$fielddata = []; $fielddata = [];
$current['fielddata'] = [];
if (count($fo->fields)) { if (count($fo->fields)) {
// Get our first editable field. // Get our first editable field.

View File

@ -13,6 +13,8 @@ class Ansi extends AbstractServer {
define('ESC', chr(27)); define('ESC', chr(27));
define('CON', ESC.'[?25h'); // Cursor On define('CON', ESC.'[?25h'); // Cursor On
define('COFF', ESC.'[?25l'); // Cursor Off define('COFF', ESC.'[?25l'); // Cursor Off
define('CSAVE', ESC.'[s'); // Save Cursor position
define('CRESTORE',ESC.'[u'); // Restore to saved position
define('HOME', ESC.'[0;0f'); define('HOME', ESC.'[0;0f');
define('LEFT', ESC.'[D'); // Move Cursor define('LEFT', ESC.'[D'); // Move Cursor
define('RIGHT', ESC.'[C'); // Move Cursor define('RIGHT', ESC.'[C'); // Move Cursor
@ -54,14 +56,15 @@ class Ansi extends AbstractServer {
// Abstract function // Abstract function
public function sendBaseline($client,$text,$reposition=FALSE) { public function sendBaseline($client,$text,$reposition=FALSE) {
$client->send(ESC.'[24;0f'.$text. $client->send(CSAVE.ESC.'[24;0f'.$text.
($this->blp > $this->strlenv($text) ($this->blp > $this->strlenv($text)
? str_repeat(' ',$this->blp-$this->strlenv($text)). ? str_repeat(' ',$this->blp-$this->strlenv($text)).
($reposition ? ESC.'[24;0f'.str_repeat(RIGHT,$this->strlenv($text)) : '') ($reposition ? ESC.'[24;0f'.str_repeat(RIGHT,$this->strlenv($text)) : CRESTORE)
: '') : ($reposition ? '' : CRESTORE))
); );
$this->blp = $this->strlenv($text); $this->blp = $this->strlenv($text);
$this->baseline = $text;
} }
// Abstract function // Abstract function

View File

@ -3,6 +3,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Models\Frame; use App\Models\Frame;
use App\Models\Mode;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
@ -15,9 +16,9 @@ class FrameImport extends Command
*/ */
protected $signature = 'frame:import {frame} {index} {file} '. protected $signature = 'frame:import {frame} {index} {file} '.
'{--access=0 : Is frame accessible }'. '{--access=0 : Is frame accessible }'.
'{--closed=1 : Is frame limited to CUG }'. '{--public=0 : Is frame limited to CUG }'.
'{--cost=0 : Frame Cost }'. '{--cost=0 : Frame Cost }'.
'{--mode=1 : Frame Emulation Mode }'. '{--mode=videotex : Frame Emulation Mode }'.
'{--replace : Replace existing frame}'. '{--replace : Replace existing frame}'.
'{--type=i : Frame Type}'. '{--type=i : Frame Type}'.
'{--trim : Trim off header (first 40 chars)}'; '{--trim : Trim off header (first 40 chars)}';
@ -56,12 +57,14 @@ class FrameImport extends Command
if (! file_exists($this->argument('file'))) if (! file_exists($this->argument('file')))
throw new \Exception('File not found: '.$this->argument('file')); throw new \Exception('File not found: '.$this->argument('file'));
$mo = Mode::where('name',$this->option('mode'))->firstOrFail();
$o = new Frame; $o = new Frame;
if ($this->option('replace')) { if ($this->option('replace')) {
try { try {
$o = $o->where('frame',$this->argument('frame')) $o = $o->where('frame',$this->argument('frame'))
->where('index',$this->argument('index')) ->where('index',$this->argument('index'))
->where('mode_id',$this->option('mode')) ->where('mode_id',$mo->id)
->firstOrFail(); ->firstOrFail();
} catch (ModelNotFoundException $e) { } catch (ModelNotFoundException $e) {
@ -72,7 +75,7 @@ class FrameImport extends Command
} else { } else {
$o->frame = $this->argument('frame'); $o->frame = $this->argument('frame');
$o->index = $this->argument('index'); $o->index = $this->argument('index');
$o->mode_id = $this->option('mode'); $o->mode_id = $mo->id;
} }
$o->content = ($this->option('trim')) $o->content = ($this->option('trim'))
@ -80,7 +83,7 @@ class FrameImport extends Command
: file_get_contents($this->argument('file')); : file_get_contents($this->argument('file'));
$o->access = $this->option('access'); $o->access = $this->option('access');
$o->closed = $this->option('closed'); $o->public = $this->option('public');
$o->cost = $this->option('cost'); $o->cost = $this->option('cost');
$o->type = $this->option('type'); $o->type = $this->option('type');

40
app/Mail/SendToken.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Models\Service;
class SendToken extends Mailable
{
use Queueable, SerializesModels;
public $token = '';
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(string $token)
{
$this->token = $token;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this
->markdown('email.sendtoken')
->subject('Token to complete registration')
->with(['token'=>$this->token]);
}
}

View File

@ -25,6 +25,18 @@ class Frame extends Model
}); });
} }
/**
* For cockroachDB, content is a "resource stream"
*
* @return bool|string
*/
public function getContentAttribute()
{
return is_resource($this->attributes['content'])
? stream_get_contents($this->attributes['content'])
: $this->attributes['content'];
}
/** /**
* Return the Page Number * Return the Page Number
* *

View File

@ -13,7 +13,8 @@
"fideloper/proxy": "^4.0", "fideloper/proxy": "^4.0",
"laravel/framework": "5.7.*", "laravel/framework": "5.7.*",
"laravel/tinker": "^1.0", "laravel/tinker": "^1.0",
"lukaszkujawa/php-multithreaded-socket-server": "0.0.*" "lukaszkujawa/php-multithreaded-socket-server": "0.0.*",
"nbj/cockroachdb-laravel": "^0.0.4@alpha"
}, },
"require-dev": { "require-dev": {
"beyondcode/laravel-dump-server": "^1.0", "beyondcode/laravel-dump-server": "^1.0",

61
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "ff208b67c5f938a92c08bec4d362e0b4", "content-hash": "d320d65a20b1a9c380331a5c8b043c98",
"packages": [ "packages": [
{ {
"name": "dnoegel/php-xdg-base-dir", "name": "dnoegel/php-xdg-base-dir",
@ -116,16 +116,16 @@
}, },
{ {
"name": "doctrine/dbal", "name": "doctrine/dbal",
"version": "v2.9.0", "version": "v2.9.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/dbal.git", "url": "https://github.com/doctrine/dbal.git",
"reference": "21fdabe2fc01e004e1966f200d900554876bc63c" "reference": "ec74d6e300d78fbc896669c3ca57ef9719adc9c6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/21fdabe2fc01e004e1966f200d900554876bc63c", "url": "https://api.github.com/repos/doctrine/dbal/zipball/ec74d6e300d78fbc896669c3ca57ef9719adc9c6",
"reference": "21fdabe2fc01e004e1966f200d900554876bc63c", "reference": "ec74d6e300d78fbc896669c3ca57ef9719adc9c6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -194,7 +194,7 @@
"php", "php",
"queryobject" "queryobject"
], ],
"time": "2018-12-04T04:39:48+00:00" "time": "2018-12-14T04:51:13+00:00"
}, },
{ {
"name": "doctrine/event-manager", "name": "doctrine/event-manager",
@ -1065,6 +1065,51 @@
], ],
"time": "2018-11-05T09:00:11+00:00" "time": "2018-11-05T09:00:11+00:00"
}, },
{
"name": "nbj/cockroachdb-laravel",
"version": "0.0.4-alpha",
"source": {
"type": "git",
"url": "https://github.com/nbj/cockroachdb-laravel.git",
"reference": "852ac919fc57e4a483a027287000c6e37234d3c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nbj/cockroachdb-laravel/zipball/852ac919fc57e4a483a027287000c6e37234d3c8",
"reference": "852ac919fc57e4a483a027287000c6e37234d3c8",
"shasum": ""
},
"type": "package",
"extra": {
"laravel": {
"providers": [
"Nbj\\Cockroach\\CockroachServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Nbj\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nikolaj Boel Jensen",
"email": "nbj@cego.dk"
}
],
"description": "CockroachDB driver for Laravel 5.6",
"keywords": [
"cockroach",
"cockroachdb",
"laravel"
],
"time": "2018-09-08T19:28:36+00:00"
},
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "1.36.1", "version": "1.36.1",
@ -4370,7 +4415,9 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "dev", "minimum-stability": "dev",
"stability-flags": [], "stability-flags": {
"nbj/cockroachdb-laravel": 15
},
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {

View File

@ -82,6 +82,25 @@ return [
'prefix_indexes' => true, 'prefix_indexes' => true,
], ],
'cockroach' => [
'driver' => 'cockroach',
'host' => env('DB_HOST', 'HOSTNAME-OF-COCKROACH-SERVER'),
'port' => env('DB_PORT', '26257'),
'database' => env('DB_DATABASE', 'DATABASE-NAME'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
'sslmode' => 'prefer',
// Only set these keys if you want to run en secure mode
// otherwise you can them out of the configuration array
#'sslcert' => env('DB_SSLCERT', 'client.crt'),
#'sslkey' => env('DB_SSLKEY', 'client.key'),
#'sslrootcert' => env('DB_SSLROOTCERT', 'ca.crt'),
],
], ],
/* /*

136
config/mail.php Normal file
View File

@ -0,0 +1,136 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Mail Driver
|--------------------------------------------------------------------------
|
| Laravel supports both SMTP and PHP's "mail" function as drivers for the
| sending of e-mail. You may specify which one you're using throughout
| your application here. By default, Laravel is setup for SMTP mail.
|
| Supported: "smtp", "sendmail", "mailgun", "mandrill", "ses",
| "sparkpost", "log", "array"
|
*/
'driver' => env('MAIL_DRIVER', 'smtp'),
/*
|--------------------------------------------------------------------------
| SMTP Host Address
|--------------------------------------------------------------------------
|
| Here you may provide the host address of the SMTP server used by your
| applications. A default option is provided that is compatible with
| the Mailgun mail service which will provide reliable deliveries.
|
*/
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
/*
|--------------------------------------------------------------------------
| SMTP Host Port
|--------------------------------------------------------------------------
|
| This is the SMTP port used by your application to deliver e-mails to
| users of the application. Like the host we have set this value to
| stay compatible with the Mailgun e-mail application by default.
|
*/
'port' => env('MAIL_PORT', 587),
/*
|--------------------------------------------------------------------------
| Global "From" Address
|--------------------------------------------------------------------------
|
| You may wish for all e-mails sent by your application to be sent from
| the same address. Here, you may specify a name and address that is
| used globally for all e-mails that are sent by your application.
|
*/
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],
/*
|--------------------------------------------------------------------------
| E-Mail Encryption Protocol
|--------------------------------------------------------------------------
|
| Here you may specify the encryption protocol that should be used when
| the application send e-mail messages. A sensible default using the
| transport layer security protocol should provide great security.
|
*/
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
/*
|--------------------------------------------------------------------------
| SMTP Server Username
|--------------------------------------------------------------------------
|
| If your SMTP server requires a username for authentication, you should
| set it here. This will get used to authenticate with your server on
| connection. You may also set the "password" value below this one.
|
*/
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
/*
|--------------------------------------------------------------------------
| Sendmail System Path
|--------------------------------------------------------------------------
|
| When using the "sendmail" driver to send e-mails, we will need to know
| the path to where Sendmail lives on this server. A default path has
| been provided here, which will work well on most of your systems.
|
*/
'sendmail' => '/usr/sbin/sendmail -bs',
/*
|--------------------------------------------------------------------------
| Markdown Mail Settings
|--------------------------------------------------------------------------
|
| If you are using Markdown based email rendering, you may configure your
| theme and component paths here, allowing you to customize the design
| of the emails. Or, you may simply stick with the Laravel defaults!
|
*/
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
/*
|--------------------------------------------------------------------------
| Log Channel
|--------------------------------------------------------------------------
|
| If you are using the "log" driver, you may specify the logging channel
| if you prefer to keep mail messages separate from other log entries
| for simpler reading. Otherwise, the default channel will be used.
|
*/
'log_channel' => env('MAIL_LOG_CHANNEL'),
];

19
data/1a-main.ans Normal file
View File

@ -0,0 +1,19 @@
 ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿
ͳù Õ¸Õ¸ú³ ͳù Õ͸ù³ ÍÔ͸ù Õ; ͳù Õ͸ú³ ddddddddddddddddd ³ ³Ô¾³ ³  ³ ÀÄÙ ³  ²²³ ³°²  ³ ³²³ ³
°³ ³²±³ ³ °³ Õ͸ ³ °°°³ ³²Û °³ ³±³ ³
±³ ³±°³ ³ ±³ ³°³ ³ ±±±³ ³°± ±³ ³°³ ³
ͳù ³Íͳù³ ͳù ³Í³ù³ ÍÚÄÙù ÀÄ¿ ͳù ³Í³ù³  *0# to get back here anytime.  ÔÍ; Ô; ÔÍÍ; Ô; ÔÍÍÍÍÍÍ; ÔÍÍ; Ô;
 ß ß ßßß ßßÜ ßßß ßßß
 Ü Ü Ü Ü Ü Ü Üß  ÜßÜ
 ßßß ß ß ßß ßßß ß ß
ßßß ßßß ßßß ßßß ßßß ßßß ß ß ßßß ßßß ß ßßß ßßß
Ü Ü Ü Ü Ü ßßÜ Ü ÜßÜ Ü Ü ÜÜ Ü Ü Ü Ü Ü
ßßß ßßß ß ß ßßß ß ß ß ßßß ßßß ß ß ßßß ß ß
 1 Messages*90# User Menu
 3 Fido Networks*91# Messages
 5 Directory*95# Help
 8 Help*97# Directory
 9 About this System*99# Log Off

20
data/980a-login.ans Normal file
View File

@ -0,0 +1,20 @@
 ÚÄÄ¿ ÚÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄ¿ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿
ͳù ³Íͳù³Í³ù Õ͸ù³Í³ù ³ÍÍÍÍͳù Õ͸ù³Í³ù Õ͸ù³Í³ù Õ¸Õ¸ú³Í³ù Õ͸ù³Í
°³ ³²Û³ ³ ³ À¿ÀÄÙ°³ ³Û²²² ³ ³²ÀÄÙ°³ ³Û³ ³ ³ ³Ô¾³ ³ ³ À¿ÀÄÙ°
±³ ³Õ¸³ ³°³ ÚÙÚÄ¿±³ ³²ÚÄ¿°³ ³°ÚÄ¿±³ ³²³ ³°³ ³²±³ ³°³ ÚÙÚÄ¿±
²³ ÀÙÀÙ ³±³ ³°³ ³²³ ÀÄÙ ³±³ ³°³ ³²³ ÀÄÙ ³±³ ³±°³ ³±³ ³°³ ³²
ͳùù³Í³ù Ô;ù³Í³ùù³Í³ù Ô;ù³Í³ùù³Í³ù ³Íͳù³Í³ù Ô;ù³Í
 ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍ; Ô; ÔÍÍÍÍÍÍ;
 A vBBS by ....deon 
You have connected to VBBS.
This is a public access ANSItex BBS.
 While this system is currently under development, you are welcome to use it
 and make recommendations.
 If you would like to host your own pages on this system, please let deon
 know.
 User: uuuuuuuuuuu [New Accounts use NEW#]
 Pass: ppppppppppp

18
data/981a-register.ans Normal file
View File

@ -0,0 +1,18 @@
 ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄ¿ ÚÄ¿ ÚÄÄÄ¿ ÚÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄ¿
ͳù Õ͸ú³Í³ù Õ͸ù³Í³ù ³Íͳù³ÍÍͳù ³Í³ù³Í³ùÕÍÍÍÍ;ͳù Õ͸ù³Í³ù Õ͸ù³Í
 ³ ³²³ ³ ³ À¿ÀÄÙ°³ ³²Û³ ³°°°³ ³Û³ ³²³ ÀÄÄÄÄÄ¿ ³ À¿ÀÄÙ ³ ÀÄÙÚÙ°
°³ ³±³ ³°³ ÚÙÚÄ¿±³ ³Õ¸³ ³±±±³ ³²³ ³ÛÔÍÍ͸ ù³°³ ÚÙÚÄ¿°³ Õ͸À¿±
±³ ³°³ ³±³ ³°³ ³²³ ÀÙÀÙ ³²²²³ ÀÄÙ ³²ÚÄÄÄÙ ³±³ ³°³ ³±³ ³°³ ³²
ͳù ³Í³ù³Í³ù Ô;ù³Í³ùù³ÍÍͳùù³Í³ùù³Í³ù Ô;ù³Í³ù ³Í³ù³Í
 ÔÍÍ; Ô; ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍÍÍÍÍÍ; ÔÍÍ; Ô;
 Thanks for your interest! To get started we just need a few details: 
Preferred User Name: ttttttttttt
Real Name: ttttttttttttttttttttttttttttt
Email Address: ttttttttttttttttttttttttttttt
Password: ppppppppppp
Repeat Password: ppppppppppp
Location: ttttttttttttttttttttttttttttt
Token: ttttt

View File

@ -0,0 +1,10 @@

 ß ß ßßß ßßÜ ßßß ßßß
 Ü Ü Ü Ü Ü Ü Üß  ÜßÜ
 ßßß ß ß ßß ßßß ß ß
ßßß ßßß ßßß ßßß ßßß ßßß ß ß ßßß ßßß ß ßßß ßßß
Ü Ü Ü Ü Ü ßßÜ Ü ÜßÜ Ü Ü ÜÜ Ü Ü Ü Ü Ü
ßßß ßßß ß ß ßßß ß ß ß ßßß ßßß ß ß ßßß ß ß
 Lets hope that this frame is installed soon! Please check back another time...
*# to go back...

View File

@ -17,7 +17,7 @@ class InitDatabase extends Migration
Schema::create('modes', function (Blueprint $table) { Schema::create('modes', function (Blueprint $table) {
$table->timestamps(); $table->timestamps();
$table->integer('id')->autoIncrement(); $table->integer('id')->autoIncrement()->index();
$table->string('name',16); $table->string('name',16);
$table->string('note',255); $table->string('note',255);
@ -26,42 +26,37 @@ class InitDatabase extends Migration
Schema::create('cugs', function (Blueprint $table) { Schema::create('cugs', function (Blueprint $table) {
$table->timestamps(); $table->timestamps();
$table->integer('id'); $table->integer('id')->index()->unique();
$table->string('name', 16); $table->string('name', 16);
$table->string('note', 255); $table->string('note', 255);
$table->integer('parent_id')->nullable(); $table->integer('parent_id')->nullable()->index();
});
$table->primary('id'); Schema::table('cugs', function (Blueprint $table) {
$table->foreign('parent_id')->references('id')->on('cugs'); $table->foreign('parent_id')->references('id')->on('cugs');
$table->unique(['name']); $table->unique(['name']);
}); });
Schema::create('frames', function (Blueprint $table) { Schema::create('frames', function (Blueprint $table) {
$table->timestamps(); $table->timestamps();
$table->integer('id')->autoIncrement(); $table->integer('id')->autoIncrement()->index();
$table->integer('frame'); $table->integer('frame');
$table->char('index', 1); $table->char('index', 1);
$table->integer('mode_id'); $table->integer('mode_id')->index();
$table->char('type', 2); $table->char('type', 2);
$table->smallInteger('cost')->default(0); $table->smallInteger('cost')->default(0);
$table->integer('cug_id')->default(0); $table->integer('cug_id')->default(0)->index();
$table->boolean('public')->default(FALSE); $table->boolean('public')->default(FALSE);
$table->binary('content'); $table->binary('content');
$table->string('note', 255)->nullable(); $table->string('note', 255)->nullable();
//$table->unique(['frame','index','mode_id']); // Not needed since we have timewarp //$table->unique(['frame','index','mode_id']); // Not needed since we have timewarp
});
Schema::table('frames', function (Blueprint $table) {
$table->foreign('mode_id')->references('id')->on('modes'); $table->foreign('mode_id')->references('id')->on('modes');
$table->foreign('cug_id')->references('id')->on('cugs'); $table->foreign('cug_id')->references('id')->on('cugs');
}); });
Schema::create('routes', function (Blueprint $table) {
$table->integer('id')->autoIncrement();
$table->char('key',1);
$table->integer('route');
$table->foreign('route')->references('id')->on('frames');
});
} }
/** /**

View File

@ -16,7 +16,7 @@ class CreateFramemeta extends Migration
$this->down(); $this->down();
Schema::create('framemeta', function (Blueprint $table) { Schema::create('framemeta', function (Blueprint $table) {
$table->integer('frame_id')->primary(); $table->integer('frame_id')->index();
$table->string('r0')->default('*'); $table->string('r0')->default('*');
$table->string('r1')->default('*'); $table->string('r1')->default('*');
$table->string('r2')->default('*'); $table->string('r2')->default('*');
@ -28,6 +28,9 @@ class CreateFramemeta extends Migration
$table->string('r8')->default('*'); $table->string('r8')->default('*');
$table->string('r9')->default('*'); $table->string('r9')->default('*');
});
Schema::table('framemeta', function (Blueprint $table) {
$table->foreign('frame_id')->references('id')->on('frames'); $table->foreign('frame_id')->references('id')->on('frames');
}); });
} }

View File

@ -16,9 +16,11 @@ class CreateUserCug extends Migration
$this->down(); $this->down();
Schema::create('cug_users', function (Blueprint $table) { Schema::create('cug_users', function (Blueprint $table) {
$table->integer('cug_id'); $table->integer('cug_id')->index();
$table->integer('user_id')->unsigned(); $table->integer('user_id')->unsigned()->index();
});
Schema::table('cug_users', function (Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users'); $table->foreign('user_id')->references('id')->on('users');
$table->foreign('cug_id')->references('id')->on('cugs'); $table->foreign('cug_id')->references('id')->on('cugs');
$table->unique(['user_id','cug_id']); $table->unique(['user_id','cug_id']);

View File

@ -16,9 +16,11 @@ class CreateCugOwners extends Migration
$this->down(); $this->down();
Schema::create('cug_owners', function (Blueprint $table) { Schema::create('cug_owners', function (Blueprint $table) {
$table->integer('cug_id'); $table->integer('cug_id')->index();
$table->integer('user_id')->unsigned(); $table->integer('user_id')->unsigned()->index();
});
Schema::table('cug_owners', function (Blueprint $table) {
$table->foreign('user_id')->references('id')->on('users'); $table->foreign('user_id')->references('id')->on('users');
$table->foreign('cug_id')->references('id')->on('cugs'); $table->foreign('cug_id')->references('id')->on('cugs');
$table->unique(['user_id','cug_id']); $table->unique(['user_id','cug_id']);

View File

@ -14,7 +14,6 @@ class FrameAddAccess extends Migration
public function up() public function up()
{ {
Schema::table('frames', function (Blueprint $table) { Schema::table('frames', function (Blueprint $table) {
$table->renameColumn('public','closed');
$table->boolean('access')->default(FALSE); $table->boolean('access')->default(FALSE);
$table->dropForeign(['cug_id']); $table->dropForeign(['cug_id']);
$table->dropColumn('cug_id'); $table->dropColumn('cug_id');
@ -30,7 +29,6 @@ class FrameAddAccess extends Migration
{ {
Schema::table('frames', function (Blueprint $table) { Schema::table('frames', function (Blueprint $table) {
$table->dropColumn('access'); $table->dropColumn('access');
$table->renameColumn('closed','public');
$table->integer('cug_id')->default(0); $table->integer('cug_id')->default(0);
$table->foreign('cug_id')->references('id')->on('cugs'); $table->foreign('cug_id')->references('id')->on('cugs');
}); });

View File

@ -13,8 +13,13 @@ class SeedMode extends Seeder
{ {
DB::table('modes')->insert([ DB::table('modes')->insert([
'created_at' => now(), 'created_at' => now(),
'name' => 'VideoTex', 'name' => 'videotex',
'note' => 'Original ViewData/VideoTex 40x25 char mode.', 'note' => 'Original ViewData/VideoTex 40x25 char mode.',
]); ]);
DB::table('modes')->insert([
'created_at' => now(),
'name' => 'ansi',
'note' => 'ANSItex 80x25 char mode.',
]);
} }
} }

View File

@ -0,0 +1,14 @@
@component('mail::message')
# New User Token
Use this token to sign into ANSItex
If this email is a surprise to you, you can ignore it.
@component('mail::panel')
TOKEN: <b>{{ $token }}</b>
@endcomponent
Thanks,
{{ config('app.name') }}
@endcomponent