records_management.cpp 11.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * Copyright (C) 2014-2018 CZ.NIC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QMessageBox>

#include "src/datovka_shared/io/records_management_db.h"
#include "src/datovka_shared/records_management/json/service_info.h"
28 29
#include "src/datovka_shared/records_management/json/upload_file.h"
#include "src/datovka_shared/records_management/json/upload_hierarchy.h"
30
#include "src/datovka_shared/settings/records_management.h"
31
#include "src/models/accountmodel.h"
32
#include "src/qml_interaction/image_provider.h"
33
#include "src/records_management/models/upload_hierarchy_list_model.h"
34
#include "src/records_management.h"
35
#include "src/settings.h"
36
#include "src/sqlite/zfo_db.h"
37
#include "src/worker/emitter.h"
38 39
#include "src/worker/pool.h"
#include "src/worker/task_records_management_stored_messages.h"
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
/*!
 * @brief Process upload file service response.
 *
 * @note Stores location into database.
 *
 * @param[in] ifRes Response structure.
 * @param[in] dmId Message identifier.
 * @patam[in] parent Parent window for potential error dialogues.
 * @return True if response could be processed and location has been saved.
 */
static
bool processUploadFileResponse(const UploadFileResp &ufRes, qint64 dmId,
    QWidget *parent = Q_NULLPTR)
{
	if (ufRes.id().isEmpty()) {
		QString errorMessage(
		    QObject::tr("Message '%1' could not be uploaded.")
		        .arg(dmId));
		errorMessage += QLatin1String("\n");
		errorMessage += QObject::tr("Received error") +
		    QLatin1String(": ") + ufRes.error().trVerbose();
		errorMessage += QLatin1String("\n");
		errorMessage += ufRes.error().description();

		QMessageBox::critical(parent, QObject::tr("File Upload Error"),
		    errorMessage);
		return false;
	}

	QMessageBox::information(parent, QObject::tr("Successful File Upload"),
	    QObject::tr("Message '%1' was successfully uploaded into the records management service.").arg(dmId) +
	    QStringLiteral("\n") +
	    QObject::tr("It can be now found in the records management service in these locations:") +
	    QStringLiteral("\n") +
	    ufRes.locations().join(QStringLiteral("\n")));

	if (!ufRes.locations().isEmpty()) {
		qCritical("%s", "Message has been stored into records management service.");
		if (Q_NULLPTR != globRecordsManagementDbPtr) {
			return globRecordsManagementDbPtr->updateStoredMsg(dmId,
			    ufRes.locations());
		} else {
			Q_ASSERT(0);
			return true;
		}
	} else {
		qCritical("%s",
		    "Received empty location list when uploading message.");
	}

	return false;
}

94
RecordsManagement::RecordsManagement(QObject *parent)
95
    : QObject(parent),
96
    m_rmc(RecordsManagementConnection::ignoreSslErrorsDflt, this)
97
{
98
	globWorkPool.start();
99 100 101 102

	connect(&globMsgProcEmitter,
	    SIGNAL(rmSyncFinishedSignal(QString, int, int)),
	    this, SLOT(rmSyncFinished(QString, int, int)));
103 104 105 106 107 108
}

RecordsManagement::~RecordsManagement(void)
{
	globWorkPool.wait();
	globWorkPool.stop();
109 110
}

111 112
bool RecordsManagement::callServiceInfo(const QString &urlStr,
    const QString &tokenStr)
113 114
{
	QByteArray response;
115 116 117 118

	if (urlStr.trimmed().isEmpty() || tokenStr.trimmed().isEmpty()) {
		return false;
	}
119 120

	emit statusBarTextChanged(tr("Get service info"), true, true);
121

122 123
	m_rmc.setConnection(urlStr.trimmed(), tokenStr.trimmed());

124 125
	if (m_rmc.communicate(RecordsManagementConnection::SRVC_SERVICE_INFO,
	        QByteArray(), response)) {
126 127 128 129
		if (!response.isEmpty()) {
			bool ok = false;
			ServiceInfoResp siRes(
			    ServiceInfoResp::fromJson(response, &ok));
130
			if (ok && siRes.isValid()) {
131 132 133 134
				if (globImgProvPtr != Q_NULLPTR) {
					globImgProvPtr->setSvg(RM_SVG_LOGO_ID,
					    siRes.logoSvg());
				}
135 136 137
				emit serviceInfo(siRes.name(), siRes.tokenName());
				emit statusBarTextChanged(tr("Done"), false, true);
				return true;
138
			}
139 140
		}
	}
141

142 143
	emit statusBarTextChanged(tr("Communication error"), false, true);
	return false;
144 145
}

146 147
void RecordsManagement::callUploadHierarchy(
    const QVariant &hirerachyModelVariant)
