Merge pull request #520 from vsvyatski/develop

Add context menu entry to clean the Recycle Bin in databases
This commit is contained in:
louib 2017-04-22 19:14:45 -04:00 committed by GitHub
commit ad79162061
14 changed files with 208 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -308,6 +308,22 @@ void Database::recycleGroup(Group* group)
} }
} }
void Database::emptyRecycleBin()
{
if (m_metadata->recycleBinEnabled() && m_metadata->recycleBin()) {
// destroying direct entries of the recycle bin
QList<Entry*> subEntries = m_metadata->recycleBin()->entries();
for (Entry* entry : subEntries) {
delete entry;
}
// destroying direct subgroups of the recycle bin
QList<Group*> subGroups = m_metadata->recycleBin()->children();
for (Group* group : subGroups) {
delete group;
}
}
}
void Database::merge(const Database* other) void Database::merge(const Database* other)
{ {
m_rootGroup->merge(other->rootGroup()); m_rootGroup->merge(other->rootGroup());

View File

@ -108,6 +108,7 @@ public:
bool verifyKey(const CompositeKey& key) const; bool verifyKey(const CompositeKey& key) const;
void recycleEntry(Entry* entry); void recycleEntry(Entry* entry);
void recycleGroup(Group* group); void recycleGroup(Group* group);
void emptyRecycleBin();
void setEmitModified(bool value); void setEmitModified(bool value);
void copyAttributesFrom(const Database* other); void copyAttributesFrom(const Database* other);
void merge(const Database* other); void merge(const Database* other);

View File

@ -1267,3 +1267,25 @@ void DatabaseWidget::hideMessage()
m_messageWidget->animatedHide(); m_messageWidget->animatedHide();
} }
} }
bool DatabaseWidget::isRecycleBinSelected() const
{
return m_groupView->currentGroup() && m_groupView->currentGroup() == m_db->metadata()->recycleBin();
}
void DatabaseWidget::emptyRecycleBin()
{
if(!isRecycleBinSelected()) {
return;
}
QMessageBox::StandardButton result = MessageBox::question(
this, tr("Empty recycle bin?"),
tr("Are you sure you want to permanently delete everything from your recycle bin?"),
QMessageBox::Yes | QMessageBox::No);
if (result == QMessageBox::Yes) {
m_db->emptyRecycleBin();
refreshSearch();
}
}

View File

@ -102,6 +102,7 @@ public:
void closeUnlockDialog(); void closeUnlockDialog();
void blockAutoReload(bool block = true); void blockAutoReload(bool block = true);
void refreshSearch(); void refreshSearch();
bool isRecycleBinSelected() const;
signals: signals:
void closeRequest(); void closeRequest();
@ -152,6 +153,7 @@ public slots:
void switchToImportKeepass1(const QString& fileName); void switchToImportKeepass1(const QString& fileName);
void databaseModified(); void databaseModified();
void databaseSaved(); void databaseSaved();
void emptyRecycleBin();
// Search related slots // Search related slots
void search(const QString& searchtext); void search(const QString& searchtext);

View File

