From dac08458d410c021511d9bf92e4e7b8bb0531a12 Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 01:13:34 +0100 Subject: [PATCH 1/9] Started building update functions out --- app/Helpers/UpdateHelper.php | 13 +++++++++++++ app/Http/Controllers/UpdateController.php | 16 ++++++++++++++++ composer.lock | 10 +++++----- config/app.php | 8 -------- config/speedtest.php | 21 +++++++++++++++++++++ public/js/app.js | 2 +- resources/js/components/Data/Restore.js | 2 +- resources/views/app.blade.php | 2 +- routes/api.php | 8 ++++++++ 9 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 app/Helpers/UpdateHelper.php create mode 100644 app/Http/Controllers/UpdateController.php create mode 100644 config/speedtest.php diff --git a/app/Helpers/UpdateHelper.php b/app/Helpers/UpdateHelper.php new file mode 100644 index 00000000..77aa0d98 --- /dev/null +++ b/app/Helpers/UpdateHelper.php @@ -0,0 +1,13 @@ +json([ + 'update' => UpdateHelper::check(), + ], 200); + } +} diff --git a/composer.lock b/composer.lock index d76fb65c..8806a544 100644 --- a/composer.lock +++ b/composer.lock @@ -690,16 +690,16 @@ }, { "name": "laravel/framework", - "version": "v7.5.1", + "version": "v7.5.2", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "b2457b1ddb9c59396313eae4e948bdc5fa5251db" + "reference": "3a3b3f7fea69813f5a03449c6314bfb42c3ccf78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/b2457b1ddb9c59396313eae4e948bdc5fa5251db", - "reference": "b2457b1ddb9c59396313eae4e948bdc5fa5251db", + "url": "https://api.github.com/repos/laravel/framework/zipball/3a3b3f7fea69813f5a03449c6314bfb42c3ccf78", + "reference": "3a3b3f7fea69813f5a03449c6314bfb42c3ccf78", "shasum": "" }, "require": { @@ -837,7 +837,7 @@ "framework", "laravel" ], - "time": "2020-04-07T18:52:38+00:00" + "time": "2020-04-08T15:54:18+00:00" }, { "name": "laravel/tinker", diff --git a/config/app.php b/config/app.php index 0243232d..8409e00e 100644 --- a/config/app.php +++ b/config/app.php @@ -123,14 +123,6 @@ return [ 'cipher' => 'AES-256-CBC', - /* - |-------------------------------------------------------------------------- - | Version numebr - |-------------------------------------------------------------------------- - */ - - 'version' => '1.1.0', - /* |-------------------------------------------------------------------------- | Autoloaded Service Providers diff --git a/config/speedtest.php b/config/speedtest.php new file mode 100644 index 00000000..a49e37b9 --- /dev/null +++ b/config/speedtest.php @@ -0,0 +1,21 @@ + '1.1.0', + + /* + |-------------------------------------------------------------------------- + | GitHub Repo Variables + |-------------------------------------------------------------------------- + */ + + 'user' => 'henrywhitaker3', + 'repo' => 'Speedtest-Tracker', + 'branch' => 'master', +]; diff --git a/public/js/app.js b/public/js/app.js index 2246af1c..6877cd20 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -126769,7 +126769,7 @@ var Restore = /*#__PURE__*/function (_Component) { }; var url = '/api/restore'; axios__WEBPACK_IMPORTED_MODULE_4___default.a.post(url, data).then(function (resp) { - react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].success('Your is being restored...'); + react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].success('Your data is being restored...'); _this.setState({ show: false, diff --git a/resources/js/components/Data/Restore.js b/resources/js/components/Data/Restore.js index 1c472efa..ffd28268 100644 --- a/resources/js/components/Data/Restore.js +++ b/resources/js/components/Data/Restore.js @@ -57,7 +57,7 @@ export default class Restore extends Component { Axios.post(url, data) .then((resp) => { - toast.success('Your is being restored...'); + toast.success('Your data is being restored...'); this.setState({ show: false, data: null, diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php index cdb73d5b..f93ffdf6 100644 --- a/resources/views/app.blade.php +++ b/resources/views/app.blade.php @@ -5,7 +5,7 @@ - + diff --git a/routes/api.php b/routes/api.php index 353f9372..45580e18 100644 --- a/routes/api.php +++ b/routes/api.php @@ -37,3 +37,11 @@ Route::group([ Route::post('restore', 'BackupController@restore') ->name('data.restore'); }); + +Route::group([ + 'middleware' => 'api', + 'prefix' => 'update', +], function () { + Route::get('check', 'UpdateController@checkForUpdate') + ->name('update.check'); +}); From 16f9db371ea4f52de76e537c7a950a0171e47f63 Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 01:35:21 +0100 Subject: [PATCH 2/9] Added check for updates Uses the version number in config/speedtest.php hosted on github --- app/Helpers/UpdateHelper.php | 44 +++++++++++++++++++++-- app/Http/Controllers/UpdateController.php | 1 + 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/Helpers/UpdateHelper.php b/app/Helpers/UpdateHelper.php index 77aa0d98..6c20b6a1 100644 --- a/app/Helpers/UpdateHelper.php +++ b/app/Helpers/UpdateHelper.php @@ -7,7 +7,47 @@ use Exception; class UpdateHelper { public static function check() { - $current = config('app.version', false); - (!$current) ? false : ''; + $current = config('speedtest.version', false); + if($current === false) { + return false; + } + + $gitVersion = UpdateHelper::checkLatestVersion(); + if($gitVersion === false) { + return false; + } + + return (bool)(version_compare($current, $gitVersion['version'])); + } + + public static function checkLatestVersion() + { + $user = config('speedtest.user'); + $repo = config('speedtest.repo'); + $branch = config('speedtest.branch'); + + $url = 'https://raw.githubusercontent.com/'.$user + .'/' + .$repo + .'/' + .$branch + .'/config/speedtest.php'; + + try { + $gitFile = file_get_contents($url); + } catch(Exception $e) { + return false; + } + + $pattern = "/'version' => '([0-9]{1,}\.[0-9]{1,}\.[0-9]{1,})'/"; + $version = []; + preg_match($pattern, $gitFile, $version); + $version = $version[1]; + + return [ + 'repo' => $user . '/' . $repo, + 'branch' => $branch, + 'version' => $version, + ]; } } diff --git a/app/Http/Controllers/UpdateController.php b/app/Http/Controllers/UpdateController.php index 970692e6..c8b9ed89 100644 --- a/app/Http/Controllers/UpdateController.php +++ b/app/Http/Controllers/UpdateController.php @@ -10,6 +10,7 @@ class UpdateController extends Controller public function checkForUpdate() { return response()->json([ + 'method' => 'check for updates', 'update' => UpdateHelper::check(), ], 200); } From 23f837ac34844d400df6ad00e24274616be70429 Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 01:58:11 +0100 Subject: [PATCH 3/9] Added a changelog file to repo --- app/Helpers/UpdateHelper.php | 2 +- changelog.json | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 changelog.json diff --git a/app/Helpers/UpdateHelper.php b/app/Helpers/UpdateHelper.php index 6c20b6a1..3b24a160 100644 --- a/app/Helpers/UpdateHelper.php +++ b/app/Helpers/UpdateHelper.php @@ -17,7 +17,7 @@ class UpdateHelper { return false; } - return (bool)(version_compare($current, $gitVersion['version'])); + return ((bool)(version_compare($current, $gitVersion['version']))) ? $gitVersion['version'] : false; } public static function checkLatestVersion() diff --git a/changelog.json b/changelog.json new file mode 100644 index 00000000..fe5b17ae --- /dev/null +++ b/changelog.json @@ -0,0 +1,12 @@ +{ + "1.1.0": [ + { + "description": "Added a version number to the app", + "link": "" + }, + { + "description": "Added an backup/restore function", + "link": "" + } + ], +} From 2d009e8c7470a0a9770319165c25e47557779ee8 Mon Sep 17 00:00:00 2001 From: Henry Whitaker <36062479+henrywhitaker3@users.noreply.github.com> Date: Fri, 10 Apr 2020 00:59:23 +0000 Subject: [PATCH 4/9] Update changelog.json --- changelog.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.json b/changelog.json index fe5b17ae..404b5ca2 100644 --- a/changelog.json +++ b/changelog.json @@ -8,5 +8,5 @@ "description": "Added an backup/restore function", "link": "" } - ], + ] } From 76dece1bb65562cd58f63662370c538fd2dad1d4 Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 02:20:06 +0100 Subject: [PATCH 5/9] Added UI display of the changelog --- app/Helpers/UpdateHelper.php | 46 ++++++++++-- changelog.json | 2 +- resources/js/components/Home/Footer.js | 13 +--- resources/js/components/Home/Version.js | 97 +++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 19 deletions(-) create mode 100644 resources/js/components/Home/Version.js diff --git a/app/Helpers/UpdateHelper.php b/app/Helpers/UpdateHelper.php index 3b24a160..beadbc87 100644 --- a/app/Helpers/UpdateHelper.php +++ b/app/Helpers/UpdateHelper.php @@ -17,7 +17,15 @@ class UpdateHelper { return false; } - return ((bool)(version_compare($current, $gitVersion['version']))) ? $gitVersion['version'] : false; + if((bool)(version_compare($current, $gitVersion['version']))) { + $changelog = UpdateHelper::getChangelog(); + return [ + 'version' => $gitVersion['version'], + 'changelog' => $changelog[$gitVersion['version']], + ]; + } else { + return false; + } } public static function checkLatestVersion() @@ -26,12 +34,13 @@ class UpdateHelper { $repo = config('speedtest.repo'); $branch = config('speedtest.branch'); - $url = 'https://raw.githubusercontent.com/'.$user - .'/' - .$repo - .'/' - .$branch - .'/config/speedtest.php'; + $url = 'https://raw.githubusercontent.com/' + .$user + .'/' + .$repo + .'/' + .$branch + .'/config/speedtest.php'; try { $gitFile = file_get_contents($url); @@ -50,4 +59,27 @@ class UpdateHelper { 'version' => $version, ]; } + + public static function getChangelog() + { + $user = config('speedtest.user'); + $repo = config('speedtest.repo'); + $branch = config('speedtest.branch'); + + $url = 'https://raw.githubusercontent.com/' + .$user + .'/' + .$repo + .'/' + .$branch + .'/changelog.json'; + + try { + $changelog = json_decode(file_get_contents($url), true); + } catch(Exception $e) { + $changelog = []; + } + + return $changelog; + } } diff --git a/changelog.json b/changelog.json index 404b5ca2..4931325b 100644 --- a/changelog.json +++ b/changelog.json @@ -5,7 +5,7 @@ "link": "" }, { - "description": "Added an backup/restore function", + "description": "Added a backup/restore function", "link": "" } ] diff --git a/resources/js/components/Home/Footer.js b/resources/js/components/Home/Footer.js index c37d05d6..19592489 100644 --- a/resources/js/components/Home/Footer.js +++ b/resources/js/components/Home/Footer.js @@ -2,24 +2,15 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import { Container, Row } from 'react-bootstrap'; import { Col } from 'react-bootstrap'; +import Version from './Version'; export default class Footer extends Component { - constructor(props) { - super(props) - - this.state = { - version: document.querySelector('meta[name="version"]').content - }; - } - render() { - var version = this.state.version; - return ( -

Speedtest Tracker Version: {version}

+

See the code on GitHub

diff --git a/resources/js/components/Home/Version.js b/resources/js/components/Home/Version.js new file mode 100644 index 00000000..b7f982c8 --- /dev/null +++ b/resources/js/components/Home/Version.js @@ -0,0 +1,97 @@ +import React, { Component } from 'react'; +import ReactDOM from 'react-dom'; +import Axios from 'axios'; +import { toast } from 'react-toastify'; +import { Modal } from 'react-bootstrap'; + +export default class Version extends Component { + constructor(props) { + super(props) + + this.state = { + version: document.querySelector('meta[name="version"]').content, + update: false, + modalShow: false, + changelog: [], + }; + } + + componentDidMount() { + this.checkForUpdates(); + } + + checkForUpdates = () => { + var url = '/api/update/check'; + + Axios.get(url) + .then((resp) => { + var update = resp.data.update; + if(update !== false) { + toast.info('A new version of Speedtest Tracker is available (v' + update.version + '). Go to the bottom of the page to update.'); + this.setState({ + update: update.version, + changelog: update.changelog, + }); + } + }) + .catch((err) => { + console.log(err); + }); + } + + showModal = () => { + this.setState({ + modalShow: true + }); + } + + hideModal = () => { + this.setState({ + modalShow: false + }); + } + + render() { + var version = this.state.version; + var update = this.state.update; + var modalShow = this.state.modalShow; + var changelog = this.state.changelog; + + if(update === false) { + return ( +

Speedtest Tracker Version: {version}

+ ); + } else { + return ( +
+

Speedtest Tracker Version: {version} -

+ New version available - v{update} + + + + Update to v{update} + + +
Changelog:
+
    + {changelog.map((e, i) => { + if(e.link == '') { + return ( +
  • {e.description}
  • + ); + } else { +
  • {e.description}
  • + } + })} +
+
+
+
+ ); + } + } +} + +if (document.getElementById('Version')) { + ReactDOM.render(, document.getElementById('Version')); +} From 188b085a06863838c213fe4c00445f10b228c005 Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 10:20:33 +0100 Subject: [PATCH 6/9] Added functions to download latest zip from github Have moved UpdateHelper into a facade --- app/Facades/UpdaterFacade.php | 13 ++ app/Helpers/UpdateHelper.php | 98 +++++++++--- app/Http/Controllers/UpdateController.php | 55 ++++++- app/Providers/UpdaterServiceProvider.php | 31 ++++ changelog.json | 6 + config/app.php | 3 +- public/js/app.js | 177 ++++++++++++++++++++-- routes/api.php | 6 + 8 files changed, 349 insertions(+), 40 deletions(-) create mode 100644 app/Facades/UpdaterFacade.php create mode 100644 app/Providers/UpdaterServiceProvider.php diff --git a/app/Facades/UpdaterFacade.php b/app/Facades/UpdaterFacade.php new file mode 100644 index 00000000..7b22df7e --- /dev/null +++ b/app/Facades/UpdaterFacade.php @@ -0,0 +1,13 @@ +currentVersion = config('speedtest.version'); + $this->user = config('speedtest.user'); + $this->repo = config('speedtest.repo'); + $this->branch = config('speedtest.branch'); + $this->latestVersion = 'unknown'; + $this->download = null; + } + + public function check() { - $current = config('speedtest.version', false); - if($current === false) { + if($this->currentVersion === false) { return false; } - $gitVersion = UpdateHelper::checkLatestVersion(); + $gitVersion = $this->checkLatestVersion(); if($gitVersion === false) { return false; } - if((bool)(version_compare($current, $gitVersion['version']))) { - $changelog = UpdateHelper::getChangelog(); + if((bool)(version_compare($this->currentVersion, $gitVersion['version']))) { + $changelog = $this->getChangelog(); return [ 'version' => $gitVersion['version'], 'changelog' => $changelog[$gitVersion['version']], @@ -28,18 +43,15 @@ class UpdateHelper { } } - public static function checkLatestVersion() + public function checkLatestVersion() { - $user = config('speedtest.user'); - $repo = config('speedtest.repo'); - $branch = config('speedtest.branch'); $url = 'https://raw.githubusercontent.com/' - .$user + .$this->user .'/' - .$repo + .$this->repo .'/' - .$branch + .$this->branch .'/config/speedtest.php'; try { @@ -51,27 +63,23 @@ class UpdateHelper { $pattern = "/'version' => '([0-9]{1,}\.[0-9]{1,}\.[0-9]{1,})'/"; $version = []; preg_match($pattern, $gitFile, $version); - $version = $version[1]; + $this->latestVersion = $version[1]; return [ - 'repo' => $user . '/' . $repo, - 'branch' => $branch, - 'version' => $version, + 'repo' => $this->user . '/' . $this->repo, + 'branch' => $this->branch, + 'version' => $this->latestVersion, ]; } - public static function getChangelog() + public function getChangelog() { - $user = config('speedtest.user'); - $repo = config('speedtest.repo'); - $branch = config('speedtest.branch'); - $url = 'https://raw.githubusercontent.com/' - .$user + .$this->user .'/' - .$repo + .$this->repo .'/' - .$branch + .$this->branch .'/changelog.json'; try { @@ -82,4 +90,44 @@ class UpdateHelper { return $changelog; } + + public function downloadLatest() + { + $url = 'https://github.com/' + .$this->user + .'/' + .$this->repo + .'/archive/' + .$this->branch + .'.zip'; + + try { + $zip = file_get_contents($url); + $name = '/tmp/'.$this->repo.'-update.zip'; + file_put_contents($name, $zip); + return true; + } catch(Exception $e) { + return $e; + } + } + + public function extractFiles() + { + $zip = new ZipArchive(); + $res = $zip->open('/tmp/'.$this->repo.'-update.zip'); + if($res === true) { + $zip->extractTo('/tmp/'.$this->repo.'-update/'); + $zip->close(); + return true; + } else { + return false; + } + } + + public function updateFiles() + { + foreach (glob('/tmp/'.$this->repo.'-update/') as $folder) { + return $folder; + } + } } diff --git a/app/Http/Controllers/UpdateController.php b/app/Http/Controllers/UpdateController.php index c8b9ed89..a966ec5f 100644 --- a/app/Http/Controllers/UpdateController.php +++ b/app/Http/Controllers/UpdateController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers; -use App\Helpers\UpdateHelper; +use Updater; use Illuminate\Http\Request; class UpdateController extends Controller @@ -11,7 +11,58 @@ class UpdateController extends Controller { return response()->json([ 'method' => 'check for updates', - 'update' => UpdateHelper::check(), + 'update' => Updater::check(), ], 200); } + + public function downloadUpdate() + { + $dl = Updater::downloadLatest(); + + if($dl) { + return response()->json([ + 'method' => 'download latest version', + 'success' => true, + ], 200); + } else { + return response()->json([ + 'method' => 'download latest version', + 'success' => false, + ], 500); + } + } + + public function extractUpdate() + { + $ex = Updater::extractFiles(); + + if($ex) { + return response()->json([ + 'method' => 'extract latest version', + 'success' => true, + ], 200); + } else { + return response()->json([ + 'method' => 'extract latest version', + 'success' => false, + ], 500); + } + } + + public function moveUpdate() + { + $cp = Updater::updateFiles(); + + if($cp) { + return response()->json([ + 'method' => 'copy latest version', + 'success' => true, + ], 200); + } else { + return response()->json([ + 'method' => 'copy latest version', + 'success' => false, + ], 500); + } + } } diff --git a/app/Providers/UpdaterServiceProvider.php b/app/Providers/UpdaterServiceProvider.php new file mode 100644 index 00000000..8b9a8132 --- /dev/null +++ b/app/Providers/UpdaterServiceProvider.php @@ -0,0 +1,31 @@ +app->bind('updater', function() { + return new UpdateHelper(); + }); + } + + /** + * Bootstrap services. + * + * @return void + */ + public function boot() + { + // + } +} diff --git a/changelog.json b/changelog.json index 4931325b..c8c6d749 100644 --- a/changelog.json +++ b/changelog.json @@ -1,4 +1,10 @@ { + "1.2.0": [ + { + "description": "Added an updating mechainism within the app.", + "link": "" + } + ], "1.1.0": [ { "description": "Added a version number to the app", diff --git a/config/app.php b/config/app.php index 8409e00e..dfc4fee9 100644 --- a/config/app.php +++ b/config/app.php @@ -174,6 +174,7 @@ return [ // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, + App\Providers\UpdaterServiceProvider::class, ], @@ -226,7 +227,7 @@ return [ 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, - + 'Updater' => App\Facades\UpdaterFacade::class, ], ]; diff --git a/public/js/app.js b/public/js/app.js index 6877cd20..1346259e 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -127670,6 +127670,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom */ "./node_modules/react-dom/index.js"); /* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var react_bootstrap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-bootstrap */ "./node_modules/react-bootstrap/esm/index.js"); +/* harmony import */ var _Version__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Version */ "./resources/js/components/Home/Version.js"); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -127697,35 +127698,27 @@ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || func + var Footer = /*#__PURE__*/function (_Component) { _inherits(Footer, _Component); var _super = _createSuper(Footer); - function Footer(props) { - var _this; - + function Footer() { _classCallCheck(this, Footer); - _this = _super.call(this, props); - _this.state = { - version: document.querySelector('meta[name="version"]').content - }; - return _this; + return _super.apply(this, arguments); } _createClass(Footer, [{ key: "render", value: function render() { - var version = this.state.version; return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Container"], null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Row"], null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Col"], { sm: { span: 12 }, className: "text-center" - }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", { - className: "text-muted mb-0" - }, "Speedtest Tracker Version: ", version), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", { + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Version__WEBPACK_IMPORTED_MODULE_3__["default"], null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", { className: "text-muted" }, "See the code on ", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", { href: "https://github.com/henrywhitaker3/Speedtest-Tracker", @@ -127824,6 +127817,166 @@ if (document.getElementById('homePage')) { /***/ }), +/***/ "./resources/js/components/Home/Version.js": +/*!*************************************************!*\ + !*** ./resources/js/components/Home/Version.js ***! + \*************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Version; }); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js"); +/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-dom */ "./node_modules/react-dom/index.js"); +/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! axios */ "./node_modules/axios/index.js"); +/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var react_toastify__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-toastify */ "./node_modules/react-toastify/esm/react-toastify.js"); +/* harmony import */ var react_bootstrap__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react-bootstrap */ "./node_modules/react-bootstrap/esm/index.js"); +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +function _createSuper(Derived) { return function () { var Super = _getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } + +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } + +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } + +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } + +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + + + + + + + +var Version = /*#__PURE__*/function (_Component) { + _inherits(Version, _Component); + + var _super = _createSuper(Version); + + function Version(props) { + var _this; + + _classCallCheck(this, Version); + + _this = _super.call(this, props); + + _defineProperty(_assertThisInitialized(_this), "checkForUpdates", function () { + var url = '/api/update/check'; + axios__WEBPACK_IMPORTED_MODULE_2___default.a.get(url).then(function (resp) { + var update = resp.data.update; + + if (update !== false) { + react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].info('A new version of Speedtest Tracker is available (v' + update.version + '). Go to the bottom of the page to update.'); + + _this.setState({ + update: update.version, + changelog: update.changelog + }); + } + })["catch"](function (err) { + console.log(err); + }); + }); + + _defineProperty(_assertThisInitialized(_this), "showModal", function () { + _this.setState({ + modalShow: true + }); + }); + + _defineProperty(_assertThisInitialized(_this), "hideModal", function () { + _this.setState({ + modalShow: false + }); + }); + + _this.state = { + version: document.querySelector('meta[name="version"]').content, + update: false, + modalShow: false, + changelog: [] + }; + return _this; + } + + _createClass(Version, [{ + key: "componentDidMount", + value: function componentDidMount() { + this.checkForUpdates(); + } + }, { + key: "render", + value: function render() { + var version = this.state.version; + var update = this.state.update; + var modalShow = this.state.modalShow; + var changelog = this.state.changelog; + + if (update === false) { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", { + className: "text-muted mb-0" + }, "Speedtest Tracker Version: ", version); + } else { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", { + className: "text-muted mb-0 d-inline" + }, "Speedtest Tracker Version: ", version, " - "), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", { + href: "#!", + className: "mb-0 d-inline", + onClick: this.showModal + }, "New version available - v", update), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_4__["Modal"], { + show: modalShow, + onHide: this.hideModal, + animation: true + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_4__["Modal"].Header, { + closeButton: true + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_4__["Modal"].Title, null, "Update to v", update)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_4__["Modal"].Body, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h5", null, "Changelog:"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("ul", null, changelog.map(function (e, i) { + if (e.link == '') { + return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("li", { + key: i + }, e.description); + } else { + /*#__PURE__*/ + react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("li", { + key: i + }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", { + href: e.link, + target: "_blank", + rel: "noopener noreferer" + }, e.description)); + } + }))))); + } + } + }]); + + return Version; +}(react__WEBPACK_IMPORTED_MODULE_0__["Component"]); + + + +if (document.getElementById('Version')) { + react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Version, null), document.getElementById('Version')); +} + +/***/ }), + /***/ "./resources/js/components/Loader.js": /*!*******************************************!*\ !*** ./resources/js/components/Loader.js ***! diff --git a/routes/api.php b/routes/api.php index 45580e18..41f33966 100644 --- a/routes/api.php +++ b/routes/api.php @@ -44,4 +44,10 @@ Route::group([ ], function () { Route::get('check', 'UpdateController@checkForUpdate') ->name('update.check'); + Route::get('download', 'UpdateController@downloadUpdate') + ->name('update.download'); + Route::get('extract', 'UpdateController@extractUpdate') + ->name('update.extract'); + Route::get('extract', 'UpdateController@moveUpdate') + ->name('update.move'); }); From c47d7723aadc12e56fa58e9f3f200fdf0bc315ac Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 13:12:31 +0100 Subject: [PATCH 7/9] Added methods to exclude files and backup whole installation --- app/Helpers/UpdateHelper.php | 87 ++++++++++++++++++++++- app/Http/Controllers/UpdateController.php | 2 +- routes/api.php | 2 +- 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/app/Helpers/UpdateHelper.php b/app/Helpers/UpdateHelper.php index eadef32e..9f8b08fd 100644 --- a/app/Helpers/UpdateHelper.php +++ b/app/Helpers/UpdateHelper.php @@ -3,6 +3,10 @@ namespace App\Helpers; use Exception; +use File; +use Illuminate\Support\Facades\Log; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; use ZipArchive; class UpdateHelper { @@ -23,6 +27,8 @@ class UpdateHelper { public function check() { + Log::info('Checking for new version'); + if($this->currentVersion === false) { return false; } @@ -33,6 +39,7 @@ class UpdateHelper { } if((bool)(version_compare($this->currentVersion, $gitVersion['version']))) { + Log::info('New version found! v' . $gitVersion['version']); $changelog = $this->getChangelog(); return [ 'version' => $gitVersion['version'], @@ -45,7 +52,6 @@ class UpdateHelper { public function checkLatestVersion() { - $url = 'https://raw.githubusercontent.com/' .$this->user .'/' @@ -93,6 +99,7 @@ class UpdateHelper { public function downloadLatest() { + Log::info('Downloading the latest version from GitHub'); $url = 'https://github.com/' .$this->user .'/' @@ -105,29 +112,103 @@ class UpdateHelper { $zip = file_get_contents($url); $name = '/tmp/'.$this->repo.'-update.zip'; file_put_contents($name, $zip); + Log::info('New version successfully downloaded'); return true; } catch(Exception $e) { + Log::error('Couldn\'t download the update'); + Log::error($e); return $e; } } public function extractFiles() { + Log::info('Extracting the update'); $zip = new ZipArchive(); $res = $zip->open('/tmp/'.$this->repo.'-update.zip'); if($res === true) { $zip->extractTo('/tmp/'.$this->repo.'-update/'); $zip->close(); + Log::info('Update extracted'); return true; } else { + Log::error('Couldn\'t extract the update'); return false; } } public function updateFiles() { - foreach (glob('/tmp/'.$this->repo.'-update/') as $folder) { - return $folder; + Log::info('Applying update'); + $dir = array_filter(glob('/tmp/'.$this->repo.'-update/*'), 'is_dir'); + $dir = $dir[0].DIRECTORY_SEPARATOR; + + $this->deleteExcluded($dir); + $this->backupCurrent(); + + Log::info('Successfully applied update'); + } + + private function deleteExcluded($path) + { + Log::info('Deleting excluded items'); + $exclude_dirs = config('speedtest.exclude_dirs', []); + foreach($exclude_dirs as $dir) { + $dir = $path . $dir; + Log::info('Deleting excluded directory: ' . $dir); + + File::deleteDirectory($dir); } + + $exclude_files = config('speedtest.exclude_files', []); + foreach($exclude_files as $file) { + $file = $path . $file; + Log::info('Deleting excluded file: ' . $file); + + File::delete($file); + } + Log::info('Excluded items deleted'); + } + + private function backupCurrent() + { + Log::info('Backing up current installation'); + + $rootPath = realpath(base_path()); + $backupZip = '/tmp/speedtest-backup-'.time().'.zip'; + + // Initialize archive object + $zip = new ZipArchive(); + $zip->open($backupZip, ZipArchive::CREATE | ZipArchive::OVERWRITE); + + // Create recursive directory iterator + /** @var SplFileInfo[] $files */ + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($rootPath), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($files as $name => $file) + { + // Skip directories (they would be added automatically) + if (!$file->isDir()) + { + // Get real and relative path for current file + $filePath = $file->getRealPath(); + $relativePath = substr($filePath, strlen($rootPath) + 1); + + // Add current file to archive + $zip->addFile($filePath, $relativePath); + } + } + + // Zip archive will be created only after closing object + $zip->close(); + Log::info('Backup created at: ' . $backupZip); + } + + private function moveFiles() + { + } } diff --git a/app/Http/Controllers/UpdateController.php b/app/Http/Controllers/UpdateController.php index a966ec5f..6e680c4f 100644 --- a/app/Http/Controllers/UpdateController.php +++ b/app/Http/Controllers/UpdateController.php @@ -56,7 +56,7 @@ class UpdateController extends Controller if($cp) { return response()->json([ 'method' => 'copy latest version', - 'success' => true, + 'success' => $cp, ], 200); } else { return response()->json([ diff --git a/routes/api.php b/routes/api.php index 41f33966..cf4ecbda 100644 --- a/routes/api.php +++ b/routes/api.php @@ -48,6 +48,6 @@ Route::group([ ->name('update.download'); Route::get('extract', 'UpdateController@extractUpdate') ->name('update.extract'); - Route::get('extract', 'UpdateController@moveUpdate') + Route::get('move', 'UpdateController@moveUpdate') ->name('update.move'); }); From d276cb73833ee7807a776c8ac540fcb6383b5705 Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 15:55:19 +0100 Subject: [PATCH 8/9] Finished update functions Should hopefully work well. Doesn't clean up atm, but all the new files are stored in /tmp/ so not that important --- app/Helpers/UpdateHelper.php | 79 ++++++++++++++++++++++++++++++++++-- config/speedtest.php | 28 +++++++++++++ 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/app/Helpers/UpdateHelper.php b/app/Helpers/UpdateHelper.php index 9f8b08fd..3fe46756 100644 --- a/app/Helpers/UpdateHelper.php +++ b/app/Helpers/UpdateHelper.php @@ -145,17 +145,18 @@ class UpdateHelper { $this->deleteExcluded($dir); $this->backupCurrent(); + $this->moveFiles(); Log::info('Successfully applied update'); } private function deleteExcluded($path) { - Log::info('Deleting excluded items'); + Log::info('Deleting excluded items from update directory'); $exclude_dirs = config('speedtest.exclude_dirs', []); foreach($exclude_dirs as $dir) { $dir = $path . $dir; - Log::info('Deleting excluded directory: ' . $dir); + Log::debug('Deleting excluded directory: ' . $dir); File::deleteDirectory($dir); } @@ -163,11 +164,11 @@ class UpdateHelper { $exclude_files = config('speedtest.exclude_files', []); foreach($exclude_files as $file) { $file = $path . $file; - Log::info('Deleting excluded file: ' . $file); + Log::debug('Deleting excluded file: ' . $file); File::delete($file); } - Log::info('Excluded items deleted'); + Log::info('Excluded items deleted from update directory'); } private function backupCurrent() @@ -209,6 +210,76 @@ class UpdateHelper { private function moveFiles() { + $new = array_filter(glob('/tmp/'.$this->repo.'-update/*'), 'is_dir'); + $new = $new[0].DIRECTORY_SEPARATOR; + + foreach(File::files($new) as $file) { + $filename = explode('/', $file); + $filename = array_slice($filename, -1)[0]; + try { + Log::info('Overwriting ' . $filename); + Log::debug('From: ' . $file . ' to: ' . base_path().DIRECTORY_SEPARATOR.$filename); + File::delete(base_path().DIRECTORY_SEPARATOR.$filename); + File::move($file, base_path().DIRECTORY_SEPARATOR.$filename); + } catch(Exception $e) { + Log::error('Failed to overwrite: ' . $filename); + Log::debug($e); + } + } + + $this->tempStoreExcludedFiles(); + + foreach(File::directories($new) as $dir) { + $dirname = explode('/', $dir); + $dirname = array_slice($dirname, -1)[0]; + Log::info('Overwriting ' . $dir); + File::deleteDirectory(base_path().DIRECTORY_SEPARATOR.$dirname); + File::move($dir, base_path().DIRECTORY_SEPARATOR.$dirname); + } + + $this->restoreExcludedFiles(); } + + private function tempStoreExcludedFiles() + { + Log::info('Temporarily moving exluded files from root directory'); + foreach(config('speedtest.exclude_files', []) as $file) { + try { + Log::info('Moving ' . $file); + File::copy(base_path().DIRECTORY_SEPARATOR.$file, '/tmp/'.$file); + } catch(Exception $e) { + Log::error('Couldn\'t backup '.$file); + } + } + foreach(config('speedtest.exclude_dirs', []) as $dir) { + try { + Log::info('Moving ' . $dir); + File::copyDirectory(base_path().DIRECTORY_SEPARATOR.$dir, '/tmp/'.$dir); + } catch(Exception $e) { + Log::error('Couldn\'t backup '.$dir); + } + } + } + + private function restoreExcludedFiles() + { + Log::info('Restoring exluded files to root directory'); + foreach(config('speedtest.exclude_files', []) as $file) { + try { + Log::info('Moving ' . $file); + File::copy('/tmp/'.$file, base_path().DIRECTORY_SEPARATOR.$file); + } catch(Exception $e) { + Log::error('Couldn\'t restore '.$file); + } + } + foreach(config('speedtest.exclude_dirs', []) as $dir) { + try { + Log::info('Moving ' . $dir); + File::copyDirectory('/tmp/'.$dir, base_path().DIRECTORY_SEPARATOR.$dir); + } catch(Exception $e) { + Log::error('Couldn\' restore ' . $dir); + } + } + } } diff --git a/config/speedtest.php b/config/speedtest.php index a49e37b9..3c87f73f 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -18,4 +18,32 @@ return [ 'user' => 'henrywhitaker3', 'repo' => 'Speedtest-Tracker', 'branch' => 'master', + + /* + |-------------------------------------------------------------------------- + | Excluded Dirs + |-------------------------------------------------------------------------- + | + | Dirs excluded from the self-updating function + */ + + 'exclude_dirs' => [ + 'node_modules/', + 'bootstrap/cache/', + 'bower/', + 'storage/', + 'vendor/', + ], + + /* + |-------------------------------------------------------------------------- + | Excluded Files + |-------------------------------------------------------------------------- + | + | Files excluded from the self-updating function + */ + + 'exclude_files' => [ + 'database/speed.db', + ], ]; From 7b43187c8d595fd0aa82361a0015033b78dc3817 Mon Sep 17 00:00:00 2001 From: Henry Whitaker Date: Fri, 10 Apr 2020 18:45:15 +0100 Subject: [PATCH 9/9] Finished UI for updater --- app/Helpers/UpdateHelper.php | 12 ++++++ app/Http/Controllers/UpdateController.php | 15 ++----- changelog.json | 2 +- config/speedtest.php | 2 +- public/js/app.js | 50 +++++++++++++++++++++- resources/js/components/Home/Version.js | 51 ++++++++++++++++++++++- 6 files changed, 116 insertions(+), 16 deletions(-) diff --git a/app/Helpers/UpdateHelper.php b/app/Helpers/UpdateHelper.php index 3fe46756..1a39b23d 100644 --- a/app/Helpers/UpdateHelper.php +++ b/app/Helpers/UpdateHelper.php @@ -146,6 +146,7 @@ class UpdateHelper { $this->deleteExcluded($dir); $this->backupCurrent(); $this->moveFiles(); + $this->clearup(); Log::info('Successfully applied update'); } @@ -282,4 +283,15 @@ class UpdateHelper { } } } + + private function clearup() + { + try { + File::deleteDirectory('/tmp/'.$this->repo.'-update/'); + Log::info('Deleted download directory'); + } catch(Exception $e) { + Log::error('Failed cleaning up update'); + Log::error($e); + } + } } diff --git a/app/Http/Controllers/UpdateController.php b/app/Http/Controllers/UpdateController.php index 6e680c4f..bc2b132c 100644 --- a/app/Http/Controllers/UpdateController.php +++ b/app/Http/Controllers/UpdateController.php @@ -53,16 +53,9 @@ class UpdateController extends Controller { $cp = Updater::updateFiles(); - if($cp) { - return response()->json([ - 'method' => 'copy latest version', - 'success' => $cp, - ], 200); - } else { - return response()->json([ - 'method' => 'copy latest version', - 'success' => false, - ], 500); - } + return response()->json([ + 'method' => 'copy latest version', + 'success' => $cp, + ], 200); } } diff --git a/changelog.json b/changelog.json index c8c6d749..dbe20fb4 100644 --- a/changelog.json +++ b/changelog.json @@ -1,7 +1,7 @@ { "1.2.0": [ { - "description": "Added an updating mechainism within the app.", + "description": "Added an updating mechainism within the app to keep code up to date.", "link": "" } ], diff --git a/config/speedtest.php b/config/speedtest.php index 3c87f73f..b1e89675 100644 --- a/config/speedtest.php +++ b/config/speedtest.php @@ -7,7 +7,7 @@ return [ |-------------------------------------------------------------------------- */ - 'version' => '1.1.0', + 'version' => '1.2.0', /* |-------------------------------------------------------------------------- diff --git a/public/js/app.js b/public/js/app.js index 1346259e..99cf6633 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -127865,6 +127865,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope + var Version = /*#__PURE__*/function (_Component) { _inherits(Version, _Component); @@ -127907,11 +127908,48 @@ var Version = /*#__PURE__*/function (_Component) { }); }); + _defineProperty(_assertThisInitialized(_this), "updateApp", function () { + _this.setState({ + showProgress: true, + updateProgress: 0 + }); + + react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].info('Downloading update'); + axios__WEBPACK_IMPORTED_MODULE_2___default.a.get('/api/update/download').then(function (resp) { + _this.setState({ + updateProgress: 50 + }); + + react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].info('Extracting update'); + axios__WEBPACK_IMPORTED_MODULE_2___default.a.get('/api/speedtest/extract').then(function (resp) { + _this.setState({ + updateProgress: 75 + }); + + react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].info('Applying update'); + axios__WEBPACK_IMPORTED_MODULE_2___default.a.get('/api/update/move').then(function (resp) { + _this.setState({ + updateProgress: 100 + }); + + react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].success('Update successful. Refreshing your page...'); + setTimeout(function () { + location.reload(true); + }, 5000); + }); + }); + })["catch"](function (err) { + react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].error('Something went wrong...'); + }); + }); + _this.state = { version: document.querySelector('meta[name="version"]').content, update: false, modalShow: false, - changelog: [] + changelog: [], + showProgress: false, + updateProgress: 0 }; return _this; } @@ -127928,6 +127966,8 @@ var Version = /*#__PURE__*/function (_Component) { var update = this.state.update; var modalShow = this.state.modalShow; var changelog = this.state.changelog; + var showProgress = this.state.showProgress; + var updateProgress = this.state.updateProgress; if (update === false) { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", { @@ -127961,7 +128001,13 @@ var Version = /*#__PURE__*/function (_Component) { rel: "noopener noreferer" }, e.description)); } - }))))); + })), showProgress && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, "Update progress:"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_4__["ProgressBar"], { + animated: true, + now: updateProgress + })), !showProgress && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_4__["Button"], { + variant: "primary", + onClick: this.updateApp + }, "Update")))); } } }]); diff --git a/resources/js/components/Home/Version.js b/resources/js/components/Home/Version.js index b7f982c8..8ea1e224 100644 --- a/resources/js/components/Home/Version.js +++ b/resources/js/components/Home/Version.js @@ -2,7 +2,8 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import Axios from 'axios'; import { toast } from 'react-toastify'; -import { Modal } from 'react-bootstrap'; +import { Modal, ProgressBar } from 'react-bootstrap'; +import { Button } from 'react-bootstrap'; export default class Version extends Component { constructor(props) { @@ -13,6 +14,8 @@ export default class Version extends Component { update: false, modalShow: false, changelog: [], + showProgress: false, + updateProgress: 0, }; } @@ -51,11 +54,48 @@ export default class Version extends Component { }); } + updateApp = () => { + this.setState({ + showProgress: true, + updateProgress: 0, + }); + toast.info('Downloading update'); + Axios.get('/api/update/download') + .then((resp) => { + this.setState({ + updateProgress: 50, + }); + toast.info('Extracting update'); + Axios.get('/api/speedtest/extract') + .then((resp) => { + this.setState({ + updateProgress: 75, + }); + toast.info('Applying update'); + Axios.get('/api/update/move') + .then((resp) => { + this.setState({ + updateProgress: 100, + }); + toast.success('Update successful. Refreshing your page...'); + setTimeout(function() { + location.reload(true); + }, 5000); + }) + }) + }) + .catch((err) => { + toast.error('Something went wrong...'); + }) + } + render() { var version = this.state.version; var update = this.state.update; var modalShow = this.state.modalShow; var changelog = this.state.changelog; + var showProgress = this.state.showProgress; + var updateProgress = this.state.updateProgress; if(update === false) { return ( @@ -84,6 +124,15 @@ export default class Version extends Component { } })} + {showProgress && +
+

Update progress:

+ +
+ } + {!showProgress && + + }