mirror of
https://github.com/henrywhitaker3/Speedtest-Tracker.git
synced 2025-12-21 21:33:08 +01:00
Merge pull request #249 from henrywhitaker3/alpha
Updated backup functions
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Speedtest Tracker
|
# Speedtest Tracker
|
||||||
|
|
||||||
[](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits)  [](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE)
|
[](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker) [](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [](https://github.com/henrywhitaker3/Speedtest-Tracker/actions) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits) [](https://github.com/henrywhitaker3/Speedtest-Tracker/issues) [](https://github.com/henrywhitaker3/Speedtest-Tracker/commits)  [](https://github.com/henrywhitaker3/Speedtest-Tracker/blob/master/LICENSE)
|
||||||
|
|
||||||
This program runs a speedtest check every hour and graphs the results. The back-end is written in [Laravel](https://laravel.com/) and the front-end uses [React](https://reactjs.org/). It uses the [Ookla's speedtest cli](https://www.speedtest.net/apps/cli) package to get the data and uses [Chart.js](https://www.chartjs.org/) to plot the results.
|
This program runs a speedtest check every hour and graphs the results. The back-end is written in [Laravel](https://laravel.com/) and the front-end uses [React](https://reactjs.org/). It uses the [Ookla's speedtest cli](https://www.speedtest.net/apps/cli) package to get the data and uses [Chart.js](https://www.chartjs.org/) to plot the results.
|
||||||
|
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ class BackupHelper {
|
|||||||
case 'csv':
|
case 'csv':
|
||||||
$data = Speedtest::get();
|
$data = Speedtest::get();
|
||||||
|
|
||||||
$csv = Storage::disk('local')->getDriver()->getAdapter()->getPathPrefix() . $name . '.csv';
|
$csv = storage_path() . '/app/' . $name . '.csv';
|
||||||
$name = $name . '.csv';
|
$name = $name . '.csv';
|
||||||
$handle = fopen($csv, 'w+');
|
$handle = fopen($csv, 'w+');
|
||||||
fputcsv($handle, array('id', 'ping', 'download', 'upload', 'created_at', 'updated_at'));
|
fputcsv($handle, array('id', 'ping', 'download', 'upload', 'server_id', 'server_name', 'server_host', 'url', 'scheduled', 'failed', 'created_at', 'updated_at'));
|
||||||
|
|
||||||
foreach($data as $d) {
|
foreach($data as $d) {
|
||||||
fputcsv($handle, array($d->id, $d->ping, $d->download, $d->upload, $d->created_at, $d->updated_at));
|
fputcsv($handle, BackupHelper::createCSVBackupArray($d));
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
@@ -62,22 +62,24 @@ class BackupHelper {
|
|||||||
if($format == 'json') {
|
if($format == 'json') {
|
||||||
foreach($array as $test) {
|
foreach($array as $test) {
|
||||||
try {
|
try {
|
||||||
$st = Speedtest::create([
|
$data = BackupHelper::backupJSONToArray($test);
|
||||||
'ping' => $test['ping'],
|
|
||||||
'download' => $test['download'],
|
if($data === false) {
|
||||||
'upload' => $test['upload'],
|
continue;
|
||||||
'created_at' => $test['created_at'],
|
}
|
||||||
]);
|
|
||||||
|
Speedtest::create($data);
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
|
Log::error($e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if($format == 'csv') {
|
} else if($format == 'csv') {
|
||||||
$csv = explode(PHP_EOL, $array);
|
$csv = explode(PHP_EOL, $array);
|
||||||
$headers = 'id,ping,download,upload,created_at,updated_at';
|
|
||||||
if($csv[0] != $headers) {
|
$headers = BackupHelper::validateCSV($csv[0]);
|
||||||
Log::error('Incorrect CSV format');
|
if($headers === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,14 +87,14 @@ class BackupHelper {
|
|||||||
$csv = array_values($csv);
|
$csv = array_values($csv);
|
||||||
|
|
||||||
for($i = 0; $i < sizeof($csv); $i++) {
|
for($i = 0; $i < sizeof($csv); $i++) {
|
||||||
$e = explode(',', $csv[$i]);
|
$data = BackupHelper::backupCSVToArray($csv[$i]);
|
||||||
|
|
||||||
|
if($data === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$st = Speedtest::create([
|
Speedtest::create($data);
|
||||||
'ping' => $e[1],
|
|
||||||
'download' => $e[2],
|
|
||||||
'upload' => $e[3],
|
|
||||||
'created_at' => substr($e[4], 1, -1),
|
|
||||||
]);
|
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
Log::error($e);
|
Log::error($e);
|
||||||
continue;
|
continue;
|
||||||
@@ -104,4 +106,179 @@ class BackupHelper {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a CSV file passed for restore
|
||||||
|
*
|
||||||
|
* @param String $csv The line containing the CSV headers
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
public static function validateCSV(String $csv)
|
||||||
|
{
|
||||||
|
$headers = [
|
||||||
|
'old' => 'id,ping,download,upload,created_at,updated_at',
|
||||||
|
'new' => 'id,ping,download,upload,server_id,server_name,server_host,url,scheduled,failed,created_at,updated_at',
|
||||||
|
];
|
||||||
|
$backupHeaders = null;
|
||||||
|
|
||||||
|
foreach($headers as $key => $h) {
|
||||||
|
if($csv == $h) {
|
||||||
|
$backupHeaders = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($backupHeaders === null) {
|
||||||
|
Log::info('Incorrect CSV format');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $backupHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array from the raw CSV data
|
||||||
|
*
|
||||||
|
* @param String $line The line of CSV data
|
||||||
|
* @param String $header The type of backup header
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public static function backupCSVToArray(String $line, String $header = 'new')
|
||||||
|
{
|
||||||
|
$basic = explode(',', $line);
|
||||||
|
|
||||||
|
if($header == 'old') {
|
||||||
|
$array = [
|
||||||
|
'ping' => $basic[1],
|
||||||
|
'download' => $basic[2],
|
||||||
|
'upload' => $basic[3],
|
||||||
|
'created_at' => substr($basic[4], 1, -1),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if($header == 'new') {
|
||||||
|
$array = [
|
||||||
|
'ping' => $basic[1],
|
||||||
|
'download' => $basic[2],
|
||||||
|
'upload' => $basic[3],
|
||||||
|
'server_id' => $basic[4],
|
||||||
|
'server_name' => $basic[5],
|
||||||
|
'server_host' => $basic[6],
|
||||||
|
'url' => $basic[7],
|
||||||
|
'scheduled' => $basic[8],
|
||||||
|
'failed' => $basic[9],
|
||||||
|
'created_at' => substr($basic[10], 1, -1),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset($array)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackupHelper::cleanRestoreDataArray($array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean an array, setting values with '' to null
|
||||||
|
*
|
||||||
|
* @param array $array
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function cleanRestoreDataArray(array $array)
|
||||||
|
{
|
||||||
|
foreach($array as $key => $val) {
|
||||||
|
if($val === '') {
|
||||||
|
$array[$key] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array from the JSON data
|
||||||
|
*
|
||||||
|
* @param array $json json_decoded data
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public static function backupJSONToArray($json)
|
||||||
|
{
|
||||||
|
$required = [
|
||||||
|
'ping',
|
||||||
|
'upload',
|
||||||
|
'download',
|
||||||
|
'created_at',
|
||||||
|
];
|
||||||
|
|
||||||
|
$extras = [
|
||||||
|
'server_id',
|
||||||
|
'server_name',
|
||||||
|
'server_host',
|
||||||
|
'url',
|
||||||
|
'failed',
|
||||||
|
'scheduled'
|
||||||
|
];
|
||||||
|
|
||||||
|
$array = [];
|
||||||
|
|
||||||
|
foreach($required as $req) {
|
||||||
|
if(!array_key_exists($req, $json)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$val = $json[$req];
|
||||||
|
|
||||||
|
if($val === '') {
|
||||||
|
$val = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$array[$req] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($extras as $extra) {
|
||||||
|
if(array_key_exists($extra, $json)) {
|
||||||
|
$val = $json[$extra];
|
||||||
|
|
||||||
|
if($val === '') {
|
||||||
|
$val = null;
|
||||||
|
}
|
||||||
|
$array[$extra] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array to store in CSV
|
||||||
|
*
|
||||||
|
* @param Speedtest $test
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function createCSVBackupArray(Speedtest $test)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
$test->id,
|
||||||
|
$test->ping,
|
||||||
|
$test->download,
|
||||||
|
$test->upload,
|
||||||
|
$test->server_id,
|
||||||
|
$test->server_name,
|
||||||
|
$test->server_host,
|
||||||
|
$test->url,
|
||||||
|
$test->scheduled,
|
||||||
|
$test->failed,
|
||||||
|
$test->created_at,
|
||||||
|
$test->updated_at
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach($data as $key => $val) {
|
||||||
|
if(strpos($val, ',') !== false) {
|
||||||
|
$val = str_replace(',', ' -', $val);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[$key] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
{
|
{
|
||||||
|
"1.7.18": [
|
||||||
|
{
|
||||||
|
"description": "Fixed issue with widgets not updating when switching between failed/successful tests.",
|
||||||
|
"link": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Updated backup/restore functions to reflect new DB fields.",
|
||||||
|
"link": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
"1.7.17": [
|
"1.7.17": [
|
||||||
{
|
{
|
||||||
"description": "Updated dependencies.",
|
"description": "Updated dependencies.",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ parameters:
|
|||||||
level: 5
|
level: 5
|
||||||
|
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
- '#Unsafe usage of new static#'
|
|
||||||
|
|
||||||
excludes_analyse:
|
excludes_analyse:
|
||||||
- ./*/*/FileToBeExcluded.php
|
- ./*/*/FileToBeExcluded.php
|
||||||
|
|||||||
2
public/js/app.js
vendored
2
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
30
resources/js/components/Data/Restore.js
vendored
30
resources/js/components/Data/Restore.js
vendored
@@ -75,6 +75,36 @@ export default class Restore extends Component {
|
|||||||
inputName: 'created_at',
|
inputName: 'created_at',
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "server_id",
|
||||||
|
inputName: 'server_id',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "server_name",
|
||||||
|
inputName: 'server_name',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "server_host",
|
||||||
|
inputName: 'server_host',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "url",
|
||||||
|
inputName: 'url',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "scheduled",
|
||||||
|
inputName: 'scheduled',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "failed",
|
||||||
|
inputName: 'failed',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "updated_at",
|
name: "updated_at",
|
||||||
inputName: 'updated_at',
|
inputName: 'updated_at',
|
||||||
|
|||||||
5
resources/js/components/Graphics/Widget.js
vendored
5
resources/js/components/Graphics/Widget.js
vendored
@@ -18,14 +18,15 @@ export default class Widget extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate = () => {
|
componentDidUpdate = () => {
|
||||||
if(this.props.title != this.state.title || this.props.value != this.state.value || this.props.unit != this.state.unit || this.props.icon != this.state.icon || this.props.avg != this.state.avg || this.props.max != this.state.max) {
|
if(this.props.title != this.state.title || this.props.value != this.state.value || this.props.unit != this.state.unit || this.props.icon != this.state.icon || this.props.avg != this.state.avg || this.props.max != this.state.max || this.props.failed != this.state.failed) {
|
||||||
this.setState({
|
this.setState({
|
||||||
title: this.props.title,
|
title: this.props.title,
|
||||||
value: this.props.value,
|
value: this.props.value,
|
||||||
unit: this.props.unit,
|
unit: this.props.unit,
|
||||||
icon: this.props.icon,
|
icon: this.props.icon,
|
||||||
avg: this.props.avg,
|
avg: this.props.avg,
|
||||||
max: this.props.max
|
max: this.props.max,
|
||||||
|
failed: this.props.failed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user