Commit 95f93150 authored by Martin Straka's avatar Martin Straka

Added simple log file viewer

parent 88cbef11
......@@ -8,7 +8,7 @@
*
* 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
* 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
......@@ -69,6 +69,7 @@ ApplicationWindow {
property Component pageDataboxDetail: PageDataboxDetail {}
property Component pageDataboxSearch: PageDataboxSearch {}
property Component pageImportMessage: PageImportMessage {}
property Component pageLog: PageLog {}
property Component pageMenuAccount: PageMenuAccount {}
property Component pageMenuDatovkaSettings: PageMenuDatovkaSettings {}
property Component pageMenuMessage: PageMenuMessage {}
......
/*
* 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.
*/
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import cz.nic.mobileDatovka 1.0
Item {
id: pageLog
/* These properties must be set by caller. */
property var pageView
property var statusBar
property string logFilePath: ""
Component.onCompleted: {
logContent.text = files.loadLogContent(logFilePath)
}
/* File dialog for choose of files from the storage */
FileDialogue {
id: fileDialogue
multiSelect: false
onFinished: {
if (pathListModel.count === 1) {
logFilePath = pathListModel.get(pathListModel.count-1).path
logContent.text = files.loadLogContent(logFilePath)
}
}
}
PageHeader {
id: headerBar
title: qsTr("Log Viewer")
onBackClicked: {
pageView.pop(StackView.Immediate)
}
AccessibleOverlaidImageButton {
id: actionButton
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: defaultMargin
image.sourceSize.height: imgHeightHeader
image.source: "qrc:/ui/send-msg.svg"
accessibleName: qsTr("Send log to helpdesk")
onClicked: {
files.sendLogFileViaEmail(logFilePath)
}
}
}
Flickable {
id: flickable
z: 0
anchors.top: headerBar.bottom
anchors.right: parent.right
anchors.left: parent.left
contentHeight: flickContent.implicitHeight
height: parent.height * 0.8
Pane {
id: flickContent
anchors.fill: parent
Text {
id: logContent
color: datovkaPalette.text
anchors.fill: parent
textFormat: TextEdit.RichText
wrapMode: Text.WordWrap
font.pointSize: textFontSizeSmall
}
} // Pane
ScrollIndicator.vertical: ScrollIndicator {}
} // Flickable
Rectangle {
id: attachmentArea
anchors.top: flickable.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
color: datovkaPalette.window
AccessibleButton {
visible: true
text: qsTr("Choose log file")
height: inputItemHeight
font.pointSize: defaultTextFont.font.pointSize
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
fileDialogue.raise("Choose log file", ["*.log"], true)
}
}
}
} // Item
......@@ -8,7 +8,7 @@
*
* 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
* 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
......@@ -131,6 +131,12 @@ Component {
"accountModel": accountModel
}, StackView.Immediate)
},
"logViewer": function callLogViewer() {
pageView.replace(pageLog, {
"pageView": pageView,
"statusBar": statusBar
}, StackView.Immediate)
},
"userGuide": function callUserGuide() {
Qt.openUrlExternally("https://secure.nic.cz/files/datove_schranky/redirect/mobile-manual.html")
pageView.pop(StackView.Immediate)
......@@ -202,6 +208,13 @@ Component {
name: qsTr("Security and PIN")
funcName: "settSecPin"
}
ListElement {
image: "qrc:/ui/book-open.svg"
showEntry: true
showNext: true
name: qsTr("Log Viewer")
funcName: "logViewer"
}
ListElement {
image: "qrc:/ui/information.svg"
showEntry: true
......
......@@ -135,6 +135,7 @@
<file>../qml/pages/PageDataboxDetail.qml</file>
<file>../qml/pages/PageDataboxSearch.qml</file>
<file>../qml/pages/PageImportMessage.qml</file>
<file>../qml/pages/PageLog.qml</file>
<file>../qml/pages/PageMenuAccount.qml</file>
<file>../qml/pages/PageMenuDatovkaSettings.qml</file>
<file>../qml/pages/PageMenuMessage.qml</file>
......
......@@ -8,7 +8,7 @@
*
* 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
* 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
......@@ -24,13 +24,16 @@
#include <QDesktopServices>
#include <QFileInfo>
#include <QQmlEngine>
#include <QTextStream>
#include "ios/src/url_opener.h"
#include "src/auxiliaries/attachment_helper.h"
#include "src/auxiliaries/email_helper.h"
#include "src/common.h"
#include "src/crypto/crypto.h"
#include "src/datovka_shared/log/global.h"
#include "src/datovka_shared/log/log.h"
#include "src/datovka_shared/log/memory_log.h"
#include "src/dialogues/dialogues.h"
#include "src/files.h"
#include "src/global.h"
......@@ -151,6 +154,48 @@ QByteArray Files::getFileRawContentFromDb(const QString &userName, int fileId)
return fDb->getFileFromDb(fileId).binaryContent();
}
QString Files::loadLogContent(const QString &filePath)
{
debugFuncCall();
QString log;
log.append("<ul>");
if (filePath.isEmpty()) {
MemoryLog *mLog = GlobInstcs::logPtr->memoryLog();
if (mLog == Q_NULLPTR) {
return QString();
}
const QList<quint64> keys(mLog->keys());
foreach (quint64 key, keys) {
log.append("<li>");
log.append(mLog->message(key));
}
} else {
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Q_ASSERT(0);
logErrorNL("Cannot open file '%s'.",
filePath.toUtf8().constData());
return QString();
}
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
log.append("<li>");
log.append(line);
}
file.close();
}
log.append("</ul>");
return log;
}
void Files::openAttachmentFromDb(const QString &userName, int fileId)
{
debugFuncCall();
......@@ -244,6 +289,33 @@ void Files::openAttachmentFromPath(const QString &filePath)
#endif
}
bool Files::sendLogFileViaEmail(const QString &filePath)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
Q_ASSERT(0);
logErrorNL("Cannot open file '%s'.",
filePath.toUtf8().constData());
return false;
}
/* TODO */
QString log(file.readAll());
QStringList attachmentList;
attachmentList.append(filePath);
QString subject = tr("Log file");
QString body = tr("Log file");
removeDirFromDocLoc(DATOVKA_MAIL_DIR_NAME);
const QString boundary = generateBoundaryString();
QString emailMessage = createEmailMessage(body, subject, boundary);
addAttachmentToEmailMessage(emailMessage, "mdatovka.log",
log.toUtf8().toBase64(), boundary);
finishEmailMessage(emailMessage, boundary);
sendEmail(emailMessage, attachmentList, subject, body, 0);
return true;
}
void Files::sendMsgFilesWithEmail(const QString &userName, qint64 msgId,
MsgAttachFlags attachFlags)
{
......
......@@ -8,7 +8,7 @@
*
* 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
* 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
......@@ -115,6 +115,14 @@ public:
Q_INVOKABLE static
QByteArray getFileRawContentFromDb(const QString &userName, int fileId);
/*!
* @brief Load log content from file or memory into QML.
*
* @param[in] filePath Log file path (empty = use memory log).
*/
Q_INVOKABLE static
QString loadLogContent(const QString &filePath);
/*!
* @brief Open attachment from database.
*
......@@ -142,6 +150,14 @@ public:
Q_INVOKABLE static
void openAttachmentFromPath(const QString &filePath);
/*!
* @brief Send log via email.
*
* @param[in] filePath Log file path (empty = send memory log).
*/
Q_INVOKABLE static
bool sendLogFileViaEmail(const QString &filePath);
/*!
* @brief Send message attachments or complete zfo message
* from database with email application.
......
......@@ -8,7 +8,7 @@
*
* 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
* 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
......@@ -21,6 +21,7 @@
* the two.
*/
#include <QDateTime>
#include <QDir>
#include <QDirIterator>
#include <QRegExp>
......@@ -56,6 +57,11 @@ QString appEmailDirPath(const QString &msgIdStr)
QLatin1String(DATOVKA_MAIL_DIR_NAME) + QDir::separator() + msgIdStr);
}
QString appLogDirPath(void)
{
return existingAppPath(dfltAttachSavingLoc(), DATOVKA_LOG_DIR_NAME);
}
QString appMsgAttachDirPath(const QString &msgIdStr)
{
return existingAppPath(dfltAttachSavingLoc(), msgIdStr);
......@@ -220,3 +226,39 @@ QString writeFile(const QString &filePath, const QString &fileName,
return fullName;
}
void deleteOldestLogFile(void)
{
debugFuncCall();
QDir locFileLocation(appLogDirPath());
QFileInfoList logFiles(locFileLocation.entryInfoList(
QStringList() << "*.log", QDir::Files));
if (logFiles.count() <= DATOVKA_MAX_LOG_FILES) {
return;
}
/* Find and delete oldest log file */
QFileInfo oldest;
foreach (QFileInfo fileInfo, logFiles) {
if (oldest.filePath().isEmpty() ||
fileInfo.created() < oldest.created()) {
oldest = fileInfo;
}
}
QFile logFile(oldest.filePath());
if (logFile.remove()) {
logInfoNL("Deleted oldest log file: '%s'.",
oldest.filePath().toUtf8().constData());
}
}
QString constructLogFileName(void) {
QString logFileName("mdatovka_"
+ QDateTime::currentDateTime().toString("MMddhhmmss")
+ ".log");
return appLogDirPath() + QDir::separator() + logFileName;
}
......@@ -8,7 +8,7 @@
*
* 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
* 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
......@@ -31,9 +31,15 @@
*/
#define DATOVKA_BASE_DIR_NAME "Datovka"
#define DATOVKA_CERT_DIR_NAME "Certs"
#define DATOVKA_LOG_DIR_NAME "Logs"
#define DATOVKA_MAIL_DIR_NAME "Email"
#define DATOVKA_TEMP_DIR_NAME "Temp"
/*!
* @brief Max number of log files.
*/
#define DATOVKA_MAX_LOG_FILES 5
/*!
* @brief Return path to location where the application stores the attachments.
*
......@@ -57,6 +63,13 @@ QString appCertDirPath(void);
*/
QString appEmailDirPath(const QString &msgIdStr);
/*!
* @brief Return path to location where the application stores log files.
*
* @return Full path.
*/
QString appLogDirPath(void);
/*!
* @brief Return path to location where attachments of a particular message
* can be stored.
......@@ -147,3 +160,15 @@ QString existingAppPath(const QString &basePath, const QString &dirName);
*/
QString writeFile(const QString &filePath, const QString &fileName,
const QByteArray &data, bool deleteOnError = false);
/*!
* @brief Delete oldest log file from local storage.
*/
void deleteOldestLogFile(void);
/*!
* @brief Construct log path and file file.
*
* @return Full path including log file name.
*/
QString constructLogFileName(void);
......@@ -8,7 +8,7 @@
*
* 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
* 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
......@@ -40,6 +40,7 @@
#include "src/datovka_shared/io/records_management_db.h"
#include "src/datovka_shared/localisation/localisation.h"
#include "src/datovka_shared/log/log.h"
#include "src/datovka_shared/log/memory_log.h"
#include "src/datovka_shared/settings/records_management.h"
#include "src/datovka_shared/worker/pool.h"
#include "src/dialogues/qml_dialogue_helper.h"
......@@ -117,6 +118,7 @@ const struct QmlTypeEntry qmlPages[] = {
{ "PageDataboxDetail", 1, 0 },
{ "PageDataboxSearch", 1, 0 },
{ "PageImportMessage", 1, 0 },
{ "PageLog", 1, 0 },
{ "PageMenuAccount", 1, 0 },
{ "PageMenuDatovkaSettings", 1, 0 },
{ "PageMenuMessage", 1, 0 },
......@@ -263,10 +265,6 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
/* Log everything. */
GlobInstcs::logPtr->setLogLevelBits(LogDevice::LF_STDERR, LOGSRC_ANY,
LOG_UPTO(LOG_DEBUG));
/* Set application data, identification, etc. */
app.setOrganizationName(APP_ORG_NAME);
app.setOrganizationDomain(APP_ORG_DOMAIN);
......@@ -282,8 +280,21 @@ int main(int argc, char *argv[])
#endif
}
/* Memory log. */
MemoryLog memLog;
/* At least 2 or 3 maximum-sized (20 MB) ZFOs should fit into 80 MB. */
memLog.setMaxMemory(80 * 1024 * 1024);
GlobInstcs::logPtr->installMemoryLog(&memLog);
/* File log. */
GlobInstcs::logPtr->openFile(constructLogFileName(),
LogDevice::LM_WRONLY);
GlobInstcs::logPtr->setLogLevelBits(LogDevice::LF_STDERR, LOGSRC_ANY,
LOG_UPTO(LOG_DEBUG));
GlobInstcs::logPtr->setDebugVerbosity(2);
GlobInstcs::logPtr->setLogVerbosity(0);
deleteOldestLogFile();
/*
* This object needs to be created in the same thread as the
......@@ -584,6 +595,7 @@ int main(int argc, char *argv[])
}
/* Check for certificates. */
/*
{
const struct pem_str *pem_desc = conn_pem_strs;
Q_ASSERT(Q_NULLPTR != pem_desc);
......@@ -613,6 +625,7 @@ int main(int argc, char *argv[])
++pem_desc;
}
}
*/
/* Deletion of messages from db is disabled when equal to 0. */
if (GlobInstcs::setPtr->msgLifeTimeInDays > 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment