Database round2 (#193)
* Dont throw as many errors * hold a QSqlDatabase in the connection * only Make Dir if it doesn't exist * more database cleanup * Replace remaining FileError use with other methods * Try not do * allow database to report errors Co-authored-by: Chris Rizzitello <crizzitello@ics.com>main
parent
45ee47b145
commit
5928942399
|
@ -3,7 +3,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_subdirectory(components)
|
add_subdirectory(components)
|
||||||
add_subdirectory(db)
|
add_subdirectory(db)
|
||||||
add_subdirectory(dtos)
|
add_subdirectory(dtos)
|
||||||
add_subdirectory(exceptions)
|
|
||||||
add_subdirectory(forms)
|
add_subdirectory(forms)
|
||||||
add_subdirectory(helpers)
|
add_subdirectory(helpers)
|
||||||
add_subdirectory(models)
|
add_subdirectory(models)
|
||||||
|
@ -54,7 +53,6 @@ target_link_libraries ( ashirt
|
||||||
ASHIRT::COMPONENTS
|
ASHIRT::COMPONENTS
|
||||||
ASHIRT::HELPERS
|
ASHIRT::HELPERS
|
||||||
ASHIRT::DTOS
|
ASHIRT::DTOS
|
||||||
ASHIRT::EXCEPTIONS
|
|
||||||
ASHIRT::FORMS
|
ASHIRT::FORMS
|
||||||
ASHIRT::PORTING
|
ASHIRT::PORTING
|
||||||
)
|
)
|
||||||
|
|
|
@ -44,19 +44,13 @@ void CodeBlockView::buildUi() {
|
||||||
gridLayout->addWidget(codeEditor, 1, 0, 1, gridLayout->columnCount());
|
gridLayout->addWidget(codeEditor, 1, 0, 1, gridLayout->columnCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeBlockView::loadFromFile(QString filepath) {
|
void CodeBlockView::loadFromFile(QString filepath)
|
||||||
try {
|
{
|
||||||
|
codeEditor->setPlainText(tr("No Codeblock Loaded"));
|
||||||
loadedCodeblock = Codeblock::readCodeblock(filepath);
|
loadedCodeblock = Codeblock::readCodeblock(filepath);
|
||||||
|
|
||||||
codeEditor->setPlainText(loadedCodeblock.content);
|
codeEditor->setPlainText(loadedCodeblock.content);
|
||||||
sourceTextBox->setText(loadedCodeblock.source);
|
sourceTextBox->setText(loadedCodeblock.source);
|
||||||
UIHelpers::setComboBoxValue(languageComboBox, loadedCodeblock.subtype);
|
UIHelpers::setComboBoxValue(languageComboBox, loadedCodeblock.subtype);
|
||||||
}
|
|
||||||
catch (std::exception& e) {
|
|
||||||
QString msg = tr("Unable to load codeblock. Error: %1").arg(e.what());
|
|
||||||
codeEditor->setPlainText(msg);
|
|
||||||
setReadonly(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeBlockView::saveEvidence() {
|
bool CodeBlockView::saveEvidence() {
|
||||||
|
|
|
@ -95,36 +95,32 @@ void EvidenceEditor::setEnabled(bool enable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvidenceEditor::loadData() {
|
void EvidenceEditor::loadData()
|
||||||
// get local db evidence data
|
{
|
||||||
clearEditor();
|
// get local db evidence data
|
||||||
try {
|
clearEditor();
|
||||||
originalEvidenceData = db->getEvidenceDetails(evidenceID);
|
originalEvidenceData = db->getEvidenceDetails(evidenceID);
|
||||||
|
if(originalEvidenceData.id == -1) {
|
||||||
|
loadedPreview = new ErrorView(tr("Unable to load evidence: %1").arg(db->errorString()), this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
descriptionTextBox->setText(originalEvidenceData.description);
|
descriptionTextBox->setText(originalEvidenceData.description);
|
||||||
operationSlug = originalEvidenceData.operationSlug;
|
operationSlug = originalEvidenceData.operationSlug;
|
||||||
|
|
||||||
if (originalEvidenceData.contentType == QStringLiteral("image")) {
|
if (originalEvidenceData.contentType == QStringLiteral("image")) {
|
||||||
loadedPreview = new ImageView(this);
|
loadedPreview = new ImageView(this);
|
||||||
loadedPreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
loadedPreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
}
|
} else if (originalEvidenceData.contentType == QStringLiteral("codeblock")) {
|
||||||
else if (originalEvidenceData.contentType == QStringLiteral("codeblock")) {
|
loadedPreview = new CodeBlockView(this);
|
||||||
loadedPreview = new CodeBlockView(this);
|
loadedPreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
loadedPreview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
} else {
|
||||||
}
|
loadedPreview = new ErrorView(tr("Unsupported evidence type: %1").arg(originalEvidenceData.contentType), this);
|
||||||
else {
|
|
||||||
loadedPreview =
|
|
||||||
new ErrorView(tr("Unsupported evidence type: %1").arg(originalEvidenceData.contentType), this);
|
|
||||||
}
|
}
|
||||||
loadedPreview->loadFromFile(originalEvidenceData.path);
|
loadedPreview->loadFromFile(originalEvidenceData.path);
|
||||||
loadedPreview->setReadonly(readonly);
|
loadedPreview->setReadonly(readonly);
|
||||||
|
|
||||||
// get all remote tags (for op)
|
// get all remote tags (for op)
|
||||||
tagEditor->loadTags(operationSlug, originalEvidenceData.tags);
|
tagEditor->loadTags(operationSlug, originalEvidenceData.tags);
|
||||||
}
|
splitter->insertWidget(0, loadedPreview);
|
||||||
catch (QSqlError &e) {
|
|
||||||
loadedPreview = new ErrorView(tr("Unable to load evidence: %1").arg(e.text()), this);
|
|
||||||
}
|
|
||||||
splitter->insertWidget(0, loadedPreview);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvidenceEditor::revert() {
|
void EvidenceEditor::revert() {
|
||||||
|
@ -161,22 +157,28 @@ void EvidenceEditor::onTagsLoaded(bool success) {
|
||||||
|
|
||||||
// saveEvidence is a helper method to save (to the database) the currently
|
// saveEvidence is a helper method to save (to the database) the currently
|
||||||
// loaded evidence, using the editor changes.
|
// loaded evidence, using the editor changes.
|
||||||
SaveEvidenceResponse EvidenceEditor::saveEvidence() {
|
SaveEvidenceResponse EvidenceEditor::saveEvidence()
|
||||||
if (loadedPreview != nullptr) {
|
{
|
||||||
loadedPreview->saveEvidence();
|
if (loadedPreview != nullptr) {
|
||||||
}
|
loadedPreview->saveEvidence();
|
||||||
auto evi = encodeEvidence();
|
}
|
||||||
auto resp = SaveEvidenceResponse(evi);
|
auto evi = encodeEvidence();
|
||||||
try {
|
auto resp = SaveEvidenceResponse(evi);
|
||||||
db->updateEvidenceDescription(evi.description, evi.id);
|
db->updateEvidenceDescription(evi.description, evi.id);
|
||||||
|
if(!db->errorString().isEmpty()) {
|
||||||
|
resp.actionSucceeded = false;
|
||||||
|
resp.errorText = db->errorString();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
db->setEvidenceTags(evi.tags, evi.id);
|
db->setEvidenceTags(evi.tags, evi.id);
|
||||||
|
if(!db->errorString().isEmpty()) {
|
||||||
|
resp.actionSucceeded = false;
|
||||||
|
resp.errorText = db->errorString();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
resp.actionSucceeded = true;
|
resp.actionSucceeded = true;
|
||||||
}
|
return resp;
|
||||||
catch (QSqlError &e) {
|
|
||||||
resp.actionSucceeded = false;
|
|
||||||
resp.errorText = e.text();
|
|
||||||
}
|
|
||||||
return resp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<DeleteEvidenceResponse> EvidenceEditor::deleteEvidence(QList<qint64> evidenceIDs)
|
QList<DeleteEvidenceResponse> EvidenceEditor::deleteEvidence(QList<qint64> evidenceIDs)
|
||||||
|
@ -185,12 +187,9 @@ QList<DeleteEvidenceResponse> EvidenceEditor::deleteEvidence(QList<qint64> evide
|
||||||
for (qint64 id : evidenceIDs) {
|
for (qint64 id : evidenceIDs) {
|
||||||
model::Evidence evi = db->getEvidenceDetails(id);
|
model::Evidence evi = db->getEvidenceDetails(id);
|
||||||
DeleteEvidenceResponse resp(evi);
|
DeleteEvidenceResponse resp(evi);
|
||||||
|
resp.dbDeleteSuccess = db->deleteEvidence(evi.id);
|
||||||
try{
|
if(!resp.dbDeleteSuccess)
|
||||||
resp.dbDeleteSuccess = db->deleteEvidence(evi.id);
|
resp.errorText = db->errorString();
|
||||||
} catch(QSqlError &e) {
|
|
||||||
resp.errorText = e.text();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto localFile = QFile(evi.path);
|
auto localFile = QFile(evi.path);
|
||||||
if (!localFile.remove()) {
|
if (!localFile.remove()) {
|
||||||
|
|
|
@ -6,68 +6,61 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
#include "exceptions/fileerror.h"
|
|
||||||
#include "helpers/file_helpers.h"
|
#include "helpers/file_helpers.h"
|
||||||
|
|
||||||
DatabaseConnection::DatabaseConnection(const QString& dbPath, const QString& databaseName)
|
DatabaseConnection::DatabaseConnection(const QString& dbPath, const QString& databaseName)
|
||||||
: _dbName(databaseName)
|
: _dbName(databaseName)
|
||||||
, _dbPath(dbPath)
|
, _dbPath(dbPath)
|
||||||
|
, _db(QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), databaseName))
|
||||||
{
|
{
|
||||||
auto db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), databaseName);
|
const auto dbDir = FileHelpers::getDirname(_dbPath);
|
||||||
QDir().mkpath(FileHelpers::getDirname(dbPath));
|
if(!QDir().exists(dbDir))
|
||||||
db.setDatabaseName(dbPath);
|
QDir().mkpath(dbDir);
|
||||||
|
_db.setDatabaseName(_dbPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::withConnection(const QString& dbPath, const QString &dbName,
|
bool DatabaseConnection::withConnection(const QString& dbPath, const QString &dbName,
|
||||||
const std::function<void(DatabaseConnection)> &actions) {
|
const std::function<void(DatabaseConnection)> &actions)
|
||||||
DatabaseConnection conn(dbPath, dbName);
|
{
|
||||||
conn.connect();
|
DatabaseConnection conn(dbPath, dbName);
|
||||||
try {
|
if(!conn.connect())
|
||||||
|
return false;
|
||||||
actions(conn);
|
actions(conn);
|
||||||
} catch(const std::runtime_error& e) {
|
bool rtn = true;
|
||||||
qWarning() << "Error running action: " << e.what();
|
if( conn._db.lastError().type() != QSqlError::NoError)
|
||||||
}
|
rtn = false;
|
||||||
|
|
||||||
conn.close();
|
conn.close();
|
||||||
QSqlDatabase::removeDatabase(dbName);
|
QSqlDatabase::removeDatabase(dbPath);
|
||||||
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseConnection::connect()
|
bool DatabaseConnection::connect()
|
||||||
{
|
{
|
||||||
auto db = getDB();
|
if (!_db.open())
|
||||||
if (!db.open()) {
|
|
||||||
return false;
|
return false;
|
||||||
throw db.lastError();
|
|
||||||
}
|
|
||||||
return migrateDB();
|
return migrateDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::close() noexcept { getDB().close(); }
|
qint64 DatabaseConnection::createEvidence(const QString &filepath, const QString &operationSlug, const QString &contentType)
|
||||||
|
{
|
||||||
qint64 DatabaseConnection::createEvidence(const QString &filepath, const QString &operationSlug,
|
auto qKeys = QStringLiteral("path, operation_slug, content_type, recorded_date");
|
||||||
const QString &contentType) {
|
auto qValues = QStringLiteral("?, ?, ?, datetime('now')");
|
||||||
return doInsert(getDB(),
|
auto qStr = _sqlBasicInsert.arg(_tblEvidence, qKeys, qValues);
|
||||||
"INSERT INTO evidence"
|
return doInsert(_db, qStr, {filepath, operationSlug, contentType});
|
||||||
" (path, operation_slug, content_type, recorded_date)"
|
|
||||||
" VALUES"
|
|
||||||
" (?, ?, ?, datetime('now'))",
|
|
||||||
{filepath, operationSlug, contentType});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 DatabaseConnection::createFullEvidence(const model::Evidence &evidence) {
|
qint64 DatabaseConnection::createFullEvidence(const model::Evidence &evidence) {
|
||||||
return doInsert(getDB(),
|
auto qKeys = QStringLiteral("path, operation_slug, content_type, description, error, recorded_date, upload_date");
|
||||||
"INSERT INTO evidence"
|
auto qValues = QStringLiteral("?, ?, ?, ?, ?, ?, ?");
|
||||||
" (path, operation_slug, content_type, description, error, recorded_date, upload_date)"
|
auto qStr = _sqlBasicInsert.arg(_tblEvidence, qKeys, qValues);
|
||||||
" VALUES"
|
return doInsert(_db, qStr,
|
||||||
" (?, ?, ?, ?, ?, ?, ?)",
|
|
||||||
{evidence.path, evidence.operationSlug, evidence.contentType, evidence.description,
|
{evidence.path, evidence.operationSlug, evidence.contentType, evidence.description,
|
||||||
evidence.errorText, evidence.recordedDate, evidence.uploadDate});
|
evidence.errorText, evidence.recordedDate, evidence.uploadDate});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::batchCopyFullEvidence(const QList<model::Evidence> &evidence) {
|
void DatabaseConnection::batchCopyFullEvidence(const QList<model::Evidence> &evidence) {
|
||||||
QString baseQuery = "INSERT INTO evidence"
|
auto baseQuery = QStringLiteral("INSERT INTO evidence (%1) VALUES %2").arg(_evidenceAllKeys, QStringLiteral("%1"));
|
||||||
" (id, path, operation_slug, content_type, description, error, recorded_date, upload_date)"
|
|
||||||
" VALUES %1";
|
|
||||||
int varsPerRow = 8; // count number of "?"
|
int varsPerRow = 8; // count number of "?"
|
||||||
std::function<QVariantList(int)> getItemValues = [evidence](int i){
|
std::function<QVariantList(int)> getItemValues = [evidence](int i){
|
||||||
auto item = evidence.at(i);
|
auto item = evidence.at(i);
|
||||||
|
@ -79,28 +72,13 @@ void DatabaseConnection::batchCopyFullEvidence(const QList<model::Evidence> &evi
|
||||||
batchInsert(baseQuery, varsPerRow, evidence.size(), getItemValues);
|
batchInsert(baseQuery, varsPerRow, evidence.size(), getItemValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 DatabaseConnection::copyFullEvidence(const model::Evidence &evidence) {
|
|
||||||
return doInsert(getDB(),
|
|
||||||
"INSERT INTO evidence"
|
|
||||||
" (id, path, operation_slug, content_type, description, error, recorded_date, upload_date)"
|
|
||||||
" VALUES"
|
|
||||||
" (?, ?, ?, ?, ?, ?, ?)",
|
|
||||||
{evidence.id, evidence.path, evidence.operationSlug, evidence.contentType,
|
|
||||||
evidence.description, evidence.errorText, evidence.recordedDate,
|
|
||||||
evidence.uploadDate});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
model::Evidence DatabaseConnection::getEvidenceDetails(qint64 evidenceID)
|
||||||
model::Evidence DatabaseConnection::getEvidenceDetails(qint64 evidenceID) {
|
{
|
||||||
model::Evidence rtn;
|
model::Evidence rtn;
|
||||||
auto query = executeQuery(getDB(),
|
auto qStr = QStringLiteral("%1 WHERE id=? LIMIT 1").arg(_sqlSelectTemplate.arg(_evidenceAllKeys, _tblEvidence));
|
||||||
"SELECT"
|
auto query = executeQuery(_db, qStr, {evidenceID});
|
||||||
" id, path, operation_slug, content_type, description, error, recorded_date, upload_date"
|
if (_db.lastError().type() == QSqlError::NoError && query.first()) {
|
||||||
" FROM evidence"
|
|
||||||
" WHERE id=? LIMIT 1",
|
|
||||||
{evidenceID});
|
|
||||||
|
|
||||||
if (query.first()) {
|
|
||||||
rtn.id = query.value(QStringLiteral("id")).toLongLong();
|
rtn.id = query.value(QStringLiteral("id")).toLongLong();
|
||||||
rtn.path = query.value(QStringLiteral("path")).toString();
|
rtn.path = query.value(QStringLiteral("path")).toString();
|
||||||
rtn.operationSlug = query.value(QStringLiteral("operation_slug")).toString();
|
rtn.operationSlug = query.value(QStringLiteral("operation_slug")).toString();
|
||||||
|
@ -109,43 +87,39 @@ model::Evidence DatabaseConnection::getEvidenceDetails(qint64 evidenceID) {
|
||||||
rtn.errorText = query.value(QStringLiteral("error")).toString();
|
rtn.errorText = query.value(QStringLiteral("error")).toString();
|
||||||
rtn.recordedDate = query.value(QStringLiteral("recorded_date")).toDateTime();
|
rtn.recordedDate = query.value(QStringLiteral("recorded_date")).toDateTime();
|
||||||
rtn.uploadDate = query.value(QStringLiteral("upload_date")).toDateTime();
|
rtn.uploadDate = query.value(QStringLiteral("upload_date")).toDateTime();
|
||||||
|
|
||||||
rtn.recordedDate.setTimeSpec(Qt::UTC);
|
rtn.recordedDate.setTimeSpec(Qt::UTC);
|
||||||
rtn.uploadDate.setTimeSpec(Qt::UTC);
|
rtn.uploadDate.setTimeSpec(Qt::UTC);
|
||||||
|
|
||||||
rtn.tags = getTagsForEvidenceID(evidenceID);
|
rtn.tags = getTagsForEvidenceID(evidenceID);
|
||||||
}
|
} else {
|
||||||
else {
|
rtn.id = -1;
|
||||||
qWarning() << "Could not find evidence with id: " << evidenceID;
|
|
||||||
}
|
}
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::updateEvidenceDescription(const QString &newDescription,
|
bool DatabaseConnection::updateEvidenceDescription(const QString &newDescription, qint64 evidenceID)
|
||||||
qint64 evidenceID) {
|
{
|
||||||
executeQuery(getDB(), "UPDATE evidence SET description=? WHERE id=?", {newDescription, evidenceID});
|
auto q = executeQuery(_db, QStringLiteral("UPDATE evidence SET description=? WHERE id=?"), {newDescription, evidenceID});
|
||||||
|
return (q.lastError().type() == QSqlError::NoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseConnection::deleteEvidence(qint64 evidenceID)
|
bool DatabaseConnection::deleteEvidence(qint64 evidenceID)
|
||||||
{
|
{
|
||||||
auto q = executeQuery(getDB(), "DELETE FROM evidence WHERE id=?", {evidenceID});
|
auto q = executeQuery(_db, QStringLiteral("DELETE FROM evidence WHERE id=?"), {evidenceID});
|
||||||
if (q.lastError().type() == QSqlError::NoError)
|
return (q.lastError().type() == QSqlError::NoError);
|
||||||
return true;
|
|
||||||
qWarning() << "Unable to Delete " << evidenceID << " " << q.lastError().text();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::updateEvidenceError(const QString &errorText, qint64 evidenceID) {
|
bool DatabaseConnection::updateEvidenceError(const QString &errorText, qint64 evidenceID) {
|
||||||
executeQuery(getDB(), "UPDATE evidence SET error=? WHERE id=?", {errorText, evidenceID});
|
auto q = executeQuery(_db, QStringLiteral("UPDATE evidence SET error=? WHERE id=?"), {errorText, evidenceID});
|
||||||
|
return (q.lastError().type() == QSqlError::NoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::updateEvidenceSubmitted(qint64 evidenceID) {
|
void DatabaseConnection::updateEvidenceSubmitted(qint64 evidenceID) {
|
||||||
executeQuery(getDB(), "UPDATE evidence SET upload_date=datetime('now') WHERE id=?", {evidenceID});
|
executeQuery(_db, QStringLiteral("UPDATE evidence SET upload_date=datetime('now') WHERE id=?"), {evidenceID});
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<model::Tag> DatabaseConnection::getTagsForEvidenceID(qint64 evidenceID) {
|
QList<model::Tag> DatabaseConnection::getTagsForEvidenceID(qint64 evidenceID) {
|
||||||
QList<model::Tag> tags;
|
QList<model::Tag> tags;
|
||||||
auto getTagQuery = executeQuery(getDB(), "SELECT id, tag_id, name FROM tags WHERE evidence_id=?",
|
auto getTagQuery = executeQuery(_db, QStringLiteral("SELECT id, tag_id, name FROM tags WHERE evidence_id=?"),
|
||||||
{evidenceID});
|
{evidenceID});
|
||||||
while (getTagQuery.next()) {
|
while (getTagQuery.next()) {
|
||||||
auto tag = model::Tag(getTagQuery.value(QStringLiteral("id")).toLongLong(),
|
auto tag = model::Tag(getTagQuery.value(QStringLiteral("id")).toLongLong(),
|
||||||
|
@ -160,7 +134,7 @@ QList<model::Tag> DatabaseConnection::getFullTagsForEvidenceIDs(
|
||||||
const QList<qint64>& evidenceIDs) {
|
const QList<qint64>& evidenceIDs) {
|
||||||
QList<model::Tag> tags;
|
QList<model::Tag> tags;
|
||||||
|
|
||||||
batchQuery("SELECT id, evidence_id, tag_id, name FROM tags WHERE evidence_id IN (%1)", 1, evidenceIDs.size(),
|
batchQuery(QStringLiteral("SELECT id, evidence_id, tag_id, name FROM tags WHERE evidence_id IN (%1)"), 1, evidenceIDs.size(),
|
||||||
[evidenceIDs](unsigned int index){
|
[evidenceIDs](unsigned int index){
|
||||||
return QVariantList{evidenceIDs[index]};
|
return QVariantList{evidenceIDs[index]};
|
||||||
},
|
},
|
||||||
|
@ -175,33 +149,37 @@ QList<model::Tag> DatabaseConnection::getFullTagsForEvidenceIDs(
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::setEvidenceTags(const QList<model::Tag> &newTags, qint64 evidenceID)
|
bool DatabaseConnection::setEvidenceTags(const QList<model::Tag> &newTags, qint64 evidenceID)
|
||||||
{
|
{
|
||||||
// todo: this this actually work?
|
|
||||||
if(newTags.isEmpty())
|
if(newTags.isEmpty())
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
auto db = getDB();
|
|
||||||
QVariantList newTagIds;
|
QVariantList newTagIds;
|
||||||
for (const auto &tag : newTags) {
|
for (const auto &tag : newTags)
|
||||||
newTagIds.append(tag.serverTagId);
|
newTagIds.append(tag.serverTagId);
|
||||||
}
|
|
||||||
executeQuery(db, "DELETE FROM tags WHERE tag_id NOT IN (?) AND evidence_id = ?",
|
|
||||||
{newTagIds, evidenceID});
|
|
||||||
|
|
||||||
auto currentTagsResult =
|
auto qDelStr = QStringLiteral("DELETE FROM tags WHERE tag_id NOT IN (?) AND evidence_id = ?");
|
||||||
executeQuery(db, "SELECT tag_id FROM tags WHERE evidence_id = ?", {evidenceID});
|
auto a = executeQuery(_db, qDelStr, {newTagIds, evidenceID});
|
||||||
|
if(a.lastError().type() != QSqlError::NoError)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto qSelStr = QStringLiteral("SELECT tag_id FROM tags WHERE evidence_id = ?");
|
||||||
|
auto currentTagsResult = executeQuery(_db, qSelStr, {evidenceID});
|
||||||
|
if (currentTagsResult.lastError().type() != QSqlError::NoError)
|
||||||
|
return false;
|
||||||
|
|
||||||
QList<qint64> currentTags;
|
QList<qint64> currentTags;
|
||||||
while (currentTagsResult.next()) {
|
while (currentTagsResult.next())
|
||||||
currentTags.append(currentTagsResult.value(QStringLiteral("tag_id")).toLongLong());
|
currentTags.append(currentTagsResult.value(QStringLiteral("tag_id")).toLongLong());
|
||||||
}
|
|
||||||
struct dataset {
|
struct dataset {
|
||||||
qint64 evidenceID = 0;
|
qint64 evidenceID = 0;
|
||||||
qint64 tagID = 0;
|
qint64 tagID = 0;
|
||||||
QString name;
|
QString name;
|
||||||
};
|
};
|
||||||
QList<dataset> tagDataToInsert;
|
QList<dataset> tagDataToInsert;
|
||||||
QString baseQuery = "INSERT INTO tags (evidence_id, tag_id, name) VALUES ";
|
|
||||||
|
QString baseQuery = QStringLiteral("INSERT INTO tags (evidence_id, tag_id, name) VALUES ");
|
||||||
for (const auto &newTag : newTags) {
|
for (const auto &newTag : newTags) {
|
||||||
if (currentTags.count(newTag.serverTagId) == 0) {
|
if (currentTags.count(newTag.serverTagId) == 0) {
|
||||||
dataset item;
|
dataset item;
|
||||||
|
@ -216,19 +194,23 @@ void DatabaseConnection::setEvidenceTags(const QList<model::Tag> &newTags, qint6
|
||||||
// sqlite indicates it's default is 100 passed parameter, but it can "handle thousands"
|
// sqlite indicates it's default is 100 passed parameter, but it can "handle thousands"
|
||||||
if (!tagDataToInsert.empty()) {
|
if (!tagDataToInsert.empty()) {
|
||||||
QVariantList args;
|
QVariantList args;
|
||||||
baseQuery += "(?,?,?)";
|
baseQuery.append(QStringLiteral("(?, ?, ?"));
|
||||||
baseQuery += QString(", (?,?,?)").repeated(int(tagDataToInsert.size() - 1));
|
baseQuery.append(QString(", (?,?,?)").repeated(int(tagDataToInsert.size() - 1)));
|
||||||
|
baseQuery.append(QStringLiteral(")"));
|
||||||
for (const auto &item : tagDataToInsert) {
|
for (const auto &item : tagDataToInsert) {
|
||||||
args.append(item.evidenceID);
|
args.append(item.evidenceID);
|
||||||
args.append(item.tagID);
|
args.append(item.tagID);
|
||||||
args.append(item.name);
|
args.append(item.name);
|
||||||
}
|
}
|
||||||
executeQuery(db, baseQuery, args);
|
auto q = executeQuery(_db, baseQuery, args);
|
||||||
|
if (q.lastError().type() != QSqlError::NoError)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::batchCopyTags(const QList<model::Tag> &allTags) {
|
void DatabaseConnection::batchCopyTags(const QList<model::Tag> &allTags) {
|
||||||
QString baseQuery = "INSERT INTO tags (id, evidence_id, tag_id, name) VALUES %1";
|
QString baseQuery = QStringLiteral("INSERT INTO tags (id, evidence_id, tag_id, name) VALUES %1");
|
||||||
int varsPerRow = 4;
|
int varsPerRow = 4;
|
||||||
std::function<QVariantList(int)> getItemValues = [allTags](int i){
|
std::function<QVariantList(int)> getItemValues = [allTags](int i){
|
||||||
model::Tag item = allTags.at(i);
|
model::Tag item = allTags.at(i);
|
||||||
|
@ -237,23 +219,26 @@ void DatabaseConnection::batchCopyTags(const QList<model::Tag> &allTags) {
|
||||||
batchInsert(baseQuery, varsPerRow, allTags.size(), getItemValues);
|
batchInsert(baseQuery, varsPerRow, allTags.size(), getItemValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBQuery DatabaseConnection::buildGetEvidenceWithFiltersQuery(const EvidenceFilters &filters) {
|
DBQuery DatabaseConnection::buildGetEvidenceWithFiltersQuery(const EvidenceFilters &filters)
|
||||||
QString query =
|
{
|
||||||
"SELECT"
|
QString query = _sqlSelectTemplate.arg(_evidenceAllKeys, _tblEvidence);
|
||||||
" id, path, operation_slug, content_type, description, error, recorded_date, upload_date"
|
|
||||||
" FROM evidence";
|
|
||||||
QVariantList values;
|
QVariantList values;
|
||||||
QStringList parts;
|
QStringList parts;
|
||||||
|
|
||||||
if (filters.hasError != Tri::Any) {
|
if (filters.hasError != Tri::Any) {
|
||||||
parts.append(" error LIKE ? ");
|
parts.append(QStringLiteral(" error LIKE ? "));
|
||||||
// _% will ensure at least one character exists in the error column, ensuring it's populated
|
// _% will ensure at least one character exists in the error column, ensuring it's populated
|
||||||
values.append(filters.hasError == Tri::Yes ? "_%" : "");
|
values.append(filters.hasError == Tri::Yes ? QStringLiteral("_%") : QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.submitted != Tri::Any) {
|
if (filters.submitted != Tri::Any) {
|
||||||
parts.append((filters.submitted == Tri::Yes) ? " upload_date IS NOT NULL "
|
auto sub = QStringLiteral(" upload_data IS%1NULL");
|
||||||
: " upload_date IS NULL ");
|
if(filters.submitted == Tri::Yes)
|
||||||
|
parts.append(sub.arg(QStringLiteral(" NOT ")));
|
||||||
|
else
|
||||||
|
parts.append(sub.arg(QStringLiteral(" ")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filters.operationSlug.isEmpty()) {
|
if (!filters.operationSlug.isEmpty()) {
|
||||||
parts.append(" operation_slug = ? ");
|
parts.append(" operation_slug = ? ");
|
||||||
values.append(filters.operationSlug);
|
values.append(filters.operationSlug);
|
||||||
|
@ -273,194 +258,156 @@ DBQuery DatabaseConnection::buildGetEvidenceWithFiltersQuery(const EvidenceFilte
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parts.empty()) {
|
if (!parts.empty()) {
|
||||||
query += " WHERE " + parts.at(0);
|
query.append(QStringLiteral(" WHERE %1").arg(parts.at(0)));
|
||||||
for (size_t i = 1; i < parts.size(); i++) {
|
for (size_t i = 1; i < parts.size(); i++)
|
||||||
query += " AND " + parts.at(i);
|
query.append(QStringLiteral(" AND %1").arg(parts.at(i)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return DBQuery(query, values);
|
return DBQuery(query, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::updateEvidencePath(const QString& newPath, qint64 evidenceID) {
|
void DatabaseConnection::updateEvidencePath(const QString& newPath, qint64 evidenceID)
|
||||||
executeQuery(getDB(), "UPDATE evidence SET path=? WHERE id=?", {newPath, evidenceID});
|
{
|
||||||
|
executeQuery(_db, QStringLiteral("UPDATE evidence SET path=? WHERE id=?"), {newPath, evidenceID});
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<model::Evidence> DatabaseConnection::getEvidenceWithFilters(
|
QList<model::Evidence> DatabaseConnection::getEvidenceWithFilters(const EvidenceFilters &filters)
|
||||||
const EvidenceFilters &filters) {
|
{
|
||||||
auto dbQuery = buildGetEvidenceWithFiltersQuery(filters);
|
auto dbQuery = buildGetEvidenceWithFiltersQuery(filters);
|
||||||
auto resultSet = executeQuery(getDB(), dbQuery.query(), dbQuery.values());
|
auto resultSet = executeQuery(_db, dbQuery.query(), dbQuery.values());
|
||||||
|
QList<model::Evidence> allEvidence;
|
||||||
|
|
||||||
QList<model::Evidence> allEvidence;
|
while (resultSet.next()) {
|
||||||
while (resultSet.next()) {
|
model::Evidence evi;
|
||||||
model::Evidence evi;
|
evi.id = resultSet.value(QStringLiteral("id")).toLongLong();
|
||||||
evi.id = resultSet.value(QStringLiteral("id")).toLongLong();
|
evi.path = resultSet.value(QStringLiteral("path")).toString();
|
||||||
evi.path = resultSet.value(QStringLiteral("path")).toString();
|
evi.operationSlug = resultSet.value(QStringLiteral("operation_slug")).toString();
|
||||||
evi.operationSlug = resultSet.value(QStringLiteral("operation_slug")).toString();
|
evi.contentType = resultSet.value(QStringLiteral("content_type")).toString();
|
||||||
evi.contentType = resultSet.value(QStringLiteral("content_type")).toString();
|
evi.description = resultSet.value(QStringLiteral("description")).toString();
|
||||||
evi.description = resultSet.value(QStringLiteral("description")).toString();
|
evi.errorText = resultSet.value(QStringLiteral("error")).toString();
|
||||||
evi.errorText = resultSet.value(QStringLiteral("error")).toString();
|
evi.recordedDate = resultSet.value(QStringLiteral("recorded_date")).toDateTime();
|
||||||
evi.recordedDate = resultSet.value(QStringLiteral("recorded_date")).toDateTime();
|
evi.uploadDate = resultSet.value(QStringLiteral("upload_date")).toDateTime();
|
||||||
evi.uploadDate = resultSet.value(QStringLiteral("upload_date")).toDateTime();
|
evi.recordedDate.setTimeSpec(Qt::UTC);
|
||||||
|
evi.uploadDate.setTimeSpec(Qt::UTC);
|
||||||
|
allEvidence.append(evi);
|
||||||
|
}
|
||||||
|
|
||||||
evi.recordedDate.setTimeSpec(Qt::UTC);
|
return allEvidence;
|
||||||
evi.uploadDate.setTimeSpec(Qt::UTC);
|
|
||||||
|
|
||||||
allEvidence.append(evi);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allEvidence;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<model::Evidence> DatabaseConnection::createEvidenceExportView(
|
QList<model::Evidence> DatabaseConnection::createEvidenceExportView(
|
||||||
const QString& pathToExport, const EvidenceFilters& filters, DatabaseConnection *runningDB) {
|
const QString& pathToExport, const EvidenceFilters& filters, DatabaseConnection *runningDB)
|
||||||
QList<model::Evidence> exportEvidence;
|
|
||||||
|
|
||||||
auto exportViewAction = [runningDB, filters, &exportEvidence](DatabaseConnection exportDB) {
|
|
||||||
exportEvidence = runningDB->getEvidenceWithFilters(filters);
|
|
||||||
|
|
||||||
exportDB.batchCopyFullEvidence(exportEvidence);
|
|
||||||
QList<qint64> evidenceIds;
|
|
||||||
evidenceIds.resize(exportEvidence.size());
|
|
||||||
std::transform(exportEvidence.begin(), exportEvidence.end(), evidenceIds.begin(),
|
|
||||||
[](const model::Evidence& e) { return e.id; });
|
|
||||||
QList<model::Tag> tags = runningDB->getFullTagsForEvidenceIDs(evidenceIds);
|
|
||||||
exportDB.batchCopyTags(tags);
|
|
||||||
};
|
|
||||||
|
|
||||||
withConnection(pathToExport, QStringLiteral("exportDB"), exportViewAction);
|
|
||||||
|
|
||||||
return exportEvidence;
|
|
||||||
}
|
|
||||||
|
|
||||||
// migrateDB checks the migration status and then performs the full migration for any
|
|
||||||
// lacking update.
|
|
||||||
//
|
|
||||||
// Throws exceptions/FileError if a migration file cannot be found.
|
|
||||||
bool DatabaseConnection::migrateDB() {
|
|
||||||
auto db = getDB();
|
|
||||||
qInfo() << "Checking database state";
|
|
||||||
auto migrationsToApply = DatabaseConnection::getUnappliedMigrations(db);
|
|
||||||
|
|
||||||
for (const QString &newMigration : migrationsToApply) {
|
|
||||||
QFile migrationFile(QStringLiteral(":/migrations/%1").arg(newMigration));
|
|
||||||
auto ok = migrationFile.open(QFile::ReadOnly);
|
|
||||||
if (!ok)
|
|
||||||
return false;
|
|
||||||
auto content = QString(migrationFile.readAll());
|
|
||||||
migrationFile.close();
|
|
||||||
|
|
||||||
qInfo() << "Applying Migration: " << newMigration;
|
|
||||||
auto upScript = extractMigrateUpContent(content);
|
|
||||||
executeQuery(db, upScript);
|
|
||||||
executeQuery(db,
|
|
||||||
"INSERT INTO migrations (migration_name, applied_at) VALUES (?, datetime('now'))",
|
|
||||||
{newMigration});
|
|
||||||
}
|
|
||||||
qInfo() << "All migrations applied";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// getUnappliedMigrations retrieves a list of all of the migrations that have not been applied
|
|
||||||
// to the local database.
|
|
||||||
//
|
|
||||||
// Note: All sql files must end in ".sql" to be picked up
|
|
||||||
//
|
|
||||||
// Throws:
|
|
||||||
// * BadDatabaseStateError if some migrations have been applied that are not known
|
|
||||||
// * QSqlError if database queries fail
|
|
||||||
QStringList DatabaseConnection::getUnappliedMigrations(const QSqlDatabase &db)
|
|
||||||
{
|
{
|
||||||
QDir migrationsDir(QStringLiteral(":/migrations"));
|
QList<model::Evidence> exportEvidence;
|
||||||
const auto allMigrations = migrationsDir.entryList(QDir::Files, QDir::Name);
|
auto exportViewAction = [runningDB, filters, &exportEvidence](DatabaseConnection exportDB) {
|
||||||
QStringList appliedMigrations;
|
exportEvidence = runningDB->getEvidenceWithFilters(filters);
|
||||||
QStringList migrationsToApply;
|
exportDB.batchCopyFullEvidence(exportEvidence);
|
||||||
|
QList<qint64> evidenceIds;
|
||||||
|
evidenceIds.resize(exportEvidence.size());
|
||||||
|
std::transform(exportEvidence.begin(), exportEvidence.end(), evidenceIds.begin(),
|
||||||
|
[](const model::Evidence& e) { return e.id; });
|
||||||
|
QList<model::Tag> tags = runningDB->getFullTagsForEvidenceIDs(evidenceIds);
|
||||||
|
exportDB.batchCopyTags(tags);
|
||||||
|
};
|
||||||
|
withConnection(pathToExport, QStringLiteral("exportDB"), exportViewAction);
|
||||||
|
return exportEvidence;
|
||||||
|
}
|
||||||
|
|
||||||
auto queryResult = executeQueryNoThrow(db, "SELECT migration_name FROM migrations");
|
bool DatabaseConnection::migrateDB()
|
||||||
QSqlQuery* dbMigrations = &queryResult.query;
|
{
|
||||||
while (queryResult.success && queryResult.query.next()) {
|
qInfo() << "Checking database state";
|
||||||
appliedMigrations << dbMigrations->value(QStringLiteral("migration_name")).toString();
|
auto migrationsToApply = DatabaseConnection::getUnappliedMigrations();
|
||||||
}
|
|
||||||
// compare the two list to find gaps
|
|
||||||
for (const QString &possibleMigration : allMigrations) {
|
|
||||||
if (!possibleMigration.endsWith(QStringLiteral(".sql")))
|
|
||||||
continue; // assume non-sql files aren't actual migrations.
|
|
||||||
|
|
||||||
auto foundIndex = appliedMigrations.indexOf(possibleMigration);
|
for (const auto &newMigration : migrationsToApply) {
|
||||||
if (foundIndex == -1)
|
QFile migrationFile(QStringLiteral("%1/%2").arg(_migrationPath, newMigration));
|
||||||
migrationsToApply << possibleMigration;
|
if (!migrationFile.open(QFile::ReadOnly))
|
||||||
else
|
return false;
|
||||||
appliedMigrations.removeAt(foundIndex);
|
auto content = QString(migrationFile.readAll());
|
||||||
}
|
migrationFile.close();
|
||||||
if (!appliedMigrations.empty()) {
|
qInfo() << "Applying Migration: " << newMigration;
|
||||||
qWarning() << "Database is in an inconsistent state";
|
auto upScript = extractMigrateUpContent(content);
|
||||||
}
|
executeQuery(_db, upScript);
|
||||||
return migrationsToApply;
|
executeQuery(_db, _sqlAddAppliedMigration, {newMigration});
|
||||||
|
}
|
||||||
|
|
||||||
|
qInfo() << "All migrations applied";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList DatabaseConnection::getUnappliedMigrations()
|
||||||
|
{
|
||||||
|
QDir migrationsDir(_migrationPath);
|
||||||
|
const auto allMigrations = migrationsDir.entryList(QDir::Files, QDir::Name);
|
||||||
|
QStringList appliedMigrations;
|
||||||
|
QStringList migrationsToApply;
|
||||||
|
|
||||||
|
auto queryResult = executeQueryNoThrow(_db, _sqlSelectTemplate.arg(_migration_name, _tblMigrations));
|
||||||
|
QSqlQuery* dbMigrations = &queryResult.query;
|
||||||
|
while (queryResult.success && queryResult.query.next())
|
||||||
|
appliedMigrations << dbMigrations->value(_migration_name).toString();
|
||||||
|
// compare the two list to find gaps
|
||||||
|
for (const auto &possibleMigration : allMigrations) {
|
||||||
|
if (!possibleMigration.endsWith(QStringLiteral(".sql")))
|
||||||
|
continue;
|
||||||
|
auto foundIndex = appliedMigrations.indexOf(possibleMigration);
|
||||||
|
if (foundIndex == -1)
|
||||||
|
migrationsToApply << possibleMigration;
|
||||||
|
else
|
||||||
|
appliedMigrations.removeAt(foundIndex);
|
||||||
|
}
|
||||||
|
if (!appliedMigrations.empty()) {
|
||||||
|
qWarning() << "Database is in an inconsistent state";
|
||||||
|
}
|
||||||
|
return migrationsToApply;
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractMigrateUpContent parses the given migration content and retrieves only
|
// extractMigrateUpContent parses the given migration content and retrieves only
|
||||||
// the portion that applies to the "up" / apply logic. The "down" section is ignored.
|
// the portion that applies to the "up" / apply logic. The "down" section is ignored.
|
||||||
QString DatabaseConnection::extractMigrateUpContent(const QString &allContent) noexcept {
|
QString DatabaseConnection::extractMigrateUpContent(const QString &allContent) noexcept
|
||||||
QString upContent;
|
{
|
||||||
const QStringList lines = allContent.split(_newLine);
|
QString upContent;
|
||||||
for (const QString &line : lines) {
|
const QStringList lines = allContent.split(_newLine);
|
||||||
auto lowerLine = line.trimmed().toLower();
|
for (const QString &line : lines) {
|
||||||
if (lowerLine == _migrateUp)
|
auto lowerLine = line.trimmed().toLower();
|
||||||
continue;
|
if (lowerLine == _migrateUp)
|
||||||
else if (lowerLine == _migrateDown)
|
continue;
|
||||||
break;
|
else if (lowerLine == _migrateDown)
|
||||||
upContent.append(_lineTemplate.arg(line));
|
break;
|
||||||
}
|
upContent.append(_lineTemplate.arg(line));
|
||||||
return upContent;
|
}
|
||||||
|
return upContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeQuery simply attempts to execute the given stmt with the passed args. The statement is
|
// executeQuery simply attempts to execute the given stmt with the passed args. The statement is
|
||||||
// first prepared, and arg placements can be specified with "?"
|
// first prepared, and arg placements can be specified with "?"
|
||||||
//
|
|
||||||
// Throws: QSqlError when a query error occurs
|
|
||||||
QSqlQuery DatabaseConnection::executeQuery(const QSqlDatabase& db, const QString &stmt,
|
QSqlQuery DatabaseConnection::executeQuery(const QSqlDatabase& db, const QString &stmt,
|
||||||
const QVariantList &args) {
|
const QVariantList &args) {
|
||||||
auto result = executeQueryNoThrow(db, stmt, args);
|
auto result = executeQueryNoThrow(db, stmt, args);
|
||||||
if (!result.success) {
|
if (!result.success)
|
||||||
throw result.err;
|
qWarning() << "Error executing Query: " << result.err.text();
|
||||||
}
|
|
||||||
return std::move(result.query);
|
return std::move(result.query);
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryResult DatabaseConnection::executeQueryNoThrow(const QSqlDatabase& db, const QString &stmt,
|
QueryResult DatabaseConnection::executeQueryNoThrow(const QSqlDatabase& db, const QString &stmt,
|
||||||
const QVariantList &args) noexcept {
|
const QVariantList &args) noexcept
|
||||||
QSqlQuery query(db);
|
{
|
||||||
|
QSqlQuery query(db);
|
||||||
bool prepared = query.prepare(stmt);
|
if (!query.prepare(stmt))
|
||||||
if (!prepared) {
|
return QueryResult(std::move(query));
|
||||||
|
for (const auto &arg : args)
|
||||||
|
query.addBindValue(arg);
|
||||||
|
query.exec();
|
||||||
return QueryResult(std::move(query));
|
return QueryResult(std::move(query));
|
||||||
}
|
|
||||||
for (const auto &arg : args) {
|
|
||||||
query.addBindValue(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
query.exec();
|
|
||||||
return QueryResult(std::move(query));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// doInsert is a version of executeQuery that returns the last inserted id, rather than the
|
// doInsert is a version of executeQuery that returns the last inserted id, rather than the
|
||||||
// underlying query/response
|
// underlying query/response
|
||||||
//
|
// Logs then returns -1
|
||||||
// Throws: QSqlError when a query error occurs
|
qint64 DatabaseConnection::doInsert(const QSqlDatabase& db, const QString &stmt, const QVariantList &args)
|
||||||
qint64 DatabaseConnection::doInsert(const QSqlDatabase& db, const QString &stmt,
|
{
|
||||||
const QVariantList &args) {
|
|
||||||
auto query = executeQuery(db, stmt, args);
|
auto query = executeQuery(db, stmt, args);
|
||||||
|
if(query.lastInsertId() != QVariant())
|
||||||
return query.lastInsertId().toLongLong();
|
return query.lastInsertId().toLongLong();
|
||||||
}
|
return -1;
|
||||||
|
|
||||||
QSqlDatabase DatabaseConnection::getDB()
|
|
||||||
{
|
|
||||||
return QSqlDatabase::database(_dbName);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString DatabaseConnection::getDatabasePath()
|
|
||||||
{
|
|
||||||
return _dbPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseConnection::batchInsert(const QString& baseQuery, unsigned int varsPerRow, unsigned int numRows,
|
void DatabaseConnection::batchInsert(const QString& baseQuery, unsigned int varsPerRow, unsigned int numRows,
|
||||||
|
@ -484,7 +431,6 @@ void DatabaseConnection::batchQuery(const QString &baseQuery, unsigned int varsP
|
||||||
variableTemplate = QString("?,").repeated(int(varsPerRow));
|
variableTemplate = QString("?,").repeated(int(varsPerRow));
|
||||||
}
|
}
|
||||||
int runningRowIndex = 0; // tracks what row is next to be encoded/"inserted"
|
int runningRowIndex = 0; // tracks what row is next to be encoded/"inserted"
|
||||||
auto db = getDB();
|
|
||||||
/// prepArgString generates a string that looks like ?,?,?, with as many ? as rowInsertTemplate * numRows
|
/// prepArgString generates a string that looks like ?,?,?, with as many ? as rowInsertTemplate * numRows
|
||||||
auto prepArgString = [variableTemplate](unsigned int numRows){
|
auto prepArgString = [variableTemplate](unsigned int numRows){
|
||||||
auto inst = variableTemplate.repeated(int(numRows));
|
auto inst = variableTemplate.repeated(int(numRows));
|
||||||
|
@ -501,8 +447,8 @@ void DatabaseConnection::batchQuery(const QString &baseQuery, unsigned int varsP
|
||||||
return values;
|
return values;
|
||||||
};
|
};
|
||||||
/// runQuery executes the given query, and iterates over the result set
|
/// runQuery executes the given query, and iterates over the result set
|
||||||
auto runQuery = [db, decodeRows](const QString &query, const QVariantList& values) {
|
auto runQuery = [this, decodeRows](const QString &query, const QVariantList& values) {
|
||||||
auto completedQuery = executeQuery(db, query, values);
|
auto completedQuery = executeQuery(_db, query, values);
|
||||||
while (completedQuery.next()) {
|
while (completedQuery.next()) {
|
||||||
decodeRows(completedQuery);
|
decodeRows(completedQuery);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,15 @@ class DBQuery {
|
||||||
inline QString query() { return _query; }
|
inline QString query() { return _query; }
|
||||||
inline QVariantList values() { return _values; }
|
inline QVariantList values() { return _values; }
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @brief The DatabaseConnection class Interface to the local database
|
||||||
|
* All Changes / reads to db should return true on success
|
||||||
|
* any failed actions can have erorrs checked with DatabaseConnection::errorString()
|
||||||
|
*/
|
||||||
class DatabaseConnection {
|
class DatabaseConnection {
|
||||||
public:
|
public:
|
||||||
|
const unsigned long SQLITE_MAX_VARS = 999;
|
||||||
|
QString getDatabasePath() { return _dbPath; }
|
||||||
/**
|
/**
|
||||||
* @brief DatabaseConnection construct a connect to the database,
|
* @brief DatabaseConnection construct a connect to the database,
|
||||||
* Uses QSQLite Driver if the driver is missing the app to exit with code 255.
|
* Uses QSQLite Driver if the driver is missing the app to exit with code 255.
|
||||||
|
@ -48,29 +54,39 @@ class DatabaseConnection {
|
||||||
* Specifically, it should NOT be the value from Constants::databaseName)
|
* Specifically, it should NOT be the value from Constants::databaseName)
|
||||||
* @param actions A function that will execute after a connection is established. This is where
|
* @param actions A function that will execute after a connection is established. This is where
|
||||||
* all db interactions should occur.
|
* all db interactions should occur.
|
||||||
|
* Returns True is successful
|
||||||
*/
|
*/
|
||||||
static void withConnection(const QString& dbPath, const QString &dbName,
|
static bool withConnection(const QString& dbPath, const QString &dbName,
|
||||||
const std::function<void(DatabaseConnection)> &actions);
|
const std::function<void(DatabaseConnection)> &actions);
|
||||||
|
|
||||||
|
///Return the last Error
|
||||||
|
QString errorString() {return _db.lastError().text();}
|
||||||
bool connect();
|
bool connect();
|
||||||
void close() noexcept;
|
void close() noexcept {_db.close();}
|
||||||
|
|
||||||
static DBQuery buildGetEvidenceWithFiltersQuery(const EvidenceFilters &filters);
|
static DBQuery buildGetEvidenceWithFiltersQuery(const EvidenceFilters &filters);
|
||||||
|
|
||||||
model::Evidence getEvidenceDetails(qint64 evidenceID);
|
model::Evidence getEvidenceDetails(qint64 evidenceID);
|
||||||
QList<model::Evidence> getEvidenceWithFilters(const EvidenceFilters &filters);
|
QList<model::Evidence> getEvidenceWithFilters(const EvidenceFilters &filters);
|
||||||
|
|
||||||
|
/// Return -1 if Failed
|
||||||
qint64 createEvidence(const QString &filepath, const QString &operationSlug,
|
qint64 createEvidence(const QString &filepath, const QString &operationSlug,
|
||||||
const QString &contentType);
|
const QString &contentType);
|
||||||
qint64 createFullEvidence(const model::Evidence &evidence);
|
qint64 createFullEvidence(const model::Evidence &evidence);
|
||||||
void batchCopyFullEvidence(const QList<model::Evidence> &evidence);
|
void batchCopyFullEvidence(const QList<model::Evidence> &evidence);
|
||||||
qint64 copyFullEvidence(const model::Evidence &evidence);
|
qint64 copyFullEvidence(const model::Evidence &evidence);
|
||||||
|
|
||||||
void updateEvidenceDescription(const QString &newDescription, qint64 evidenceID);
|
/**
|
||||||
void updateEvidenceError(const QString &errorText, qint64 evidenceID);
|
* @brief updateEvidenceDescription
|
||||||
|
* @param newDescription
|
||||||
|
* @param evidenceID
|
||||||
|
* @return True if successful
|
||||||
|
*/
|
||||||
|
bool updateEvidenceDescription(const QString &newDescription, qint64 evidenceID);
|
||||||
|
bool updateEvidenceError(const QString &errorText, qint64 evidenceID);
|
||||||
void updateEvidenceSubmitted(qint64 evidenceID);
|
void updateEvidenceSubmitted(qint64 evidenceID);
|
||||||
void updateEvidencePath(const QString& newPath, qint64 evidenceID);
|
void updateEvidencePath(const QString& newPath, qint64 evidenceID);
|
||||||
void setEvidenceTags(const QList<model::Tag> &newTags, qint64 evidenceID);
|
bool setEvidenceTags(const QList<model::Tag> &newTags, qint64 evidenceID);
|
||||||
void batchCopyTags(const QList<model::Tag> &allTags);
|
void batchCopyTags(const QList<model::Tag> &allTags);
|
||||||
QList<model::Tag> getFullTagsForEvidenceIDs(const QList<qint64>& evidenceIDs);
|
QList<model::Tag> getFullTagsForEvidenceIDs(const QList<qint64>& evidenceIDs);
|
||||||
|
|
||||||
|
@ -91,25 +107,38 @@ class DatabaseConnection {
|
||||||
DatabaseConnection *runningDB);
|
DatabaseConnection *runningDB);
|
||||||
QList<model::Tag> getTagsForEvidenceID(qint64 evidenceID);
|
QList<model::Tag> getTagsForEvidenceID(qint64 evidenceID);
|
||||||
|
|
||||||
/// getDatabasePath returns the filepath associated with the loaded database
|
QSqlError lastError() {return _db.lastError();}
|
||||||
QString getDatabasePath();
|
|
||||||
|
|
||||||
public:
|
|
||||||
const unsigned long SQLITE_MAX_VARS = 999;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _dbName;
|
QString _dbName;
|
||||||
QString _dbPath;
|
QString _dbPath;
|
||||||
|
QSqlDatabase _db = QSqlDatabase();
|
||||||
inline static const auto _migrateUp = QStringLiteral("-- +migrate up");
|
inline static const auto _migrateUp = QStringLiteral("-- +migrate up");
|
||||||
inline static const auto _migrateDown = QStringLiteral("-- +migrate down");
|
inline static const auto _migrateDown = QStringLiteral("-- +migrate down");
|
||||||
inline static const auto _newLine = QStringLiteral("\n");
|
inline static const auto _newLine = QStringLiteral("\n");
|
||||||
inline static const auto _lineTemplate =QStringLiteral("%1").append(_newLine);
|
inline static const auto _lineTemplate = QStringLiteral("%1").append(_newLine);
|
||||||
|
inline static const auto _migrationPath = QStringLiteral(":/migrations");
|
||||||
|
inline static const auto _sqlSelectTemplate = QStringLiteral("SELECT %1 FROM %2");
|
||||||
|
inline static const auto _sqlBasicInsert = QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)");
|
||||||
|
inline static const auto _sqlAddAppliedMigration = QStringLiteral("INSERT INTO migrations (migration_name, applied_at) VALUES (?, datetime('now'))");
|
||||||
|
inline static const auto _migration_name = QStringLiteral("migration_name");
|
||||||
|
inline static const auto _tblEvidence = QStringLiteral("evidence");
|
||||||
|
inline static const auto _tblMigrations = QStringLiteral("migrations");
|
||||||
|
inline static const auto _evidenceAllKeys = QStringLiteral("id, path, operation_slug, content_type, description, error, recorded_date, upload_date");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief migrateDB - Check migration status and apply any outstanding ones
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
bool migrateDB();
|
bool migrateDB();
|
||||||
QSqlDatabase getDB();
|
|
||||||
|
|
||||||
static QStringList getUnappliedMigrations(const QSqlDatabase &db);
|
/**
|
||||||
static QString extractMigrateUpContent(const QString &allContent) noexcept;
|
* @brief getUnappliedMigrations retrieves a list of all of the migrations that have not been applied to the database db
|
||||||
|
* Note: only files ending in ".sql" are checked
|
||||||
|
* @return List of migrations that have not be applied
|
||||||
|
*/
|
||||||
|
QStringList getUnappliedMigrations();
|
||||||
|
QString extractMigrateUpContent(const QString &allContent) noexcept;
|
||||||
static QSqlQuery executeQuery(const QSqlDatabase& db, const QString &stmt,
|
static QSqlQuery executeQuery(const QSqlDatabase& db, const QString &stmt,
|
||||||
const QVariantList &args = {});
|
const QVariantList &args = {});
|
||||||
|
|
||||||
|
@ -118,6 +147,14 @@ class DatabaseConnection {
|
||||||
/// QueryResult.sucess/QueryResult.err fields to determine the actual result.
|
/// QueryResult.sucess/QueryResult.err fields to determine the actual result.
|
||||||
static QueryResult executeQueryNoThrow(const QSqlDatabase& db, const QString &stmt,
|
static QueryResult executeQueryNoThrow(const QSqlDatabase& db, const QString &stmt,
|
||||||
const QVariantList &args = {}) noexcept;
|
const QVariantList &args = {}) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief doInsert is a version of executeQuery that returns the last inserted id, rather than the underlying query/response
|
||||||
|
* @param db database to act upon
|
||||||
|
* @param stmt sql to run
|
||||||
|
* @param args args
|
||||||
|
* @return Inserted ID or -1 if failed.
|
||||||
|
*/
|
||||||
static qint64 doInsert(const QSqlDatabase &db, const QString &stmt, const QVariantList &args);
|
static qint64 doInsert(const QSqlDatabase &db, const QString &stmt, const QVariantList &args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
add_library (EXCEPTIONS STATIC fileerror.h)
|
|
||||||
|
|
||||||
add_library(ASHIRT::EXCEPTIONS ALIAS EXCEPTIONS)
|
|
||||||
|
|
||||||
target_include_directories (EXCEPTIONS
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries ( EXCEPTIONS PUBLIC Qt::Core)
|
|
|
@ -1,76 +0,0 @@
|
||||||
// Copyright 2020, Verizon Media
|
|
||||||
// Licensed under the terms of MIT. See LICENSE file in project root for terms.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QFileDevice>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class FileError : public std::runtime_error {
|
|
||||||
public:
|
|
||||||
/// mkError constructs an std::runtime_error with the given details.
|
|
||||||
static FileError mkError(QString msg, QString path, QFileDevice::FileError err) {
|
|
||||||
return FileError::mkError(msg.toStdString(), path.toStdString(), err);
|
|
||||||
}
|
|
||||||
/// mkError constructs an std::runtime_error with the given details.
|
|
||||||
static FileError mkError(std::string msg, std::string path, QFileDevice::FileError err) {
|
|
||||||
std::string suberror;
|
|
||||||
switch (err) {
|
|
||||||
case QFileDevice::ReadError:
|
|
||||||
suberror = "Error reading file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::WriteError:
|
|
||||||
suberror = "Error writing file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::FatalError:
|
|
||||||
suberror = "Fatal error occurred";
|
|
||||||
break;
|
|
||||||
case QFileDevice::ResourceError:
|
|
||||||
suberror = "Insufficient resources available";
|
|
||||||
break;
|
|
||||||
case QFileDevice::OpenError:
|
|
||||||
suberror = "Could not open file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::AbortError:
|
|
||||||
suberror = "Operation was aborted";
|
|
||||||
break;
|
|
||||||
case QFileDevice::TimeOutError:
|
|
||||||
suberror = "Operation timed out";
|
|
||||||
break;
|
|
||||||
case QFileDevice::UnspecifiedError:
|
|
||||||
suberror = "Unknown Error";
|
|
||||||
break;
|
|
||||||
case QFileDevice::RemoveError:
|
|
||||||
suberror = "Unable to remove file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::RenameError:
|
|
||||||
suberror = "Unable to rename/move file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::PositionError:
|
|
||||||
suberror = "Position error"; // I don't think we'll ever enounter this error
|
|
||||||
break;
|
|
||||||
case QFileDevice::ResizeError:
|
|
||||||
suberror = "Unable to resize file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::PermissionsError:
|
|
||||||
suberror = "Unable to access file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::CopyError:
|
|
||||||
suberror = "Unable to copy file";
|
|
||||||
break;
|
|
||||||
case QFileDevice::NoError:
|
|
||||||
suberror = "Actually, no error occurred -- just bad programming.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FileError wrappedErr(msg + " (path: " + path + "): " + suberror);
|
|
||||||
wrappedErr.fileDeviceError = err;
|
|
||||||
return wrappedErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
QFileDevice::FileError fileDeviceError;
|
|
||||||
|
|
||||||
private:
|
|
||||||
FileError(std::string msg) : std::runtime_error(msg) {}
|
|
||||||
};
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include "appconfig.h"
|
#include "appconfig.h"
|
||||||
#include "dtos/tag.h"
|
#include "dtos/tag.h"
|
||||||
#include "exceptions/fileerror.h"
|
|
||||||
#include "forms/evidence_filter/evidencefilter.h"
|
#include "forms/evidence_filter/evidencefilter.h"
|
||||||
#include "forms/evidence_filter/evidencefilterform.h"
|
#include "forms/evidence_filter/evidencefilterform.h"
|
||||||
#include "helpers/netman.h"
|
#include "helpers/netman.h"
|
||||||
|
@ -194,23 +193,23 @@ void EvidenceManager::showEvent(QShowEvent* evt) {
|
||||||
resetFilterButtonClicked();
|
resetFilterButtonClicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvidenceManager::submitEvidenceTriggered() {
|
void EvidenceManager::submitEvidenceTriggered()
|
||||||
loadingAnimation->startAnimation();
|
{
|
||||||
evidenceTable->setEnabled(false); // prevent switching evidence while one is being submitted.
|
loadingAnimation->startAnimation();
|
||||||
if (saveData()) {
|
evidenceTable->setEnabled(false); // prevent switching evidence while one is being submitted.
|
||||||
|
if (!saveData())
|
||||||
|
return;
|
||||||
evidenceIDForRequest = selectedRowEvidenceID();
|
evidenceIDForRequest = selectedRowEvidenceID();
|
||||||
try {
|
model::Evidence evi = db->getEvidenceDetails(evidenceIDForRequest);
|
||||||
model::Evidence evi = db->getEvidenceDetails(evidenceIDForRequest);
|
if(evi.id == -1) {
|
||||||
uploadAssetReply = NetMan::uploadAsset(evi);
|
evidenceTable->setEnabled(true);
|
||||||
connect(uploadAssetReply, &QNetworkReply::finished, this, &EvidenceManager::onUploadComplete);
|
loadingAnimation->stopAnimation();
|
||||||
|
QMessageBox::warning(this, tr("Cannot submit evidence"),
|
||||||
|
tr("Could not retrieve data. Please try again."));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (QSqlError& e) {
|
uploadAssetReply = NetMan::uploadAsset(evi);
|
||||||
evidenceTable->setEnabled(true);
|
connect(uploadAssetReply, &QNetworkReply::finished, this, &EvidenceManager::onUploadComplete);
|
||||||
loadingAnimation->stopAnimation();
|
|
||||||
QMessageBox::warning(this, tr("Cannot submit evidence"),
|
|
||||||
tr("Could not retrieve data. Please try again."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvidenceManager::deleteEvidenceTriggered() {
|
void EvidenceManager::deleteEvidenceTriggered() {
|
||||||
|
@ -277,19 +276,15 @@ void EvidenceManager::deleteSet(QList<qint64> ids) {
|
||||||
auto errLogPath = QStringLiteral("%1/%2.log")
|
auto errLogPath = QStringLiteral("%1/%2.log")
|
||||||
.arg(AppConfig::value(CONFIG::EVIDENCEREPO)
|
.arg(AppConfig::value(CONFIG::EVIDENCEREPO)
|
||||||
, QDateTime::currentDateTime().toMSecsSinceEpoch());
|
, QDateTime::currentDateTime().toMSecsSinceEpoch());
|
||||||
try {
|
|
||||||
QByteArray dataToWrite = tr("Paths to files that could not be deleted: \n\n %1")
|
|
||||||
.arg(undeletedFiles.join(QStringLiteral("\n"))).toUtf8();
|
|
||||||
FileHelpers::writeFile(errLogPath, dataToWrite);
|
|
||||||
}
|
|
||||||
catch(FileError &e) {
|
|
||||||
logWritten = false;
|
|
||||||
}
|
|
||||||
QString msg = tr("Some files could not be deleted.");
|
|
||||||
|
|
||||||
if (logWritten) {
|
QByteArray dataToWrite = tr("Paths to files that could not be deleted: \n\n %1")
|
||||||
msg.append(tr(" A list of the excluded files can be found here: \n").arg(errLogPath));
|
.arg(undeletedFiles.join(QStringLiteral("\n"))).toUtf8();
|
||||||
}
|
logWritten = FileHelpers::writeFile(errLogPath, dataToWrite);
|
||||||
|
|
||||||
|
QString msg = tr("Some files could not be deleted.");
|
||||||
|
if (logWritten)
|
||||||
|
msg.append(tr(" A list of the excluded files can be found here: \n").arg(errLogPath));
|
||||||
|
|
||||||
QMessageBox::warning(this, tr("Could not complete evidence deletion"), msg);
|
QMessageBox::warning(this, tr("Could not complete evidence deletion"), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,17 +327,20 @@ void EvidenceManager::applyFilterForm(const EvidenceFilters& filter) {
|
||||||
loadEvidence();
|
loadEvidence();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvidenceManager::loadEvidence() {
|
void EvidenceManager::loadEvidence()
|
||||||
qint64 reselectId = -1;
|
{
|
||||||
if (evidenceTable->selectedItems().size() > 0) {
|
qint64 reselectId = -1;
|
||||||
reselectId = selectedRowEvidenceID();
|
if (evidenceTable->selectedItems().size() > 0) {
|
||||||
}
|
reselectId = selectedRowEvidenceID();
|
||||||
|
}
|
||||||
|
|
||||||
evidenceTable->clearContents();
|
evidenceTable->clearContents();
|
||||||
|
|
||||||
try {
|
|
||||||
auto filter = EvidenceFilters::parseFilter(filterTextBox->text());
|
auto filter = EvidenceFilters::parseFilter(filterTextBox->text());
|
||||||
QList<model::Evidence> operationEvidence = db->getEvidenceWithFilters(filter);
|
QList<model::Evidence> operationEvidence = db->getEvidenceWithFilters(filter);
|
||||||
|
if(db->lastError().type() != QSqlError::NoError){
|
||||||
|
qWarning() << "Could not retrieve evidence for operation. Error: " << db->lastError().text();
|
||||||
|
}
|
||||||
evidenceTable->setRowCount(operationEvidence.size());
|
evidenceTable->setRowCount(operationEvidence.size());
|
||||||
|
|
||||||
// removing sorting temporarily to solve a bug (per qt: not a bug)
|
// removing sorting temporarily to solve a bug (per qt: not a bug)
|
||||||
|
@ -351,38 +349,34 @@ void EvidenceManager::loadEvidence() {
|
||||||
// see also: https://bugreports.qt.io/browse/QTBUG-75479
|
// see also: https://bugreports.qt.io/browse/QTBUG-75479
|
||||||
evidenceTable->setSortingEnabled(false);
|
evidenceTable->setSortingEnabled(false);
|
||||||
for (size_t row = 0; row < operationEvidence.size(); row++) {
|
for (size_t row = 0; row < operationEvidence.size(); row++) {
|
||||||
auto evi = operationEvidence.at(row);
|
auto evi = operationEvidence.at(row);
|
||||||
auto rowData = buildBaseEvidenceRow(evi.id);
|
auto rowData = buildBaseEvidenceRow(evi.id);
|
||||||
|
|
||||||
evidenceTable->setItem(row, COL_OPERATION, rowData.operation);
|
evidenceTable->setItem(row, COL_OPERATION, rowData.operation);
|
||||||
evidenceTable->setItem(row, COL_DESCRIPTION, rowData.description);
|
evidenceTable->setItem(row, COL_DESCRIPTION, rowData.description);
|
||||||
evidenceTable->setItem(row, COL_CONTENT_TYPE, rowData.contentType);
|
evidenceTable->setItem(row, COL_CONTENT_TYPE, rowData.contentType);
|
||||||
evidenceTable->setItem(row, COL_DATE_CAPTURED, rowData.dateCaptured);
|
evidenceTable->setItem(row, COL_DATE_CAPTURED, rowData.dateCaptured);
|
||||||
evidenceTable->setItem(row, COL_PATH, rowData.path);
|
evidenceTable->setItem(row, COL_PATH, rowData.path);
|
||||||
evidenceTable->setItem(row, COL_FAILED, rowData.failed);
|
evidenceTable->setItem(row, COL_FAILED, rowData.failed);
|
||||||
evidenceTable->setItem(row, COL_ERROR_MSG, rowData.errorText);
|
evidenceTable->setItem(row, COL_ERROR_MSG, rowData.errorText);
|
||||||
evidenceTable->setItem(row, COL_SUBMITTED, rowData.submitted);
|
evidenceTable->setItem(row, COL_SUBMITTED, rowData.submitted);
|
||||||
evidenceTable->setItem(row, COL_DATE_SUBMITTED, rowData.dateSubmitted);
|
evidenceTable->setItem(row, COL_DATE_SUBMITTED, rowData.dateSubmitted);
|
||||||
|
|
||||||
setRowText(row, evi);
|
setRowText(row, evi);
|
||||||
}
|
}
|
||||||
evidenceTable->setSortingEnabled(true);
|
evidenceTable->setSortingEnabled(true);
|
||||||
if (evidenceTable->rowCount() > 0) {
|
if (evidenceTable->rowCount() > 0) {
|
||||||
// try to reselect the last viewed evidence, if it's still in the list
|
// try to reselect the last viewed evidence, if it's still in the list
|
||||||
int selectRow = 0;
|
int selectRow = 0;
|
||||||
for (int rowIndex = 0; rowIndex < evidenceTable->rowCount(); rowIndex++) {
|
for (int rowIndex = 0; rowIndex < evidenceTable->rowCount(); rowIndex++) {
|
||||||
auto evidenceID = evidenceTable->item(rowIndex, 0)->data(Qt::UserRole).toLongLong();
|
auto evidenceID = evidenceTable->item(rowIndex, 0)->data(Qt::UserRole).toLongLong();
|
||||||
if(evidenceID == reselectId) {
|
if(evidenceID == reselectId) {
|
||||||
selectRow = rowIndex;
|
selectRow = rowIndex;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
evidenceTable->setCurrentCell(selectRow, 0);
|
||||||
evidenceTable->setCurrentCell(selectRow, 0);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (QSqlError& e) {
|
|
||||||
qWarning() << "Could not retrieve evidence for operation. Error: " << e.text();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildBaseEvidenceRow constructs a container for a row of data.
|
// buildBaseEvidenceRow constructs a container for a row of data.
|
||||||
|
@ -432,15 +426,15 @@ void EvidenceManager::setRowText(int row, const model::Evidence& model) {
|
||||||
setColText(COL_DATE_SUBMITTED, uploadDateText);
|
setColText(COL_DATE_SUBMITTED, uploadDateText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvidenceManager::refreshRow(int row) {
|
void EvidenceManager::refreshRow(int row)
|
||||||
auto evidenceID = selectedRowEvidenceID();
|
{
|
||||||
try {
|
auto evidenceID = selectedRowEvidenceID();
|
||||||
auto updatedData = db->getEvidenceDetails(evidenceID);
|
auto updatedData = db->getEvidenceDetails(evidenceID);
|
||||||
setRowText(row, updatedData);
|
if (updatedData.id != -1) {
|
||||||
}
|
setRowText(row, updatedData);
|
||||||
catch (QSqlError& e) {
|
return;
|
||||||
qWarning() << "Could not refresh table row: " << e.text();
|
}
|
||||||
}
|
qWarning() << "Could not refresh table row: " << db->errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EvidenceManager::saveData() {
|
bool EvidenceManager::saveData() {
|
||||||
|
@ -500,25 +494,13 @@ void EvidenceManager::onUploadComplete() {
|
||||||
NetMan::extractResponse(uploadAssetReply, isValid);
|
NetMan::extractResponse(uploadAssetReply, isValid);
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
auto errMessage =
|
auto errMessage = tr("Unable to upload evidence: Network error (%1)").arg(uploadAssetReply->errorString());
|
||||||
tr("Unable to upload evidence: Network error (%1)").arg(uploadAssetReply->errorString());
|
db->updateEvidenceError(errMessage, evidenceIDForRequest);
|
||||||
try {
|
|
||||||
db->updateEvidenceError(errMessage, evidenceIDForRequest);
|
|
||||||
}
|
|
||||||
catch (QSqlError& e) {
|
|
||||||
qWarning() << "Upload failed. Could not update internal database. Error: " << e.text();
|
|
||||||
}
|
|
||||||
QMessageBox::warning(this, tr("Cannot Submit Evidence"),
|
QMessageBox::warning(this, tr("Cannot Submit Evidence"),
|
||||||
tr("Upload failed: Network error. Check your connection and try again.\n"
|
tr("Upload failed: Network error. Check your connection and try again.\n"
|
||||||
"(Error: %1)").arg(uploadAssetReply->errorString()));
|
"(Error: %1)").arg(uploadAssetReply->errorString()));
|
||||||
}
|
} else {
|
||||||
else {
|
db->updateEvidenceSubmitted(evidenceIDForRequest);
|
||||||
try {
|
|
||||||
db->updateEvidenceSubmitted(evidenceIDForRequest);
|
|
||||||
}
|
|
||||||
catch (QSqlError& e) {
|
|
||||||
qWarning() << "Upload successful. Could not update internal database. Error: " << e.text();
|
|
||||||
}
|
|
||||||
Q_EMIT evidenceChanged(evidenceIDForRequest, true); // lock the editing form
|
Q_EMIT evidenceChanged(evidenceIDForRequest, true); // lock the editing form
|
||||||
}
|
}
|
||||||
refreshRow(evidenceTable->currentRow());
|
refreshRow(evidenceTable->currentRow());
|
||||||
|
|
|
@ -84,20 +84,20 @@ bool GetInfo::saveData() {
|
||||||
return saveResponse.actionSucceeded;
|
return saveResponse.actionSucceeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetInfo::submitButtonClicked() {
|
void GetInfo::submitButtonClicked()
|
||||||
submitButton->startAnimation();
|
{
|
||||||
Q_EMIT setActionButtonsEnabled(false);
|
submitButton->startAnimation();
|
||||||
if (saveData()) {
|
Q_EMIT setActionButtonsEnabled(false);
|
||||||
try {
|
if (!saveData())
|
||||||
model::Evidence evi = db->getEvidenceDetails(evidenceID);
|
return;
|
||||||
uploadAssetReply = NetMan::uploadAsset(evi);
|
model::Evidence evi = db->getEvidenceDetails(evidenceID);
|
||||||
connect(uploadAssetReply, &QNetworkReply::finished, this, &GetInfo::onUploadComplete);
|
if(evi.id == -1) {
|
||||||
|
QMessageBox::warning(this, tr("Cannot submit evidence"),
|
||||||
|
tr("Could not retrieve data. Please try again."));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (QSqlError& e) {
|
uploadAssetReply = NetMan::uploadAsset(evi);
|
||||||
QMessageBox::warning(this, tr("Cannot submit evidence"),
|
connect(uploadAssetReply, &QNetworkReply::finished, this, &GetInfo::onUploadComplete);
|
||||||
tr("Could not retrieve data. Please try again."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetInfo::deleteButtonClicked() {
|
void GetInfo::deleteButtonClicked() {
|
||||||
|
@ -127,35 +127,28 @@ void GetInfo::deleteButtonClicked() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetInfo::onUploadComplete() {
|
void GetInfo::onUploadComplete()
|
||||||
if (uploadAssetReply->error() != QNetworkReply::NoError) {
|
{
|
||||||
auto errMessage =
|
if (uploadAssetReply->error() != QNetworkReply::NoError) {
|
||||||
tr("Unable to upload evidence: Network error (%1)").arg(uploadAssetReply->errorString());
|
auto errMessage = tr("Unable to upload evidence: Network error (%1)").arg(uploadAssetReply->errorString());
|
||||||
try {
|
db->updateEvidenceError(errMessage, evidenceID);
|
||||||
db->updateEvidenceError(errMessage, evidenceID);
|
if(!db->errorString().isEmpty())
|
||||||
|
qWarning() << "Upload failed. Could not update internal database. Error: " << db->errorString();
|
||||||
|
QMessageBox::warning(this, tr("Cannot submit evidence"),
|
||||||
|
tr("Upload failed: Network error. Check your connection and try again.\n"
|
||||||
|
"Note: This evidence has been saved. You can close this window and "
|
||||||
|
"re-submit from the evidence manager."
|
||||||
|
"\n(Error: %1)").arg(uploadAssetReply->errorString()));
|
||||||
|
} else {
|
||||||
|
db->updateEvidenceSubmitted(evidenceID);
|
||||||
|
if(!db->errorString().isEmpty())
|
||||||
|
qWarning() << "Upload successful. Could not update internal database. Error: " << db->errorString();
|
||||||
|
Q_EMIT evidenceSubmitted(db->getEvidenceDetails(evidenceID));
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
catch (QSqlError& e) {
|
// we don't actually need anything from the uploadAssets reply, so just clean it up.
|
||||||
qWarning() << "Upload failed. Could not update internal database. Error: " << e.text();
|
// one thing we might want to record: evidence uuid... not sure why we'd need it though.
|
||||||
}
|
submitButton->stopAnimation();
|
||||||
QMessageBox::warning(this, tr("Cannot submit evidence"),
|
Q_EMIT setActionButtonsEnabled(true);
|
||||||
tr("Upload failed: Network error. Check your connection and try again.\n"
|
tidyReply(&uploadAssetReply);
|
||||||
"Note: This evidence has been saved. You can close this window and "
|
|
||||||
"re-submit from the evidence manager."
|
|
||||||
"\n(Error: %1)").arg(uploadAssetReply->errorString()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
db->updateEvidenceSubmitted(evidenceID);
|
|
||||||
Q_EMIT evidenceSubmitted(db->getEvidenceDetails(evidenceID));
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
catch (QSqlError& e) {
|
|
||||||
qWarning() << "Upload successful. Could not update internal database. Error: " << e.text();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// we don't actually need anything from the uploadAssets reply, so just clean it up.
|
|
||||||
// one thing we might want to record: evidence uuid... not sure why we'd need it though.
|
|
||||||
submitButton->stopAnimation();
|
|
||||||
Q_EMIT setActionButtonsEnabled(true);
|
|
||||||
tidyReply(&uploadAssetReply);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <QtConcurrent/QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
#include "db/databaseconnection.h"
|
#include "db/databaseconnection.h"
|
||||||
#include "exceptions/fileerror.h"
|
|
||||||
|
|
||||||
PortingDialog::PortingDialog(PortType dialogType, DatabaseConnection* db, QWidget *parent)
|
PortingDialog::PortingDialog(PortType dialogType, DatabaseConnection* db, QWidget *parent)
|
||||||
: AShirtDialog(parent)
|
: AShirtDialog(parent)
|
||||||
|
@ -156,63 +155,52 @@ QString PortingDialog::getPortPath() {
|
||||||
return portPath;
|
return portPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortingDialog::doExport(porting::SystemManifest* manifest, const QString& exportPath) {
|
void PortingDialog::doExport(porting::SystemManifest* manifest, const QString& exportPath)
|
||||||
porting::SystemManifestExportOptions options;
|
{
|
||||||
options.exportDb = portEvidenceCheckBox->isChecked();
|
porting::SystemManifestExportOptions options;
|
||||||
options.exportConfig = portConfigCheckBox->isChecked();
|
options.exportDb = portEvidenceCheckBox->isChecked();
|
||||||
|
options.exportConfig = portConfigCheckBox->isChecked();
|
||||||
// Qt db access is limited to single-thread access. A new connection needs to be made, hence
|
|
||||||
// the withconnection here that connects to the same database. Note: we shouldn't write to the db
|
// Qt db access is limited to single-thread access. A new connection needs to be made, hence
|
||||||
// in this thread, if possible.
|
// the withconnection here that connects to the same database. Note: we shouldn't write to the db
|
||||||
QString threadedDbName = QStringLiteral("%1_mt_forExport").arg(Constants::defaultDbName);
|
// in this thread, if possible.
|
||||||
DatabaseConnection::withConnection(
|
QString threadedDbName = QStringLiteral("%1_mt_forExport").arg(Constants::defaultDbName);
|
||||||
db->getDatabasePath(), threadedDbName, [this, &manifest, exportPath, options](DatabaseConnection conn){
|
auto success = DatabaseConnection::withConnection(
|
||||||
try {
|
db->getDatabasePath(), threadedDbName, [this, &manifest, exportPath, options](DatabaseConnection conn) {
|
||||||
manifest->exportManifest(&conn, exportPath, options);
|
manifest->exportManifest(&conn, exportPath, options);
|
||||||
}
|
});
|
||||||
catch(const FileError &e) {
|
if(success) {
|
||||||
portStatusLabel->setText(tr("Error during export: %1").arg(e.what()));
|
Q_EMIT onWorkComplete(true);
|
||||||
Q_EMIT onWorkComplete(false);
|
return;
|
||||||
}
|
}
|
||||||
catch(const QSqlError &e) {
|
portStatusLabel->setText(tr("Error during export: %1").arg(db->errorString()));
|
||||||
portStatusLabel->setText(tr("Error during export: %1").arg(e.text()));
|
Q_EMIT onWorkComplete(false);
|
||||||
Q_EMIT onWorkComplete(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Q_EMIT onWorkComplete(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
porting::SystemManifest* PortingDialog::doPreImport(const QString& pathToSystemManifest) {
|
porting::SystemManifest* PortingDialog::doPreImport(const QString& pathToSystemManifest) {
|
||||||
porting::SystemManifest* manifest = nullptr;
|
porting::SystemManifest* manifest = nullptr;
|
||||||
try {
|
manifest = porting::SystemManifest::readManifest(pathToSystemManifest);
|
||||||
manifest = porting::SystemManifest::readManifest(pathToSystemManifest);
|
if(!manifest) {
|
||||||
}
|
portStatusLabel->setText(tr("Unable to parse system file."));
|
||||||
catch(const FileError& e) {
|
onPortComplete(false);
|
||||||
portStatusLabel->setText(tr("Unable to parse system file."));
|
|
||||||
onPortComplete(false);
|
|
||||||
}
|
}
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortingDialog::doImport(porting::SystemManifest* manifest) {
|
void PortingDialog::doImport(porting::SystemManifest* manifest)
|
||||||
porting::SystemManifestImportOptions options;
|
{
|
||||||
options.importDb = portEvidenceCheckBox->isChecked() ? options.Merge : options.None;
|
porting::SystemManifestImportOptions options;
|
||||||
options.importConfig = portConfigCheckBox->isChecked();
|
options.importDb = portEvidenceCheckBox->isChecked() ? options.Merge : options.None;
|
||||||
|
options.importConfig = portConfigCheckBox->isChecked();
|
||||||
QString threadedDbName = QStringLiteral("%1_mt_forImport").arg(Constants::defaultDbName);
|
QString threadedDbName = QStringLiteral("%1_mt_forImport").arg(Constants::defaultDbName);
|
||||||
DatabaseConnection::withConnection(
|
auto success = DatabaseConnection::withConnection(
|
||||||
db->getDatabasePath(), threadedDbName, [this, &manifest, options](DatabaseConnection conn){
|
db->getDatabasePath(), threadedDbName, [this, &manifest, options](DatabaseConnection conn){
|
||||||
try {
|
manifest->applyManifest(options, &conn);
|
||||||
manifest->applyManifest(options, &conn);
|
});
|
||||||
}
|
if(success) {
|
||||||
catch(const FileError &e) {
|
Q_EMIT onWorkComplete(true);
|
||||||
portStatusLabel->setText(tr("Error during import: %1").arg(e.what()));
|
return;
|
||||||
Q_EMIT onWorkComplete(false);
|
}
|
||||||
}
|
portStatusLabel->setText(tr("Error during import: %1").arg(db->errorString()));
|
||||||
catch(const QSqlError &e) {
|
Q_EMIT onWorkComplete(false);
|
||||||
portStatusLabel->setText(tr("Error during import: ").arg(e.text()));
|
|
||||||
Q_EMIT onWorkComplete(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Q_EMIT onWorkComplete(true);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ public:
|
||||||
/// Callers should retrieve the result by listening for the releasesChecked signal
|
/// Callers should retrieve the result by listening for the releasesChecked signal
|
||||||
static void checkForNewRelease(QString owner, QString repo) {
|
static void checkForNewRelease(QString owner, QString repo) {
|
||||||
if (owner.isEmpty() || repo.isEmpty()) {
|
if (owner.isEmpty() || repo.isEmpty()) {
|
||||||
qWarning() << "Skipping release check: no owner or repo set.";
|
qInfo() << "Skipping release check: no owner or repo set.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
get()->githubReleaseReply = get()->getGithubReleases(owner, repo);
|
get()->githubReleaseReply = get()->getGithubReleases(owner, repo);
|
||||||
|
|
|
@ -35,7 +35,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
auto conn = new DatabaseConnection(Constants::dbLocation, Constants::defaultDbName);
|
auto conn = new DatabaseConnection(Constants::dbLocation, Constants::defaultDbName);
|
||||||
if(!conn->connect()) {
|
if(!conn->connect()) {
|
||||||
showMsgBox(QT_TRANSLATE_NOOP("main", "Unable to connect to database"));
|
showMsgBox(QString(QT_TRANSLATE_NOOP("main", "Database Error: %1")).arg(conn->errorString()));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,9 +120,11 @@ void SystemManifest::exportManifest(DatabaseConnection* db, const QString& outpu
|
||||||
QJsonDocument(EvidenceManifest::serialize(evidenceManifest)).toJson());
|
QJsonDocument(EvidenceManifest::serialize(evidenceManifest)).toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pathToManifest = QStringLiteral("%1/system.json").arg(basePath);
|
m_pathToManifest = QStringLiteral("%1/system.json").arg(basePath);
|
||||||
FileHelpers::writeFile(m_pathToManifest, QJsonDocument(serialize(*this)).toJson());
|
if(FileHelpers::writeFile(m_pathToManifest, QJsonDocument(serialize(*this)).toJson()))
|
||||||
Q_EMIT onComplete();
|
Q_EMIT onComplete();
|
||||||
|
else
|
||||||
|
Q_EMIT onExportError(QStringLiteral("Error On Exporting manifest"));
|
||||||
}
|
}
|
||||||
|
|
||||||
porting::EvidenceManifest SystemManifest::copyEvidence(const QString& baseExportPath,
|
porting::EvidenceManifest SystemManifest::copyEvidence(const QString& baseExportPath,
|
||||||
|
|
|
@ -36,7 +36,6 @@ namespace porting {
|
||||||
* @brief applyManifest takes the given manifest object (and options), and begins merging that data with the running system
|
* @brief applyManifest takes the given manifest object (and options), and begins merging that data with the running system
|
||||||
* @param options switches to control what gets imported
|
* @param options switches to control what gets imported
|
||||||
* @param systemDb The currently running/system database
|
* @param systemDb The currently running/system database
|
||||||
* @throws QSqlError If there is an issue ingesting database records from the exported database
|
|
||||||
*/
|
*/
|
||||||
void applyManifest(SystemManifestImportOptions options, DatabaseConnection* systemDb);
|
void applyManifest(SystemManifestImportOptions options, DatabaseConnection* systemDb);
|
||||||
|
|
||||||
|
@ -46,7 +45,6 @@ namespace porting {
|
||||||
* @param outputDirPath the path to the expected export directory. Files will be placed under this directory
|
* @param outputDirPath the path to the expected export directory. Files will be placed under this directory
|
||||||
* (not wrapped in another directory)
|
* (not wrapped in another directory)
|
||||||
* @param options exporting options (e.g. do you want to copy both evidence *and* config
|
* @param options exporting options (e.g. do you want to copy both evidence *and* config
|
||||||
* @throws QSqlError if there is an issue accessing the system database, or the copied database
|
|
||||||
*/
|
*/
|
||||||
void exportManifest(DatabaseConnection* db, const QString& outputDirPath,
|
void exportManifest(DatabaseConnection* db, const QString& outputDirPath,
|
||||||
const SystemManifestExportOptions& options);
|
const SystemManifestExportOptions& options);
|
||||||
|
@ -69,6 +67,8 @@ namespace porting {
|
||||||
void onFileProcessed(quint64 runningCount);
|
void onFileProcessed(quint64 runningCount);
|
||||||
/// onComplete fires when the entire import/export is finished
|
/// onComplete fires when the entire import/export is finished
|
||||||
void onComplete();
|
void onComplete();
|
||||||
|
/// onComplete fires when the export has an error
|
||||||
|
void onExportError(QString errorString);
|
||||||
/// onCopyFileError fires when a file cannot be copied during import or export
|
/// onCopyFileError fires when a file cannot be copied during import or export
|
||||||
void onCopyFileError(QString srcPath, QString dstPath, const QString& errStr);
|
void onCopyFileError(QString srcPath, QString dstPath, const QString& errStr);
|
||||||
/// onStatusUpdate fires when the system moves between import/export phases
|
/// onStatusUpdate fires when the system moves between import/export phases
|
||||||
|
@ -89,7 +89,6 @@ namespace porting {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief migrateConfig imports the config file associated with the started import
|
* @brief migrateConfig imports the config file associated with the started import
|
||||||
* @throws FileError if the config file cannot be copied
|
|
||||||
*/
|
*/
|
||||||
void migrateConfig();
|
void migrateConfig();
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "appconfig.h"
|
#include "appconfig.h"
|
||||||
#include "db/databaseconnection.h"
|
#include "db/databaseconnection.h"
|
||||||
#include "exceptions/fileerror.h"
|
|
||||||
#include "forms/getinfo/getinfo.h"
|
#include "forms/getinfo/getinfo.h"
|
||||||
#include "helpers/netman.h"
|
#include "helpers/netman.h"
|
||||||
#include "helpers/screenshot.h"
|
#include "helpers/screenshot.h"
|
||||||
|
@ -211,6 +210,7 @@ void TrayManager::onClipboardCapture()
|
||||||
QString clipboardContent = mimeData->text();
|
QString clipboardContent = mimeData->text();
|
||||||
if (clipboardContent.isEmpty())
|
if (clipboardContent.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Codeblock evidence(clipboardContent);
|
Codeblock evidence(clipboardContent);
|
||||||
if(!Codeblock::saveCodeblock(evidence)) {
|
if(!Codeblock::saveCodeblock(evidence)) {
|
||||||
setTrayMessage(NO_ACTION, _recordErrorTitle, tr("Error Gathering Evidence from clipboard"), QSystemTrayIcon::Information);
|
setTrayMessage(NO_ACTION, _recordErrorTitle, tr("Error Gathering Evidence from clipboard"), QSystemTrayIcon::Information);
|
||||||
|
@ -227,30 +227,27 @@ void TrayManager::onClipboardCapture()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int evidenceID = 0;
|
int evidenceID = createNewEvidence(path, type);
|
||||||
try {
|
if(evidenceID == -1) {
|
||||||
evidenceID = createNewEvidence(path, type);
|
showDBWriteErrorTrayMessage();
|
||||||
}
|
return;
|
||||||
catch (QSqlError& e) {
|
|
||||||
showDBWriteErrorTrayMessage(e.text());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
spawnGetInfoWindow(evidenceID);
|
spawnGetInfoWindow(evidenceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrayManager::onScreenshotCaptured(const QString& path) {
|
void TrayManager::onScreenshotCaptured(const QString& path)
|
||||||
try {
|
|
||||||
auto evidenceID = createNewEvidence(path, QStringLiteral("image"));
|
|
||||||
spawnGetInfoWindow(evidenceID);
|
|
||||||
}
|
|
||||||
catch (QSqlError& e) {
|
|
||||||
showDBWriteErrorTrayMessage(e.text());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrayManager::showDBWriteErrorTrayMessage(const QString &errorMessage)
|
|
||||||
{
|
{
|
||||||
setTrayMessage(NO_ACTION, _recordErrorTitle, tr("Could not write to database: %1").arg(errorMessage), QSystemTrayIcon::Warning);
|
auto evidenceID = createNewEvidence(path, QStringLiteral("image"));
|
||||||
|
if(evidenceID == -1) {
|
||||||
|
showDBWriteErrorTrayMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spawnGetInfoWindow(evidenceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrayManager::showDBWriteErrorTrayMessage()
|
||||||
|
{
|
||||||
|
setTrayMessage(NO_ACTION, _recordErrorTitle,tr("Could not write to database"), QSystemTrayIcon::Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrayManager::showNoOperationSetTrayMessage() {
|
void TrayManager::showNoOperationSetTrayMessage() {
|
||||||
|
|
|
@ -61,7 +61,7 @@ class TrayManager : public QDialog {
|
||||||
qint64 createNewEvidence(const QString& filepath, const QString& evidenceType);
|
qint64 createNewEvidence(const QString& filepath, const QString& evidenceType);
|
||||||
void spawnGetInfoWindow(qint64 evidenceID);
|
void spawnGetInfoWindow(qint64 evidenceID);
|
||||||
void showNoOperationSetTrayMessage();
|
void showNoOperationSetTrayMessage();
|
||||||
void showDBWriteErrorTrayMessage(const QString &errorMessage = QString());
|
void showDBWriteErrorTrayMessage();
|
||||||
void checkForUpdate();
|
void checkForUpdate();
|
||||||
void cleanChooseOpSubmenu();
|
void cleanChooseOpSubmenu();
|
||||||
/// setTrayMessage mostly mirrors QSystemTrayIcon::showMessage, but adds the ability to set a message type,
|
/// setTrayMessage mostly mirrors QSystemTrayIcon::showMessage, but adds the ability to set a message type,
|
||||||
|
|
Loading…
Reference in New Issue