@ -197,6 +197,7 @@ MainWindow::MainWindow()
m_ui->actionGroupNew->setIcon(filePath()->icon("actions", "group-new", false)); m_ui->actionGroupNew->setIcon(filePath()->icon("actions", "group-new", false));
m_ui->actionGroupEdit->setIcon(filePath()->icon("actions", "group-edit", false)); m_ui->actionGroupEdit->setIcon(filePath()->icon("actions", "group-edit", false));
m_ui->actionGroupDelete->setIcon(filePath()->icon("actions", "group-delete", false)); m_ui->actionGroupDelete->setIcon(filePath()->icon("actions", "group-delete", false));
m_ui->actionGroupEmptyRecycleBin->setIcon(filePath()->icon("actions", "group-empty-trash", false));
m_ui->actionSettings->setIcon(filePath()->icon("actions", "configure")); m_ui->actionSettings->setIcon(filePath()->icon("actions", "configure"));
m_ui->actionSettings->setMenuRole(QAction::PreferencesRole); m_ui->actionSettings->setMenuRole(QAction::PreferencesRole);
@ -295,6 +296,8 @@ MainWindow::MainWindow()
SLOT(switchToGroupEdit())); SLOT(switchToGroupEdit()));
m_actionMultiplexer.connect(m_ui->actionGroupDelete, SIGNAL(triggered()), m_actionMultiplexer.connect(m_ui->actionGroupDelete, SIGNAL(triggered()),
SLOT(deleteGroup())); SLOT(deleteGroup()));
m_actionMultiplexer.connect(m_ui->actionGroupEmptyRecycleBin, SIGNAL(triggered()),
SLOT(emptyRecycleBin()));
connect(m_ui->actionSettings, SIGNAL(triggered()), SLOT(switchToSettings())); connect(m_ui->actionSettings, SIGNAL(triggered()), SLOT(switchToSettings()));
connect(m_ui->actionPasswordGenerator, SIGNAL(toggled(bool)), SLOT(switchToPasswordGen(bool))); connect(m_ui->actionPasswordGenerator, SIGNAL(toggled(bool)), SLOT(switchToPasswordGen(bool)));
@ -413,6 +416,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1; bool singleEntrySelected = dbWidget->numberOfSelectedEntries() == 1;
bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0; bool entriesSelected = dbWidget->numberOfSelectedEntries() > 0;
bool groupSelected = dbWidget->isGroupSelected(); bool groupSelected = dbWidget->isGroupSelected();
bool recycleBinSelected = dbWidget->isRecycleBinSelected();
m_ui->actionEntryNew->setEnabled(!inSearch); m_ui->actionEntryNew->setEnabled(!inSearch);
m_ui->actionEntryClone->setEnabled(singleEntrySelected); m_ui->actionEntryClone->setEnabled(singleEntrySelected);
@ -429,6 +433,8 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionGroupNew->setEnabled(groupSelected); m_ui->actionGroupNew->setEnabled(groupSelected);
m_ui->actionGroupEdit->setEnabled(groupSelected); m_ui->actionGroupEdit->setEnabled(groupSelected);
m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup()); m_ui->actionGroupDelete->setEnabled(groupSelected && dbWidget->canDeleteCurrentGroup());
m_ui->actionGroupEmptyRecycleBin->setVisible(recycleBinSelected);
m_ui->actionGroupEmptyRecycleBin->setEnabled(recycleBinSelected);
m_ui->actionChangeMasterKey->setEnabled(true); m_ui->actionChangeMasterKey->setEnabled(true);
m_ui->actionChangeDatabaseSettings->setEnabled(true); m_ui->actionChangeDatabaseSettings->setEnabled(true);
m_ui->actionDatabaseSave->setEnabled(true); m_ui->actionDatabaseSave->setEnabled(true);

View File

@ -162,7 +162,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>800</width>
<height>29</height> <height>21</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">
@ -235,8 +235,10 @@
<string>&amp;Groups</string> <string>&amp;Groups</string>
</property> </property>
<addaction name="actionGroupNew"/> <addaction name="actionGroupNew"/>
<addaction name="separator"/>
<addaction name="actionGroupEdit"/> <addaction name="actionGroupEdit"/>
<addaction name="actionGroupDelete"/> <addaction name="actionGroupDelete"/>
<addaction name="actionGroupEmptyRecycleBin"/>
</widget> </widget>
<widget class="QMenu" name="menuTools"> <widget class="QMenu" name="menuTools">
<property name="title"> <property name="title">
@ -521,6 +523,14 @@
<string>Re&amp;pair database</string> <string>Re&amp;pair database</string>
</property> </property>
</action> </action>
<action name="actionGroupEmptyRecycleBin">
<property name="text">
<string>Empty recycle bin</string>
</property>
<property name="visible">
<bool>false</bool>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -177,6 +177,9 @@ add_unit_test(NAME testykchallengeresponsekey
SOURCES TestYkChallengeResponseKey.cpp TestYkChallengeResponseKey.h SOURCES TestYkChallengeResponseKey.cpp TestYkChallengeResponseKey.h
LIBS ${TEST_LIBRARIES}) LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testdatabase SOURCES TestDatabase.cpp
LIBS ${TEST_LIBRARIES})
if(WITH_GUI_TESTS) if(WITH_GUI_TESTS)
add_subdirectory(gui) add_subdirectory(gui)
endif(WITH_GUI_TESTS) endif(WITH_GUI_TESTS)

