From 42fb700c413806ffdfc431b2d8590a9f3732c644 Mon Sep 17 00:00:00 2001 From: Andy Heathershaw Date: Wed, 21 Sep 2016 12:10:37 +0100 Subject: [PATCH] Started working on an install experience for the application --- app/Configuration.php | 5 + app/Helpers/ConfigHelper.php | 12 +- app/Helpers/ThemeHelper.php | 11 +- app/Http/Controllers/Controller.php | 3 + app/Http/Controllers/InstallController.php | 130 ++++++++++++++++++ app/Providers/AppServiceProvider.php | 77 ++++++++--- app/User.php | 23 ++-- public/.htaccess | 5 + public/install.php | 99 +++++++++++++ .../bootstrap3/images/empty-fuel-gauge.jpg | Bin 0 -> 19804 bytes public/upload-license.php | 41 ++++++ resources/lang/en/installer.php | 12 ++ .../views/install/administrator.blade.php | 37 +++++ resources/views/install/database.blade.php | 47 +++++++ resources/views/install/layout.blade.php | 42 ++++++ .../views/themes/base/gallery/index.blade.php | 46 ++++--- routes/web.php | 2 + verify-license.php | 5 + 18 files changed, 538 insertions(+), 59 deletions(-) create mode 100644 app/Http/Controllers/InstallController.php create mode 100644 public/install.php create mode 100644 public/themes/bootstrap3/images/empty-fuel-gauge.jpg create mode 100644 public/upload-license.php create mode 100644 resources/lang/en/installer.php create mode 100644 resources/views/install/administrator.blade.php create mode 100644 resources/views/install/database.blade.php create mode 100644 resources/views/install/layout.blade.php create mode 100644 verify-license.php diff --git a/app/Configuration.php b/app/Configuration.php index 376e9c1..f1b1e27 100644 --- a/app/Configuration.php +++ b/app/Configuration.php @@ -32,4 +32,9 @@ class Configuration extends Model * @var string */ protected $table = 'configuration'; + + public static function installCompleted() + { + return (!is_null(Configuration::where('key', 'install_completed')->first())); + } } \ No newline at end of file diff --git a/app/Helpers/ConfigHelper.php b/app/Helpers/ConfigHelper.php index eb5521e..192064e 100644 --- a/app/Helpers/ConfigHelper.php +++ b/app/Helpers/ConfigHelper.php @@ -68,7 +68,8 @@ class ConfigHelper 'sender_address' => sprintf('hostmaster@%s', (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost')), 'sender_name' => (is_null($currentAppName) ? trans('global.app_name') : $currentAppName), 'smtp_server' => 'localhost', - 'smtp_port' => 25 + 'smtp_port' => 25, + 'theme' => 'bootstrap3' ); } @@ -78,8 +79,13 @@ class ConfigHelper if (is_null($config)) { - $defaults = $this->defaults(); - return ($defaultIfUnset && isset($defaults[$key]) ? $defaults[$key] : null); + if ($defaultIfUnset) + { + $defaults = $this->defaults(); + return (isset($defaults[$key]) ? $defaults[$key] : null); + } + + return null; } return $config->value; diff --git a/app/Helpers/ThemeHelper.php b/app/Helpers/ThemeHelper.php index db75587..f8d5ebc 100644 --- a/app/Helpers/ThemeHelper.php +++ b/app/Helpers/ThemeHelper.php @@ -3,6 +3,7 @@ namespace App\Helpers; use App\Configuration; +use App\Facade\UserConfig; class ThemeHelper { @@ -76,15 +77,7 @@ class ThemeHelper private function getThemeName() { - $themeName = ThemeHelper::DEFAULT_THEME; - - $currentTheme = Configuration::where('key', 'theme')->first(); - if (!is_null($currentTheme)) - { - $themeName = $currentTheme->value; - } - - return $this->sanitiseThemeName($themeName); + return $this->sanitiseThemeName(UserConfig::get('theme')); } private function sanitiseThemeName($themeName) diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 93f0bea..dc0280f 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -4,10 +4,13 @@ namespace App\Http\Controllers; use App\User; use Illuminate\Foundation\Bus\DispatchesJobs; +use Illuminate\Http\Request; use Illuminate\Routing\Controller as BaseController; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; class Controller extends BaseController { diff --git a/app/Http/Controllers/InstallController.php b/app/Http/Controllers/InstallController.php new file mode 100644 index 0000000..295bb98 --- /dev/null +++ b/app/Http/Controllers/InstallController.php @@ -0,0 +1,130 @@ +isDatabaseWorking()) + { + return $this->databaseConnection($request); + } + else if (!$this->isAdministratorAccountCreated()) + { + return $this->administratorAccount($request); + } + } + + protected function administratorAccount(Request $request) + { + if (strtolower($request->method()) == 'post') + { + $user = new User(); + $user->name = $request->get('name'); + $user->email = $request->get('email'); + $user->password = bcrypt($request->get('password')); + $user->is_admin = true; + $user->is_activated = true; + $user->save(); + + $request->session()->flash('', ''); + + return redirect(route('home')); + } + + return view('install/administrator'); + } + + protected function databaseConnection(Request $request) + { + if (strtolower($request->method()) == 'post') + { + $baseDirectory = dirname(dirname(dirname(__DIR__))); + + $data = [ + 'APP_KEY=' . config('app.key'), + 'DB_CONNECTION=mysql', + 'DB_HOST=' . $request->get('mysql-server'), + 'DB_PORT=' . intval($request->get('mysql-port')), + 'DB_DATABASE=' . $request->get('mysql-database'), + 'DB_USERNAME=' . $request->get('mysql-username'), + 'DB_PASSWORD=' . $request->get('mysql-password') + ]; + file_put_contents(sprintf('%s/.env', $baseDirectory), join(PHP_EOL, $data) . PHP_EOL); + + // Update the in-memory configuration ready for Artisan :) + $configData = [ + 'connections' => [ + 'mysql' => [ + 'driver' => 'mysql', + 'host' => $request->get('mysql-server'), + 'port' => intval($request->get('mysql-port')), + 'database' => $request->get('mysql-database'), + 'username' => $request->get('mysql-username'), + 'password' => $request->get('mysql-password') + ] + ] + ]; + config(['database' => array_replace_recursive(config('database'), $configData)]); + + DB::reconnect(); + + try + { + Artisan::call('cache:clear'); + Artisan::call('migrate', ['--force' => true]); + + $result = Configuration::where('key', 'install_date')->first(); + if (is_null($result)) + { + $result = new Configuration(); + $result->key = 'install_completed'; + $result->value = true; + $result->save(); + } + + return redirect('/install'); + } + catch (\Exception $ex) + { + $request->session()->flash('database_error', $ex->getMessage()); + return redirect('/install') + ->withInput($request->input()); + } + } + + return view('install/database', [ + 'database_error' => $request->session()->get('database_error') + ]); + } + + private function isAdministratorAccountCreated() + { + return (count(User::administrators()) > 0); + } + + private function isDatabaseWorking() + { + try + { + if (!Configuration::installCompleted()) + { + throw new \Exception(sprintf('install_completed configuration record is not present!')); + } + + return true; + } + catch (\Exception $ex) + { + return false; + } + } +} \ No newline at end of file diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 39ceaaf..a69d6c3 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,13 +3,16 @@ namespace App\Providers; use App\Album; +use App\Configuration; use App\Facade\Theme; use App\Facade\UserConfig; use App\Helpers\ConfigHelper; use App\Helpers\ImageHelper; +use App\Helpers\MiscHelper; use App\Helpers\ThemeHelper; use Illuminate\Database\QueryException; use Illuminate\Mail\Mailer; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; @@ -22,28 +25,31 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { - $this->app->singleton('image', function($app) + if ($this->checkIfInstalled()) { - return new ImageHelper(); - }); - $this->app->singleton('theme', function($app) - { - return new ThemeHelper(); - }); - $this->app->singleton('user_config', function($app) - { - return new ConfigHelper(); - }); + $this->app->singleton('image', function ($app) + { + return new ImageHelper(); + }); + $this->app->singleton('theme', function ($app) + { + return new ThemeHelper(); + }); + $this->app->singleton('user_config', function ($app) + { + return new ConfigHelper(); + }); - // When running migrations or CLI tasks, don't need to add things to the view - if (php_sapi_name() != 'cli') - { - $this->addThemeInfoToView(); - $this->addAlbumsToView(); + // When running migrations or CLI tasks, don't need to add things to the view + if (php_sapi_name() != 'cli') + { + $this->addThemeInfoToView(); + $this->addAlbumsToView(); + } + + // Set the default mail configuration as per user's requirements + $this->updateMailConfig(); } - - // Set the default mail configuration as per user's requirements - $this->updateMailConfig(); } /** @@ -56,6 +62,39 @@ class AppServiceProvider extends ServiceProvider // } + private function checkIfInstalled() + { + if ($_SERVER['REQUEST_URI'] == '/install') + { + $baseDirectory = dirname(dirname(__DIR__)); + + // Generate an application key and store to the .env file + if (!file_exists($baseDirectory . '/.env')) + { + $key = MiscHelper::randomString(32); + file_put_contents($baseDirectory . '/.env', sprintf('APP_KEY=%s', $key) . PHP_EOL); + app('config')->set(['app' => ['key' => $key]]); + } + + return false; + } + + try + { + if (!Configuration::installCompleted()) + { + throw new \Exception(sprintf('install_completed configuration record is not present!')); + } + + return true; + } + catch (\Exception $ex) + { + header(sprintf('Location: %s', url('/install'))); + die(); + } + } + private function addAlbumsToView() { $albums = Album::all()->sortBy('name'); diff --git a/app/User.php b/app/User.php index 6636862..6121de8 100644 --- a/app/User.php +++ b/app/User.php @@ -9,15 +9,6 @@ class User extends Authenticatable { use Notifiable; - public static function anonymous() - { - $user = new User(); - $user->id = -1; - $user->name = 'Anonymous'; - - return $user; - } - /** * The attributes that are mass assignable. * @@ -35,4 +26,18 @@ class User extends Authenticatable protected $hidden = [ 'password', 'remember_token', 'activation_token' ]; + + public static function administrators() + { + return User::where('is_admin', true)->get(); + } + + public static function anonymous() + { + $user = new User(); + $user->id = -1; + $user->name = 'Anonymous'; + + return $user; + } } diff --git a/public/.htaccess b/public/.htaccess index 903f639..b4480b8 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -5,6 +5,11 @@ RewriteEngine On + # If not installed, redirect to install folder + RewriteCond %{DOCUMENT_ROOT}/../blue-twilight.lic !-f + RewriteCond %{REQUEST_URI} !^/upload-license.php + RewriteRule .* /upload-license.php [L,R=302] + # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)/$ /$1 [L,R=301] diff --git a/public/install.php b/public/install.php new file mode 100644 index 0000000..e1f6a3a --- /dev/null +++ b/public/install.php @@ -0,0 +1,99 @@ +baseDirectory = dirname(__DIR__); + + // Display errors so installer never gets a WSOD! + ini_set('display_errors', true); + + require $this->baseDirectory . '/vendor/autoload.php'; + } + + public function run() + { + $licenseFile = new \SplFileInfo(sprintf('%s/blue-twilight.lic', $this->baseDirectory)); + if (!$licenseFile->isReadable()) + { + return $this->needLicense(); + } + + try + { + $this->licenseInfo = $this->verifyLicense(); + } + catch (\Exception $ex) + { + unlink($licenseFile->getRealPath()); + return $this->needLicense(); + } + + $environmentFile = new \SplFileInfo(sprintf('%s/.env', $this->baseDirectory)); + if (!$environmentFile->isReadable()) + { + return $this->needEnvironmentSetup(); + } + } + + private function needEnvironmentSetup() + { + if ($_SERVER['REQUEST_METHOD'] != 'POST') + { + return $this->render('database-connection'); + } + else + { + $rc = Artisan::call('migrate'); + $output = Artisan::output(); + + var_dump($rc); + var_dump($output); + } + } + + private function needLicense() + { + if ($_SERVER['REQUEST_METHOD'] != 'POST') + { + return $this->render('license'); + } + else + { + move_uploaded_file($_FILES['license-file']['tmp_name'], sprintf('%s/blue-twilight.lic', $this->baseDirectory)); + header(sprintf('Location: %s', $_SERVER['REQUEST_URI']), true, 302); + die(); + } + } + + private function render($viewName) + { + $viewName = pathinfo($viewName, PATHINFO_BASENAME); + $viewPath = sprintf('%s/resources/views/installer/%s.php', $this->baseDirectory, $viewName); + + $translator = new Translator('en'); + $translator->addLoader('file', new PhpFileLoader()); + $translator->addResource('file', sprintf('%s/resources/lang/en/installer.php', $this->baseDirectory), 'en'); + $licenseInfo = $this->licenseInfo; + + require $viewPath; + } + + private function verifyLicense() + { + return (require $this->baseDirectory . '/verify-license.php'); + } +} + +$installer = new BlueTwilightInstaller(); +$installer->run(); \ No newline at end of file diff --git a/public/themes/bootstrap3/images/empty-fuel-gauge.jpg b/public/themes/bootstrap3/images/empty-fuel-gauge.jpg new file mode 100644 index 0000000000000000000000000000000000000000..08371c8e60389d407b3674ac2e559f99a670ba0c GIT binary patch literal 19804 zcmdVC2Ut_v);79mhN488C@4Vz0ck2Ioq%jWL_}1&5ET^=5s}^!1d%Ez2v~_yL`6X9 z(n3c;rT1Q>mjomP((Vjy_ul86@3im!_dfT=m9QLhX00{b81ES4ouT*8N1*K|^bPeP zCMF1C0{d%Ek$UZDHTaxpgZSCl}W? zZr<(NxOup_xVG=u&cnwqARw?6F1T|C|4v?h0e;3sm{`DfSlKw(*f{vNac$%OuV3^^ zh=-j?mf4bpX&=PQ!^FbFM6ZPqppk4$n=k117ZWph#w{>*4o)smp1^RMy$IXq#(((sgO}`L$39dEoN2|2D_*)4%)z-saOW-|iT#pN z(g&1|9933PRnz@VPv79U;fb^7%*-t;t*q@YU%Bew=yc89!_&*#$Ja09PUzjR@QBE` z_=gFJNsk^sNl8shf0gn2&D-3({DQ)w;*TZOHMMp14WB+YwzYS3c6Imk_Kl8>Pkf)8 znx2^@EU)}nC9aXyHyG_=f>?ew3w-`;*x$8_2egZsm6e4R#%LE4vp0CN@UXJ&J+y^a z#}szajc?!K+wAMp{cTA)8Myr6dONDP2vBgcJ>*0FffiO&{}3+VKTz^LpJbI;4`G z62ym`;&-5ofjTGY&@)r)%J1I=Uk8U2M29q`81Gcdj~6VIAK*_)B=ocJKQ14qL`pj{ zsnDT)G00Dhd&VwH0U3Cr|NqNCb9f_>&DP+6Kqsw&;|23C0q7xVOtZDgN>>o)W}jK3 z!08|L|60uGWJksuN{L`d ziNj~|f*0F-va@c8SzS!t#gZ0YbD*&%m|ZkjZ8B&-W6;yVhZCb^BeX*So_K{yICr0O z1+se#zZmcBA^Y-U;*e9w7t?3^#q`C#-}`pFL0|%bUmotwq(z2i(6|(Eq&lA@%8pW+ zaZc4R@n{VlO7r$4)o3GHk+0{{QV<|t#qj1 zI<6pr^={3A^i-&(aMQQ>-Me?2C#}zEbLb(avcLf$rqcOwQ(2Ng#sbePQ}710 zP4yUk^3YV9jo%`OHfV<=h2V3DP6T9Bh0s91wR4|Af}2uaUsjD=Ha<63CZP1;!GQM{ z3xs1HGA#{Hr3>Iu6y7l68v?um$3|+`Ce)W|m5+TDp}MA)mR_7Ra#E>04Y6>DyS6~A z;fGM*IgJd#{k0K^2>f{j>_ZXBZ0vQ%ym>{tKk!F%19kQP*H?<$2iFCay*i(5+pveYNLls5q zwtb8x?W04{bf^$_b(n{QHW)k_F}CZ3!rH|rJD+0+t51TE+Ky?AY5M}+97~e(raVQ3 z;O1Sz=+N=SIYKbb0XI@GyzGMJrb8bJ5md3#oO&T>EvHA3W+FJMKn=S{)5oRs(L8V$ zhSxPvcW}f#Ve3M)C@H4Rt4ilK-mhIg-uU2!?3V!ucE*tfpFym8P@#^gI_X-5}|a^iwsqnD0|C>J{RvWcw3p4+{hxWJB|#s~;d6kR&N0cFebxJbxa22n3^puLQ1RMWZEudI65s7>}2uH+#dVm00Cjf{IjDWOBb zUbODv-83YvL+x(FYoDNNTI|nI&VHfyR!fYC>_!NADTzu?X2VO`X$hR%f{_r_HYF~0 zr7dVj}L(bG-7u z{Q3DsnCJ;U*|fXlG^RLqnwN&&n6XXW#^BJ0>}%eB^;tfXHc@jkeNM0J2cJiXQyp10 z;(~n^FUB}twz~8{H!Zv}Q+gLGPlpg@eGUa0U9}&14MVcQa9k$2=GgfrAHaK@NX!zu zvY0=xaIgG}0S{L1kf(U}5LjeD31waN!PX>-9K?5Jy_kK^^<3dxeq!V74h=*8aMNyr z`M&(=7w~F@URbR+n64QVer5$O=lDn0frgXBCuWERWQw2pv}0F!(icmK<~4UzDNt$X zqu?Q~(6%8%Xi6m4G4tnqy3S+%hg`g6?b%#if?r=UIM%u|hz?~Nqh4Wi4eHO4$YeE= zSp7YzL>jT`V#lGr<$ag1F})9V1^u|FEmBVNYh!5Hhxtt7xI)PghIMcf4}NwT?askea`6h-JUUg{Lx*v+sWhnOdGD?p@0d!tOhI2fj+yd=jnZJslE5wK{+i`-Ytd80fE37sjyoq884MBS{vxJcruh?Xt<|yU-%# z2ao!lY{}K5L$SHtZ!JP;eRK#GU_~Gk-3ZD-6k*Q{>uVc%{Ve-46zc>NcF)LUPZ+3b zS?)RX`7=M$dM{YJC-4r$*m^{`)&a*g`Ggd`j7*WpHN`Lr;aUyh2pLZE>#oP)PcHT9 z*5PuSft?hx_8IDG>$mG%^|(wHsQwmbUB?;Te{*K#^T8^J(EfycAc${s#R2@GwG(KB z@_=h}DAbdD#9&ldJyynykUj!*{M{Wl7ZSZhYS#~8os8WvcztZ}Fg`p0-i_WnRFzAI z>WV6iQ{PX`o7dgvnJKY98t5e#5JHF8WJsZ}(XF_`cXn)eg7SyyxPFq&soU@-iTOCV z3K?bz?RDnKh^`~kcK#*>aqr*Cux+u@n%9XLc{d>~H9)X! zjwy3ar6}WX6pUfF+h)Z?rCA&Ldfyzb5t5c<`KVIK5_g;>3!{R__im80C*C7{9z%*a zv!w>=-;#6Tx@>Ko)3jBL+Q}mBdFgA%6Nr{5x45q~Sal>}|6M)qIQ^=Gj_6?aS@tCp zpk$m0Yc%%tag%5fQBsok=%9M7AYZ_N)&=YFb00eRo43l3-r?zwbLY#uab3F4Z1??B zGDL317%(uBBfzx3Mgu6Qcp%-BY?l31BRW#189MWqMl{(}gnz3v|4o(63;##~`jcVm z{xw?sD-Hyz6dVlX{s$ucXZW&t{VT)|5D35_Es(YtE3*tX*7%%$1LE~O>T4RSvmJjguQMKAG@W#2 zyT;QF*agYlVmV6?i{cU(>fa>^H{=BcR&cpMq7pn*Rm7A30=06>W zedzPMjcS7h1-PdMoWz?)jN#yea*I*#tPOmfRc1}=wZ-zd?|8Cq_p?}GdpqO(MC6U{ ztJxiGy~Dj(J2yF}yA#HWsRSLNJImTuMBOS+2Tp7t(!aLro7B2Ti9HTtRKw(SzB ztm5KZpegU&-Gg9N0FAQ=*MLp~|AQm|bj$yHh>P|Idfgc}(MQ<>;L&yDhJiOK`Uq8u z){4oq2ti&`fX&c^2qh@PSC+%ssqF2G0bwiVs$#oTRE00!&`Mb8rl`^(VjvyDVtDD$ z$S@rOt!y0bQT{9NXNqzaRd3cn6=vz!U8?Pu^|Fz4Pv?^@=M`c-Q+D90AlWUP1)$~5^YE@||dhZ?YsvCxT1T2Z0P*4`N zU@~QFkJqi~#)_luQpXG;N{Y6*UPC`SQ8T2Vi%Rml@znF(?9r0Idu2)9-M7-V+f=6~ zTkQ-rJFOOX9P;m^Lpw>O=7hD#RSd6lQ7q=&Z1)*E+kwwrhPF|Mh`ThHDt9th(803xv{ly*|llAT@U-GXAV$`gl?aIyu~lv6u3QsEg=t;m^S3de6+9T*xac~ z7vbuK-7aG?FR3rHZ6&o_#$OM-EPZ!D)_Ims)3Up4(*|SzoF)#G$-nxBKnwior~QKm z`dIJhT$38*g{<41J9TIF5(`Ph_elvm< zuvyA4K^^W}KC;DGCJ3IS@!O9p;)IsqMxXsbhjCY$`)q1Z1<2}BgrHAgU3p8b(5r`w zLN;9YnH>8&P0X$bH0q2@!0mD>ajZT?V-^%X7%{ceSm&-w9oJ1G`{w+7?Q$O zZzRPN3@?r`ymx$N+s9#H^F+rAvHLd8hP;&bsL=H*D$^2rV4b<_j876+Ul~;pxK_bN z(2pOJ<6bsKTDE1UmgSd3Q(8|%@3I-bud;+{TdPNgT1(b1-PPKMM~1&#@yNQ`nKc;H zbc|}Bph!7Bdfxwa&Lo&f)q}1h8MV0WB(d7l>uQBjUR`bX*{v+zo_I`y9m~#W4TUhj zA##@*1{H{jBrkyrWVFmGg&BnGcrv!=Fy7o+NNM z8Gh)$m!L&3Rpty_Y>U~28{N{9qXDe`VT&R;zAN&p@KTL3PmWk=blmovs~b&Zt2xYe z4+OwVbt@G4R{0~%LZ7c)$c=1$Xar#rrnHX_O@}@UX^T*Rd-gDwPv18t{Q-k*c0C;2#pe7&j#^(Z(*jNuc9fe)rW`4(iD^T)Q1-0&!BV zf<6zY4f!?HFNK?9wrTNQQ%*qc7S$clg_qToL!C`Ig2eDmV)(T^K4^lUDQXgp)W{T7?;ixqQx6T<)$R1o!>%wHu|%(GJvC$uF&0EiHV2&%D*>SfMz{gQA{gNY#vcF_ z^fn_ZjBo>pQ2avY0O~Q!SUv;uF;2ilVSEojidIH_M#u$R0%$dGF2|T+j93mh`Ca0U z;MLmaILxK77c-{mHU2rbz;3&JKpUb|h!&W|Tf zeU|I@7kkA3Md0oHS&Nz0rX@^TNPiDdYJ?q*dGTYLK)W4pV%2EFV0Bc*F?8yvvkXpnrfc|0VaNBA z3DEcRIfI84_MX4j$N~MRgryklYZ5AnGYh(4vimGRTR<;w`p3@IS_g z=N*l5b$=_H*=gq6J)8x<#tRG+WBeHdg`3Kfkb@*QJI82qFu^%EVSH{@|8I-z z1j)bA>M)!br;Zqm;54(`4b2oyZzDI?zNkCJJX3JY>-V*yaE_0J9gUYxY@Lb@ASfudE2r$cwmO~;%0 zbocez?QBlSsMNBO9MBiiKE>l(wf;1SCGhci<$8r+El$$<$a=t`@hr}5-i8jmDW4z4 zali~>^!7d|iGH(-HRS$rfSoX;{TA~I$a)ly9wBT@GcC!EKmVgsev{1nhc5Y=E3e|c zheCxl(d1z6WABl6SA6p7N|bMFsJ?cl?d@2|cM&uRZ}trI6$Jz2El$(+6c188vLZO&4;(fTk|)`a zV%J^9k*@2W+RP#Ma`4(#KJwKgh%%{1U#=gt+$;WYDtMPRtPAyP&HY?z{0tTTbB&s6 z!!`$%5lv*QQE>c=Qn1=#pdwhv27e8o{&F0cz`9{v;TO0Cw}4DRO-5zL_kJ%GxHkq| zX~!W=Jas4{$5Qu=Q<6;KaS22`OQ)qL>xG!kJTRqzQgJf0ns+*tHvRS7tG>9-BdI1O z4wE?z3cWRTs62=8Q35K|^~O}o-baScZ~LE_T&l&#+ZU+}uGy%FI>2U3dY=+2+ba&F z7lj3!#?RQvL*lmrKOJG2#SX@Is?#C(i;ZK;-?r(uIorIp|5*5V>#dr@cMZ-QG`l?# ztS&@SCqAY|%a=(=G)JLDYUJu4-uddD_M4HhQ;bo~;C;Wq?+Xvs(CAkp+03U3g)LWO z*AWFH?q#LX?+J~h+pjO}csS>nO*VQ}UWh)Ehw<-@r?p`7_ebHyYP15#3I*f>F_U(d z3!g9*)UJbm$y8WT5UmMS7|@-hh6xD>RBYDBE+h)|vOVs3ChI;PXIRM_sO){MjarDj z>Oah1-cYNsZGEi>U!8iUJxWlHcPq!GJ%zU$x!EV&pZ(~lSL?B`;L4({$(yS^g+ke6zDwi6(G&-?O$FgQ}bKSo0znzIH#j>&nVBwCYdiYpWJ|2EMUl;?||L!tDU{Cgc{7_`ioip`sl1tIo zF+SZgU`Aw-zS5y%VYiWZ?ln3TmpPTwqdo#u2wDT(A;OQhh+4Q>)^dbB$9in1q@!)L zSKOyZo~nq$(m7plk_T@7JNWWYCLIdNjHMk2(h{dbVOjVHAb=C-5+I-Zo|Nlj!%~atHy?d z=@8G4=SRExs^q@oZxmg~a`D|)T533Tzg8V)R>`pj``Q(x6~_R}Id?1AFjajIYY5zTL6IhR}NmM;InPAc6J4wukiL;>Z%0ld{vx{D~Pmfe!)oL2ksS zA63p&irBsn=iYMI2>l3Mi^7{=xzLSI&Z|vk5;43K!{R7Gq0;@Aa<^(ZX6fuQ?fImA zb!suBuw0#Zo*J(KCrgo}9ESw+$)_@Jz4g@en=$CinLrF7D}$!4+uvR^v|m6nx)WeC zpfy|mRKowA03bfJ2S9!bAg{v)vQ7U4@$E*`H%FCtSD7%`l458I1;^jL@9TxJcPlFY z27~Qpt{oYXeis{p%a0AFDfNr{f$(Y1YS72{71ks?xjtqUxU79Tke_Gmo{vOUN0$Z9d7Cf9mD;ND#Qg_8RZeU- z5RJ87w_Y!MGbR*VwgZd5fziLBwd*3`qpW09d`1MeJh0tu9CDB4Hx1Du$5TWVtz*QY77sK69(9N%5LAaDe=b+&6G>t!WI zYV3FfO;C4bFHzLu*`t!00Wuo2@C|> zp0viye;=`x8GGup(SF?WNL(1tezuY?e&622h>MAd#TeH6<`{1}mwBNoXL0)qzI{2R z$al}p=Sj>BX+7Ja&)1V4;FA{akwG--lIB!wfUpA{;+@=YYjN^6W_(~(u|AaqH#c4L zi%~2Z_oL=}Sn)jQIQ(8Tb8E1s%t}A8f|?*aO6_cjrbt|~sZp$$>z7JG_AZ(XnbIMR z2qd1@ttC33&>?Ags9Ye!Yy;b>!BkI&EKfHos*=gaOmZBHhV$kMi4|+}sbu@3_lU?X zBqF{LTYFTfV<8@PCFYV}#)YZH9~!rCo~iG`v!i!eUOqU%gNpE6b(nucMtvQD<>Qm0 z7e%IOehXhX0&6n7IGr_^LbWK`&7$yS-9^8&J(Ug}97jWD>nj>5BDCe;xxqT`C6V$Y zt+YE}_MS6OI*qc?b$3zn-mxMYr+Vqar&)a+)|)zeX012c*Rx(de+1kRb_V_hK?>`i z0SbI>lm&A`Yp_l{`GQTa= z4zJNbAT9C*yp5Bx0yJ|E=JQ9A0Qix}c7IY%h4&F%)?0_~SjSybbx+#itIlkc1#2g0we-f(`(K?ygVs zF4!nQg@F`-Lf_Qr(tM6Tfse-5|CD^LJL!~-L2jNhV2|j4i-a zWBL$ZqAJmfAG%yqOb#2Xb}lTo`WM9?$V}MN!>qcy1@;+*w=%iiC9A){UW7tA$@Us@BIO%73=2Y~i_h7fYCP^NvR?dT|QPAcpA;T^AAQS3F) zrorlay>{8Mx+Ts;JkGysYJoaBI_BEbJyw_em1Z8(UEDyydti}a3E1k2)1a^R`nE#3f8d{X5wOApDY%1=Y>Xq2N$ z%%P;mpM=vAn&lU6Cu;ndhqCKI3YKxx>$zz>8gXh3Ld;+0Z}M}eVNXDT7fIa>S_qQ+ zXj3_+PN*~Sc1oZ8OilquqEvj#Df$<{cyX-4D?-w|6SROkjGq1a6p>28Z@$iASpLS=e zvcBhff7xMPVWkb1Xv=3^fuGE~nCawwrf1fiuffyVlgq{DivHG^j1R2LS_xD^bOR>e zGi*T@FQZF{)|V;>MSXBS>PCl}%I7cm25~o5zKfzY<=k{+>1TxceqU{jKY->U#h?VG zL`p&6&4k&^Fi26R0riNHYuMxsJ#BhY;q3$_Z>YjVAihzHxM#SD5<4Tmhj1+6#(6DI z5i5*_c`U`qb2hsy4yg`W+m8>s=Q#|`nO++b>6G_)eoQOgrs6QNq$XA2wP?tUHG)TL zhfnILd9KGWpA+9qJ8!@n%Nutus5gkNTLy9)1XxI;)H-GwoAqM{_i7x~3R60N?d+4~ zht`y{21AT|vTM1zC0Q$hz&+@ZS#!tsYO7(9``o^*54FZ+n)L)$yB@!_nls;ya$37N zY;~%1thngD;qIu}cPe5ts7TCIx*ww2HCF2|=@4d;%U7FhV)nJ^D6nrssb3MFsBJ%XEJ;$rgz*%|f4_M2b4L$n2b-jRWg>H(c zh;>X55MeLlFfiNCja&1amicP0V~R}%?P)VpY!$9xDmfD~E!t!Y7Ubtnb-37 zGI{9o*0{YpMPpA;zEWS)A>bhe3lTazY7>{L*4lWSZ=$ajx;Mw~U7ahyg~LxfkGsp_ zdWx*$*8H-E@$gwR^Z1n~`l@#J3d0I_O%~DtoyZq6(e!Ptmzqe2oYjZ#c%Sz1u8lJa z9GO9}50pLel}yy>c;zci%2D06p_n$?<+u3Q<@HRrsa?-Ny~N!y*w#2{fKp6Rkp)Z0 zJmiAG+W?-9_>&zc`>-L4;$ONRH}%E&#_gtE@k7{u-G#n9-Iw67_#+TE!ga5hQ#B>g zKB2y|=%JsSwjq?CU;#v{lxVi<}E1M;wSAfdpME6_zTyz~}X9Q-|r4(S1g&kJxF zC!mz1{-ob*l5!YXVnELU>g2yGzLs3{w&BHe(Z;jZ^CsI8%97v$@AR!~O^pP8+nu-j zg4Dz_PKpEdEpjAVM45yoeq|Z;P$a=>Odj>0y$Un?h&tW$;08Q}cX$D$;97I~yoq>{ z4O!mC*g0z!+mDvvcvN;It>m+3oXX*63!#3uro?Z(9h3otiWD$wLMUgb8R;L}a})rI z62v>l@zp%}E&9Xp@`_f;ZK^X>)t4`e<~+HPol#NpWOC9;UVgv3c>IaF=RMC7FZqfm zPo@CV6xY?|-2W(RVKi=R%z~$Z|Af_GMCECiczj<41%&cP;m_hx2m$M5^}Q(VK4wUy||wNbHtwk zSg@FZJNM5@f5zj1=k|NB?GN7Lf9@1+F^SZWO!etDz@F&#=y$O=^>nF!P=AkmPwX*u zo=*!X!GP=3pc~iAs1~DNKbM9jxo{It9BeP7crZ>u42N@6DsM~qU@+9 zuRp6KDUNPDBOOSL8d9*tnQdeu6$v&#e^J!m3^?_rKiu%7mR?Wnn>`xyn^vgFzNhI< z-qw>DP8pWk-4;devfFibHXWbWHWQh6fXYVj(>Q!|$3-3!QM^u08q?_)ad*NOFVLY| zCmr?>pS@Y!<}+N0>nVZX!3fBg8T!Ai%eJ%z-Y0LUW24dTd-t0~XAS3ZHKXEx`C*~M8yV!kgu_r*s{N&UrJ;{^jOHh@r>diW9 z^9pSSkYZj%241pG*y2k${_9+P#w;sZ>)fLe6+{TP!A%W6+!c!ZNTBeTa_CYSGRInO z@u}BSTaKE&^Rt-H+Y>^RLee^3(uyQ7w$`5GZ9AhZfi>v}9=#z3d-=oj(^lLu718e6 zNfp>#bQ`vk4zX>N2%c{hspM>R<&j$|sZ5WWwo;!PUtEU?-8>>oR1m&> zLM3$h>~dgwFC{tAc{MrmJ6ech+@dAxW8QCvUmf|FpY%QM=$NH=!=X>O>Y8PZ?Z-vC z%>c2gul|J73Hcf9=Ynao8nXnUR=0px z;{e5ghwKFmSTe;LFebKAX%Cs!xq$fqalQC4Jc4?&1NS4?k4ng?Tp~%JC|JQDIy84T z9gv*)x|d=Z^kTFxFc{a769W`MK-@Tw*)VWNy~F~d-apE6Y$Q~szxS{H_C zjG9Jc^2w-7_V6lNd;hL4umk5MT>Qw8M`c3#N?)ye!IL13W*Ue8JDp5gEt0!S(mbwt zp({^nA~kD%f`tw-T|wRpP$2Ki^=YDUj*l%|{SnZx3EOo2Q;?lT&C(uPSt~+W)-syjQZV#M&%R~pN4Bf z5_ck1cHV*w93f|c$#Wmwg~;oAN!f8JK1``?#2z zatNa=@S}OY6tt8~N++8%xxBUnX+(Uqk7|z~K_o|5{8Tw5oaEGuDh>Tq<%UYdIwr$0P5HYNGgrN!fgZ2A2V1%Kb^nLfdLNP=8*iPjQq1IG6|%o_-0*F z-Y6Fi?%Xxx`L4#})@x=XU)bOS_|;t$9nlG1nYSsgOwXP=Y;kfZ)UWv3hb;Y5hoefI zJzCed5uT1Le#D=xSDf~%MPD|4EW7l;ZBK{QXm<-yrUP-Euc~`)xE>j@fvCsA&O2Iv z@kczCQ!sUxdsjT#-T%Sv4w@Bh8E~3ppB*4Z2pkS8n8O^H+bD(0rE&@eC}i{P=s(XGFLFEI*DhL8tRoA9^8pJOuMp?9s4=eU}UNuvz@|6IN>a` zyMHu5?)#mzb!F3#HA^qCX9p(`mvpE|k`5uN2JkrpWJK~_o)4J2Q}W?{tXkK}z-~nH z&YK3ONR*K5qS3IrJ(y8MWY+2u+;&}%W4VcIqRvgkH%4zUV`YyH>(yxPi?TA`6W>$H z+3I%-hK;G2@EmKY)pOi1YDA?D`ewmkc9RcK$ACebAD3^RkTf9Z@Mvs zBOmuaI5*6?T~mhgBd0jy%#lkOFpuU5jjP-h%w_nV*DBxSzar-r{WV((C@Zv1RK7)> zI-uGQ?!b^!dHAPi(7F$29LRS1f)QQM2oru4rQT880*5Vdpnex!itg) zHkuWdY}YpnSJ4R8^HZiA6>I=LgcjHsR2@7=hoW+(u{43HP|UOy@W${cphx)(C^F5Q zbf_f{#1BU*6lnW{kk4aD*A-&0KP&@49`yD0 z>pHpY+`BjUV0hWY2scc;g>{0Z<7(nB@)ZcG{2d+ZKaog5ApXKwr~glcayAjrpP?RS zf(4CJkE~5G$6GAKk1fG{&W))NT119Y<*ssY30iz&?|NW}4F%u4u)RGfP>QQtr~`)LvWeJxT$ z;jNECtzh5&0tbn^84i0R9VK?ZSrvH^z1@Hns4x+AHd%3U-F)+W1hSl@wiA&S2ky&Uspt+{PQ<`$j94iC0P-=J;5rX zcpcH!;06;8d4hk=GPmsLZUw&6xGFoD!K4{^0>ympEhc}{smbzjnC~Q?c0%p;NN-;X z$Wp8$woZ=K?v|*I$*oCF?exnjo-A*xm`$)W4}Pxf(LDaHLB8&a%HxZN?tg#ght4bs z+zG}Upei|m50eqU?^!U_=J-h*Xl0NZ0By9bl_A;WQvRPS>mFHaSc*aIS&i+7H&krF zqiV524Vn#6OG;Ui$8!k+b!FO56OX^tzH&})8m6uJnq@6yb6VxpAxNi(@u#sH9F*UH zru&XuKODO$iT#Tt2}u?Xp^s_|Vp?ZaTV&+qg0&)6#iFZ~L>0@MA^D=*22$>^}k! zEO>t!C(y-`>ton#5ZF)iS|!(@f^qnBnTfg75{kpkAjP^Jk43k&Jh;L%S*}P!*b<^> zca{JG9XT>Zhs0Z8^Q!_RpmE{Zq&kpI_Xf;aywD0r5jejfF@pW~NCjg{2$I9G5`0p~ zzJksp>dw-a@Al2BrNzBHbbf&6{?2jH7TDY>NFC>c;}7x)+rJn1pcZtUJ5 z%Yp5)v2`vE2IY8SruVCB=DAj=zT+*;u7?wR25#yIm;gK67TZ@tv<(@fB}j$`Ah&wa z4&}uzMjx2vxlPN8U2DL9phF&D*V@yfME99Bck4l2iGnZO_KCaBWu~$Ozk`d0)XR*x zJu)0UaH~A|3$1k&y}!my9^QXu?V5pM!&}VTKtz+r=X{r|lMb^$Wh;)G$r@9#7bPSz)rk*uh`xx%alt zcgr@m+GEFGg*KL5=hl_p9Sm1Z<%oWB=lS^C*^r206s)$`^@`2l8^m2_Pny#z%JVT9 z1@fRMSz05mU;$Taxey>d&K158aOQ=9i(k+2Rk*glY{j5(k%mRb@Kjddcg`P#?Pp*8 zK;Fv>!0vi5_C2J&y3I!Gp0~+c41Uie5bgj6WAPTW_@w-mMx^jJoN$nPZDIaDR*VX1 zqC?X5bg1Ml=Epdy3^kR7(Ln7%i`oT9Q!C2c$2GP3xSAGN8j}1T?pRY@PV>px)oJ4d zV~x3~^8!A7E0S^pfS$epQ()ius*&pe0yQ}PqlAU1AGzK{u1KoTUYiFRW6iY({sX^T?Y*Vk4Rr1YNo zd--cMVhSBXga45)QejEW!CWyTML4;QBRH)?33??rO7p_)$vV(1jIzp-u@<&RJLe4m zftoVOH_wj&ZwG(cY{#)Cvvlls! zPMP2y`VSklEjUrxD95R3T01DB2`>prvH5WL;Oo!1B^9v?Dy!Rr&&Q^8Cn!+(Ylu$H zSkZvfg~QJ-&v;iMmvY2h=TObH?S^iOO)~kpr8~Uc6EFG2nVdbD^AUMJb|!ulx3CT0 zJVs`x>>4kJ)mn((IGSkDT2LK(mP5UABg=0OMy9antmQzRn~PH78qYzW?-7wD2Y<3Y z$W26GID_Aj`bUqxv>#oH6jZiT#oG%+EvzU%e$%61T&??MRy{LrDEd%-5W2_IvSKSC zIg9|W?sJIHP=3=tCnS>2UYuWE;PUwZVnXMW=m^;NzFqG+gT4*;kBqI>f7yKfFC+yd zMa_H*EZ*$1XtH=RhnDn1pNZ3rm9s!avRW*GFznxI5p6^<4u6~EObZ>9p+nFmIy44U z!X0=G>WBOcip0Y3Z)_f(X0ug4k=wfPWyg-2mX$VcF?|yE+~i%<})cJ1Vc_0!_oVTYM-@oB1eC(xmq*Z|-p>e-(Ko{JKO;)Of) z`UU(8isZHwhM9f`82|fY=}=579pcu+FHr^VflYR-;D3ZZs#;2rMg!5AB<4z1q448} zYch?kZEp#rMNv!;nfNlY*Nbl&_t`<7W={dMGjr8-L#Q z_uKzMt_%nE7jpfN9Jb9ZOuwegzx;I#a5>OA(60Yif1;xTbV6{(uCRG!0$1a=VMXH= zH|p>L7iKPUqXwjCrKp(|yNn63#G9nB5way^Zo%OA(|I>;?}2&^5L=8>;%B1tn4V}f zjeLKgawPbmPTD3hgE3*4aWCPd{jHB^wOFn)$`V=Pn=;0GAsz&}8{AOM&$IHoiw@cJ z*RGf-hL1-c8TeK^0)E%P7;_SpH&qjlj~a2ktsyLG>XtIyRhYzPvP~u0H!bk|M~Wj$ zixguWg7<$BdSz7KT(z6H;bX8NYt;2j~F- z5U`t#(G0*YVw3@7v?=;UY5BK-lJq}GNtABQCkfV_{a8O(zS3hM_#cYWZo z1{5jE*?Yu<~PsH}_TN+!di*k+dTaAaa zkxqQST6j38De!f+kT}XLd`w^KB}_dA>5>VntYB-=+C?%j!sG5L6)OdDoxG#teC0;5 zWd}Mf&QSK2p?I9({vyYJO6mIfBN+dj_VurW%bNrGtIB3f$NJZgOoaSy4gW}|@^dnb z%D>WL3{`jP$KUOa_``DkgDL%=1;8h1JJa&VekhRB{r&d~5-2CBiD(|mrQ*1$dIa2K z&$SH`9GaLZ&>rXzdp(S{kt2n`8|CyqzEQSBGGCw4vg$sv2byhSA0fAS=zGP51S(9?|R{=e1O|JnB#eWd&Q#*zQFYXE+M H(R=?dGX#!_ literal 0 HcmV?d00001 diff --git a/public/upload-license.php b/public/upload-license.php new file mode 100644 index 0000000..fe6bf93 --- /dev/null +++ b/public/upload-license.php @@ -0,0 +1,41 @@ +getMessage(); + } +} +?> + + + + + + + + Blue Twilight - License Needed + + +

Blue Twilight - License Needed

+ +
+

+

+

+
+ + \ No newline at end of file diff --git a/resources/lang/en/installer.php b/resources/lang/en/installer.php new file mode 100644 index 0000000..7412473 --- /dev/null +++ b/resources/lang/en/installer.php @@ -0,0 +1,12 @@ + 'Blue Twilight Installer', + 'license_file_label' => 'Upload your license file:', + 'license_required_text' => 'Blue Twilight requires a license file to run. The license file is called "blue-twilight.lic" ' . + 'and can be downloaded from the %link_start%My Orders%link_end% page on the %link2_start%Apps by Andy - Web Store%link2_end%.', + 'license_required_text2' => 'The host name in the license file must be: ', + 'license_required_text3' => 'Once you have your license file, please upload it using the field below.', + 'licensed_to' => 'Licensed to: ', + 'save_button' => 'Save', + 'upload_button' => 'Upload' +]; \ No newline at end of file diff --git a/resources/views/install/administrator.blade.php b/resources/views/install/administrator.blade.php new file mode 100644 index 0000000..048f020 --- /dev/null +++ b/resources/views/install/administrator.blade.php @@ -0,0 +1,37 @@ +@extends('install.layout') + +@section('content') +

You will need an administrator account to access Blue Twilight.

+

Please enter the below details to create your administrator account:

+ +
+
+
+ {{ csrf_field() }} +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/install/database.blade.php b/resources/views/install/database.blade.php new file mode 100644 index 0000000..3979d41 --- /dev/null +++ b/resources/views/install/database.blade.php @@ -0,0 +1,47 @@ +@extends('install.layout') + +@section('content') +

Please provide the connection details to your MySQL database:

+ +
+
+ @if (!is_null($database_error)) +
+

Database error: {{ $database_error }}

+
+ @endif + +
+ {{ csrf_field() }} +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/install/layout.blade.php b/resources/views/install/layout.blade.php new file mode 100644 index 0000000..2f166ff --- /dev/null +++ b/resources/views/install/layout.blade.php @@ -0,0 +1,42 @@ + + + + + + + + + Blue Twilight - Installation + + + + + + + +
+
+
+

Install Blue Twilight

+ @yield('content') +
+
+
+ + + + + \ No newline at end of file diff --git a/resources/views/themes/base/gallery/index.blade.php b/resources/views/themes/base/gallery/index.blade.php index 6176ffd..dd7ba8f 100644 --- a/resources/views/themes/base/gallery/index.blade.php +++ b/resources/views/themes/base/gallery/index.blade.php @@ -4,27 +4,35 @@ @section('content')
- @foreach ($albums as $album) -
-
- -
-

- @php($albumUrl = $album->thumbnailUrl('preview')) - @if (strlen($albumUrl) > 0) - - @endif -

-

{{ $album->description }}

-
- - @endforeach + @endforeach + @else +
+ + +

Nothing to see here!

+
+ @endif
diff --git a/routes/web.php b/routes/web.php index e04168b..47e55d0 100644 --- a/routes/web.php +++ b/routes/web.php @@ -36,6 +36,8 @@ Route::group(['prefix' => 'admin'], function () { // Gallery Route::get('/', 'Gallery\DefaultController@index')->name('home'); +Route::get('/install', 'InstallController@start'); +Route::post('/install', 'InstallController@start'); Route::get('/activate/{token}', 'Auth\ActivateController@activate')->name('auth.activate'); Route::get('{albumUrlAlias}', 'Gallery\AlbumController@index')->name('viewAlbum'); Route::get('{albumUrlAlias}/{photoFilename}', 'Gallery\PhotoController@show')->name('viewPhoto'); diff --git a/verify-license.php b/verify-license.php new file mode 100644 index 0000000..80bc2f1 --- /dev/null +++ b/verify-license.php @@ -0,0 +1,5 @@ + sg_get_const('lic_name'), + 'lic_num' => sg_get_const('lic_num') +];