From 3651a6508a520c092ca4208f2768886f02039fc4 Mon Sep 17 00:00:00 2001 From: Deon George Date: Mon, 3 Dec 2018 23:59:22 +1100 Subject: [PATCH] Created frames table with migration --- app/Classes/Frame.php | 43 +- app/Console/Commands/FrameDelete.php | 61 + app/Console/Commands/FrameImport.php | 84 + app/Console/Commands/Server.php | 1393 ++++++++--------- app/Models/Frame.php | 20 +- app/Traits/HasCompositePrimaryKey.php | 53 + composer.json | 2 +- .../2018_12_03_104758_init_database.php | 79 + database/seeds/DatabaseSeeder.php | 5 +- database/seeds/SeedCUG.php | 21 + database/seeds/SeedMode.php | 20 + 11 files changed, 1049 insertions(+), 732 deletions(-) create mode 100644 app/Console/Commands/FrameDelete.php create mode 100644 app/Console/Commands/FrameImport.php create mode 100644 app/Traits/HasCompositePrimaryKey.php create mode 100644 database/migrations/2018_12_03_104758_init_database.php create mode 100644 database/seeds/SeedCUG.php create mode 100644 database/seeds/SeedMode.php diff --git a/app/Classes/Frame.php b/app/Classes/Frame.php index e262461..29f9322 100644 --- a/app/Classes/Frame.php +++ b/app/Classes/Frame.php @@ -56,7 +56,7 @@ class Frame if (! $this->hasFlag('ip')) { // Set the page header: CUG/Site Name | Page # | Cost $this->output .= $this->render_header($this->header). - $this->render_page($this->frame->frame_id,$this->frame->subframe_id). + $this->render_page($this->frame->frame,$this->frame->index). $this->render_cost($this->frame->cost); } @@ -93,14 +93,14 @@ class Frame for ($x=0;$x<$this->frame_width;$x++) { $posn = $y*40+$x; - $byte = ord(isset($this->frame->frame_content{$posn}) ? $this->frame->frame_content{$posn} : ' ')%128; + $byte = ord(isset($this->frame->content{$posn}) ? $this->frame->content{$posn} : ' ')%128; // dump(sprintf('Y: %s,X: %s, POSN: %s, BYTE: %s',$y,$x,$posn,$byte)); // Check for start-of-field if ($byte == ord(ESC)) { // Esc designates start of field (Esc-K is end of edit) $infield = TRUE; $fieldlength = 0; - $fieldtype = ord(substr($this->frame->frame_content,$posn+1,1))%128; + $fieldtype = ord(substr($this->frame->content,$posn+1,1))%128; $byte = ord(' '); // Replace ESC with space. } else { @@ -132,7 +132,7 @@ class Frame // Replace field with Date if ($field == '%date') { if ($fieldlength == 1) - $datetime = strtoupper(date('D d M Y H:i:s')); + $datetime = date('D d M H:ia'); if ($fieldlength <= strlen($datetime)) $byte = ord($datetime{$fieldlength-1}); @@ -168,7 +168,7 @@ class Frame } // truncate end of lines - if (isset($pageflags['tru']) && substr($this->frame->frame_content,$y*40+$x,40-$x) === str_repeat(' ',40-$x)) { + if (isset($pageflags['tru']) && substr($this->frame->content,$posn,40-$x) === str_repeat(' ',40-$x)) { $this->output .= CR . LF; break; } @@ -183,7 +183,7 @@ class Frame */ public function framenum() { - return $this->frame->frame_id.$this->frame->subframe_id; + return $this->frame->frame.$this->frame->index; } /** @@ -253,6 +253,17 @@ class Frame return sprintf(WHITE.'% '.$this->pagenum_length.'.0f%s',$num,$frame); } + /** + * Get the route for the key press + * + * @param string $read + */ + public function route(string $read) + { + // @todo + return FALSE; + } + /** * Calculate the length of text * @@ -270,21 +281,21 @@ class Frame // Simulate a DB load $o = new \App\Models\Frame; - $o->frame_content = ''; + $o->content = ''; $o->flags = ['ip']; - $o->frametype = 'a'; - $o->frame_id = 999; - $o->subframe_id = 'a'; + $o->type = 'a'; + $o->frame = 999; + $o->index = 'a'; // Header - $o->frame_content .= substr(R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T-12345678901234567890',0,20). + $o->content .= substr(R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T-12345678901234567890',0,20). R_WHITE.'999999999a'.R_RED.sprintf('%07.0f',999).'u'; - $o->frame_content .= str_repeat('+-',18).' '.R_RED.'01'; - $o->frame_content .= 'Date: '.ESC.str_repeat('d',25).str_repeat('+-',4); - $o->frame_content .= 'Name: '.ESC.str_repeat('u',5).str_repeat('+-',14); - $o->frame_content .= 'Address: '.ESC.str_repeat('a',20).''.str_repeat('+-',5); - $o->frame_content .= ' : '.ESC.str_repeat('a',20).''.str_repeat('+-',5); + $o->content .= str_repeat('+-',18).' '.R_RED.'01'; + $o->content .= 'Date: '.ESC.str_repeat('d',25).str_repeat('+-',4); + $o->content .= 'Name: '.ESC.str_repeat('u',5).str_repeat('+-',14); + $o->content .= 'Address: '.ESC.str_repeat('a',20).''.str_repeat('+-',5); + $o->content .= ' : '.ESC.str_repeat('a',20).''.str_repeat('+-',5); return $o; } diff --git a/app/Console/Commands/FrameDelete.php b/app/Console/Commands/FrameDelete.php new file mode 100644 index 0000000..3a65a8b --- /dev/null +++ b/app/Console/Commands/FrameDelete.php @@ -0,0 +1,61 @@ +argument('frame'))) + throw new \Exception('Frame is not numeric: '.$this->argument('frame')); + + if (strlen($this->argument('index')) != 1 OR ! preg_match('/^[a-z]$/',$this->argument('index'))) + throw new \Exception('Subframe failed validation'); + + try { + $o = Frame::where('frame',$this->argument('frame')) + ->where('index',$this->argument('index')) + ->firstOrFail(); + + } catch (ModelNotFoundException $e) { + $this->error('Page not found to delete: '.$this->argument('frame').$this->argument('index')); + die(1); + } + + $o->delete(); + $this->info('Page deleted: '.$this->argument('frame').$this->argument('index')); + } +} \ No newline at end of file diff --git a/app/Console/Commands/FrameImport.php b/app/Console/Commands/FrameImport.php new file mode 100644 index 0000000..be43c4c --- /dev/null +++ b/app/Console/Commands/FrameImport.php @@ -0,0 +1,84 @@ +argument('frame'))) + throw new \Exception('Frame is not numeric: '.$this->argument('frame')); + + if (strlen($this->argument('index')) != 1 OR ! preg_match('/^[a-z]$/',$this->argument('index'))) + throw new \Exception('Subframe failed validation'); + + if (! file_exists($this->argument('file'))) + throw new \Exception('File not found: '.$this->argument('file')); + + $o = new Frame; + if ($this->option('replace')) { + try { + $o = $o->where('frame',$this->argument('frame')) + ->where('index',$this->argument('index')) + ->firstOrFail(); + + } catch (ModelNotFoundException $e) { + $this->error('Page not found to replace: '.$this->argument('frame').$this->argument('index')); + die(1); + } + + } else { + $o->frame = $this->argument('frame'); + $o->index = $this->argument('index'); + } + + $o->content = ($this->option('trim')) + ? substr(file_get_contents($this->argument('file')),40) + : file_get_contents($this->argument('file')); + + $o->cost = $this->option('cost'); + $o->mode_id = $this->option('mode'); + $o->type = $this->option('type'); + + $o->save(); + } +} \ No newline at end of file diff --git a/app/Console/Commands/Server.php b/app/Console/Commands/Server.php index 89215bd..ec1c3eb 100644 --- a/app/Console/Commands/Server.php +++ b/app/Console/Commands/Server.php @@ -79,6 +79,8 @@ class Server extends Command /** * Connection handler + * + * @todo: Pressing * three times gets "Shouldnt get here". */ function onConnect(SocketClient $client) { Log::info('Connection from: ',['client'=>$client->getAddress()]); @@ -97,771 +99,767 @@ class Server extends Command return; // We are now the child. - // @todo Need to intercept any crashes and close the TCP port. + try { + $session_init = $session_option = FALSE; + $session_note = ''; // TCP Session Notice + $session_term = ''; // TCP Terminal Type - $session_init = $session_option = FALSE; - $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_WONT . TCP_OPT_LINEMODE); // WONT LINEMODE + $client->send(TCP_IAC . TCP_DO . TCP_OPT_ECHO); // DO ECHO +// $client->send(TCP_IAC.TCP_AYT); // AYT + $client->send(TCP_IAC . TCP_DO . TCP_OPT_TERMTYPE . TCP_IAC . TCP_SB . TCP_OPT_TERMTYPE . TCP_OPT_ECHO . TCP_IAC . TCP_SE); // Request Term Type - $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_DO.TCP_OPT_ECHO); // DO ECHO -// $client->send(TCP_IAC.TCP_AYT); // AYT - $client->send(TCP_IAC.TCP_DO.TCP_OPT_TERMTYPE.TCP_IAC.TCP_SB.TCP_OPT_TERMTYPE.TCP_OPT_ECHO.TCP_IAC.TCP_SE); // Request Term Type + $client->send(CLS); - $client->send(CLS); - $read = ''; + // @todo Deprecate and have an exception handler handle this. + // like throw new FatalClientException(CLS.UP.ERR_DATABASE,500,NULL,$client); - // @todo Deprecate and have an exception handler handle this. - // like throw new FatalClientException(CLS.UP.ERR_DATABASE,500,NULL,$client); + // @todo Get the login/start page, and if it is not available, throw the ERR_DATEBASE error. - // @todo Get the login page, and if it is not available, throw the ERR_DATEBASE error. + $db = new \vvdb(); + // Connect to database. Returns error message if unable to connect. + $r = $db->connect($config['dbserver'], $config['database'], $config['dbuser'], $config['dbpass']); + /* + if (!empty($r)) { + http_response_code(500); + $client->send(CLS . UP . ERR_DATABASE); + die ($r); + } + */ - $db = new \vvdb(); - // Connect to database. Returns error message if unable to connect. - $r = $db->connect($config['dbserver'],$config['database'],$config['dbuser'], $config['dbpass']); - /* - if (!empty($r)) { - http_response_code(500); - $client->send(CLS . UP . ERR_DATABASE); - die ($r); - } - */ + // $user will eventually contain validated user details. + $user = array('systel' => '019990001', + 'username' => 'DEMONSTRATION DATA USER', + 'address1' => '8 HERBAL HILL', + 'address2' => 'LONDON', + 'address3' => 'EC1R 5EJ', + 'address4' => '', + 'address5' => '', + 'CUGS' => array(7800, 15500), // Closed User Groups this user has access to + ); - // $user will eventually contain validated user details. - $user = array( 'systel' => '019990001', - 'username' => 'DEMONSTRATION DATA USER', - 'address1' => '8 HERBAL HILL', - 'address2' => 'LONDON', - 'address3' => 'EC1R 5EJ', - 'address4' => '', - 'address5' => '', - 'CUGS' => array( 7800, 15500), // Closed User Groups this user has access to - ); + $history = array(); // backup history - $history = array(); // backup history + $cmd = ''; // Current *command being typed in + $mode = false; // input mode. + $prevmode = false; // previous mode + $timewarp = false; + $action = ACTION_GOTO; // do something if set. used here to trigger a goto to the login form. + if (isset($config['loginpage'])) { + $page = $config['loginpage']; + $subpage = 'a'; + } else if (!empty($service['start_page'])) { + $page = $service['start_page']; + $subpage = 'a'; + } else { + $page = '98'; // next page + $subpage = 'a'; + } + $curpage = ''; // current page + $cursub = ''; + $curfield = null; // current input field + $curfp = 0; // current field, position within. + $blp = 0; // botton line polluted (by this no. of characters) + $resetpsn = false; // flag to reset position (used in fields) - $cmd = ''; // current *command being typed in - $mode = false; // input mode. - $prevmode = false; // previous mode - $timewarp = false; - $action = ACTION_GOTO; // do something if set. used here to trigger a goto to the login form. - if (isset($config['loginpage'])) { - $page = $config['loginpage']; - $subpage = 'a'; - } else if (!empty($service['start_page'])) { - $page = $service['start_page']; - $subpage = 'a'; - } else { - $page = '999'; // next page - $subpage = 'a'; - } - $curpage = ''; // current page - $cursub = ''; - $curfield = null; // current input field - $curfp = 0; // current field, position within. - $blp = 0; // botton line polluted (by this no. of characters) - $resetpsn = false; // flag to reset position (used in fields) - - if (! isset($config['varient_id'])) - $config['varient_id'] = NULL; - $service = $db->getServiceById($config['service_id']); - //dd($service); - $varient = $db->getAllVarients($config['service_id'], $config['varient_id']); - if ($varient === false) { - die ("no varient"); - } - $varient = reset($varient); + if (!isset($config['varient_id'])) + $config['varient_id'] = NULL; + $service = $db->getServiceById($config['service_id']); + //dd($service); + $varient = $db->getAllVarients($config['service_id'], $config['varient_id']); + if ($varient === false) { + die ("no varient"); + } + $varient = reset($varient); - $matches = array(); - if (preg_match('@'.$service['page_format'].'@',$service['start_frame'],$matches)) { - $page = $matches[1]; - $subpage = $matches[2]; - echo " Using start page ".$page.$subpage."\n"; - } + $matches = array(); + if (preg_match('@' . $service['page_format'] . '@', $service['start_frame'], $matches)) { + $page = $matches[1]; + $subpage = $matches[2]; + echo " Using start page " . $page . $subpage . "\n"; + } // $start = $service['start_frame']; // where to start from - while( $action != ACTION_TERMINATE ) { - // Read a character from the client session - $read = $client->read(1); + while ($action != ACTION_TERMINATE) { + // Read a character from the client session + $read = $client->read(1); - if ($read != '') { - dump(sprintf('Mode: [%s] CMD: [%s] frame: [%s] Received [%s (%s)]',$mode,$cmd,$page,$read,ord($read))); + if ($read != '') { + dump(sprintf('Mode: [%s] CMD: [%s] frame: [%s] Received [%s (%s)]', $mode, $cmd, $page, $read, ord($read))); - // Client initiation input - // TELNET http://pcmicro.com/netfoss/telnet.html - if ($read == TCP_IAC OR $session_init OR $session_option) - { - Log::debug(sprintf('Session Char (%s)',ord($read)),['init'=>$session_init,'option'=>$session_option]); - - switch ($read) { - // Command being sent. - case TCP_IAC: - $session_init = TRUE; - $session_note = 'IAC '; - - continue 2; - - case TCP_SB: - $session_option = TRUE; - - continue 2; - - case TCP_SE: - $session_option = $session_init = FALSE; - Log::debug('Session Terminal: '.$session_term); - - break; - - case TCP_DO: - $session_note .= 'DO '; - - continue 2; - - case TCP_WILL: - $session_note .= 'WILL '; - - 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 = ''; - Log::debug($session_note); - - continue; - - case TCP_OPT_SUP_GOAHEAD: - $session_note .= 'SUPPRESS GO AHEAD'; - $session_init = FALSE; - $read = ''; - Log::debug($session_note); - - continue; - - default: - if ($session_option AND $read) { - $session_term .= $read; - $read = ''; - - } else { - Log::debug(sprintf('Unhandled char in session_init :%s (%s)',$read,ord($read))); - } - } - } - - switch($mode){ - // Key presses during field input. - case MODE_FIELD: - //dump(sprintf('** Processing Keypress in MODE_FIELD [%s (%s)]. Last POS [%s]',$read,ord($read),$curfp)); - $cmd = ''; - $action = FALSE; - - switch ($fo->type()) { - // Input frame. - case 'a': - switch ($read) { - // End of field entry. - case HASH: - // Next Field - $curfield++; - - //dump(['current'=>$curfield, 'numfields'=>count($fields)]); - - if ($curfield < count($fields)) { // skip past non-editable fields - for ($i = $curfield; $i < count($fields); $i++) { - if (isset($this->fieldoptions[$fields[$i]['type']]) && - $this->fieldoptions[$fields[$i]['type']]['edit']) { - $curfield = $i; - break; - } - } - - if ($curfield !== false) { - $client->send(outputPosition($fields[$curfield]['x'],$fields[$curfield]['y']).CON); - $mode = MODE_FIELD; - $fielddate[$curfield] = ''; - - } else { - // there were no (more) editable fields. - $action = ACTION_SUBMITRF; - } - - } else { - // done them all editable fields. - $action = ACTION_SUBMITRF; - } - break; - - case STAR: - $prevmode = MODE_FIELD; - $action = ACTION_STAR; - break; - - case KEY_LEFT: - if ($curfp) { - $client->send(LEFT); - $curfp--; - }; - break; - - case KEY_RIGHT: - if ($curfp++ < $fields[$curfield]['length']) { - $client->send(RIGHT); - //$curfp++; - }; - break; - - case KEY_DOWN: - if ($curfp + 40 < $fields[$curfield]['length']) { - $client->send(DOWN); - $curfp = $curfp + 40; - }; - break; - - case KEY_UP: - if ($curfp - 40 >= 0) { - $client->send($read); - $curfp = $curfp - 40; - }; - break; - - case CR: - if ($curfp + $fields[$curfield]['x'] > 40) { // on second or later line of a field - $client->send($read); - $curfp = (($curfp + $fields[$curfield]['x'])%40)*40; - } else { - $client->send(outputPosition($fields[$curfield]['x'],$fields[$curfield]['y']).CON); - $curfp = 0; - } - break; - - case ESC: - break; ; - - // Record Data Entry - default: - if (ord($read) > 31 && $curfp < $fields[$curfield]['length']) { - $fielddata[$curfield]{$curfp} = $read; - $curfp++; - $client->send($read); - } - } - - break; - - // Other Frame Types - Shouldnt get here. - default: - throw new \Exception('Shouldnt get here',500); - - } // switch frame types - - break; - - // Form submission: 1 to send, 2 not to send. - case MODE_SUBMITRF: - switch($read){ - // @todo Input received, process it. - case '1': - dump(['s'=>$service,'f'=>$fielddata]); - if(TRUE) { - sendBaseline($client, $blp, MSG_SENT); - $mode = MODE_RFSENT; - } else { - sendBaseline($client, $blp, ERR_NOTSENT); - $mode = MODE_RFERROR; - } - break; - case '2': - - sendBaseline($client, $blp, MSG_NOTSENT);; - $mode = MODE_RFNOTSENT; - break; - - case STAR: - $action = ACTION_STAR; - break; - - } - break; - - // Response form after Sent processing - // @todo To fix. - case MODE_RFSENT: - $client->send(COFF); - - if ($read == HASH) { - if (!empty($pagedata['route1'])) { - $action = ACTION_GOTO; - $page = $pagedata['route1']; - $subpage = 'a'; - - } else if ($r = $db->getFrame($service['service_id'],$varient['varient_id'],$page,chr(1+ord($subpage)))) { - $action = ACTION_GOTO; - $page = $curpage; - $subpage = chr(1+ord($subpage)); - - } else if (!empty($pagedata['route0'])) { - $action = ACTION_GOTO; - $page = $pagedata['route0']; - $subpage = 'a'; - - // No further routes defined, go home. - } else { - $action = ACTION_GOTO; - $page = '0'; - $subpage = 'a'; - } - - } elseif ($read == STAR) { - $action = ACTION_STAR; - - break; - } - - break; - - // Response form after NOT sending - case MODE_RFNOTSENT: - - // Response form ERROR - // @todo To fix - case MODE_RFERROR: - $client->send(COFF); - - if ($read == HASH) { - if (!empty($pagedata['route2'])) { - $action = ACTION_GOTO; - $page = $pagedata['route2']; - $subpage = 'a'; - - } else if ($r = $db->getFrame($service['service_id'],$varient['varient_id'],$page,chr(1+ord($subpage)))) { - $action = ACTION_GOTO; - $page = $curpage; - $subpage = chr(1+ord($subpage)); - - } else if (!empty($pagedata['route0'])) { - $action = ACTION_GOTO; - $page = $pagedata['route0']; - $subpage = 'a'; - - // No further routes defined, go home. - } else { - $action = ACTION_GOTO; - $page = '0'; - $subpage = 'a'; - } - - } else if ($read == STAR) { - $action = ACTION_STAR; - - break; - } - - break; - - /* - List of alternate options has been presented - */ - - case MODE_WARPTO: // expecting a timewarp selection - if (isset($alts[$read - 1 ])) { - $v = $db->getAllVarients($config['service_id'], $alts[$read - 1]['varient_id']); - if (!empty($v)) { - $varient = reset($v); - $page = $curpage; - $subpage = $cursub; - $action = ACTION_GOTO; - break; - } - } - // if wasn't a valid warpto keypress, - //drop into - - // Not doing anything in particular. - case FALSE: - $cmd = ''; - Log::debug('Idle',['pid'=>'TBA']); + // Client initiation input + // TELNET http://pcmicro.com/netfoss/telnet.html + if ($read == TCP_IAC OR $session_init OR $session_option) { + Log::debug(sprintf('Session Char (%s)', ord($read)), ['init' => $session_init, 'option' => $session_option]); switch ($read) { - case HASH: - $action = ACTION_NEXT; + // Command being sent. + case TCP_IAC: + $session_init = TRUE; + $session_note = 'IAC '; + + continue 2; + + case TCP_SB: + $session_option = TRUE; + + continue 2; + + case TCP_SE: + $session_option = $session_init = FALSE; + Log::debug('Session Terminal: ' . $session_term); + break; - case STAR: - $action = ACTION_STAR; - break; + case TCP_DO: + $session_note .= 'DO '; + + continue 2; + + case TCP_WILL: + $session_note .= 'WILL '; + + 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 = ''; + Log::debug($session_note); + + continue; + + case TCP_OPT_SUP_GOAHEAD: + $session_note .= 'SUPPRESS GO AHEAD'; + $session_init = FALSE; + $read = ''; + Log::debug($session_note); + + continue; + + default: + if ($session_option AND $read) { + $session_term .= $read; + $read = ''; - // Frame Routing - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (isset($pagedata['route' . $read]) && $pagedata['route' . $read] != '*') { - $action = ACTION_GOTO; - $page = $pagedata['route' . $read]; - $subpage = 'a'; - break; } else { - sendBaseline($client, $blp, ERR_ROUTE); - $mode = $action = false; + Log::debug(sprintf('Unhandled char in session_init :%s (%s)', $read, ord($read))); + } + } + } + + switch ($mode) { + // Key presses during field input. + case MODE_FIELD: + //dump(sprintf('** Processing Keypress in MODE_FIELD [%s (%s)]. Last POS [%s]',$read,ord($read),$curfp)); + $cmd = ''; + $action = FALSE; + + switch ($fo->type()) { + // Input frame. + case 'a': + switch ($read) { + // End of field entry. + case HASH: + // Next Field + $curfield++; + + //dump(['current'=>$curfield, 'numfields'=>count($fields)]); + + if ($curfield < count($fields)) { // skip past non-editable fields + for ($i = $curfield; $i < count($fields); $i++) { + if (isset($this->fieldoptions[$fields[$i]['type']]) && + $this->fieldoptions[$fields[$i]['type']]['edit']) { + $curfield = $i; + break; + } + } + + if ($curfield !== false) { + $client->send(outputPosition($fields[$curfield]['x'], $fields[$curfield]['y']) . CON); + $mode = MODE_FIELD; + $fielddate[$curfield] = ''; + + } else { + // there were no (more) editable fields. + $action = ACTION_SUBMITRF; + } + + } else { + // done them all editable fields. + $action = ACTION_SUBMITRF; + } + break; + + case STAR: + $prevmode = MODE_FIELD; + $action = ACTION_STAR; + break; + + case KEY_LEFT: + if ($curfp) { + $client->send(LEFT); + $curfp--; + }; + break; + + case KEY_RIGHT: + if ($curfp++ < $fields[$curfield]['length']) { + $client->send(RIGHT); + //$curfp++; + }; + break; + + case KEY_DOWN: + if ($curfp + 40 < $fields[$curfield]['length']) { + $client->send(DOWN); + $curfp = $curfp + 40; + }; + break; + + case KEY_UP: + if ($curfp - 40 >= 0) { + $client->send($read); + $curfp = $curfp - 40; + }; + break; + + case CR: + if ($curfp + $fields[$curfield]['x'] > 40) { // on second or later line of a field + $client->send($read); + $curfp = (($curfp + $fields[$curfield]['x']) % 40) * 40; + } else { + $client->send(outputPosition($fields[$curfield]['x'], $fields[$curfield]['y']) . CON); + $curfp = 0; + } + break; + + case ESC: + break;; + + // Record Data Entry + default: + if (ord($read) > 31 && $curfp < $fields[$curfield]['length']) { + $fielddata[$curfield]{$curfp} = $read; + $curfp++; + $client->send($read); + } + } + + break; + + // Other Frame Types - Shouldnt get here. + default: + $client->close(); + throw new \Exception('Shouldnt get here', 500); + + } // switch frame types + + break; + + // Form submission: 1 to send, 2 not to send. + case MODE_SUBMITRF: + switch ($read) { + // @todo Input received, process it. + case '1': + dump(['s' => $service, 'f' => $fielddata]); + if (TRUE) { + sendBaseline($client, $blp, MSG_SENT); + $mode = MODE_RFSENT; + } else { + sendBaseline($client, $blp, ERR_NOTSENT); + $mode = MODE_RFERROR; + } + break; + case '2': + + sendBaseline($client, $blp, MSG_NOTSENT);; + $mode = MODE_RFNOTSENT; + break; + + case STAR: + $action = ACTION_STAR; + break; + + } + break; + + // Response form after Sent processing + // @todo To fix. + case MODE_RFSENT: + $client->send(COFF); + + if ($read == HASH) { + if (!empty($pagedata['route1'])) { + $action = ACTION_GOTO; + $page = $pagedata['route1']; + $subpage = 'a'; + + } else if ($r = $db->getFrame($service['service_id'], $varient['varient_id'], $page, chr(1 + ord($subpage)))) { + $action = ACTION_GOTO; + $page = $curpage; + $subpage = chr(1 + ord($subpage)); + + } else if (!empty($pagedata['route0'])) { + $action = ACTION_GOTO; + $page = $pagedata['route0']; + $subpage = 'a'; + + // No further routes defined, go home. + } else { + $action = ACTION_GOTO; + $page = '0'; + $subpage = 'a'; + } + + } elseif ($read == STAR) { + $action = ACTION_STAR; + + break; + } + + break; + + // Response form after NOT sending + case MODE_RFNOTSENT: + + // Response form ERROR + // @todo To fix + case MODE_RFERROR: + $client->send(COFF); + + if ($read == HASH) { + if (!empty($pagedata['route2'])) { + $action = ACTION_GOTO; + $page = $pagedata['route2']; + $subpage = 'a'; + + } else if ($r = $db->getFrame($service['service_id'], $varient['varient_id'], $page, chr(1 + ord($subpage)))) { + $action = ACTION_GOTO; + $page = $curpage; + $subpage = chr(1 + ord($subpage)); + + } else if (!empty($pagedata['route0'])) { + $action = ACTION_GOTO; + $page = $pagedata['route0']; + $subpage = 'a'; + + // No further routes defined, go home. + } else { + $action = ACTION_GOTO; + $page = '0'; + $subpage = 'a'; + } + + } else if ($read == STAR) { + $action = ACTION_STAR; + + break; + } + + break; + + /* + List of alternate options has been presented + */ + + case MODE_WARPTO: // expecting a timewarp selection + if (isset($alts[$read - 1])) { + $v = $db->getAllVarients($config['service_id'], $alts[$read - 1]['varient_id']); + if (!empty($v)) { + $varient = reset($v); + $page = $curpage; + $subpage = $cursub; + $action = ACTION_GOTO; + break; + } + } + // if wasn't a valid warpto keypress, + //drop into + + // Not doing anything in particular. + case FALSE: + $cmd = ''; + Log::debug('Idle', ['pid' => $childpid]); + + switch ($read) { + case HASH: + $action = ACTION_NEXT; + break; + + case STAR: + $action = ACTION_STAR; + break; + + // Frame Routing + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if ($frame = $fo->route($read)) { + $action = ACTION_GOTO; + + } else { + sendBaseline($client, $blp, ERR_ROUTE); + $mode = $action = FALSE; + } + + break; + } + + break; + + /* + currently accepting baseline imput after a * was received + */ + + case MODE_BL: // entering a baseline command + echo "was waiting for page number\n"; + // if it's a number, continue entry + if (strpos('0123456789', $read) !== false) { // numeric + $cmd .= $read; + $client->send($read); + $blp++; + } + // if we hit a special numeric command, deal with it. + if ($cmd === '00') { // refresh page + $client->send(COFF); + $action = ACTION_RELOAD; + $cmd = ''; + break; + } + if ($cmd === '09') { // reload page + $client->send(COFF); + $action = ACTION_GOTO; + $cmd = ''; + break; + + } + if ($cmd === '02') { // new for emulator + $client->send(COFF); + $action = ACTION_INFO; + $cmd = ''; + break; + } + if (($cmd === '01')) { // new for emulator + $client->send(COFF); + $timewarp = !$timewarp; + sendBaseline($client, $blp, + ($timewarp ? MSG_TIMEWARP_ON : MSG_TIMEWARP_OFF)); + $cmd = ''; + $action = $mode = false; + } + // another star aborts the command. + if ($read === "*") { // abort command or reset input field. + $action = false; + sendBaseline($client, $blp, ''); + $cmd = ''; + + if ($prevmode == MODE_FIELD) { + $mode = $prevmode; + $prevmode = false; + $client->send(outputPosition($fields[$curfield]['x'], $fields[$curfield]['y']) . CON); + $client->send(str_repeat(' ', $fields[$curfield]['length'])); +// tood reset stored entered text + $resetpsn = $curfield; + } else { + $mode = false; } break; - - } - - break; - - /* - currently accepting baseline imput after a * was received - */ - - case MODE_BL: // entering a baseline command - echo "was waiting for page number\n"; - // if it's a number, continue entry - if (strpos('0123456789',$read) !== false) { // numeric - $cmd .= $read; - $client->send($read); - $blp++; - } - // if we hit a special numeric command, deal with it. - if ($cmd === '00') { // refresh page - $client->send(COFF); - $action = ACTION_RELOAD; - $cmd = ''; - break; - } - if ($cmd === '09') { // reload page - $client->send(COFF); - $action = ACTION_GOTO; - $cmd = ''; - break; - - } - if ($cmd === '02') { // new for emulator - $client->send(COFF); - $action = ACTION_INFO; - $cmd = ''; - break; - } - if (($cmd === '01')) { // new for emulator - $client->send(COFF); - $timewarp = !$timewarp; - sendBaseline($client, $blp, - ( $timewarp ? MSG_TIMEWARP_ON : MSG_TIMEWARP_OFF)); - $cmd = ''; - $action = $mode = false; - } - // another star aborts the command. - if ($read === "*") { // abort command or reset input field. - $action = false; - sendBaseline($client, $blp, ''); - $cmd = ''; - - if ($prevmode == MODE_FIELD) { - $mode = $prevmode; - $prevmode = false; - $client->send(outputPosition($fields[$curfield]['x'],$fields[$curfield]['y']).CON); - $client->send(str_repeat(' ',$fields[$curfield]['length'])); -// tood reset stored entered text - $resetpsn = $curfield; - } else { - $mode = false; + } + // user hit # to complete request + if ($read === '_') { // really the # key, + $client->send(COFF); + if ($cmd === '') { // nothing typed between * and # + $action = ACTION_BACKUP; + } else { // *# means go back + $page = $cmd; + $subpage = 'a'; + $action = ACTION_GOTO; + } + $cmd = ''; // finished with this now + break; } break; - } - // user hit # to complete request - if ($read === '_') { // really the # key, - $client->send(COFF); - if ($cmd === '') { // nothing typed between * and # - $action = ACTION_BACKUP; - } else { // *# means go back - $page = $cmd; - $subpage = 'a'; - $action = ACTION_GOTO; - } - $cmd = ''; // finished with this now - break; - } + + + default: + echo "not sure what we were doing\n"; + } // switch $mode + } // something in $read + + /* + This section performs some action if it is deemed necessary + */ + if ($action) { + echo "Performing action $action\n"; + } + switch ($action) { + case ACTION_STAR: + echo " star command started\n"; + sendBaseline($client, $blp, GREEN . '*', true); + $client->send(CON); + $action = false; + $mode = MODE_BL; break; - default: - echo "not sure what we were doing\n"; - } // switch $mode - } // something in $read - - /* - This section performs some action if it is deemed necessary - */ - if ($action) { - echo "Performing action $action\n"; - } - switch($action){ - case ACTION_STAR: - echo " star command started\n"; - sendBaseline($client, $blp, GREEN . '*', true); - $client->send(CON); - $action = false; - $mode = MODE_BL; - break; + case ACTION_SUBMITRF: + $action = false; + sendBaseline($client, $bpl, MSG_SENDORNOT); + $mode = MODE_SUBMITRF; + break; - - case ACTION_SUBMITRF: - $action = false; - sendBaseline($client, $bpl, MSG_SENDORNOT); - $mode = MODE_SUBMITRF; - break; - - - - - case ACTION_BACKUP: - // do we have anywhere to go? - if (count($history) > 1) { // because current page should always be in there. - array_pop($history); // drop current page to reveal previous - } - list($page, $subpage) = end($history); // get new last entry, - echo "Backing up to $page$subpage\n"; - // drop into - case ACTION_NEXT: - if ($action == ACTION_NEXT) { - $cursub = $subpage; - $subpage = chr(ord($subpage)+1); - } - case ACTION_GOTO: + case ACTION_BACKUP: + // do we have anywhere to go? + if (count($history) > 1) { // because current page should always be in there. + array_pop($history); // drop current page to reveal previous + } + list($page, $subpage) = end($history); // get new last entry, + echo "Backing up to $page$subpage\n"; + // drop into + case ACTION_NEXT: + if ($action == ACTION_NEXT) { + $cursub = $subpage; + $subpage = chr(ord($subpage) + 1); + } + case ACTION_GOTO: // $client->send(HOME . UP . GREEN . "Searching for page $page"); // $blp = 20 + strlenv($page); - // look for requested page + // look for requested page - try { - $fo = (new \App\Models\Frame)->fetch($page,$subpage); + try { + $fo = (new \App\Models\Frame)->fetch($page, $subpage); - } catch (ModelNotFoundException $e) { - Log::debug(sprintf('Frame: %s%s NOT found',$page,$subpage)); - if ($action == ACTION_NEXT) { - $subpage = $cursub; // Put subpage back as it was + } catch (ModelNotFoundException $e) { + Log::debug(sprintf('Frame: %s%s NOT found', $page, $subpage)); + if ($action == ACTION_NEXT) { + $subpage = $cursub; // Put subpage back as it was + } + + sendBaseline($client, $blp, ERR_PAGE); + $mode = $action = FALSE; + break; } - sendBaseline($client, $blp, ERR_PAGE); - $mode = $action = FALSE; - break; - } + dump(['m' => __METHOD__, 'service' => $service['service_id'], 'varient' => $varient['varient_id'], 'frame' => $fo->framenum(), 'type' => $fo->type()]); - dump(['m'=>__METHOD__,'service'=>$service['service_id'],'varient'=>$varient['varient_id'],'frame'=>$fo->framenum(),'type'=>$fo->type()]); + // validate if we have access top it + /* if (isset($m['access']) && $m['access'] == 'n') { + sendBaseline($client, $blp, ERR_PAGE); + $mode = $action = false; + break; + } + if (isset($m['cug']) && is_numeric($m['cug']) && $m['cug'] && !in_array($m['cug'],$usercugs)) { + sendBaseline($client, $blp, ERR_PRIVATE); + $mode = $action = false; + break; + } + */ - // validate if we have access top it - /* if (isset($m['access']) && $m['access'] == 'n') { - sendBaseline($client, $blp, ERR_PAGE); - $mode = $action = false; - break; - } - if (isset($m['cug']) && is_numeric($m['cug']) && $m['cug'] && !in_array($m['cug'],$usercugs)) { - sendBaseline($client, $blp, ERR_PRIVATE); - $mode = $action = false; - break; - } - */ - - // we have access... - if ($r['varient_id'] != $varient['varient_id']) { - if (empty($v['varient_date'])) { - sendBaseline($client, $blp, sprintf(MSG_TIMEWARP_TO, 'unknown date') ); - } else { - sendBaseline($client, $blp, sprintf(MSG_TIMEWARP_TO,date('j f Y',strtotime($v['varient_date']))) ); + // we have access... + if ($r['varient_id'] != $varient['varient_id']) { + if (empty($v['varient_date'])) { + sendBaseline($client, $blp, sprintf(MSG_TIMEWARP_TO, 'unknown date')); + } else { + sendBaseline($client, $blp, sprintf(MSG_TIMEWARP_TO, date('j f Y', strtotime($v['varient_date'])))); + } + $varient = array_merge($varient, array_intersect_key($r, $varient)); } - $varient = array_merge($varient, array_intersect_key($r, $varient)); - } - //var_dump(['B','r'=>$r,'m'=>$m]); - //$pagedata = array_merge($r, $m); - //$varient = $v; - $curpage = $page; - $cursub = $subpage; - $cufield = 0; - $curfp = 0; - //$pageflags = $db->getFrameTypeFlags($pagedata['type']); // method missing. - $pageflags = []; + //var_dump(['B','r'=>$r,'m'=>$m]); + //$pagedata = array_merge($r, $m); + //$varient = $v; + $curpage = $page; + $cursub = $subpage; + $cufield = 0; + $curfp = 0; + //$pageflags = $db->getFrameTypeFlags($pagedata['type']); // method missing. + $pageflags = []; - if ($action == ACTION_GOTO || $action == ACTION_NEXT) { // only if new location, not going backwards - $history[] = array($page,$subpage); - } + if ($action == ACTION_GOTO || $action == ACTION_NEXT) { // only if new location, not going backwards + $history[] = array($page, $subpage); + } - // drop into - case ACTION_RELOAD: - // - /* if ($pageflags['clear']) { - $output = CLS; - $blp = 0; - } else { - $output = HOME; - } - */ + // drop into + case ACTION_RELOAD: + // + /* if ($pageflags['clear']) { + $output = CLS; + $blp = 0; + } else { + $output = HOME; + } + */ // print_r($pageflags); print_r($pagedata); - switch($fo->type()){ - default: - case 'i': // standard frame - if ($timewarp && 1 < count( - $alts = $db->getAlternateFrames($service['service_id'],$varient['varient_id'],$curpage,$cursub) - )) { - $msg = MSG_TIMEWARP; - } else { - $msg = ''; - } - - $output = getOutputx($curpage, $cursub, [], $pageflags, $msg); - //var_dump(['output'=>$output,'curpage'=>$curpage,'cursub'=>$cursub,'pagedata'=>$pagedata,'pageflag'=>$pageflags,'m'=>$msg]); - $blp = strlenv($msg); - $client->send($output); - $mode = $action = false; - break; - - case 'a': // active frame. Prestel uses this for Response Framea. - - /* - if ($timewarp && 1 < count( - $alts = $db->getAlternateFrames($service['service_id'],$varient['varient_id'],$curpage,$cursub) - )) { - $msg = MSG_TIMEWARP; - } else { - $msg = ''; - } - */ - - // this is a glorious hack to fix three out of 30,000 pages but might - // break lots more. - //$pagedata = str_replace(chr(12),chr(27),$pagedata); - - // holds data entered by user. - $fielddata = array(); - - $fields = $fo->fields; - $msg = '?'; - $output = getOutputx($curpage, $cursub, [], $pageflags, $msg, $user, $fields); - $blp = strlenv($msg); - $client->send($output); - - if ($fields->count()) { - // dump($fields,count($fields)); - // need t skip to first field that is.. - // of a field type that is editable - // or finish. - $curfield = FALSE; - - for ($i = 0; $i < count($fields); $i++) { - //dump($this->fieldoptions,$i,isset($this->fieldoptions[$fields[$i]['type']])); - - if (isset($this->fieldoptions[$fields[$i]['type']]) && - $this->fieldoptions[$fields[$i]['type']]['edit']) { - $curfield = $i; - break; - } - } - - $resetpsn = $curfield; - - if ($curfield !== false) { - $mode = MODE_FIELD; - + switch ($fo->type()) { + default: + case 'i': // standard frame + if ($timewarp && 1 < count( + $alts = $db->getAlternateFrames($service['service_id'], $varient['varient_id'], $curpage, $cursub) + )) { + $msg = MSG_TIMEWARP; } else { - // there were no editable fields. - $mode = MODE_COMPLETE; + $msg = ''; } - $curfp = 0; + $output = getOutputx($curpage, $cursub, [], $pageflags, $msg); + //var_dump(['output'=>$output,'curpage'=>$curpage,'cursub'=>$cursub,'pagedata'=>$pagedata,'pageflag'=>$pageflags,'m'=>$msg]); + $blp = strlenv($msg); + $client->send($output); + $mode = $action = false; + break; - //dump(['curfield'=>$curfield,'mode'=>$mode]); - } + case 'a': // active frame. Prestel uses this for Response Framea. + /* + if ($timewarp && 1 < count( + $alts = $db->getAlternateFrames($service['service_id'],$varient['varient_id'],$curpage,$cursub) + )) { + $msg = MSG_TIMEWARP; + } else { + $msg = ''; + } + */ - break; + // this is a glorious hack to fix three out of 30,000 pages but might + // break lots more. + //$pagedata = str_replace(chr(12),chr(27),$pagedata); - case 't': // terminate - $output = getOutputx($curpage, $cursub, [], $pageflags); - $client->send($output); - $action = ACTION_TERMINATE; - break; + // holds data entered by user. + $fielddata = array(); - } // switch + $fields = $fo->fields; + $msg = '?'; + $output = getOutputx($curpage, $cursub, [], $pageflags, $msg, $user, $fields); + $blp = strlenv($msg); + $client->send($output); + + if ($fields->count()) { + // dump($fields,count($fields)); + // need t skip to first field that is.. + // of a field type that is editable + // or finish. + $curfield = FALSE; + + for ($i = 0; $i < count($fields); $i++) { + //dump($this->fieldoptions,$i,isset($this->fieldoptions[$fields[$i]['type']])); + + if (isset($this->fieldoptions[$fields[$i]['type']]) && + $this->fieldoptions[$fields[$i]['type']]['edit']) { + $curfield = $i; + break; + } + } + + $resetpsn = $curfield; + + if ($curfield !== false) { + $mode = MODE_FIELD; + + } else { + // there were no editable fields. + $mode = MODE_COMPLETE; + } + + $curfp = 0; + + //dump(['curfield'=>$curfield,'mode'=>$mode]); + } + + break; + + case 't': // terminate + $output = getOutputx($curpage, $cursub, [], $pageflags); + $client->send($output); + $action = ACTION_TERMINATE; + break; + + } // switch - break; + break; + case ACTION_INFO: // special emulator command + $mode = false; + $cmd = ''; + $action = false; + $output = outputPosition(0, 0) . WHITE . NEWBG . RED . 'TIMEWARP INFO FOR Pg.' . BLUE . $curpage . $cursub . WHITE; + $output .= outputPosition(0, 1) . WHITE . NEWBG . BLUE . 'Service : ' . substr($service['service_name'] . str_repeat(' ', 27), 0, 27); + $output .= outputPosition(0, 2) . WHITE . NEWBG . BLUE . 'Varient : ' . substr($varient['varient_name'] . str_repeat(' ', 27), 0, 27); + $output .= outputPosition(0, 3) . WHITE . NEWBG . BLUE . 'Dated : ' . substr(date('j F Y', strtotime($varient['varient_date'])) . str_repeat(' ', 27), 0, 27); - case ACTION_INFO: // special emulator command - $mode = false; - $cmd=''; - $action = false; - - $output = outputPosition(0,0) . WHITE . NEWBG . RED . 'TIMEWARP INFO FOR Pg.' . BLUE . $curpage . $cursub . WHITE; - $output .= outputPosition(0,1) . WHITE . NEWBG . BLUE . 'Service : ' . substr($service['service_name'] . str_repeat(' ',27),0,27) ; - $output .= outputPosition(0,2) . WHITE . NEWBG . BLUE . 'Varient : ' . substr($varient['varient_name'] . str_repeat(' ',27),0,27) ; - $output .= outputPosition(0,3) . WHITE . NEWBG . BLUE . 'Dated : ' . substr(date('j F Y',strtotime($varient['varient_date'])) . str_repeat(' ',27),0,27); - - $alts = $db->getAlternateFrames($service['service_id'],$varient['varient_id'],$curpage,$cursub); - if (count($alts) > 1) { - $n = 1; - $output .= outputPosition(0,4) . WHITE . NEWBG . RED . 'ALTERNATIVE VERSIONS:' . str_repeat(' ',16); - $y = 5; - foreach ($alts as $ss){ + $alts = $db->getAlternateFrames($service['service_id'], $varient['varient_id'], $curpage, $cursub); + if (count($alts) > 1) { + $n = 1; + $output .= outputPosition(0, 4) . WHITE . NEWBG . RED . 'ALTERNATIVE VERSIONS:' . str_repeat(' ', 16); + $y = 5; + foreach ($alts as $ss) { // if (is_numeric($ss['varient_date'])) { - $date = date('d M Y', strtotime($ss['varient_date'])); + $date = date('d M Y', strtotime($ss['varient_date'])); // } else { // $date = 'unknown'; // } - $line = WHITE . NEWBG; - if ($timewarp) { - $line .= RED . $n; + $line = WHITE . NEWBG; + if ($timewarp) { + $line .= RED . $n; + } + $line .= BLUE . $date . ' ' . $ss['varient_name']; + + + $output .= outputPosition(0, $y) . $line . str_repeat(' ', 40 - strlenv($line)); + $y++; + $n++; + + } + if ($timewarp) { + $mode = MODE_WARPTO; } - $line .= BLUE . $date . ' ' . $ss['varient_name']; - - - $output .= outputPosition(0,$y) . $line . str_repeat(' ',40-strlenv($line)); - $y++; - $n++; - } - if ($timewarp) { - $mode = MODE_WARPTO; - } - } - $client->send($output); + $client->send($output); - break; + break; - default: - ; - } // switch $action + default: + ; + } // switch $action - if ($resetpsn !== false && isset($fields[$resetpsn])) { - $client->send(outputPosition($fields[$resetpsn]['x'],$fields[$resetpsn]['y']).CON); - $resetpsn = false; + if ($resetpsn !== false && isset($fields[$resetpsn])) { + $client->send(outputPosition($fields[$resetpsn]['x'], $fields[$resetpsn]['y']) . CON); + $resetpsn = false; + } + + + if ($read === null || socket_last_error()) { + printf("[%s] Disconnected\n", $client->getaddress()); + + return false; + } } - - if( $read === null || socket_last_error()) { - printf( "[%s] Disconnected\n", $client->getaddress() ); - return false; - } + // Something bad happened. We'll log it and then disconnect. + } catch (\Exception $e) { + Log::emergency($e->getMessage()); } $client->close(); @@ -873,6 +871,7 @@ class Server extends Command return strlen($text) - substr_count($text, ESC); } + // @todo Not clearing to end of line. function sendBaseline($client, &$blp, $text, $reposition = false){ $client->send(HOME . UP . $text . ( $blp > strlenv($text) ? str_repeat(' ',$blp-strlenv($text)) . diff --git a/app/Models/Frame.php b/app/Models/Frame.php index 778b614..58838a4 100644 --- a/app/Models/Frame.php +++ b/app/Models/Frame.php @@ -13,25 +13,14 @@ class Frame extends Model * @param string $frame * @return mixed */ - public function fetch(int $page,string $frame): \App\Classes\Frame + public function fetch(int $frame,string $index): \App\Classes\Frame { - if ($page == '999' and $frame == 'a') + if ($frame == '999' and $index == 'a') { return new \App\Classes\Frame(\App\Classes\Frame::testFrame()); } - return new \App\Classes\Frame($this->where('frame_id',$page)->where('subframe_id',$frame)->firstOrFail()); - } - - /** - * Return the frame cost - * - * @return int - */ - public function getCostAttribute() - { - // @todo NOT in DB - return rand(0,999); + return new \App\Classes\Frame($this->where('frame',$frame)->where('index',$index)->firstOrFail()); } public function hasFlag(string $flag) @@ -45,7 +34,6 @@ class Frame extends Model */ public function type() { - // @todo in DB - return isset($this->frametype) ? $this->frametype : 'i'; + return $this->type ?: 'i'; } } \ No newline at end of file diff --git a/app/Traits/HasCompositePrimaryKey.php b/app/Traits/HasCompositePrimaryKey.php new file mode 100644 index 0000000..7088901 --- /dev/null +++ b/app/Traits/HasCompositePrimaryKey.php @@ -0,0 +1,53 @@ +getKeyName(); + + if (! is_array($keys)){ + return parent::setKeysForSaveQuery($query); + } + + foreach ($keys as $keyName){ + $query->where($keyName, '=', $this->getKeyForSaveQuery($keyName)); + } + + return $query; + } + + /** + * Get the primary key value for a save query. + * + * @param mixed $keyName + * @return mixed + */ + protected function getKeyForSaveQuery($keyName = null) + { + if (is_null($keyName)){ + $keyName = $this->getKeyName(); + } + + if (isset($this->original[$keyName])) { + return $this->original[$keyName]; + } + + return $this->getAttribute($keyName); + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 4adbc60..d88db76 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "App\\": "app/" }, "files": [ - "bootstrap/constants.php" + "config/constants.php" ], "classmap": [ "database/seeds", diff --git a/database/migrations/2018_12_03_104758_init_database.php b/database/migrations/2018_12_03_104758_init_database.php new file mode 100644 index 0000000..c071e0f --- /dev/null +++ b/database/migrations/2018_12_03_104758_init_database.php @@ -0,0 +1,79 @@ +down(); + + Schema::create('modes', function (Blueprint $table) { + $table->timestamps(); + $table->integer('id')->autoIncrement(); + $table->string('name',16); + $table->string('note',255); + + $table->unique(['name']); + }); + + Schema::create('cugs', function (Blueprint $table) { + $table->timestamps(); + $table->integer('id'); + $table->string('name',16); + $table->string('note',255); + $table->integer('parent_id')->nullable(); + + $table->primary('id'); + $table->foreign('parent_id')->references('id')->on('cugs'); + $table->unique(['name']); + }); + + Schema::create('frames', function (Blueprint $table) { + $table->timestamps(); + $table->integer('id')->autoIncrement(); + $table->integer('frame'); + $table->char('index',1); + $table->integer('mode_id'); + $table->char('type',2); + $table->smallInteger('cost')->default(0); + $table->integer('cug_id')->default(0); + $table->boolean('public')->default(FALSE); + $table->binary('content'); + $table->string('note',255)->nullable(); + + //$table->unique(['frame','index','mode_id']); // Not needed since we have timewarp + + $table->foreign('mode_id')->references('id')->on('modes'); + $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'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('routes'); + Schema::dropIfExists('frames'); + Schema::dropIfExists('cugs'); + Schema::dropIfExists('modes'); + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 91cb6d1..c665f1f 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -11,6 +11,7 @@ class DatabaseSeeder extends Seeder */ public function run() { - // $this->call(UsersTableSeeder::class); + $this->call(SeedMode::class); + $this->call(SeedCUG::class); } -} +} \ No newline at end of file diff --git a/database/seeds/SeedCUG.php b/database/seeds/SeedCUG.php new file mode 100644 index 0000000..bd82ef6 --- /dev/null +++ b/database/seeds/SeedCUG.php @@ -0,0 +1,21 @@ +insert([ + 'created_at' => now(), + 'id' => 0, + 'name' => 'Public Frames', + 'note' => 'All frames belong to this CUG if not any other.', + ]); + } +} diff --git a/database/seeds/SeedMode.php b/database/seeds/SeedMode.php new file mode 100644 index 0000000..937cce9 --- /dev/null +++ b/database/seeds/SeedMode.php @@ -0,0 +1,20 @@ +insert([ + 'created_at' => now(), + 'name' => 'ViewData', + 'note' => 'Original ViewData/VideoTex 40x25 char mode.', + ]); + } +}