KUserFeedback

auditloguicontroller.cpp
1/*
2 SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: MIT
5*/
6
7#include "auditloguicontroller.h"
8
9#include <provider.h>
10
11#include <QAbstractListModel>
12#include <QDateTime>
13#include <QDebug>
14#include <QDir>
15#include <QJsonArray>
16#include <QJsonDocument>
17#include <QJsonObject>
18#include <QLocale>
19#include <QMetaEnum>
20#include <QStandardPaths>
21
22#include <algorithm>
23#include <vector>
24
25using namespace KUserFeedback;
26
27namespace KUserFeedback {
28class AuditLogEntryModel : public QAbstractListModel
29{
31public:
32 explicit AuditLogEntryModel(const QString &path, QObject *parent);
33
34 void reload();
35
36 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
37 QVariant data(const QModelIndex &index, int role) const override;
38
39 QHash<int, QByteArray> roleNames() const override;
40
41private:
42 QString m_path;
43 std::vector<QDateTime> m_entries;
44};
45
46
47class AuditLogUiControllerPrivate
48{
49public:
50 QString path;
51 AuditLogEntryModel *logEntryModel;
52};
53}
54
55
56AuditLogEntryModel::AuditLogEntryModel(const QString &path, QObject *parent)
57 : QAbstractListModel(parent)
58 , m_path(path)
59{
60 reload();
61}
62
63void AuditLogEntryModel::reload()
64{
66 m_entries.clear();
67
68 foreach (auto e, QDir(m_path).entryList(QDir::Files | QDir::Readable)) {
69 if (!e.endsWith(QLatin1String(".log")))
70 continue;
71 e.chop(4);
72 const auto dt = QDateTime::fromString(e, QStringLiteral("yyyyMMdd-hhmmss"));
73 if (dt.isValid())
74 m_entries.push_back(dt);
75 }
76 std::sort(m_entries.begin(), m_entries.end(), [](const QDateTime &lhs, const QDateTime &rhs) {
77 return lhs > rhs;
78 });
80}
81
82int AuditLogEntryModel::rowCount(const QModelIndex &parent) const
83{
84 if (parent.isValid())
85 return 0;
86 return m_entries.size();
87}
88
89QVariant AuditLogEntryModel::data(const QModelIndex &index, int role) const
90{
91 switch (role) {
92 case Qt::DisplayRole:
93 return QLocale().toString(m_entries[index.row()]);
94 case Qt::UserRole:
95 return m_entries[index.row()];
96 }
97 return QVariant();
98}
99
100QHash<int, QByteArray> AuditLogEntryModel::roleNames() const
101{
103 roles.insert(Qt::DisplayRole, "display");
104 roles.insert(Qt::UserRole, "data");
105 return roles;
106}
107
108
109AuditLogUiController::AuditLogUiController(QObject* parent)
110 : QObject(parent)
111 , d(new AuditLogUiControllerPrivate)
112{
113 d->path = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QStringLiteral("/kuserfeedback/audit/");
114 d->logEntryModel = new AuditLogEntryModel(d->path, this);
115
117}
118
119AuditLogUiController::~AuditLogUiController()
120{
121}
122
124{
125 return d->logEntryModel->rowCount() != 0;
126}
127
129{
130 return d->logEntryModel;
131}
132
133static QString telemetryModeString(Provider::TelemetryMode mode)
134{
135 switch (mode) {
137 Q_ASSERT(false);
138 return QString();
140 return AuditLogUiController::tr("Basic System Information");
142 return AuditLogUiController::tr("Basic Usage Statistics");
144 return AuditLogUiController::tr("Detailed System Information");
146 return AuditLogUiController::tr("Detailed Usage Statistics");
147 }
148 Q_UNREACHABLE();
149}
150
152{
153 const QString fn = d->path + dt.toString(QStringLiteral("yyyyMMdd-hhmmss")) + QStringLiteral(".log");
154 QFile file(fn);
155 if (!file.open(QFile::ReadOnly))
156 return tr("Unable to open file %1: %2.").arg(fn, file.errorString());
157
158 const auto doc = QJsonDocument::fromJson(file.readAll());
159 const auto topObj = doc.object();
160 struct Entry {
161 QString key;
162 QString desc;
163 QString rawData;
165 };
166 std::vector<Entry> entries;
167 entries.reserve(topObj.size());
168
169 const auto idx = Provider::staticMetaObject.indexOfEnumerator("TelemetryMode");
170 Q_ASSERT(idx >= 0);
171 const auto modeEnum = Provider::staticMetaObject.enumerator(idx);
172
173 for (auto it = topObj.begin(); it != topObj.end(); ++it) {
174 Entry e;
175 e.key = it.key();
176 const auto obj = it.value().toObject();
177 e.desc = obj.value(QLatin1String("description")).toString();
178 const auto data = obj.value(QLatin1String("data"));
179 if (data.isObject())
180 e.rawData = QString::fromUtf8(QJsonDocument(data.toObject()).toJson());
181 else if (data.isArray())
182 e.rawData = QString::fromUtf8(QJsonDocument(data.toArray()).toJson());
183 e.mode = static_cast<Provider::TelemetryMode>(modeEnum.keyToValue(obj.value(QLatin1String("telemetryMode")).toString().toUtf8().constData()));
184 entries.push_back(e);
185 }
186
187 std::sort(entries.begin(), entries.end(), [](const Entry &lhs, const Entry &rhs) -> bool {
188 if (lhs.mode == rhs.mode)
189 return lhs.key < rhs.key;
190 return lhs.mode < rhs.mode;
191 });
192
193 QString res;
194 for (auto it = entries.begin(); it != entries.end(); ++it) {
195 res += QStringLiteral("<b>") + (*it).desc + QStringLiteral("</b><br/>");
196 res += tr("Category: <i>%1</i><br/>").arg(telemetryModeString((*it).mode));
197 res += tr("Key: <i>%1</i><br/>").arg((*it).key);
198 res += tr("Submitted data: <tt>%1</tt><br/><br/>").arg((*it).rawData);
199 }
200 return res;
201}
202
204{
205 QDir dir(d->path);
206 foreach (auto e, dir.entryList(QDir::Files | QDir::Readable)) {
207 if (!e.endsWith(QLatin1String(".log")))
208 continue;
209 dir.remove(e);
210 }
211
212 d->logEntryModel->reload();
213}
214
215#include "auditloguicontroller.moc"
216
217#include "moc_auditloguicontroller.cpp"
void logEntryCountChanged()
Change notification for the hasLogEntries property.
QAbstractItemModel * logEntryModel
Returns a model listing all log entries.
Q_INVOKABLE QString logEntry(const QDateTime &dt) const
Returns a formatted text for display of the specified log entry.
void clear()
Delete all audit log entries.
bool hasLogEntries
Returns true if there are log entries to display.
TelemetryMode
Telemetry collection modes.
Definition provider.h:102
@ BasicSystemInformation
Transmit basic information about the system.
Definition provider.h:104
@ DetailedSystemInformation
Transmit detailed system information.
Definition provider.h:106
@ DetailedUsageStatistics
Transmit detailed usage statistics.
Definition provider.h:107
@ BasicUsageStatistics
Transmit basic usage statistics.
Definition provider.h:105
@ NoTelemetry
Transmit no data at all.
Definition provider.h:103
QString path(const QString &relativePath)
const QList< QKeySequence > & reload()
Classes for integrating telemetry collection, survey targeting, and contribution encouragenemt and co...
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
QString toString(QStringView format, QCalendar cal) const const
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
iterator insert(const Key &key, const T &value)
QString errorString() const const
QByteArray readAll()
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QByteArray toJson(JsonFormat format) const const
QString toString(QDate date, FormatType format) const const
int row() const const
Q_OBJECTQ_OBJECT
QObject * parent() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
QString writableLocation(StandardLocation type)
QString arg(Args &&... args) const const
QString fromUtf8(QByteArrayView str)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
void reserve(qsizetype size)
DisplayRole
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:56 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.