Commit 0b4b3f76 authored by Laurent Montel's avatar Laurent Montel 😁
Browse files

Add job for clearing akonadi collection cache

parent f33abf5b
Pipeline #200022 passed with stage
in 6 minutes and 16 seconds
......@@ -92,6 +92,11 @@ target_sources(KF5AkonadiWidgets PRIVATE
tagwidget.h
tagselectwidget.h
clearcachejob.cpp
clearcachejob.h
dbaccess.cpp
dbaccess.h
)
ecm_qt_declare_logging_category(KF5AkonadiWidgets HEADER akonadiwidgets_debug.h IDENTIFIER AKONADIWIDGETS_LOG CATEGORY_NAME org.kde.pim.akonadiwidgets
......@@ -125,6 +130,7 @@ ecm_generate_headers(AkonadiWidgets_CC_HEADERS
AgentInstanceWidget
AgentTypeDialog
AgentTypeWidget
ClearCacheJob
CollectionComboBox
CollectionDialog
CollectionPropertiesDialog
......@@ -133,6 +139,7 @@ ecm_generate_headers(AkonadiWidgets_CC_HEADERS
CollectionRequester
CollectionStatisticsDelegate
ControlGui
DbAccess
EntityListView
EntityTreeView
ETMViewStateSaver
......
/*
This file is part of Akonadi
SPDX-FileCopyrightText: 2022 Laurent Montel <montel@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "clearcachejob.h"
#include "akonadiwidgets_debug.h"
#include "dbaccess.h"
#include <KLocalizedString>
#include <KMessageBox>
#include <QSqlError>
#include <QSqlQuery>
using namespace Akonadi;
ClearCacheJob::ClearCacheJob(QObject *parent)
: QObject{parent}
{
}
ClearCacheJob::~ClearCacheJob() = default;
const Akonadi::Collection &ClearCacheJob::collection() const
{
return mCollection;
}
void ClearCacheJob::setCollection(const Akonadi::Collection &newCollection)
{
mCollection = newCollection;
}
void ClearCacheJob::start()
{
if (!canStart()) {
deleteLater();
return;
}
const auto ridCount = QStringLiteral("SELECT COUNT(*) FROM PimItemTable WHERE collectionId=%1 AND remoteId=''").arg(mCollection.id());
QSqlQuery query(DbAccess::database());
if (!query.exec(ridCount)) {
qCWarning(AKONADIWIDGETS_LOG) << "Failed to execute query" << ridCount << ":" << query.lastError().text();
KMessageBox::error(mParentWidget, query.lastError().text());
return;
}
query.next();
const int emptyRidCount = query.value(0).toInt();
if (emptyRidCount > 0) {
if (KMessageBox::warningContinueCancel(mParentWidget,
QStringLiteral("The collection '%1' contains %2 items without Remote ID. "
"Those items were likely never uploaded to the destination server, "
"so clearing this collection means that those <b>data will be lost</b>. "
"Are you sure you want to proceed?")
.arg(mCollection.id())
.arg(emptyRidCount),
QStringLiteral("POSSIBLE DATA LOSS!"))
== KMessageBox::Cancel) {
return;
}
}
const QString str = QStringLiteral("DELETE FROM PimItemTable WHERE collectionId=%1").arg(mCollection.id());
qCWarning(AKONADIWIDGETS_LOG) << str;
query = QSqlQuery(str, DbAccess::database());
if (query.exec()) {
if (query.lastError().isValid()) {
qCWarning(AKONADIWIDGETS_LOG) << query.lastError();
KMessageBox::error(mParentWidget, query.lastError().text());
}
}
// TODO: Clear external parts
// TODO: Reset Akonadi's internal collection statistics cache
// TODO: Notify all clients EXCEPT FOR THE RESOURCE about the deletion?
// TODO: Clear search index
// TODO: ???
KMessageBox::information(mParentWidget, QStringLiteral("Collection cache cleared. You should restart Akonadi now."));
}
bool ClearCacheJob::canStart() const
{
return mCollection.isValid();
}
QWidget *ClearCacheJob::parentWidget() const
{
return mParentWidget;
}
void ClearCacheJob::setParentWidget(QWidget *newParentWidget)
{
mParentWidget = newParentWidget;
}
/*
This file is part of Akonadi
SPDX-FileCopyrightText: 2022 Laurent Montel <montel@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include "akonadiwidgets_export.h"
#include <Akonadi/Collection>
#include <QObject>
namespace Akonadi
{
class AKONADIWIDGETS_EXPORT ClearCacheJob : public QObject
{
Q_OBJECT
public:
explicit ClearCacheJob(QObject *parent = nullptr);
~ClearCacheJob() override;
Q_REQUIRED_RESULT const Akonadi::Collection &collection() const;
void setCollection(const Akonadi::Collection &newCollection);
void start();
Q_REQUIRED_RESULT bool canStart() const;
Q_REQUIRED_RESULT QWidget *parentWidget() const;
void setParentWidget(QWidget *newParentWidget);
private:
Akonadi::Collection mCollection;
QWidget *mParentWidget = nullptr;
};
}
/*
SPDX-FileCopyrightText: 2009 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "dbaccess.h"
#include <Akonadi/ServerManager>
#include <QSettings>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <KMessageBox>
using namespace Akonadi;
class DbAccessPrivate
{
public:
DbAccessPrivate()
{
init();
}
void init()
{
const QString serverConfigFile = ServerManager::serverConfigFilePath(ServerManager::ReadWrite);
QSettings settings(serverConfigFile, QSettings::IniFormat);
const QString driver = settings.value(QStringLiteral("General/Driver"), QStringLiteral("QMYSQL")).toString();
database = QSqlDatabase::addDatabase(driver);
settings.beginGroup(driver);
database.setHostName(settings.value(QStringLiteral("Host"), QString()).toString());
database.setDatabaseName(settings.value(QStringLiteral("Name"), QStringLiteral("akonadi")).toString());
database.setUserName(settings.value(QStringLiteral("User"), QString()).toString());
database.setPassword(settings.value(QStringLiteral("Password"), QString()).toString());
database.setConnectOptions(settings.value(QStringLiteral("Options"), QString()).toString());
if (!database.open()) {
KMessageBox::error(nullptr, QStringLiteral("Failed to connect to database: %1").arg(database.lastError().text()));
}
}
QSqlDatabase database;
};
Q_GLOBAL_STATIC(DbAccessPrivate, sInstance)
QSqlDatabase DbAccess::database()
{
// hack to detect database gone away error
QSqlQuery query(sInstance->database);
// prepare or exec of "SELECT 1" will only fail when we are not connected to database
if (!query.prepare(QStringLiteral("SELECT 1")) || !query.exec()) {
sInstance->database.close();
QSqlDatabase::removeDatabase(sInstance->database.connectionName());
sInstance->init();
}
return sInstance->database;
}
/*
SPDX-FileCopyrightText: 2009 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include "akonadiwidgets_export.h"
class QSqlDatabase;
namespace DbAccess
{
AKONADIWIDGETS_EXPORT QSqlDatabase database();
}
Supports Markdown
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