Mercurial > hg > syntilista
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 |