diff --git a/app/Classes/Frame.php b/app/Classes/Frame.php index 173ccf1..e62afaa 100644 --- a/app/Classes/Frame.php +++ b/app/Classes/Frame.php @@ -35,7 +35,8 @@ use App\Models\CUG; abstract class Frame { protected $frame = NULL; - protected $output = NULL; + protected $output = ''; + protected $startline = 1; // All this vars should be overridden in the child class /* @@ -71,17 +72,11 @@ abstract class Frame // @todo Move this to the database private $header = RED.'T'.BLUE.'E'.GREEN.'S'.YELLOW.'T'.MAGENTA.'!'; - public function __construct(\App\Models\Frame $o,string $msg=NULL) + public function __construct(\App\Models\Frame $o) { $this->frame = $o; - $this->output = $this->hasFlag('clear') ? CLS : HOME; - - // If we have a message to display on the bottom line. - if ($msg) - $this->output .= UP.$msg.HOME; - - $startline = 0; + $this->output = $this->frame->cls ? CLS : HOME; if (! $this->hasFlag('ip') AND (! $this->isCUG(0) OR $this->type() !== self::FRAMETYPE_LOGIN)) { // Set the page header: CUG/Site Name | Page # | Cost @@ -89,12 +84,16 @@ abstract class Frame $this->render_page($this->frame->frame,$this->frame->index). $this->render_cost($this->frame->cost); - $startline = 1; + $this->startline = 2; + + } elseif ($this->isCUG(0) AND $this->type() === self::FRAMETYPE_LOGIN) { + $this->startline = 2; + $this->output .= str_repeat(DOWN,$this->startline-1); } // Calculate fields and render output. - $this->fields = collect(); // Fields in this frame. - $this->fields($startline); + $this->fields = collect(); // Fields in this frame. + $this->fields($this->startline); } /** @@ -403,17 +402,18 @@ abstract class Frame $o->index = 'a'; $o->access = 1; $o->closed = 0; + $o->cls = 1; // Header $sid = R_RED.'T'.R_BLUE.'E'.R_GREEN.'S'.R_YELLOW.'T'; $o->content .= substr($sid.'-'.str_repeat('12345678901234567890',4),0,static::$header_length+(strlen($sid)-$so->strlenv($sid))). R_WHITE.'999999999a'.R_RED.sprintf('%07.0f',999).'u'; - $o->content .= str_repeat('+-',18).' '.R_RED.'01'; - $o->content .= 'Name: '.ESC.str_repeat('u',5).str_repeat('+-',14); - $o->content .= 'Date: '.ESC.str_repeat('d',25).str_repeat('+-',4); - $o->content .= 'Address: '.ESC.str_repeat('a',19).' '.str_repeat('+-',5); - $o->content .= ' : '.ESC.str_repeat('a',19).' '.str_repeat('+-',5); + $o->content .= R_WHITE.str_repeat('+-',static::$frame_width/2-3).' '.R_RED.'01'; + $o->content .= R_WHITE.'Name: '.ESC.str_repeat('u',5).' |'.str_repeat('+-',static::$frame_width/2-8).'|'; + $o->content .= R_WHITE.'Date: '.ESC.str_repeat('d',17).' |'.str_repeat('+-',static::$frame_width/2-14).'|'; + $o->content .= R_WHITE.'Address: '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|'; + $o->content .= R_WHITE.' : '.ESC.str_repeat('t',19).' |'.str_repeat('+-',static::$frame_width/2-17).'|'; return $o; } diff --git a/app/Classes/Frame/Action/Login.php b/app/Classes/Frame/Action/Login.php index c7d5561..0288864 100644 --- a/app/Classes/Frame/Action/Login.php +++ b/app/Classes/Frame/Action/Login.php @@ -46,6 +46,7 @@ class Login extends Action return FALSE; } + $this->so->log('info','User Login: '.$this->uo->name); $this->page = ['frame'=>1,'index'=>'a']; // @todo Get from DB. $this->action = 2; // ACTION_GOTO diff --git a/app/Classes/Frame/Ansi.php b/app/Classes/Frame/Ansi.php index 014f17d..2253f6b 100644 --- a/app/Classes/Frame/Ansi.php +++ b/app/Classes/Frame/Ansi.php @@ -5,6 +5,7 @@ namespace App\Classes\Frame; use Illuminate\Support\Facades\Log; use App\Classes\Frame as AbstractFrame; +use App\Classes\Parser\Ansi as AnsiParser; class Ansi extends AbstractFrame { @@ -18,9 +19,21 @@ class Ansi extends AbstractFrame public static $if_filler = '.'; - public function fields($startline=0) + public function __construct(\App\Models\Frame $o,string $msg='') { - $this->output .= str_replace(LF,CR.LF,$this->frame->content); + parent::__construct($o); + + // If we have a message to display on the bottom line. + if ($msg) + $this->output .= ESC.'[24;0f'.$msg.HOME; + } + + public function fields($startline=1) + { + $o = new AnsiParser($this->frame->content,$startline); + $this->output .= (string)$o; + + $this->fields = $o->fields; } public function strlenv($text):int { diff --git a/app/Classes/Frame/Videotex.php b/app/Classes/Frame/Videotex.php index 479e798..12978b8 100644 --- a/app/Classes/Frame/Videotex.php +++ b/app/Classes/Frame/Videotex.php @@ -19,26 +19,32 @@ class Videotex extends AbstractFrame public static $if_filler = '.'; - public function fields($startline=0) + public function __construct(\App\Models\Frame $o,string $msg='') + { + parent::__construct($o); + + // If we have a message to display on the bottom line. + if ($msg) + $this->output .= HOME.UP.$msg.HOME; + } + + public function fields($startline=1) { $infield = FALSE; // In a field $fieldtype = NULL; // Type of field $fieldlength = 0; // Length of field - if ($startline) - $this->output .= str_repeat(DOWN,$startline); - // $fieldadrline = 1; // Scan the frame for a field start - for ($y=$startline;$y<=static::$frame_length;$y++) + for ($y=$startline-1;$y<=static::$frame_length;$y++) { // Fields can only be on a single line $fieldx = $fieldy = FALSE; for ($x=0;$xframe->content{$posn}) ? $this->frame->content{$posn} : ' ')%128; @@ -62,7 +68,6 @@ class Videotex extends AbstractFrame } // Is this a magic field? - // @todo For page redisplay *00, we should show entered contents - for refresh *09 we should show updated contents if (array_get($this->fieldmap,chr($fieldtype)) ) { $field = $this->fieldmap[chr($fieldtype)]; //dump(['infield','byte'=>$byte,'fieldtype'=>$fieldtype,'field'=>$field,'strpos'=>strpos($field,'#')]); diff --git a/app/Classes/FrameFields.php b/app/Classes/FrameFields.php index b0d2281..45d87c7 100644 --- a/app/Classes/FrameFields.php +++ b/app/Classes/FrameFields.php @@ -15,4 +15,17 @@ class FrameFields { return array_get($this->fields,$key); } + + public function output(string $filler) + { + switch ($this->type) { + case 'd': + $out = date('D d M H:ia'); + + return substr($out.($this->length > strlen($out) ? str_repeat($filler,$this->length-strlen($out)) : ''),0,$this->length); + + default: + return str_repeat($filler,$this->length); + } + } } \ No newline at end of file diff --git a/app/Classes/Parser.php b/app/Classes/Parser.php new file mode 100644 index 0000000..58f1f19 --- /dev/null +++ b/app/Classes/Parser.php @@ -0,0 +1,7 @@ +content = $content; + $this->startline = $startline; + $this->fields = collect(); + } + + public function __toString(): string + { + return $this->parse($this->startline); + } + + /** + * Parse a string and look for the next character that is not $char + * + * @param string $char + * @param int $start + * @return bool|int + */ + private function findEOF(string $char,int $start) + { + for ($c=$start;$c <= strlen($this->content);$c++) + { + if ($this->content{$c} != $char) + return $c-$start; + } + + return FALSE; + } + + /** + * @param $startline + * @param int $offset + * @return string + */ + private function parse($startline): string + { + // Our starting coordinates + $x = 1; + $y = $startline; + $output = ''; + + // Scan the frame for a field start + for ($c=0; $c<=strlen($this->content); $c++) + { + // If the frame is not big enough, fill it with spaces. + $byte = isset($this->content{$c}) ? $this->content{$c} : ' '; + $advance = 0; + + switch ($byte) { + case CR: + $x = 1; + break; + + case LF: + $y++; + break; + + case ESC: + $advance = 1; + // Is the next byte something we know about + $nextbyte = isset($this->content{$c+$advance}) ? $this->content{$c+$advance} : ' '; + + switch ($nextbyte) { + case '[': + $advance++; + $chars = $nextbyte; + + // Find our end CSI param + $matches = []; + + $a = preg_match('/([0-9]+[;]?)+([a-zA-Z])/',$this->content,$matches,NULL,$c+$advance); + + if (! $a) + break; + + $advance += strlen($matches[0])-1; + $chars .= $matches[0]; + + switch ($matches[2]) { + // We ignore 'm' they are color CSIs + case 'm': break; + + case 'C': + $x += $matches[1]; // Advance our position + break; + + default: + dump('Unhandled CSI: '.$matches[2]); + } + + break; + + case ' ': + dump(['l'=>__LINE__,'LOOSE ESC?']); + + break; + + default: + $c--; // Allow for the original ESC + $advance++; + $fieldtype = ord($nextbyte)%128; // @todo Do we need the %128 for ANSI? + $fieldlength = $this->findEOF(chr($fieldtype),$c+1)+1; + + $byte = ''; + + $this->fields->push(new FrameFields([ + 'type'=>chr($fieldtype), + 'length'=>$fieldlength, + 'x'=>$x, // Adjust for the ESC char + 'y'=>$y, + ])); + + Log::debug(sprintf('Field found at [%s,%s], Type: %s, Length: %s',$x-1,$y,$fieldtype,$fieldlength)); + $advance += $fieldlength-2; + $x += $fieldlength; + $chars = $this->fields->last()->output(AnsiFrame::$if_filler); + } + + break; + + default: + $x++; + } + + $output .= $byte; + + if ($advance) { + $output .= $chars; + $c += $advance; + } + + if ($x > 80) { + $x = 1; + $y++; + } + } + + return $output; + } +} \ No newline at end of file diff --git a/app/Classes/Server.php b/app/Classes/Server.php index 10292e8..3ce4f55 100644 --- a/app/Classes/Server.php +++ b/app/Classes/Server.php @@ -23,7 +23,7 @@ abstract class Server { $this->mo = $o; define('MODE_BL', 1); // Typing a * command on the baseline - define('MODE_FIELD', 2); // typing into an imput field + define('MODE_FIELD', 2); // typing into an input field define('MODE_WARPTO', 3); // awaiting selection of a timewarp define('MODE_COMPLETE', 4); // Entry of data is complete .. define('MODE_SUBMITRF', 5); // asking if should send or not. @@ -64,12 +64,12 @@ abstract class Server { define('TCP_OPT_LINEMODE', chr(34)); define('MSG_SENDORNOT', GREEN.'KEY 1 TO SEND, 2 NOT TO SEND'); - define('MSG_SENT', GREEN.'MESSAGE SENT - KEY _ TO CONTINUE'); - define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY _ TO CONTINUE'); + define('MSG_SENT', GREEN.'MESSAGE SENT - KEY '.HASH.' TO CONTINUE'); + define('MSG_NOTSENT', GREEN.'MESSAGE NOT SENT - KEY '.HASH.' TO CONTINUE'); define('ERR_DATABASE', RED.'UNAVAILABLE AT PRESENT - PLSE TRY LATER'); define('ERR_NOTSENT', WHITE.'MESSAGE NOT SENT DUE TO AN ERROR'); - define('ERR_PRIVATE', WHITE.'PRIVATE PAGE'.GREEN.'- FOR EXPLANATION *37_..'); + define('ERR_PRIVATE', WHITE.'PRIVATE PAGE'.GREEN.'- FOR EXPLANATION *37'.HASH.'..'); define('ERR_ROUTE', WHITE.'MISTAKE?'.GREEN.'TRY AGAIN OR TELL US ON *08'); define('ERR_PAGE',ERR_ROUTE); define('ERR_USER_ALREADYMEMBER', RED.'ALREADY MEMBER OF CUG'); @@ -143,16 +143,17 @@ abstract class Server { // @todo Get the login/start page, and if it is not available, throw the ERR_DATEBASE error. if (isset($config['loginpage'])) { - $page = ['frame'=>$config['loginpage'],'index'=>'a']; + $page = ['frame'=>$config['loginpage']]; } else if (!empty($service['start_page'])) { - $page = ['frame'=>$service['start_page'],'index'=>'a']; + $page = ['frame'=>$service['start_page']]; } else { - $page = ['frame'=>'980','index'=>'a']; // next page + $page = ['frame'=>'980']; // next page } while ($action != ACTION_TERMINATE) { // Read a character from the client session $read = $client->read(1); + printf(". Got: %s (%s)\n",$read,ord($read)); // It appears that read will return '' instead of false when a disconnect has occurred. // We'll set it to NULL so its caught later @@ -181,6 +182,7 @@ abstract class Server { case TCP_SE: $session_option = $session_init = FALSE; $this->log('debug',sprintf('Session Terminal: %s',$session_term)); + $read = ''; break; @@ -258,7 +260,7 @@ abstract class Server { if ($current['field']->type == 'u' AND array_get($fielddata,$current['fieldnum']) == 'NEW') { $action = ACTION_GOTO; - $page = ['frame'=>'981','index'=>'a']; // @todo This should be in the DB. + $page = ['frame'=>'981']; // @todo This should be in the DB. } } @@ -269,6 +271,7 @@ abstract class Server { case Frame::FRAMETYPE_ACTION: switch ($read) { // End of field entry. + case LF: case HASH: // Next Field $current['fieldnum']++; @@ -391,11 +394,10 @@ abstract class Server { $route = $fo->route(1); if ($route == '*' OR is_numeric($route)) { - $this->sendBaseline($client, RED . 'NO action performed'); + $this->sendBaseline($client,RED.'NO ACTION PERFORMED'); $mode = MODE_RFSENT; } elseif ($ao = FrameClass\Action::factory($fo->route(1),$this,$user,$action,$mode)) { - $ao->handle($fielddata); $mode = $ao->mode; $action = $ao->action; @@ -431,28 +433,22 @@ abstract class Server { $client->send(COFF); if ($read == HASH) { - if (! empty($pagedata['route1'])) { - $action = ACTION_GOTO; - $page['frame'] = $pagedata['route1']; - $page['index'] = 'a'; + if ($route = $fo->route(2) AND $route !== '*' AND is_numeric($route)) { + $page = ['frame'=>$route]; } elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) { - $action = ACTION_GOTO; - $page['frame'] = array_get($current,'page.frame'); - $page['index'] = chr(1 + ord($page['index'])); + $page = ['frame'=>$fo->frame(),'index'=>$fo->index_next()]; - } elseif (! empty($pagedata['route0'])) { - $action = ACTION_GOTO; - $page['frame'] = $pagedata['route0']; - $page['index'] = 'a'; + } elseif ($route = $fo->route(0) AND $route !== '*' AND is_numeric($route)) { + $page = ['frame'=>$route]; - // No further routes defined, go home. + // No further routes defined, go home. } else { - $action = ACTION_GOTO; - $page['frame'] = '0'; - $page['index'] = 'a'; + $page = ['frame'=>0]; } + $action = ACTION_GOTO; + } elseif ($read == STAR) { $action = ACTION_STAR; @@ -469,28 +465,22 @@ abstract class Server { $client->send(COFF); if ($read == HASH) { - if (! empty($pagedata['route2'])) { - $action = ACTION_GOTO; - $page['frame'] = $pagedata['route2']; - $page['index'] = 'a'; + if ($route = $fo->route(2) AND $route !== '*' AND is_numeric($route)) { + $page = ['frame'=>$route]; } elseif (FrameModel::where('frame',$fo->frame())->where('index',$fo->index_next())->exists()) { - $action = ACTION_GOTO; - $page['frame'] = $fo->frame(); - $page['index'] = $fo->index_next(); + $page = ['frame'=>$fo->frame(),'index'=>$fo->index_next()]; - } elseif (! empty($pagedata['route0'])) { - $action = ACTION_GOTO; - $page['frame'] = $pagedata['route0']; - $page['index'] = 'a'; + } elseif ($route = $fo->route(0) AND $route !== '*' AND is_numeric($route)) { + $page = ['frame'=>$route]; - // No further routes defined, go home. + // No further routes defined, go home. } else { - $action = ACTION_GOTO; - $page['frame'] = '0'; - $page['index'] = 'a'; + $page = ['frame'=>0]; } + $action = ACTION_GOTO; + } elseif ($read == STAR) { $action = ACTION_STAR; @@ -554,7 +544,7 @@ abstract class Server { // Currently accepting baseline input after a * was received case MODE_BL: - echo "was waiting for page number\n"; + echo "- Waiting for Page Number\n"; // if it's a number, continue entry if (strpos('0123456789', $read) !== FALSE) { @@ -623,7 +613,7 @@ abstract class Server { } // Complete request - if ($read === HASH) { + if ($read === HASH or $read === LF) { $client->send(COFF); $timewarpalt = FALSE; @@ -657,21 +647,22 @@ abstract class Server { // This section performs some action if it is deemed necessary if ($action) { - echo "Performing action $action\n"; + printf("+ Performing action: %s\n",$action); } switch ($action) { case ACTION_STAR: - echo " star command started\n"; - $this->sendBaseline($client,GREEN.STAR,true); + echo "+ Star command...\n"; + + $this->sendBaseline($client,GREEN.STAR,TRUE); $client->send(CON); - $action = false; + $action = FALSE; $mode = MODE_BL; break; case ACTION_SUBMITRF: - $action = false; + $action = FALSE; $client->send(COFF); $this->sendBaseline($client,MSG_SENDORNOT); $mode = MODE_SUBMITRF; @@ -705,7 +696,7 @@ abstract class Server { try { $fo = $timewarpalt ? $this->mo->frame(FrameModel::findOrFail($timewarpalt)) - : $this->mo->frameLoad($page['frame'],$page['index'],$this); + : $this->mo->frameLoad($page['frame'],array_get($page,'index','a'),$this); $this->log('debug',sprintf('Fetched frame: %s (%s)',$fo->id(),$fo->page())); @@ -784,19 +775,8 @@ abstract class Server { // drop into case ACTION_RELOAD: - // @todo Move this $output into the object. - if ($fo->hasFlag('clear')) - { - $this->blp = 0; - $output = CLS; - - } else { - $output = HOME; - // Clear the baseline. - $this->sendBaseline($client,''); - } - - $output .= (string)$fo; + $this->sendBaseline($client,''); + $output = (string)$fo; if ($timewarpalt) { $this->sendBaseline($client,sprintf(MSG_TIMEWARP_TO,$fo->created() ? $fo->created()->format('Y-m-d H:i:s') : 'UNKNOWN')); @@ -922,21 +902,7 @@ abstract class Server { /** * Move the cursor via the shortest path. */ - function outputPosition($x,$y) { - // Take the shortest path. - if ($y < 12) { - return HOME. - (($x < 21) - ? str_repeat(DOWN,$y).str_repeat(RIGHT,$x) - : str_repeat(DOWN,$y+1).str_repeat(LEFT,40-$x)); - - } else { - return HOME.str_repeat(UP,24-$y). - (($x < 21) - ? str_repeat(RIGHT,$x) - : str_repeat(LEFT,40-$x)); - } - } + abstract function outputPosition($x,$y); /** * Send a message to the base line diff --git a/app/Classes/Server/Ansi.php b/app/Classes/Server/Ansi.php index da3499e..75e88a6 100644 --- a/app/Classes/Server/Ansi.php +++ b/app/Classes/Server/Ansi.php @@ -16,8 +16,8 @@ class Ansi extends AbstractServer { define('HOME', ESC.'[0;0f'); define('LEFT', ESC.'[D'); // Move Cursor define('RIGHT', ESC.'[C'); // Move Cursor - define('DOWN', chr(10)); // Move Cursor - define('UP', chr(11)); // Move Cursor + define('DOWN', ESC.'[B'); // Move Cursor + define('UP', ESC.'[A'); // Move Cursor define('CR', chr(13)); define('LF', chr(10)); define('CLS', ESC.'[2J'); @@ -48,6 +48,10 @@ class Ansi extends AbstractServer { parent::__construct($o); } + function outputPosition($x,$y) { + return ESC.'['.$y.';'.$x.'f'; + } + // Abstract function public function sendBaseline($client,$text,$reposition=FALSE) { $client->send(ESC.'[24;0f'.$text. diff --git a/app/Classes/Server/Videotex.php b/app/Classes/Server/Videotex.php index 30494b0..7c5f97d 100644 --- a/app/Classes/Server/Videotex.php +++ b/app/Classes/Server/Videotex.php @@ -48,6 +48,22 @@ class Videotex extends AbstractServer { parent::__construct($o); } + public function outputPosition($x,$y) { + // Take the shortest path. + if ($y < 12) { + return HOME. + (($x < 21) + ? str_repeat(DOWN,$y).str_repeat(RIGHT,$x) + : str_repeat(DOWN,$y+1).str_repeat(LEFT,40-$x)); + + } else { + return HOME.str_repeat(UP,24-$y). + (($x < 21) + ? str_repeat(RIGHT,$x) + : str_repeat(LEFT,40-$x)); + } + } + public function sendBaseline($client,$text,$reposition=FALSE) { $client->send(HOME.UP.$text. ($this->blp > $this->strlenv($text) diff --git a/app/Console/Commands/FrameImport.php b/app/Console/Commands/FrameImport.php index efaa4bb..7a6194a 100644 --- a/app/Console/Commands/FrameImport.php +++ b/app/Console/Commands/FrameImport.php @@ -61,6 +61,7 @@ class FrameImport extends Command try { $o = $o->where('frame',$this->argument('frame')) ->where('index',$this->argument('index')) + ->where('mode_id',$this->option('mode')) ->firstOrFail(); } catch (ModelNotFoundException $e) { @@ -71,6 +72,7 @@ class FrameImport extends Command } else { $o->frame = $this->argument('frame'); $o->index = $this->argument('index'); + $o->mode_id = $this->option('mode'); } $o->content = ($this->option('trim')) @@ -80,7 +82,6 @@ class FrameImport extends Command $o->access = $this->option('access'); $o->closed = $this->option('closed'); $o->cost = $this->option('cost'); - $o->mode_id = $this->option('mode'); $o->type = $this->option('type'); $o->save(); diff --git a/app/Models/Mode.php b/app/Models/Mode.php index 49f16f4..0fdc7ca 100644 --- a/app/Models/Mode.php +++ b/app/Models/Mode.php @@ -44,11 +44,11 @@ class Mode extends Model * * @param int $frame * @param string $index + * @param Server $so * @return FrameClass * @throws \Exception */ - //@todo Move Server $so first - public function frameLoad(int $frame,string $index='a',Server $so): FrameClass + public function frameLoad(int $frame,string $index,Server $so): FrameClass { return $this->frame( // Return our internal test frame. diff --git a/database/migrations/2018_12_09_103357_create_framemeta.php b/database/migrations/2018_12_09_103357_create_framemeta.php index f14de80..c90496b 100644 --- a/database/migrations/2018_12_09_103357_create_framemeta.php +++ b/database/migrations/2018_12_09_103357_create_framemeta.php @@ -16,19 +16,19 @@ class CreateFramemeta extends Migration $this->down(); Schema::create('framemeta', function (Blueprint $table) { - $table->integer('frame_id')->primary(); - $table->string('r0')->default('*'); - $table->string('r1')->default('*'); - $table->string('r2')->default('*'); - $table->string('r3')->default('*'); - $table->string('r4')->default('*'); - $table->string('r5')->default('*'); - $table->string('r6')->default('*'); - $table->string('r7')->default('*'); - $table->string('r8')->default('*'); - $table->string('r9')->default('*'); + $table->integer('frame_id')->primary(); + $table->string('r0')->default('*'); + $table->string('r1')->default('*'); + $table->string('r2')->default('*'); + $table->string('r3')->default('*'); + $table->string('r4')->default('*'); + $table->string('r5')->default('*'); + $table->string('r6')->default('*'); + $table->string('r7')->default('*'); + $table->string('r8')->default('*'); + $table->string('r9')->default('*'); - $table->foreign('frame_id')->references('id')->on('frames'); + $table->foreign('frame_id')->references('id')->on('frames'); }); } diff --git a/database/migrations/2018_12_13_223149_frame_add_clear.php.php b/database/migrations/2018_12_13_223149_frame_add_clear.php.php new file mode 100644 index 0000000..3a0bf50 --- /dev/null +++ b/database/migrations/2018_12_13_223149_frame_add_clear.php.php @@ -0,0 +1,32 @@ +boolean('cls')->default(TRUE); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('frames', function (Blueprint $table) { + $table->dropColumn('cls'); + }); + } +} \ No newline at end of file