1
0
mirror of https://github.com/QRouland/UTPass.git synced 2025-02-10 22:47:15 +00:00

Refactor unzip password store

This commit is contained in:
Quentin Rouland 2025-01-20 15:46:57 +01:00
parent 20aff3a404
commit 7a2b12419d
10 changed files with 182 additions and 85 deletions

View File

@ -24,7 +24,7 @@ signals:
/** /**
* @brief Signal emitted when the rm operation is complete. * @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. * `true` if an error occurred, `false` if the clone was successful.
*/ */
void resultReady(const bool err); void resultReady(const bool err);

View File

@ -71,6 +71,9 @@ void Pass::showResult(Error err, QString plain_text)
bool Pass::deletePasswordStore() bool Pass::deletePasswordStore()
{ {
if (!this->m_sem->tryAcquire(1, 500)) {
return false;
}
qInfo() << "Pass delete Password Store"; qInfo() << "Pass delete Password Store";
auto job = new RmJob(this->password_store()); auto job = new RmJob(this->password_store());
qDebug() << "Delete Password Store at " << this->password_store(); qDebug() << "Delete Password Store at " << this->password_store();
@ -82,6 +85,7 @@ bool Pass::deletePasswordStore()
void Pass::deletePasswordStoreResult(bool err) void Pass::deletePasswordStoreResult(bool err)
{ {
qDebug() << "Pass delete Password StoreResult"; qDebug() << "Pass delete Password StoreResult";
if (err) { //dir.removeRecursively()) { if (err) { //dir.removeRecursively()) {
qInfo() << "Pass delete Password Store Failed"; qInfo() << "Pass delete Password Store Failed";
@ -91,6 +95,7 @@ void Pass::deletePasswordStoreResult(bool err)
qInfo() << "Pass delete Password Store Succeed"; qInfo() << "Pass delete Password Store Succeed";
emit deletePasswordStoreSucceed(); emit deletePasswordStoreSucceed();
} }
this->m_sem->release(1);
} }

View File

@ -137,7 +137,7 @@ private:
public: public:
/** /**
* @brief Constructs the Pass object and initializes necessary resources. * @brief Constructs the Pass object.
*/ */
Pass(); Pass();

View File

@ -5,6 +5,7 @@ set(
SRC SRC
plugin.cpp plugin.cpp
utils.cpp utils.cpp
jobs/unzipjob.cpp
) )
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)

View File

@ -0,0 +1,57 @@
#include <QFile>
#include <QDir>
#include <QUrl>
#include <QtCore/QStandardPaths>
#include <quazip5/JlCompress.h>
#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);
}

View File

@ -0,0 +1,49 @@
#ifndef RMJOB_H
#define RMJOB_H
#include "qurl.h"
#include <QThread>
#include <QDir>
/**
* @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

View File

@ -1,67 +1,47 @@
#include <QFile>
#include <QDir> #include <QDir>
#include <QUrl> #include <QSemaphore>
#include <QtCore/QStandardPaths>
#include <quazip5/JlCompress.h>
#include "jobs/unzipjob.h"
#include "utils.h" #include "utils.h"
Utils::Utils():
m_sem(std::unique_ptr<QSemaphore>(new QSemaphore(1)))
{}
bool Utils::unzip(QUrl zip_url, QString dir_out_path) bool Utils::unzip(QUrl zip_url, QString dir_out_path)
{ {
auto tmp_dir_path = QStandardPaths::writableLocation( if (!this->m_sem->tryAcquire(1, 500)) {
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();
return false; return false;
} }
qInfo() << "Unzip path " << zip_url << " to " << dir_out_path;
qDebug() << "Guessing if it should remove a single root folder"; auto job = new UnzipJob(zip_url, QDir(dir_out_path));
QStringList files_in_tmp_dir = tmp_dir.entryList(QDir::AllEntries | QDir::Hidden | connect(job, &UnzipJob::resultReady, this, &Utils::unzipResult);
QDir::NoDotAndDotDot); connect(job, &UnzipJob::finished, job, &QObject::deleteLater);
job->start();
auto dir_import_path = return true;
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;
} }
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() QString Utils::manifestPath()
{ {
auto path = QDir(QDir::currentPath()).filePath("manifest_.json"); auto path = QDir(QDir::currentPath()).filePath("manifest_.json");
qDebug() << "Manifest path : " << path; qInfo() << "Manifest path : " << path;
return path; return path;
} }

View File

@ -4,6 +4,8 @@
#include <QObject> #include <QObject>
#include <QUrl> #include <QUrl>
#include <QQuickWindow> #include <QQuickWindow>
#include <memory>
#include <QSemaphore>
/** /**
* @class Utils * @class Utils
@ -16,16 +18,34 @@ class Utils : public QObject
{ {
Q_OBJECT 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<QSemaphore> 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. * @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); 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);
/** /**

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: utpass.qrouland\n" "Project-Id-Version: utpass.qrouland\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -122,7 +122,7 @@ msgid "You're are about to delete<br>the current Password Store.<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/DeleteRepo.qml:55 #: ../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/InfoKeys.qml:140
#: ../qml/pages/settings/git/ImportGitClone.qml:55 #: ../qml/pages/settings/git/ImportGitClone.qml:55
msgid "Yes" msgid "Yes"
@ -153,21 +153,21 @@ msgstr ""
msgid "GPG Key Import" msgid "GPG Key Import"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:61 #: ../qml/pages/settings/ImportZip.qml:65
msgid "" msgid ""
"Importing a new zip will delete<br>any existing password store!<br>Continue ?" "Importing a new zip will delete<br>any existing password store!<br>Continue ?"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:75 #: ../qml/pages/settings/ImportZip.qml:79
msgid "Password store import failed !" msgid "Password store import failed !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:84 #: ../qml/pages/settings/ImportZip.qml:88
#: ../qml/pages/settings/git/ImportGitClone.qml:77 #: ../qml/pages/settings/git/ImportGitClone.qml:77
msgid "Password store sucessfully imported !" msgid "Password store sucessfully imported !"
msgstr "" msgstr ""
#: ../qml/pages/settings/ImportZip.qml:96 #: ../qml/pages/settings/ImportZip.qml:100
msgid "Zip Password Store Import" msgid "Zip Password Store Import"
msgstr "" msgstr ""

View File

@ -13,6 +13,16 @@ Page {
property var activeTransfer property var activeTransfer
Component.onCompleted: { 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); PopupUtils.open(importZipPageImportValidation, importZipPage);
} }
@ -33,12 +43,6 @@ Page {
console.log("Charged"); console.log("Charged");
console.log(importZipPage.activeTransfer.items[0].url); console.log(importZipPage.activeTransfer.items[0].url);
var status = Utils.unzip(importZipPage.activeTransfer.items[0].url, Pass.getPasswordStore()); 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;
} }
}); });
} }