mirror of
https://github.com/henrywhitaker3/Speedtest-Tracker.git
synced 2025-12-21 13:23:04 +01:00
Added backup/restore function
This commit is contained in:
31
app/Helpers/BackupHelper.php
Normal file
31
app/Helpers/BackupHelper.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Speedtest;
|
||||
use Exception;
|
||||
|
||||
class BackupHelper {
|
||||
public static function backup()
|
||||
{
|
||||
$data = Speedtest::get();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function restore($array)
|
||||
{
|
||||
foreach($array as $test) {
|
||||
try {
|
||||
$st = Speedtest::create([
|
||||
'ping' => $test['ping'],
|
||||
'download' => $test['download'],
|
||||
'upload' => $test['upload'],
|
||||
'created_at' => $test['created_at'],
|
||||
]);
|
||||
} catch(Exception $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
app/Http/Controllers/BackupController.php
Normal file
44
app/Http/Controllers/BackupController.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\BackupHelper;
|
||||
use DateTime;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class BackupController extends Controller
|
||||
{
|
||||
public function backup()
|
||||
{
|
||||
$data = BackupHelper::backup();
|
||||
$timestamp = new DateTime();
|
||||
$timestamp = $timestamp->format('Y-m-d_H:i:s');
|
||||
$name = 'speedtest_backup_' . $timestamp . '.json';
|
||||
Storage::disk('local')->put($name, $data);
|
||||
|
||||
return Storage::disk('local')->download($name);
|
||||
}
|
||||
|
||||
public function restore(Request $request)
|
||||
{
|
||||
$rule = [
|
||||
'data' => [ 'required', 'array' ],
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rule);
|
||||
|
||||
if($validator->fails()) {
|
||||
return response()->json([
|
||||
'error' => $validator->errors()
|
||||
], 422);
|
||||
}
|
||||
|
||||
BackupHelper::restore($request->data);
|
||||
|
||||
return response()->json([
|
||||
'method' => 'restore data from backup',
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ class Speedtest extends Model
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'ping', 'download', 'upload'
|
||||
'ping', 'download', 'upload', 'created_at'
|
||||
];
|
||||
|
||||
protected $table = 'speedtests';
|
||||
|
||||
@@ -129,7 +129,7 @@ return [
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
'version' => '1.0.0',
|
||||
'version' => '1.1.0',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
4
public/css/main.css
vendored
4
public/css/main.css
vendored
@@ -43,3 +43,7 @@
|
||||
.Toastify__toast--info {
|
||||
background: #1f5a81 !important;
|
||||
}
|
||||
|
||||
.Toastify__toast--success {
|
||||
background: #28922b !important;
|
||||
}
|
||||
|
||||
376
public/js/app.js
vendored
376
public/js/app.js
vendored
@@ -126473,6 +126473,367 @@ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./resources/js/components/Data/Backup.js":
|
||||
/*!************************************************!*\
|
||||
!*** ./resources/js/components/Data/Backup.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 Backup; });
|
||||
/* 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 react_bootstrap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-bootstrap */ "./node_modules/react-bootstrap/esm/index.js");
|
||||
/* harmony import */ var react_toastify__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-toastify */ "./node_modules/react-toastify/esm/react-toastify.js");
|
||||
/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! axios */ "./node_modules/axios/index.js");
|
||||
/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_4__);
|
||||
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 Backup = /*#__PURE__*/function (_Component) {
|
||||
_inherits(Backup, _Component);
|
||||
|
||||
var _super = _createSuper(Backup);
|
||||
|
||||
function Backup() {
|
||||
var _this;
|
||||
|
||||
_classCallCheck(this, Backup);
|
||||
|
||||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
||||
args[_key] = arguments[_key];
|
||||
}
|
||||
|
||||
_this = _super.call.apply(_super, [this].concat(args));
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "backup", function () {
|
||||
var url = '/api/backup';
|
||||
react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].info('Your backup has started downloading...');
|
||||
axios__WEBPACK_IMPORTED_MODULE_4___default.a.get(url, {
|
||||
responseType: 'blob'
|
||||
}).then(function (resp) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = "";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].success('Backup downloaded');
|
||||
})["catch"](function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
return _this;
|
||||
}
|
||||
|
||||
_createClass(Backup, [{
|
||||
key: "render",
|
||||
value: function render() {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Button"], {
|
||||
variant: "primary",
|
||||
className: "mx-2",
|
||||
onClick: this.backup
|
||||
}, "Backup");
|
||||
}
|
||||
}]);
|
||||
|
||||
return Backup;
|
||||
}(react__WEBPACK_IMPORTED_MODULE_0__["Component"]);
|
||||
|
||||
|
||||
|
||||
if (document.getElementById('Backup')) {
|
||||
react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Backup, null), document.getElementById('Backup'));
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./resources/js/components/Data/DataRow.js":
|
||||
/*!*************************************************!*\
|
||||
!*** ./resources/js/components/Data/DataRow.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 DataRow; });
|
||||
/* 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 react_bootstrap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-bootstrap */ "./node_modules/react-bootstrap/esm/index.js");
|
||||
/* harmony import */ var _Backup__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Backup */ "./resources/js/components/Data/Backup.js");
|
||||
/* harmony import */ var _Restore__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Restore */ "./resources/js/components/Data/Restore.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); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var DataRow = /*#__PURE__*/function (_Component) {
|
||||
_inherits(DataRow, _Component);
|
||||
|
||||
var _super = _createSuper(DataRow);
|
||||
|
||||
function DataRow() {
|
||||
_classCallCheck(this, DataRow);
|
||||
|
||||
return _super.apply(this, arguments);
|
||||
}
|
||||
|
||||
_createClass(DataRow, [{
|
||||
key: "render",
|
||||
value: function render() {
|
||||
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", null, "Use these buttons to backup/restore your data"))), /*#__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(_Backup__WEBPACK_IMPORTED_MODULE_3__["default"], null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Restore__WEBPACK_IMPORTED_MODULE_4__["default"], null))));
|
||||
}
|
||||
}]);
|
||||
|
||||
return DataRow;
|
||||
}(react__WEBPACK_IMPORTED_MODULE_0__["Component"]);
|
||||
|
||||
|
||||
|
||||
if (document.getElementById('DataRow')) {
|
||||
react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(DataRow, null), document.getElementById('DataRow'));
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./resources/js/components/Data/Restore.js":
|
||||
/*!*************************************************!*\
|
||||
!*** ./resources/js/components/Data/Restore.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 Restore; });
|
||||
/* 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 react_bootstrap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-bootstrap */ "./node_modules/react-bootstrap/esm/index.js");
|
||||
/* harmony import */ var react_toastify__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-toastify */ "./node_modules/react-toastify/esm/react-toastify.js");
|
||||
/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! axios */ "./node_modules/axios/index.js");
|
||||
/* harmony import */ var axios__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(axios__WEBPACK_IMPORTED_MODULE_4__);
|
||||
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 Restore = /*#__PURE__*/function (_Component) {
|
||||
_inherits(Restore, _Component);
|
||||
|
||||
var _super = _createSuper(Restore);
|
||||
|
||||
function Restore(props) {
|
||||
var _this;
|
||||
|
||||
_classCallCheck(this, Restore);
|
||||
|
||||
_this = _super.call(this, props);
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "showModal", function () {
|
||||
_this.setState({
|
||||
show: true
|
||||
});
|
||||
});
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "hideModal", function () {
|
||||
_this.setState({
|
||||
show: false
|
||||
});
|
||||
});
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "readFile", function (e) {
|
||||
var file = e.target.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'UTF-8');
|
||||
|
||||
reader.onload = function (evt) {
|
||||
try {
|
||||
var data = evt.target.result.trim();
|
||||
var data = JSON.parse(data);
|
||||
this.setState({
|
||||
data: data,
|
||||
uploadReady: true,
|
||||
filename: file.name
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].error('Your upload file is not valid JSON');
|
||||
}
|
||||
}.bind(_assertThisInitialized(_this));
|
||||
|
||||
reader.onerror = function (evt) {
|
||||
react_toastify__WEBPACK_IMPORTED_MODULE_3__["toast"].error('Something went wrong parsing your backup file.');
|
||||
};
|
||||
});
|
||||
|
||||
_defineProperty(_assertThisInitialized(_this), "uploadFile", function () {
|
||||
var data = {
|
||||
data: _this.state.data
|
||||
};
|
||||
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...');
|
||||
|
||||
_this.setState({
|
||||
show: false,
|
||||
data: null,
|
||||
uploadReady: false,
|
||||
filename: 'Upload your backup JSON'
|
||||
});
|
||||
})["catch"](function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
_this.state = {
|
||||
show: false,
|
||||
data: null,
|
||||
uploadReady: false,
|
||||
filename: 'Upload your backup JSON'
|
||||
};
|
||||
return _this;
|
||||
}
|
||||
|
||||
_createClass(Restore, [{
|
||||
key: "render",
|
||||
value: function render() {
|
||||
var show = this.state.show;
|
||||
var uploadReady = this.state.uploadReady;
|
||||
var filename = this.state.filename;
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Button"], {
|
||||
variant: "secondary",
|
||||
className: "mx-2",
|
||||
onClick: this.showModal
|
||||
}, "Restore"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Modal"], {
|
||||
show: show,
|
||||
onHide: this.hideModal,
|
||||
animation: true
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Modal"].Header, {
|
||||
closeButton: true
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Modal"].Title, null, "Restore from a backup")), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Modal"].Body, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, "Upload your JSON backup file here:"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Form"].File, {
|
||||
id: "restoreFileInput",
|
||||
label: "Upload JSON file",
|
||||
className: "mb-3",
|
||||
custom: true
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Form"].File.Input, {
|
||||
onChange: this.readFile
|
||||
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Form"].File.Label, {
|
||||
"data-browse": "Choose file"
|
||||
}, filename)), uploadReady === true && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react_bootstrap__WEBPACK_IMPORTED_MODULE_2__["Button"], {
|
||||
variant: "secondary",
|
||||
onClick: this.uploadFile
|
||||
}, "Restore"))));
|
||||
}
|
||||
}]);
|
||||
|
||||
return Restore;
|
||||
}(react__WEBPACK_IMPORTED_MODULE_0__["Component"]);
|
||||
|
||||
|
||||
|
||||
if (document.getElementById('Restore')) {
|
||||
react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render( /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(Restore, null), document.getElementById('Restore'));
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./resources/js/components/ErrorPage.js":
|
||||
/*!**********************************************!*\
|
||||
!*** ./resources/js/components/ErrorPage.js ***!
|
||||
@@ -127342,20 +127703,29 @@ var Footer = /*#__PURE__*/function (_Component) {
|
||||
var _super = _createSuper(Footer);
|
||||
|
||||
function Footer(props) {
|
||||
var _this;
|
||||
|
||||
_classCallCheck(this, Footer);
|
||||
|
||||
return _super.call(this, props);
|
||||
_this = _super.call(this, props);
|
||||
_this.state = {
|
||||
version: document.querySelector('meta[name="version"]').content
|
||||
};
|
||||
return _this;
|
||||
}
|
||||
|
||||
_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", {
|
||||
className: "text-muted"
|
||||
}, "See the code on ", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
|
||||
href: "https://github.com/henrywhitaker3/Speedtest-Tracker",
|
||||
@@ -127393,6 +127763,7 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var _Graphics_HistoryGraph__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../Graphics/HistoryGraph */ "./resources/js/components/Graphics/HistoryGraph.js");
|
||||
/* harmony import */ var _Graphics_LatestResults__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Graphics/LatestResults */ "./resources/js/components/Graphics/LatestResults.js");
|
||||
/* harmony import */ var _Footer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Footer */ "./resources/js/components/Home/Footer.js");
|
||||
/* harmony import */ var _Data_DataRow__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../Data/DataRow */ "./resources/js/components/Data/DataRow.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"); } }
|
||||
@@ -127421,6 +127792,7 @@ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || func
|
||||
|
||||
|
||||
|
||||
|
||||
var HomePage = /*#__PURE__*/function (_Component) {
|
||||
_inherits(HomePage, _Component);
|
||||
|
||||
@@ -127437,7 +127809,7 @@ var HomePage = /*#__PURE__*/function (_Component) {
|
||||
value: function render() {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "my-4"
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Graphics_LatestResults__WEBPACK_IMPORTED_MODULE_3__["default"], null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Graphics_HistoryGraph__WEBPACK_IMPORTED_MODULE_2__["default"], null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Footer__WEBPACK_IMPORTED_MODULE_4__["default"], null));
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Graphics_LatestResults__WEBPACK_IMPORTED_MODULE_3__["default"], null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Graphics_HistoryGraph__WEBPACK_IMPORTED_MODULE_2__["default"], null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Data_DataRow__WEBPACK_IMPORTED_MODULE_5__["default"], null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_Footer__WEBPACK_IMPORTED_MODULE_4__["default"], null));
|
||||
}
|
||||
}]);
|
||||
|
||||
|
||||
43
resources/js/components/Data/Backup.js
vendored
Normal file
43
resources/js/components/Data/Backup.js
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import { toast } from 'react-toastify';
|
||||
import Axios from 'axios';
|
||||
|
||||
export default class Backup extends Component {
|
||||
backup = () => {
|
||||
var url = '/api/backup';
|
||||
|
||||
toast.info('Your backup has started downloading...');
|
||||
|
||||
Axios.get(url, {
|
||||
responseType: 'blob'
|
||||
})
|
||||
.then((resp) => {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = "";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
toast.success('Backup downloaded');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
variant="primary"
|
||||
className="mx-2"
|
||||
onClick={this.backup}
|
||||
>Backup</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.getElementById('Backup')) {
|
||||
ReactDOM.render(<Backup />, document.getElementById('Backup'));
|
||||
}
|
||||
31
resources/js/components/Data/DataRow.js
vendored
Normal file
31
resources/js/components/Data/DataRow.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Container } from 'react-bootstrap';
|
||||
import { Row } from 'react-bootstrap';
|
||||
import { Col } from 'react-bootstrap';
|
||||
import Backup from './Backup';
|
||||
import Restore from './Restore';
|
||||
|
||||
export default class DataRow extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col sm={{ span: 12 }} className="text-center">
|
||||
<p>Use these buttons to backup/restore your data</p>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col sm={{ span: 12 }} className="text-center">
|
||||
<Backup />
|
||||
<Restore />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.getElementById('DataRow')) {
|
||||
ReactDOM.render(<DataRow />, document.getElementById('DataRow'));
|
||||
}
|
||||
111
resources/js/components/Data/Restore.js
vendored
Normal file
111
resources/js/components/Data/Restore.js
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Button, Modal, Form, Tooltip, OverlayTrigger } from 'react-bootstrap';
|
||||
import { toast } from 'react-toastify';
|
||||
import Axios from 'axios';
|
||||
|
||||
export default class Restore extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
show: false,
|
||||
data: null,
|
||||
uploadReady: false,
|
||||
filename: 'Upload your backup JSON'
|
||||
};
|
||||
}
|
||||
|
||||
showModal = () => {
|
||||
this.setState({
|
||||
show: true
|
||||
});
|
||||
}
|
||||
|
||||
hideModal = () => {
|
||||
this.setState({
|
||||
show: false
|
||||
});
|
||||
}
|
||||
|
||||
readFile = (e) => {
|
||||
var file = e.target.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.readAsText(file, 'UTF-8');
|
||||
reader.onload = function(evt) {
|
||||
try {
|
||||
var data = evt.target.result.trim();
|
||||
var data = JSON.parse(data);
|
||||
this.setState({
|
||||
data: data,
|
||||
uploadReady: true,
|
||||
filename: file.name
|
||||
});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
toast.error('Your upload file is not valid JSON');
|
||||
}
|
||||
}.bind(this)
|
||||
reader.onerror = function (evt) {
|
||||
toast.error('Something went wrong parsing your backup file.');
|
||||
}
|
||||
}
|
||||
|
||||
uploadFile = () => {
|
||||
var data = { data: this.state.data };
|
||||
var url = '/api/restore';
|
||||
|
||||
Axios.post(url, data)
|
||||
.then((resp) => {
|
||||
toast.success('Your is being restored...');
|
||||
this.setState({
|
||||
show: false,
|
||||
data: null,
|
||||
uploadReady: false,
|
||||
filename: 'Upload your backup JSON'
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
var show = this.state.show;
|
||||
var uploadReady = this.state.uploadReady;
|
||||
var filename = this.state.filename;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant="secondary" className="mx-2" onClick={this.showModal}>Restore</Button>
|
||||
|
||||
<Modal show={show} onHide={this.hideModal} animation={true}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Restore from a backup</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<p>Upload your JSON backup file here:</p>
|
||||
<Form.File
|
||||
id="restoreFileInput"
|
||||
label="Upload JSON file"
|
||||
className="mb-3"
|
||||
custom
|
||||
>
|
||||
<Form.File.Input onChange={this.readFile} />
|
||||
<Form.File.Label data-browse="Choose file">
|
||||
{filename}
|
||||
</Form.File.Label>
|
||||
</Form.File>
|
||||
{uploadReady === true &&
|
||||
<Button variant="secondary" onClick={this.uploadFile}>Restore</Button>
|
||||
}
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.getElementById('Restore')) {
|
||||
ReactDOM.render(<Restore />, document.getElementById('Restore'));
|
||||
}
|
||||
7
resources/js/components/Home/Footer.js
vendored
7
resources/js/components/Home/Footer.js
vendored
@@ -6,13 +6,20 @@ import { Col } from 'react-bootstrap';
|
||||
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 (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col sm={{ span: 12 }} className="text-center">
|
||||
<p className="text-muted mb-0">Speedtest Tracker Version: {version}</p>
|
||||
<p className="text-muted">See the code on <a href="https://github.com/henrywhitaker3/Speedtest-Tracker" target="_blank" rel="noopener noreferrer">GitHub</a></p>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
2
resources/js/components/Home/HomePage.js
vendored
2
resources/js/components/Home/HomePage.js
vendored
@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
|
||||
import HistoryGraph from '../Graphics/HistoryGraph';
|
||||
import LatestResults from '../Graphics/LatestResults';
|
||||
import Footer from './Footer';
|
||||
import DataRow from '../Data/DataRow';
|
||||
|
||||
export default class HomePage extends Component {
|
||||
|
||||
@@ -12,6 +13,7 @@ export default class HomePage extends Component {
|
||||
<div className="my-4">
|
||||
<LatestResults />
|
||||
<HistoryGraph />
|
||||
<DataRow />
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<meta name="author" content="Henry Whitaker">
|
||||
<meta name="version" content="{{ config('app.version', 'Unknown') }}">
|
||||
|
||||
<link href="/icons/themify/themify-icons.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/bootstrap.dark.min.css">
|
||||
|
||||
@@ -28,3 +28,12 @@ Route::group([
|
||||
Route::get('run', 'SpeedtestController@run')
|
||||
->name('speedtest.run');
|
||||
});
|
||||
|
||||
Route::group([
|
||||
'middleware' => 'api'
|
||||
], function () {
|
||||
Route::get('backup', 'BackupController@backup')
|
||||
->name('data.backup');
|
||||
Route::post('restore', 'BackupController@restore')
|
||||
->name('data.restore');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user