comparison src/main.cpp @ 142:36c9cb759326

Implement simple SQLite database backup at program exit using Qt HTTP/HTTPS and a PHP script on the remote server. Needs more work, testing and better error handling.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 24 Aug 2017 15:44:33 +0300
parents 783417da6da3
children 75a4faa219a9
comparison
equal deleted inserted replaced
141:d0943d41f391 142:36c9cb759326
9 #include <QApplication> 9 #include <QApplication>
10 #include <QMessageBox> 10 #include <QMessageBox>
11 #include <QSettings> 11 #include <QSettings>
12 #include <QPrintDialog> 12 #include <QPrintDialog>
13 #include <QPrintPreviewDialog> 13 #include <QPrintPreviewDialog>
14 #include <QProgressDialog>
15 #include <QStandardPaths> 14 #include <QStandardPaths>
16 #include "main.h" 15 #include "main.h"
17 #include "ui_mainwindow.h" 16 #include "ui_mainwindow.h"
18 #include "ui_editperson.h" 17 #include "ui_editperson.h"
19 #include "ui_aboutwindow.h" 18 #include "ui_aboutwindow.h"
244 243
245 // Read configuration settings 244 // Read configuration settings
246 settings.uiPos = tmpst.value("pos", QPoint(100, 100)).toPoint(); 245 settings.uiPos = tmpst.value("pos", QPoint(100, 100)).toPoint();
247 settings.uiSize = tmpst.value("size", QSize(1000, 600)).toSize(); 246 settings.uiSize = tmpst.value("size", QSize(1000, 600)).toSize();
248 settings.uiScale = tmpst.value("scale", 1.0f).toDouble(); 247 settings.uiScale = tmpst.value("scale", 1.0f).toDouble();
249 settings.dbBackupURL = tmpst.value("dbBackupURL", "").toString(); 248 settings.dbBackupURL = tmpst.value("dbBackupURL", QString()).toString();
250 settings.dbBackupSecret = tmpst.value("dbBackupSecret", "").toString(); 249 settings.dbBackupSecret = tmpst.value("dbBackupSecret", QString()).toString();
250
251 // Check commandline arguments for configuring backup settings
252 if (argc >= 4 && strcmp(argv[1], "config") == 0)
253 {
254 settings.dbBackupURL = QString(argv[2]);
255 settings.dbBackupSecret = QString(argv[3]);
256 }
251 257
252 // 258 //
253 // Create logfile and data directory 259 // Create logfile and data directory
254 // 260 //
255 settings.dataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 261 settings.dataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
317 QMainWindow(parent), 323 QMainWindow(parent),
318 ui(new Ui::SyntilistaMainWindow) 324 ui(new Ui::SyntilistaMainWindow)
319 { 325 {
320 // Setup UI 326 // Setup UI
321 ui->setupUi(this); 327 ui->setupUi(this);
322 backupDialog = NULL;
323 328
324 // Restore window size and position 329 // Restore window size and position
325 move(settings.uiPos); 330 move(settings.uiPos);
326 resize(settings.uiSize); 331 resize(settings.uiSize);
327 332
429 delete model_Latest; 434 delete model_Latest;
430 435
431 // Commit and close database 436 // Commit and close database
432 QSqlDatabase::database().commit(); 437 QSqlDatabase::database().commit();
433 QSqlDatabase::database().close(); 438 QSqlDatabase::database().close();
439
440 // Back up the database
441 backupDatabase();
442 }
443
444
445 void SyntilistaMainWindow::backupDatabase()
446 {
447 QString dbFilename = settings.dataPath + QDir::separator() + APP_SQLITE_FILE;
448 QString backupFilename = APP_SQLITE_FILE;
449 backupReply = NULL;
450 backupDialog = NULL;
451
452 if (settings.dbBackupURL == QString() || settings.dbBackupURL == "")
453 {
454 slLog("ERROR", QStringLiteral("Database backup URL not set in configuration."));
455 return;
456 }
457
458 if (settings.dbBackupSecret == QString() || settings.dbBackupSecret == "")
459 {
460 slLog("ERROR", QStringLiteral("Database backup secret key not set in configuration."));
461 return;
462 }
463
464 // Check for network access
465 QNetworkAccessManager *manager = new QNetworkAccessManager();
466 if (manager->networkAccessible() != QNetworkAccessManager::Accessible)
467 {
468 slLog("ERROR", QStringLiteral("Network not available, cannot backup the database."));
469 return;
470 }
471
472 // Attempt to open the database file
473 QFile *file = new QFile(dbFilename);
474 if (!file->open(QIODevice::ReadOnly))
475 {
476 slLog("ERROR", QStringLiteral("Failed to open database file '%1' for backup.").arg(dbFilename));
477 return;
478 }
479
480 // Okay, we seem to be "go" ..
481 slLog("INFO",
482 QStringLiteral("Attempting database backup from '%1' to '%2'.").
483 arg(dbFilename).arg(settings.dbBackupURL));
484
485 // Create the HTTP POST request
486 QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
487
488 // The "secret" key as POST parameter
489 QHttpPart postPart;
490 postPart.setHeader(QNetworkRequest::ContentDispositionHeader,
491 QVariant("form-data; name=\"secret\";"));
492 postPart.setBody(QByteArray(settings.dbBackupSecret.toUtf8()));
493
494 // Actual data as binary octet-stream
495 QHttpPart dataPart;
496 dataPart.setHeader(QNetworkRequest::ContentTypeHeader,
497 QVariant("binary/octet-stream"));
498
499 dataPart.setHeader(QNetworkRequest::ContentDispositionHeader,
500 QVariant("form-data; name=\"file\"; filename=\""+ backupFilename +"\""));
501
502 dataPart.setBodyDevice(file);
503 file->setParent(multiPart); // we cannot delete the QFile object now, so delete it with the multiPart
504
505 multiPart->append(postPart);
506 multiPart->append(dataPart);
507
508 // Attempt to POST the whole thing
509 QUrl url(settings.dbBackupURL);
510 QNetworkRequest request(url);
511 backupReply = manager->post(request, multiPart);
512 multiPart->setParent(backupReply);
513
514 connect(
515 backupReply,
516 SIGNAL(finished()),
517 this,
518 SLOT(backupFinished()));
519
520 connect(
521 backupReply,
522 SIGNAL(uploadProgress(qint64, qint64)),
523 this,
524 SLOT(backupProgress(qint64, qint64)));
525
526 // Create progress dialog
527 backupDialog = new QProgressDialog(
528 tr("Varmuuskopioidaan tietokantaa ..."),
529 QString(),
530 0,
531 100,
532 this);
533
534 backupDialog->setAttribute(Qt::WA_DeleteOnClose);
535 backupDialog->setAutoClose(false);
536 backupDialog->setWindowModality(Qt::ApplicationModal);
537 backupDialog->exec();
538 }
539
540
541 void SyntilistaMainWindow::backupProgress(qint64 bytesSent, qint64 bytesTotal)
542 {
543 if (bytesTotal > 0)
544 {
545 slLog("INFO",
546 QStringLiteral("Backup sent %1 / %2 bytes.").
547 arg(bytesSent).
548 arg(bytesTotal));
549
550 backupDialog->setValue((bytesSent * 100) / bytesTotal);
551 }
552 }
553
554
555 void SyntilistaMainWindow::backupError(QNetworkReply::NetworkError code)
556 {
557 slLog("ERROR",
558 QStringLiteral("Backup failed with network error %1.\n").
559 arg(code)
560 );
561 }
562
563
564 void SyntilistaMainWindow::backupFinished()
565 {
566 if (backupReply)
567 {
568 slLog("PAF", QString::fromUtf8(backupReply->readAll()));
569 }
570 slLog("INFO", "Backup finished.");
571 backupDialog->close();
434 } 572 }
435 573
436 574
437 // 575 //
438 // Helper function for showing messages in the statusbar/line 576 // Helper function for showing messages in the statusbar/line