148 149
{
	QByteArray response;
150 151 152 153 154

	if (globRecordsManagementSet.url().isEmpty() ||
	    globRecordsManagementSet.token().isEmpty()) {
		return;
	}
155

156 157 158 159 160 161 162 163
	UploadHierarchyListModel *hierarchyModel =
	    UploadHierarchyListModel::fromVariant(hirerachyModelVariant);
	if (hierarchyModel == Q_NULLPTR) {
		Q_ASSERT(0);
		qCritical("%s", "Cannot access upload hierarchy model.");
		return;
	}

164 165
	emit statusBarTextChanged(tr("Upload hierarchy"), true, true);

166
	/* Clear model. */
167
	hierarchyModel->setHierarchy(UploadHierarchyResp());
168

169 170
	m_rmc.setConnection(globRecordsManagementSet.url(),
	    globRecordsManagementSet.token());
171 172 173 174 175 176 177

	if (m_rmc.communicate(RecordsManagementConnection::SRVC_UPLOAD_HIERARCHY,
	        QByteArray(), response)) {
		if (!response.isEmpty()) {
			bool ok = false;
			UploadHierarchyResp uhRes(
			    UploadHierarchyResp::fromJson(response, &ok));
178 179 180 181 182
			if (ok && uhRes.isValid()) {
				/* Set model. */
				hierarchyModel->setHierarchy(uhRes);
				emit statusBarTextChanged(tr("Done"), false, true);
				return;
183
			}
184 185
		}
	}
186

187
	emit statusBarTextChanged(tr("Communication error"), false, true);
188 189
}

190 191
void RecordsManagement::getStoredMsgInfoFromRecordsManagement(
    const QString &urlStr, const QString &tokenStr)
192
{
193 194 195 196 197 198 199
	QString url = urlStr.trimmed();
	QString token = tokenStr.trimmed();

	if (url.isEmpty() || token.isEmpty()) {
		return;
	}

200
	emit statusBarTextChanged(tr("Sync service"), true, true);
201 202 203

	TaskRecordsManagementStoredMessages *task =
	    new (::std::nothrow) TaskRecordsManagementStoredMessages(
204 205 206
	        url, token,
	        TaskRecordsManagementStoredMessages::RM_UPDATE_STORED,
	        Q_NULLPTR, QString(), 0, 0);
207 208
	if (Q_NULLPTR == task) {
		qCritical("%s", "Cannot create stored_files update task.");
209
		emit statusBarTextChanged(tr("Sync failed"), false, true);
210 211 212 213 214 215
		return;
	}
	task->setAutoDelete(true);
	/* Run in background. */
	globWorkPool.assignHi(task);

216 217 218
	int accTotal = AccountListModel::globAccounts.keys().count();
	int accNumber = 0;

219
	foreach (const QString &userName, AccountListModel::globAccounts.keys()) {
220 221
		accNumber++;

222 223 224 225 226
		MessageDb *msgDb = globMessageDbsPtr->accessMessageDb(
		    globSet.dbsLocation, userName,
		    AccountListModel::globAccounts[userName].storeToDisk());
		if (msgDb == Q_NULLPTR) {
			qWarning("%s", "Cannot open message database.");
227
			continue;
228 229 230 231
		}

		TaskRecordsManagementStoredMessages *task =
		    new (::std::nothrow) TaskRecordsManagementStoredMessages(
232
		        url, token,
233
		        TaskRecordsManagementStoredMessages::RM_DOWNLOAD_ALL,
234
		        msgDb, userName, accNumber, accTotal);
235 236 237 238 239 240 241 242 243 244 245 246
		if (Q_NULLPTR == task) {
			qWarning("Cannot create stored_files task for '%s'.",
			    userName.toUtf8().constData());
			continue;
		}
		task->setAutoDelete(true);
		/* Run in background. */
		globWorkPool.assignHi(task);

	}
}

247 248
bool RecordsManagement::isValidRecordsManagement(void)
{
249
	return globRecordsManagementSet.isValid();
250 251
}

252 253 254 255 256 257 258 259 260 261 262 263
void RecordsManagement::loadStoredServiceInfo(void)
{
	if (Q_NULLPTR == globRecordsManagementDbPtr) {
		return;
	}

	RecordsManagementDb::ServiceInfoEntry entry(
	    globRecordsManagementDbPtr->serviceInfo());
	if (!entry.isValid()) {
		return;
	}

264 265 266
	if (globImgProvPtr != Q_NULLPTR) {
		globImgProvPtr->setSvg(RM_SVG_LOGO_ID, entry.logoSvg);
	}
Martin Straka's avatar
Martin Straka committed
267
	emit serviceInfo(entry.name, entry.tokenName);
268
}
269

270 271
bool RecordsManagement::uploadMessage(const QString &userName,
    const QString &dmId, enum Messages::MessageType messageType,
272
    const QVariant &hirerachyModelVariant)