112
tests/TestDatabase.cpp Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2017 Vladimir Svyatski <v.unreal@gmail.com>
*
* 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 2 or (at your option)
* version 3 of the License.
*
* 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/>.
*/
#include "TestDatabase.h"
#include <QTest>
#include <QSignalSpy>
#include <QTemporaryFile>
#include "config-keepassx-tests.h"
#include "core/Database.h"
#include "crypto/Crypto.h"
#include "keys/PasswordKey.h"
#include "core/Metadata.h"
#include "core/Group.h"
#include "format/KeePass2Writer.h"
QTEST_GUILESS_MAIN(TestDatabase)
void TestDatabase::initTestCase()
{
QVERIFY(Crypto::init());
}
void TestDatabase::testEmptyRecycleBinOnDisabled()
{
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinDisabled.kdbx");
CompositeKey key;
key.addKey(PasswordKey("123"));
Database* db = Database::openDatabaseFile(filename, key);
QVERIFY(db);
QSignalSpy spyModified(db, SIGNAL(modifiedImmediate()));
db->emptyRecycleBin();
//The database must be unmodified in this test after emptying the recycle bin.
QCOMPARE(spyModified.count(), 0);
delete db;
}
void TestDatabase::testEmptyRecycleBinOnNotCreated()
{
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinNotYetCreated.kdbx");
CompositeKey key;
key.addKey(PasswordKey("123"));
Database* db = Database::openDatabaseFile(filename, key);
QVERIFY(db);
QSignalSpy spyModified(db, SIGNAL(modifiedImmediate()));
db->emptyRecycleBin();
//The database must be unmodified in this test after emptying the recycle bin.
QCOMPARE(spyModified.count(), 0);
delete db;
}
void TestDatabase::testEmptyRecycleBinOnEmpty()
{
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinEmpty.kdbx");
CompositeKey key;
key.addKey(PasswordKey("123"));
Database* db = Database::openDatabaseFile(filename, key);
QVERIFY(db);
QSignalSpy spyModified(db, SIGNAL(modifiedImmediate()));
db->emptyRecycleBin();
//The database must be unmodified in this test after emptying the recycle bin.
QCOMPARE(spyModified.count(), 0);
delete db;
}
void TestDatabase::testEmptyRecycleBinWithHierarchicalData()
{
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinWithData.kdbx");
CompositeKey key;
key.addKey(PasswordKey("123"));
Database* db = Database::openDatabaseFile(filename, key);
QVERIFY(db);
QFile originalFile(filename);
qint64 initialSize = originalFile.size();
db->emptyRecycleBin();
QVERIFY(db->metadata()->recycleBin());
QVERIFY(db->metadata()->recycleBin()->entries().empty());
QVERIFY(db->metadata()->recycleBin()->children().empty());
QTemporaryFile afterCleanup;
KeePass2Writer writer;
writer.writeDatabase(&afterCleanup, db);
QVERIFY(afterCleanup.size() < initialSize);
delete db;
}

35
tests/TestDatabase.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 Vladimir Svyatski <v.unreal@gmail.com>
*
* 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 2 or (at your option)
* version 3 of the License.
*
* 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/>.
*/
#ifndef KEEPASSX_TESTDATABASE_H
#define KEEPASSX_TESTDATABASE_H
#include <QObject>
class TestDatabase : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void testEmptyRecycleBinOnDisabled();
void testEmptyRecycleBinOnNotCreated();
void testEmptyRecycleBinOnEmpty();
void testEmptyRecycleBinWithHierarchicalData();
};
#endif // KEEPASSX_TESTDATABASE_H

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.