diff --git a/app/Console/Commands/FinishUpdate.php b/app/Console/Commands/FinishUpdate.php new file mode 100644 index 000000000..849336987 --- /dev/null +++ b/app/Console/Commands/FinishUpdate.php @@ -0,0 +1,49 @@ +info('Finishing update...'); + + session(['company_id' => $this->argument('company_id')]); + + $this->call('cache:clear'); + + event(new UpdateFinished($this->argument('alias'), $this->argument('new'), $this->argument('old'))); + } +} diff --git a/app/Console/Commands/Update.php b/app/Console/Commands/Update.php new file mode 100644 index 000000000..9d4150996 --- /dev/null +++ b/app/Console/Commands/Update.php @@ -0,0 +1,158 @@ +alias = $this->argument('alias'); + + $this->new = $this->getNewVersion(); + + $this->old = $this->getOldVersion(); + + session(['company_id' => $this->argument('company_id')]); + + if (!$path = $this->download()) { + return self::CMD_ERROR; + } + + if (!$this->unzip($path)) { + return self::CMD_ERROR; + } + + if (!$this->copyFiles($path)) { + return self::CMD_ERROR; + } + + if (!$this->finish()) { + return self::CMD_ERROR; + } + + return self::CMD_SUCCESS; + } + + public function getNewVersion() + { + $new = $this->argument('new'); + + if ($new == 'latest') { + $modules = ($this->alias == 'core') ? [] : [$this->alias]; + + $new = Versions::latest($modules)[$this->alias]; + } + + return $new; + } + + public function getOldVersion() + { + return ($this->alias == 'core') + ? version('short') + : module($this->alias)->get('version'); + } + + public function download() + { + $this->info('Downloading update...'); + + try { + $path = Updater::download($this->alias, $this->new, $this->old); + } catch (\Exception $e) { + $this->error($e->getMessage()); + + return false; + } + + return $path; + } + + public function unzip($path) + { + $this->info('Unzipping update...'); + + try { + Updater::unzip($path, $this->alias, $this->new, $this->old); + } catch (\Exception $e) { + $this->error($e->getMessage()); + + return false; + } + + return true; + } + + public function copyFiles($path) + { + $this->info('Copying update files...'); + + try { + Updater::copyFiles($path, $this->alias, $this->new, $this->old); + } catch (\Exception $e) { + $this->error($e->getMessage()); + + return false; + } + + return true; + } + + public function finish() + { + $this->info('Finishing update...'); + + try { + Updater::finish($this->alias, $this->new, $this->old); + } catch (\Exception $e) { + $this->error($e->getMessage()); + + return false; + } + + return true; + } +} diff --git a/app/Http/Controllers/Install/Updates.php b/app/Http/Controllers/Install/Updates.php index aee0b55bb..6438e1179 100644 --- a/app/Http/Controllers/Install/Updates.php +++ b/app/Http/Controllers/Install/Updates.php @@ -6,7 +6,6 @@ use App\Abstracts\Http\Controller; use App\Utilities\Updater; use App\Utilities\Versions; use Illuminate\Http\Request; -use Module; class Updates extends Controller { @@ -111,31 +110,31 @@ class Updates extends Controller // Download $steps[] = [ 'text' => trans('modules.installation.download', ['module' => $name]), - 'url' => url('install/updates/download') + 'url' => route('updates.download'), ]; // Unzip $steps[] = [ 'text' => trans('modules.installation.unzip', ['module' => $name]), - 'url' => url('install/updates/unzip') + 'url' => route('updates.unzip'), ]; - // File Copy + // Copy files $steps[] = [ 'text' => trans('modules.installation.file_copy', ['module' => $name]), - 'url' => url('install/updates/file-copy') + 'url' => route('updates.copy'), ]; - // Finish installation + // Finish/Apply $steps[] = [ 'text' => trans('modules.installation.finish', ['module' => $name]), - 'url' => url('install/updates/finish') + 'url' => route('updates.finish'), ]; // Redirect $steps[] = [ 'text' => trans('modules.installation.redirect', ['module' => $name]), - 'url' => url('install/updates/redirect') + 'url' => route('updates.redirect'), ]; return response()->json([ @@ -155,9 +154,27 @@ class Updates extends Controller */ public function download(Request $request) { - set_time_limit(600); // 10 minutes + set_time_limit(900); // 15 minutes - $json = Updater::download($request['alias'], $request['version'], $request['installed']); + try { + $path = Updater::download($request['alias'], $request['version'], $request['installed']); + + $json = [ + 'success' => true, + 'error' => false, + 'message' => null, + 'data' => [ + 'path' => $path, + ], + ]; + } catch (\Exception $e) { + $json = [ + 'success' => false, + 'error' => true, + 'message' => $e->getMessage(), + 'data' => [], + ]; + } return response()->json($json); } @@ -171,9 +188,27 @@ class Updates extends Controller */ public function unzip(Request $request) { - set_time_limit(600); // 10 minutes + set_time_limit(900); // 15 minutes - $json = Updater::unzip($request['path'], $request['alias'], $request['version'], $request['installed']); + try { + $path = Updater::unzip($request['path'], $request['alias'], $request['version'], $request['installed']); + + $json = [ + 'success' => true, + 'error' => false, + 'message' => null, + 'data' => [ + 'path' => $path, + ], + ]; + } catch (\Exception $e) { + $json = [ + 'success' => false, + 'error' => true, + 'message' => $e->getMessage(), + 'data' => [], + ]; + } return response()->json($json); } @@ -185,11 +220,29 @@ class Updates extends Controller * * @return Response */ - public function fileCopy(Request $request) + public function copyFiles(Request $request) { - set_time_limit(600); // 10 minutes + set_time_limit(900); // 15 minutes - $json = Updater::fileCopy($request['path'], $request['alias'], $request['version'], $request['installed']); + try { + $path = Updater::copyFiles($request['path'], $request['alias'], $request['version'], $request['installed']); + + $json = [ + 'success' => true, + 'error' => false, + 'message' => null, + 'data' => [ + 'path' => $path, + ], + ]; + } catch (\Exception $e) { + $json = [ + 'success' => false, + 'error' => true, + 'message' => $e->getMessage(), + 'data' => [], + ]; + } return response()->json($json); } @@ -203,7 +256,25 @@ class Updates extends Controller */ public function finish(Request $request) { - $json = Updater::finish($request['alias'], $request['version'], $request['installed']); + set_time_limit(900); // 15 minutes + + try { + Updater::finish($request['alias'], $request['version'], $request['installed']); + + $json = [ + 'success' => true, + 'error' => false, + 'message' => null, + 'data' => [], + ]; + } catch (\Exception $e) { + $json = [ + 'success' => false, + 'error' => true, + 'message' => $e->getMessage(), + 'data' => [], + ]; + } return response()->json($json); } @@ -215,13 +286,15 @@ class Updates extends Controller * * @return Response */ - public function redirect(Request $request) + public function redirect() { - return response()->json([ + $json = [ 'success' => true, 'errors' => false, 'redirect' => route('updates.index'), 'data' => [], - ]); + ]; + + return response()->json($json); } } diff --git a/app/Http/Controllers/Modules/Item.php b/app/Http/Controllers/Modules/Item.php index a06d5d640..2dcede65b 100644 --- a/app/Http/Controllers/Modules/Item.php +++ b/app/Http/Controllers/Modules/Item.php @@ -268,25 +268,6 @@ class Item extends Controller return redirect('apps/' . $alias)->send(); } - /** - * Final actions post update. - * - * @param $alias - * @return Response - */ - public function post($alias) - { - Artisan::call('module:install', ['alias' => $alias, 'company_id' => session('company_id')]); - - $module = module($alias); - - $message = trans('modules.installed', ['module' => $module->getName()]); - - flash($message)->success(); - - return redirect('apps/' . $alias); - } - public function reviews($alias, Request $request) { $page = $request['page']; diff --git a/app/Listeners/Update/CreateModuleUpdatedHistory.php b/app/Listeners/Update/CreateModuleUpdatedHistory.php new file mode 100644 index 000000000..39761abb4 --- /dev/null +++ b/app/Listeners/Update/CreateModuleUpdatedHistory.php @@ -0,0 +1,41 @@ +alias)->first(); + + if (empty($model)) { + return; + } + + // Get module instance + $module = module($event->alias); + + if (empty($module)) { + return; + } + + // Add history + ModuleHistory::create([ + 'company_id' => $model->company_id, + 'module_id' => $model->id, + 'category' => $module->get('category', 'payment-method'), + 'version' => $event->version, + 'description' => trans('modules.history.updated', ['module' => $module->getAlias()]), + ]); + } +} diff --git a/app/Providers/Event.php b/app/Providers/Event.php index f1dfa41b2..1bd11d3ab 100644 --- a/app/Providers/Event.php +++ b/app/Providers/Event.php @@ -73,6 +73,9 @@ class Event extends Provider 'App\Events\Menu\PortalCreated' => [ 'App\Listeners\Menu\AddPortalItems', ], + 'App\Events\Install\UpdateFinished' => [ + 'App\Listeners\Update\CreateModuleUpdatedHistory', + ], ]; /** diff --git a/app/Traits/Modules.php b/app/Traits/Modules.php index daf010204..0f29a2719 100644 --- a/app/Traits/Modules.php +++ b/app/Traits/Modules.php @@ -3,6 +3,7 @@ namespace App\Traits; use App\Traits\SiteApi; +use App\Utilities\Console; use App\Utilities\Info; use App\Models\Module\Module as Model; use App\Models\Module\Module; @@ -14,7 +15,6 @@ use Illuminate\Support\Str; use GuzzleHttp\Exception\RequestException; use ZipArchive; - trait Modules { use SiteApi; @@ -408,17 +408,19 @@ trait Modules File::copyDirectory($temp_path, $module_path); File::deleteDirectory($temp_path); - Artisan::call('cache:clear'); - $data = [ 'path' => $path, 'name' => Str::studly($module->alias), 'alias' => $module->alias ]; + $company_id = session('company_id'); + + Console::run("php artisan module:install {$module->alias} {$company_id}"); + return [ 'success' => true, - 'redirect' => url("apps/post/" . $module->alias), + 'redirect' => url('apps/' . $module->alias), 'error' => false, 'message' => null, 'data' => $data, @@ -446,7 +448,7 @@ trait Modules 'success' => true, 'error' => false, 'message' => null, - 'data' => $data + 'data' => $data, ]; } @@ -468,7 +470,7 @@ trait Modules 'success' => true, 'error' => false, 'message' => null, - 'data' => $data + 'data' => $data, ]; } @@ -490,7 +492,7 @@ trait Modules 'success' => true, 'error' => false, 'message' => null, - 'data' => $data + 'data' => $data, ]; } diff --git a/app/Utilities/Console.php b/app/Utilities/Console.php new file mode 100644 index 000000000..4dc2eac75 --- /dev/null +++ b/app/Utilities/Console.php @@ -0,0 +1,21 @@ +run(); + + if ($process->isSuccessful()) { + return true; + } + + return false; + } +} diff --git a/app/Utilities/Updater.php b/app/Utilities/Updater.php index 7eeb028b7..846ef6b84 100644 --- a/app/Utilities/Updater.php +++ b/app/Utilities/Updater.php @@ -2,8 +2,9 @@ namespace App\Utilities; -use App\Models\Module\Module as Model; -use App\Models\Module\ModuleHistory as ModelHistory; +use App\Events\Install\UpdateCopied; +use App\Events\Install\UpdateDownloaded; +use App\Events\Install\UpdateUnzipped; use App\Traits\SiteApi; use Cache; use Date; @@ -23,7 +24,7 @@ class Updater return true; } - public static function download($alias, $version, $installed) + public static function download($alias, $new, $old) { $file = null; $path = null; @@ -32,101 +33,53 @@ class Updater $info = Info::all(); if ($alias == 'core') { - $url = 'core/download/' . $version . '/' . $info['php'] . '/' . $info['mysql']; + $url = 'core/download/' . $new . '/' . $info['php'] . '/' . $info['mysql']; } else { - $url = 'apps/' . $alias . '/download/' . $version . '/' . $info['akaunting'] . '/' . $info['token']; + $url = 'apps/' . $alias . '/download/' . $new . '/' . $info['akaunting'] . '/' . $info['token']; } $response = static::getRemote($url, 'GET', ['timeout' => 50, 'track_redirects' => true]); // Exception - if ($response instanceof RequestException) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.download', ['module' => $alias]), - 'data' => [ - 'path' => $path - ] - ]; + if (!$response || ($response instanceof RequestException) || ($response->getStatusCode() != 200)) { + throw new \Exception(trans('modules.errors.download', ['module' => $alias])); } - if ($response && ($response->getStatusCode() == 200)) { - $file = $response->getBody()->getContents(); + $file = $response->getBody()->getContents(); - $path = 'temp-' . md5(mt_rand()); - $temp_path = storage_path('app/temp') . '/' . $path; + $path = 'temp-' . md5(mt_rand()); + $temp_path = storage_path('app/temp') . '/' . $path; - $file_path = $temp_path . '/upload.zip'; + $file_path = $temp_path . '/update.zip'; - // Create tmp directory - if (!File::isDirectory($temp_path)) { - File::makeDirectory($temp_path); - } - - // Add content to the Zip file - $uploaded = is_int(file_put_contents($file_path, $file)) ? true : false; - - if (!$uploaded) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.zip', ['module' => $alias]), - 'data' => [ - 'path' => $path - ] - ]; - } - - try { - event(new \App\Events\Install\UpdateDownloaded($alias, $version, $installed)); - - return [ - 'success' => true, - 'error' => false, - 'message' => null, - 'data' => [ - 'path' => $path - ] - ]; - } catch (\Exception $e) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.download', ['module' => $alias]), - 'data' => [] - ]; - } + // Create tmp directory + if (!File::isDirectory($temp_path)) { + File::makeDirectory($temp_path); } - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.download', ['module' => $alias]), - 'data' => [ - 'path' => $path - ] - ]; + // Add content to the Zip file + $uploaded = is_int(file_put_contents($file_path, $file)) ? true : false; + + if (!$uploaded) { + throw new \Exception(trans('modules.errors.zip', ['module' => $alias])); + } + + event(new UpdateDownloaded($alias, $new, $old)); + + return $path; } - public static function unzip($path, $alias, $version, $installed) + public static function unzip($path, $alias, $new, $old) { $temp_path = storage_path('app/temp') . '/' . $path; - $file = $temp_path . '/upload.zip'; + $file = $temp_path . '/update.zip'; // Unzip the file $zip = new ZipArchive(); if (($zip->open($file) !== true) || !$zip->extractTo($temp_path)) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.unzip', ['module' => $alias]), - 'data' => [ - 'path' => $path - ] - ]; + throw new \Exception(trans('modules.errors.unzip', ['module' => $alias])); } $zip->close(); @@ -134,42 +87,19 @@ class Updater // Delete zip file File::delete($file); - try { - event(new \App\Events\Install\UpdateUnzipped($alias, $version, $installed)); + event(new UpdateUnzipped($alias, $new, $old)); - return [ - 'success' => true, - 'error' => false, - 'message' => null, - 'data' => [ - 'path' => $path - ] - ]; - } catch (\Exception $e) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.unzip', ['module' => $alias]), - 'data' => [] - ]; - } + return $path; } - public static function fileCopy($path, $alias, $version, $installed) + public static function copyFiles($path, $alias, $new, $old) { $temp_path = storage_path('app/temp') . '/' . $path; if ($alias == 'core') { // Move all files/folders from temp path if (!File::copyDirectory($temp_path, base_path())) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.file_copy', ['module' => $alias]), - 'data' => [ - 'path' => $path - ] - ]; + throw new \Exception(trans('modules.errors.file_copy', ['module' => $alias])); } } else { // Get module instance @@ -184,87 +114,31 @@ class Updater // Move all files/folders from temp path if (!File::copyDirectory($temp_path, $module_path)) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.file_copy', ['module' => $alias]), - 'data' => [ - 'path' => $path - ] - ]; - } - - $model = Model::where('alias', $alias)->first(); - - if (!empty($model)) { - // Add history - ModelHistory::create([ - 'company_id' => session('company_id'), - 'module_id' => $model->id, - 'category' => $module->get('category', 'payment-method'), - 'version' => $version, - 'description' => trans('modules.history.updated', ['module' => $module->get('alias')]), - ]); + throw new \Exception(trans('modules.errors.file_copy', ['module' => $alias])); } } // Delete temp directory File::deleteDirectory($temp_path); - Artisan::call('cache:clear'); + event(new UpdateCopied($alias, $new, $old)); - try { - event(new \App\Events\Install\UpdateCopied($alias, $version, $installed)); - - return [ - 'success' => true, - 'error' => false, - 'message' => null, - 'data' => [ - 'path' => $path - ] - ]; - } catch (\Exception $e) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.file_copy', ['module' => $alias]), - 'data' => [] - ]; - } + return $path; } - public static function finish($alias, $version, $installed) + public static function finish($alias, $new, $old) { // Check if the file mirror was successful - if (($alias == 'core') && (version('short') != $version)) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.file_copy', ['module' => $alias]), - 'data' => [] - ]; + if (($alias == 'core') && (version('short') != $new)) { + throw new \Exception(trans('modules.errors.finish', ['module' => $alias])); } - // Clear cache after update - Artisan::call('cache:clear'); + $company_id = session('company_id'); - try { - event(new \App\Events\Install\UpdateFinished($alias, $installed, $version)); + $command = "php artisan update:finish {$alias} {$company_id} {$new} {$old}"; - return [ - 'success' => true, - 'error' => false, - 'message' => null, - 'data' => [] - ]; - } catch (\Exception $e) { - return [ - 'success' => false, - 'error' => true, - 'message' => trans('modules.errors.finish', ['module' => $alias]), - 'data' => [] - ]; + if (!Console::run($command)) { + throw new \Exception(trans('modules.errors.finish', ['module' => $alias])); } } diff --git a/app/Utilities/Versions.php b/app/Utilities/Versions.php index 71e71468b..7830b359c 100644 --- a/app/Utilities/Versions.php +++ b/app/Utilities/Versions.php @@ -65,7 +65,7 @@ class Versions $info = Info::all(); // No data in cache, grab them from remote - $data = array(); + $data = []; // Check core first $url = 'core/version/' . $info['akaunting'] . '/' . $info['php'] . '/' . $info['mysql'] . '/' . $info['companies']; diff --git a/overrides/akaunting/module/Commands/InstallCommand.php b/overrides/akaunting/module/Commands/InstallCommand.php index 01c5ed62f..d003e8a3f 100644 --- a/overrides/akaunting/module/Commands/InstallCommand.php +++ b/overrides/akaunting/module/Commands/InstallCommand.php @@ -39,26 +39,22 @@ class InstallCommand extends Command // Set company id session(['company_id' => $company_id]); - $request = [ - 'company_id' => $company_id, - 'alias' => strtolower($alias), - 'enabled' => '1', - ]; - - $model = Module::create($request); - $module = module($alias); + $model = Module::create([ + 'company_id' => $company_id, + 'alias' => $alias, + 'enabled' => '1', + ]); + // Add history - $data = [ + ModuleHistory::create([ 'company_id' => $company_id, 'module_id' => $model->id, 'category' => $module->get('category', 'payment-method'), 'version' => $module->get('version'), - 'description' => trans('modules.installed', ['module' => $module->get('alias')]), - ]; - - ModuleHistory::create($data); + 'description' => trans('modules.installed', ['module' => $alias]), + ]); // Clear cache $this->call('cache:clear'); diff --git a/resources/lang/en-GB/modules.php b/resources/lang/en-GB/modules.php index 30df9fe1a..df868f519 100644 --- a/resources/lang/en-GB/modules.php +++ b/resources/lang/en-GB/modules.php @@ -46,7 +46,7 @@ return [ 'unzip' => 'Extracting :module files', 'file_copy' => 'Copying :module files', 'finish' => 'Finalizing :module installation', - 'redirect' => ':module installed, redirecting to Updates page', + 'redirect' => ':module installed, redirecting to updates page', 'install' => 'Installing :module', ], diff --git a/routes/admin.php b/routes/admin.php index 54fa987eb..d51228927 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -177,8 +177,6 @@ Route::group(['as' => 'apps.', 'prefix' => 'apps'], function () { Route::post('unzip', 'Modules\Item@unzip')->name('unzip'); Route::post('install', 'Modules\Item@install')->name('install'); - Route::get('post/{alias}', 'Modules\Item@post'); - Route::post('{alias}/reviews', 'Modules\Item@reviews')->name('app.reviews'); Route::get('{alias}/uninstall', 'Modules\Item@uninstall')->name('app.uninstall'); Route::get('{alias}/enable', 'Modules\Item@enable')->name('app.enable'); @@ -191,11 +189,10 @@ Route::group(['prefix' => 'install'], function () { Route::get('updates/changelog', 'Install\Updates@changelog')->name('updates.changelog'); Route::get('updates/check', 'Install\Updates@check')->name('updates.check'); Route::get('updates/update/{alias}/{version}', 'Install\Updates@update')->name('updates.update'); - Route::get('updates/post/{alias}/{old}/{new}', 'Install\Updates@post')->name('updates.post'); Route::post('updates/steps', 'Install\Updates@steps')->name('updates.steps'); Route::post('updates/download', 'Install\Updates@download')->middleware('api.key')->name('updates.download'); Route::post('updates/unzip', 'Install\Updates@unzip')->middleware('api.key')->name('updates.unzip'); - Route::post('updates/file-copy', 'Install\Updates@fileCopy')->middleware('api.key')->name('updates.copy'); + Route::post('updates/copy-files', 'Install\Updates@copyFiles')->middleware('api.key')->name('updates.copy'); Route::post('updates/migrate', 'Install\Updates@migrate')->name('updates.migrate'); Route::post('updates/finish', 'Install\Updates@finish')->name('updates.finish'); Route::post('updates/redirect', 'Install\Updates@redirect')->name('updates.redirect');