273
{
274 275 276
	bool ok = false;
	qint64 msgId = dmId.toLongLong(&ok);
	if (!ok || (msgId < 0)) {
277 278 279
		return false;
	}

280 281 282
	QByteArray msgData =
	    QByteArray::fromBase64(globZfoDbPtr->getZfoContentFromDb(msgId,
	    AccountListModel::globAccounts[userName].isTestAccount()));
283

284
	if (msgData.isEmpty()) {
285 286 287
		return false;
	}

288 289 290 291 292 293 294 295 296 297 298 299
	QString msgType;
	switch (messageType) {
	case Messages::TYPE_RECEIVED:
		msgType = QLatin1String("DDZ");
		break;
	case Messages::TYPE_SENT:
		msgType = QLatin1String("ODZ");
		break;
	default:
		msgType = QLatin1String("DZ");
		break;
	}
300

301
	QString msgFileName = QString("%1_%2.zfo").arg(msgType).arg(dmId);
302

303 304 305 306 307 308 309 310 311
	UploadHierarchyListModel *hierarchyModel =
	    UploadHierarchyListModel::fromVariant(hirerachyModelVariant);
	if (hierarchyModel == Q_NULLPTR) {
		Q_ASSERT(0);
		qCritical("%s", "Cannot access upload hierarchy model.");
		return false;
	}

	return uploadFile(msgId, msgFileName, msgData, hierarchyModel->selectedIds());
312 313
}

314 315
bool RecordsManagement::updateServiceInfo(const QString &newUrlStr,
    const QString &oldUrlStr, const QString &srName, const QString &srToken)
Martin Straka's avatar
Martin Straka committed
316 317 318 319 320
{
	if (Q_NULLPTR == globRecordsManagementDbPtr) {
		return false;
	}

321
	QString cUrlStr = newUrlStr.trimmed();
Martin Straka's avatar
Martin Straka committed
322

323
	if (!cUrlStr.isEmpty()) {
Martin Straka's avatar
Martin Straka committed
324
		RecordsManagementDb::ServiceInfoEntry entry;
325
		entry.url = cUrlStr;
Martin Straka's avatar
Martin Straka committed
326 327
		entry.name = srName;
		entry.tokenName = srToken;
328 329
		entry.logoSvg = (globImgProvPtr != Q_NULLPTR) ?
		    globImgProvPtr->svg(RM_SVG_LOGO_ID) : QByteArray();
Martin Straka's avatar
Martin Straka committed
330
		globRecordsManagementDbPtr->updateServiceInfo(entry);
331 332
		if (oldUrlStr != cUrlStr) {
			return globRecordsManagementDbPtr->deleteAllStoredMsg();
Martin Straka's avatar
Martin Straka committed
333 334
		}
	} else {
335
		return globRecordsManagementDbPtr->deleteAllEntries();
Martin Straka's avatar
Martin Straka committed
336 337 338 339 340
	}

	return true;
}

341 342 343 344 345
void RecordsManagement::rmSyncFinished(const QString &userName, int accNumber,
    int accTotal)
{
	if (accNumber < accTotal) {
		emit statusBarTextChanged(
346
		    tr("Update account '%1' (%2/%3)").arg(userName).arg(accNumber).arg(accTotal),
347 348
		    true, true);
	} else {
349
		emit statusBarTextChanged(tr("Update done"), false, true);
350 351 352
	}
}

353 354 355
bool RecordsManagement::uploadFile(qint64 dmId, const QString &msgFileName,
    const QByteArray &msgData, const QStringList &uploadIds)
{
356 357
	QByteArray response;

358 359 360 361 362
	if (msgFileName.isEmpty() || msgData.isEmpty()) {
		Q_ASSERT(0);
		return false;
	}

363 364 365 366 367
	if (globRecordsManagementSet.url().isEmpty() ||
	    globRecordsManagementSet.token().isEmpty()) {
		return false;
	}

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	UploadFileReq ufReq(uploadIds, msgFileName, msgData);
	if (!ufReq.isValid()) {
		Q_ASSERT(0);
		return false;
	}

	emit statusBarTextChanged(tr("Upload message"), true, true);

	m_rmc.setConnection(globRecordsManagementSet.url(),
	    globRecordsManagementSet.token());

	if (m_rmc.communicate(RecordsManagementConnection::SRVC_UPLOAD_FILE,
	        ufReq.toJson(), response)) {
		if (!response.isEmpty()) {
			bool ok = false;
			UploadFileResp ufRes(
			    UploadFileResp::fromJson(response, &ok));
385 386 387
			if (ok && ufRes.isValid()) {
				emit statusBarTextChanged(tr("Done"), false, true);
				return processUploadFileResponse(ufRes, dmId);
388 389 390 391
			}
		}
	}

392
	emit statusBarTextChanged(tr("Communication error"), false, true);
393 394
	return false;
}