From 7a2b12419d34a8d7de0a620fe12e346a61882681 Mon Sep 17 00:00:00 2001 From: Quentin Rouland Date: Mon, 20 Jan 2025 15:46:57 +0100 Subject: [PATCH] Refactor unzip password store --- plugins/Pass/jobs/rmjob.h | 2 +- plugins/Pass/pass.cpp | 5 +++ plugins/Pass/pass.h | 2 +- plugins/Utils/CMakeLists.txt | 1 + plugins/Utils/jobs/unzipjob.cpp | 57 ++++++++++++++++++++++++ plugins/Utils/jobs/unzipjob.h | 49 +++++++++++++++++++++ plugins/Utils/utils.cpp | 74 ++++++++++++-------------------- plugins/Utils/utils.h | 49 ++++++++++----------- po/utpass.qrouland.pot | 12 +++--- qml/pages/settings/ImportZip.qml | 16 ++++--- 10 files changed, 182 insertions(+), 85 deletions(-) create mode 100644 plugins/Utils/jobs/unzipjob.cpp create mode 100644 plugins/Utils/jobs/unzipjob.h diff --git a/plugins/Pass/jobs/rmjob.h b/plugins/Pass/jobs/rmjob.h index 18ba55b..e1c2694 100644 --- a/plugins/Pass/jobs/rmjob.h +++ b/plugins/Pass/jobs/rmjob.h @@ -24,7 +24,7 @@ signals: /** * @brief Signal emitted when the rm operation is complete. * - * @param err A boolean indicating whether an error occurred during cloning. + * @param err A boolean indicating whether an error occurred during removing. * `true` if an error occurred, `false` if the clone was successful. */ void resultReady(const bool err); diff --git a/plugins/Pass/pass.cpp b/plugins/Pass/pass.cpp index a36081e..87a80bb 100644 --- a/plugins/Pass/pass.cpp +++ b/plugins/Pass/pass.cpp @@ -71,6 +71,9 @@ void Pass::showResult(Error err, QString plain_text) bool Pass::deletePasswordStore() { + if (!this->m_sem->tryAcquire(1, 500)) { + return false; + } qInfo() << "Pass delete Password Store"; auto job = new RmJob(this->password_store()); qDebug() << "Delete Password Store at " << this->password_store(); @@ -82,6 +85,7 @@ bool Pass::deletePasswordStore() void Pass::deletePasswordStoreResult(bool err) { + qDebug() << "Pass delete Password StoreResult"; if (err) { //dir.removeRecursively()) { qInfo() << "Pass delete Password Store Failed"; @@ -91,6 +95,7 @@ void Pass::deletePasswordStoreResult(bool err) qInfo() << "Pass delete Password Store Succeed"; emit deletePasswordStoreSucceed(); } + this->m_sem->release(1); } diff --git a/plugins/Pass/pass.h b/plugins/Pass/pass.h index a2bd0dd..5db6f29 100644 --- a/plugins/Pass/pass.h +++ b/plugins/Pass/pass.h @@ -137,7 +137,7 @@ private: public: /** - * @brief Constructs the Pass object and initializes necessary resources. + * @brief Constructs the Pass object. */ Pass(); diff --git a/plugins/Utils/CMakeLists.txt b/plugins/Utils/CMakeLists.txt index 7c2a389..f227a90 100644 --- a/plugins/Utils/CMakeLists.txt +++ b/plugins/Utils/CMakeLists.txt @@ -5,6 +5,7 @@ set( SRC plugin.cpp utils.cpp + jobs/unzipjob.cpp ) set(CMAKE_AUTOMOC ON) diff --git a/plugins/Utils/jobs/unzipjob.cpp b/plugins/Utils/jobs/unzipjob.cpp new file mode 100644 index 0000000..107ffa7 --- /dev/null +++ b/plugins/Utils/jobs/unzipjob.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +#include "qdebug.h" +#include "unzipjob.h" + +UnzipJob::UnzipJob(QUrl zip_url, QDir dir_out): + m_zip_url(zip_url), + m_dir_out(dir_out) +{ + this->setObjectName("UnzipJob"); +} + +void UnzipJob::run() +{ + auto tmp_dir_path = QStandardPaths::writableLocation( + QStandardPaths::CacheLocation).append("/unzip"); + + QDir tmp_dir(tmp_dir_path); + tmp_dir.removeRecursively(); + tmp_dir.mkpath("."); + + qDebug() << "Temp dir path is " << tmp_dir_path; + auto status = !JlCompress::extractDir( + this->m_zip_url.toLocalFile(), + tmp_dir_path + ).isEmpty(); + + if (!status) { + tmp_dir.removeRecursively(); + emit resultReady(false); + return; + } + + qDebug() << "Guessing if it should remove a single root folder"; + QStringList files_in_tmp_dir = tmp_dir.entryList(QDir::AllEntries | QDir::Hidden | + QDir::NoDotAndDotDot); + + auto dir_import_path = + files_in_tmp_dir.length() == 1 ? + tmp_dir_path.append("/" + files_in_tmp_dir.first()) : tmp_dir_path; + qDebug() << "Final imported tmp path dir is " << dir_import_path; + + qDebug() << "Removing destination"; + this->m_dir_out.removeRecursively(); + + qDebug() << "Moving zip content to destination"; + QDir dir; + qDebug() << dir_import_path << " to " << this->m_dir_out; + auto ret = dir.rename(dir_import_path, this->m_dir_out.absolutePath()); + tmp_dir.removeRecursively();; + emit resultReady(ret); + +} diff --git a/plugins/Utils/jobs/unzipjob.h b/plugins/Utils/jobs/unzipjob.h new file mode 100644 index 0000000..541ee21 --- /dev/null +++ b/plugins/Utils/jobs/unzipjob.h @@ -0,0 +1,49 @@ +#ifndef RMJOB_H +#define RMJOB_H + +#include "qurl.h" +#include +#include + +/** + * @class RmJob + * @brief A class to handle removing recursively a path in a separate thread. + * + */ +class UnzipJob : public QThread +{ + Q_OBJECT + + /** + * @brief The main function that performs the unzip operation. + * + * Handles the process of unziping a archive to a target directory. + */ + void run() override; + +signals: + /** + * @brief Signal emitted when the unzip operation is complete. + * + * @param err A boolean indicating whether an error occurred during unzipping. + * `true` if an error occurred, `false` if the clone was successful. + */ + void resultReady(const bool err); + +private: + QUrl m_zip_url; ///< The url of the archive. + QDir m_dir_out; ///< The directory where the content of the archive will be unzip. + +public: + /** + * @brief Constructor for the UnzipJob class. + * + * Initializes the UnzipJob with the specified target path to be removed. + * + * @param zip_url Url of the archive to be unzip. + * @param dir_out Target directory where the content of the archive must be extracted. + */ + UnzipJob(QUrl zip_url, QDir dir_out); +}; + +#endif // RMJOB_H diff --git a/plugins/Utils/utils.cpp b/plugins/Utils/utils.cpp index c6fc13a..dbe8d7b 100644 --- a/plugins/Utils/utils.cpp +++ b/plugins/Utils/utils.cpp @@ -1,67 +1,47 @@ -#include #include -#include -#include -#include +#include +#include "jobs/unzipjob.h" #include "utils.h" + +Utils::Utils(): + m_sem(std::unique_ptr(new QSemaphore(1))) +{} + bool Utils::unzip(QUrl zip_url, QString dir_out_path) { - auto tmp_dir_path = QStandardPaths::writableLocation( - QStandardPaths::CacheLocation).append("/unzip"); - - QDir tmp_dir(tmp_dir_path); - tmp_dir.removeRecursively(); - tmp_dir.mkpath("."); - - qDebug() << "Temp dir path is " << tmp_dir_path; - auto status = !JlCompress::extractDir( - zip_url.toLocalFile(), - tmp_dir_path - ).isEmpty(); - - if (!status) { - tmp_dir.removeRecursively(); + if (!this->m_sem->tryAcquire(1, 500)) { return false; } - - qDebug() << "Guessing if it should remove a single root folder"; - QStringList files_in_tmp_dir = tmp_dir.entryList(QDir::AllEntries | QDir::Hidden | - QDir::NoDotAndDotDot); - - auto dir_import_path = - files_in_tmp_dir.length() == 1 ? - tmp_dir_path.append("/" + files_in_tmp_dir.first()) : tmp_dir_path; - qDebug() << "Final imported tmp path dir is " << dir_import_path; - - qDebug() << "Removing destination"; - QDir dir_out(dir_out_path); - dir_out.removeRecursively(); - - qDebug() << "Moving zip content to destination"; - QDir dir; - qDebug() << dir_import_path << " to " << dir_out_path; - auto ret = dir.rename(dir_import_path, dir_out_path); - tmp_dir.removeRecursively();; - return ret; + qInfo() << "Unzip path " << zip_url << " to " << dir_out_path; + auto job = new UnzipJob(zip_url, QDir(dir_out_path)); + connect(job, &UnzipJob::resultReady, this, &Utils::unzipResult); + connect(job, &UnzipJob::finished, job, &QObject::deleteLater); + job->start(); + return true; } -bool Utils::rmFile(QUrl file_url) +void Utils::unzipResult(bool err) { - return QFile::remove(file_url.toLocalFile()); + + qDebug() << "Unzip Result"; + if (err) { + qInfo() << "Unzip Failed"; + emit unzipFailed("failed to unzip archive"); + + } else { + qInfo() << "Unzip Succeed"; + emit unzipSucceed(); + } + this->m_sem->release(1); } -bool Utils::rmDir(QUrl dir_url) -{ - QDir dir(dir_url.toLocalFile()); - return dir.removeRecursively(); -} QString Utils::manifestPath() { auto path = QDir(QDir::currentPath()).filePath("manifest_.json"); - qDebug() << "Manifest path : " << path; + qInfo() << "Manifest path : " << path; return path; } diff --git a/plugins/Utils/utils.h b/plugins/Utils/utils.h index 9fb781d..7e4dc85 100644 --- a/plugins/Utils/utils.h +++ b/plugins/Utils/utils.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include /** * @class Utils @@ -16,16 +18,34 @@ class Utils : public QObject { Q_OBJECT -public: + +private slots: /** - * @brief Default constructor for the Utils class. + * @brief Slot to handle the result of a unzip operation. + * @param err True if an error occurred during the operation. */ - Utils() = default; + void unzipResult(bool err); + +signals: + /** + * @brief Emitted when the archive is successfully extracted. + */ + void unzipSucceed(); /** - * @brief Default destructor for the Utils class. + * @brief Emitted when the unzipping operation fails. + * @param message The error message describing the failure. */ - ~Utils() override = default; + void unzipFailed(QString message); + +private: + std::unique_ptr m_sem; /**< Semaphore for managing concurrent operations. */ + +public: + /** + * @brief Constructor for the Utils class. + */ + Utils(); /** * @brief Unzips a ZIP file to the specified output directory. @@ -39,25 +59,6 @@ public: */ Q_INVOKABLE bool unzip(QUrl zip_url, QString dir_out); - /** - * @brief Removes a file at the specified URL. - * - * This method deletes a file at the specified URL. - * - * @param file_url The URL of the file to delete. - * @return `true` if the file was successfully removed, `false` otherwise. - */ - Q_INVOKABLE bool rmFile(QUrl file_url); - - /** - * @brief Removes a directory at the specified URL. - * - * This method deletes a directory at the specified URL, along with its contents. - * - * @param dir_url The URL of the directory to remove. - * @return `true` if the directory was successfully removed, `false` otherwise. - */ - Q_INVOKABLE bool rmDir(QUrl dir_url); /** diff --git a/po/utpass.qrouland.pot b/po/utpass.qrouland.pot index ab2df1d..395fc99 100644 --- a/po/utpass.qrouland.pot +++ b/po/utpass.qrouland.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: utpass.qrouland\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-01-20 15:00+0100\n" +"POT-Creation-Date: 2025-01-20 15:56+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -122,7 +122,7 @@ msgid "You're are about to delete
the current Password Store.
Continue ?" msgstr "" #: ../qml/pages/settings/DeleteRepo.qml:55 -#: ../qml/pages/settings/ImportZip.qml:62 +#: ../qml/pages/settings/ImportZip.qml:66 #: ../qml/pages/settings/InfoKeys.qml:140 #: ../qml/pages/settings/git/ImportGitClone.qml:55 msgid "Yes" @@ -153,21 +153,21 @@ msgstr "" msgid "GPG Key Import" msgstr "" -#: ../qml/pages/settings/ImportZip.qml:61 +#: ../qml/pages/settings/ImportZip.qml:65 msgid "" "Importing a new zip will delete
any existing password store!
Continue ?" msgstr "" -#: ../qml/pages/settings/ImportZip.qml:75 +#: ../qml/pages/settings/ImportZip.qml:79 msgid "Password store import failed !" msgstr "" -#: ../qml/pages/settings/ImportZip.qml:84 +#: ../qml/pages/settings/ImportZip.qml:88 #: ../qml/pages/settings/git/ImportGitClone.qml:77 msgid "Password store sucessfully imported !" msgstr "" -#: ../qml/pages/settings/ImportZip.qml:96 +#: ../qml/pages/settings/ImportZip.qml:100 msgid "Zip Password Store Import" msgstr "" diff --git a/qml/pages/settings/ImportZip.qml b/qml/pages/settings/ImportZip.qml index 35e5e14..b079b75 100644 --- a/qml/pages/settings/ImportZip.qml +++ b/qml/pages/settings/ImportZip.qml @@ -13,6 +13,16 @@ Page { property var activeTransfer Component.onCompleted: { + Utils.unzipSucceed.connect(function() { + PopupUtils.open(dialogImportZipPageSuccess); + // Utils.rmFile(importZipPage.activeTransfer.items[0].url); + importZipPage.activeTransfer = null; + }); + Utils.unzipFailed.connect(function(message) { + PopupUtils.open(dialogImportZipPageError); + // Utils.rmFile(importZipPage.activeTransfer.items[0].url); + importZipPage.activeTransfer = null; + }); PopupUtils.open(importZipPageImportValidation, importZipPage); } @@ -33,12 +43,6 @@ Page { console.log("Charged"); console.log(importZipPage.activeTransfer.items[0].url); var status = Utils.unzip(importZipPage.activeTransfer.items[0].url, Pass.getPasswordStore()); - Utils.rmFile(importZipPage.activeTransfer.items[0].url); - if (status) - PopupUtils.open(dialogImportZipPageSuccess); - else - PopupUtils.open(dialogImportZipPageError); - importZipPage.activeTransfer = null; } }); }