From 180cadce3cca278257389de4fc0b3e718c770df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Wed, 18 Sep 2024 10:16:41 -0400 Subject: [PATCH 01/25] Refs #95, begin work on WebLogin, not working yet. --- client/src/CMakeLists.txt | 6 ++- client/src/ClientApp.cpp | 5 +++ client/src/ClientApp.h | 10 +++++ client/src/dialogs/WebLoginDialog.cpp | 39 ++++++++++++++++++ client/src/dialogs/WebLoginDialog.h | 40 ++++++++++++++++++ client/src/dialogs/WebLoginDialog.ui | 59 +++++++++++++++++++++++++++ 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 client/src/dialogs/WebLoginDialog.cpp create mode 100644 client/src/dialogs/WebLoginDialog.h create mode 100644 client/src/dialogs/WebLoginDialog.ui diff --git a/client/src/CMakeLists.txt b/client/src/CMakeLists.txt index 4bb490aa..c6ed1fcd 100755 --- a/client/src/CMakeLists.txt +++ b/client/src/CMakeLists.txt @@ -119,6 +119,7 @@ if(NOT DEFINED OPENTERA_WEBASSEMBLY) dialogs/JoinSessionDialog.h dialogs/AboutDialog.h dialogs/AboutDialogPage.h + dialogs/WebLoginDialog.h # Widgets widgets/InSessionWidget.h # Services @@ -238,6 +239,7 @@ if(NOT DEFINED OPENTERA_WEBASSEMBLY) dialogs/JoinSessionDialog.cpp dialogs/AboutDialog.cpp dialogs/AboutDialogPage.cpp + dialogs/WebLoginDialog.cpp # Widgets widgets/InSessionWidget.cpp # Services @@ -280,6 +282,7 @@ SET(uis dialogs/CleanUpDialog.ui dialogs/FileUploaderDialog.ui dialogs/QRCodeDialog.ui + dialogs/WebLoginDialog.ui # Editors editors/DataListWidget.ui editors/DeviceSubTypeWidget.ui @@ -417,7 +420,8 @@ set(ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${MACOSX_BUNDLE_ICON_FILE}") # create an executable file named "OpenTeraPlus" from the source files # Put qrc files after qm files if(NOT DEFINED OPENTERA_WEBASSEMBLY) - add_executable(OpenTeraPlus MACOSX_BUNDLE WIN32 ${icon} ${srcs} ${headers} ${moc_srcs} ${moc_uis} ${ICON_PATH} ${qm_files} ${client_qrc}) + add_executable(OpenTeraPlus MACOSX_BUNDLE WIN32 ${icon} ${srcs} ${headers} ${moc_srcs} ${moc_uis} ${ICON_PATH} ${qm_files} ${client_qrc} + dialogs/WebLoginDialog.ui) else() qt_add_executable(OpenTeraPlus ${icon} ${srcs} ${headers} ${moc_srcs} ${moc_uis} ${ICON_PATH} ${qm_files} ${client_qrc}) endif() diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index a7fbd16e..7cf988f1 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -122,6 +122,10 @@ void ClientApp::showLogin() m_comMan = nullptr; } if (m_loginDiag == nullptr){ + +#ifndef OPENTERA_WEBASSEMBLY + m_loginDiag = new WebLoginDialog(); +#else m_loginDiag = new LoginDialog(); connect(m_loginDiag, &LoginDialog::loginRequest, this, &ClientApp::loginRequested); connect(m_loginDiag, &LoginDialog::quitRequest, this, &ClientApp::loginQuitRequested); @@ -131,6 +135,7 @@ void ClientApp::showLogin() // Show servers list... or not! m_loginDiag->showServers(m_config.showServers()); +#endif } // Delete main window, if present diff --git a/client/src/ClientApp.h b/client/src/ClientApp.h index ae14b5ec..607f8c61 100755 --- a/client/src/ClientApp.h +++ b/client/src/ClientApp.h @@ -15,6 +15,10 @@ #include "main/MainKitWindow.h" #endif +#ifndef OPENTERA_WEBASSEMBLY +#include "dialogs/WebLoginDialog.h" +#endif + #include "dialogs/LoginDialog.h" #include "GlobalMessageBox.h" @@ -44,7 +48,13 @@ class ClientApp : public QApplication void setTranslation(QString language = ""); ConfigManagerClient m_config; + +#ifndef OPENTERA_WEBASSEMBLY + WebLoginDialog *m_loginDiag; +#else LoginDialog* m_loginDiag; +#endif + MainWindow* m_mainWindow; #ifndef OPENTERA_WEBASSEMBLY MainKitWindow* m_mainKitWindow; diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp new file mode 100644 index 00000000..fd5bcea4 --- /dev/null +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -0,0 +1,39 @@ +#include "WebLoginDialog.h" +#include "ui_WebLoginDialog.h" +#include + + +WebLoginDialog::WebLoginDialog(QWidget *parent) + : QDialog(parent), ui(new Ui::WebLoginDialog) +{ + ui->setupUi(this); + + //Create Web View + m_webView = new QWebEngineView(ui->centralWidget); + + QVBoxLayout *layout = new QVBoxLayout(ui->centralWidget); + layout->addWidget(m_webView); + + m_webPage = new QWebEnginePage(m_webView); + + connect(m_webPage, &QWebEnginePage::certificateError, this, &WebLoginDialog::onCertificateError); + + m_webPage->setUrl(QUrl("https://127.0.0.1:40075/login")); + + m_webView->setPage(m_webPage); +} + +WebLoginDialog::~WebLoginDialog() +{ + delete ui; +} + + +void WebLoginDialog::onCertificateError(const QWebEngineCertificateError &certificateError) +{ + //TODO do Something about certificates + qDebug() << "Certificate error: " << certificateError.description(); + //TODO Do not accept certificates in production ? + auto mutableError = const_cast(certificateError); + mutableError.acceptCertificate(); +} diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h new file mode 100644 index 00000000..7268958b --- /dev/null +++ b/client/src/dialogs/WebLoginDialog.h @@ -0,0 +1,40 @@ +#ifndef WEBLOGINDIALOG_H +#define WEBLOGINDIALOG_H + +#include +#include "TeraSettings.h" +#include +#include +#include +#include + +namespace Ui { +class WebLoginDialog; +} + +class WebLoginDialog : public QDialog +{ + Q_OBJECT + +public: + explicit WebLoginDialog(QWidget *parent = nullptr); + ~WebLoginDialog(); + QString currentServerName() {return QString();} + void setStatusMessage(const QString &message, bool error=false) {qDebug() << "Unhandled message: " << message << "error: " << error;} + + +private: + +private slots: + + void onCertificateError(const QWebEngineCertificateError &certificateError); + +signals: + +private: + Ui::WebLoginDialog *ui; + QWebEngineView *m_webView; + QWebEnginePage *m_webPage; +}; + +#endif // WEBLOGINDIALOG_H diff --git a/client/src/dialogs/WebLoginDialog.ui b/client/src/dialogs/WebLoginDialog.ui new file mode 100644 index 00000000..826e7975 --- /dev/null +++ b/client/src/dialogs/WebLoginDialog.ui @@ -0,0 +1,59 @@ + + + WebLoginDialog + + + + 0 + 0 + 640 + 480 + + + + Dialog + + + + + + + 0 + 0 + + + + + 0 + 20 + + + + + 18 + true + + + + WebLogin + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 0 + 0 + + + + + + + + + From 13d69593bc8db8ae52e9986e1c4bd34682591a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Thu, 19 Sep 2024 12:11:04 -0400 Subject: [PATCH 02/25] Refs #95, prototye weblogin, not working yet. --- client/src/dialogs/WebLoginDialog.cpp | 7 +++++++ client/src/dialogs/WebLoginDialog.h | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index fd5bcea4..d4811cac 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -16,6 +16,13 @@ WebLoginDialog::WebLoginDialog(QWidget *parent) m_webPage = new QWebEnginePage(m_webView); + QWebChannel *channel = new QWebChannel(m_webPage); + + + WebLoginSharedObject *myObject = new WebLoginSharedObject(); + channel->registerObject("qtObject", myObject); + m_webPage->setWebChannel(channel); + connect(m_webPage, &QWebEnginePage::certificateError, this, &WebLoginDialog::onCertificateError); m_webPage->setUrl(QUrl("https://127.0.0.1:40075/login")); diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 7268958b..84b44edd 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -8,6 +8,17 @@ #include #include +#include + +class WebLoginSharedObject : public QObject { + Q_OBJECT +public: + Q_INVOKABLE void handleToken(const QString &token) { + qDebug() << "Token received from web page: " << token; + // Use the token in your Qt application + } +}; + namespace Ui { class WebLoginDialog; } From 3d46479d497f314a3c7d01da0fb5065b497bb726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Thu, 19 Sep 2024 16:39:39 -0400 Subject: [PATCH 03/25] Refs #95, prototye weblogin, working with local server. --- client/src/ClientApp.cpp | 13 +++++++++++++ client/src/ClientApp.h | 1 + client/src/dialogs/WebLoginDialog.cpp | 1 + client/src/dialogs/WebLoginDialog.h | 18 +++++++++++++++--- client/src/managers/ComManager.cpp | 23 +++++++++++++++++++++++ client/src/managers/ComManager.h | 1 + 6 files changed, 54 insertions(+), 3 deletions(-) diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index 7cf988f1..0428944d 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -125,6 +125,7 @@ void ClientApp::showLogin() #ifndef OPENTERA_WEBASSEMBLY m_loginDiag = new WebLoginDialog(); + connect(m_loginDiag, &WebLoginDialog::loginSuccess, this, &ClientApp::onLoginSuccess, Qt::QueuedConnection); #else m_loginDiag = new LoginDialog(); connect(m_loginDiag, &LoginDialog::loginRequest, this, &ClientApp::loginRequested); @@ -311,6 +312,18 @@ void ClientApp::on_loginResult(bool logged, QString log_msg) } } +void ClientApp::onLoginSuccess(const QString &token, const QString websocket_url, const QString &user_uuid) +{ + // Create ComManager for that server + if (m_comMan){ + m_comMan->deleteLater(); + } + m_comMan = new ComManager(QUrl("https://127.0.0.1:40075")); + m_comMan->connectToServer(token, websocket_url, user_uuid); + + showMainWindow(); +} + void ClientApp::loginQuitRequested() { QApplication::quit(); diff --git a/client/src/ClientApp.h b/client/src/ClientApp.h index 607f8c61..e9979060 100755 --- a/client/src/ClientApp.h +++ b/client/src/ClientApp.h @@ -72,6 +72,7 @@ private slots: void loginRequested(QString username, QString password, QString server_name); void logoutRequested(); void on_loginResult(bool logged, QString log_msg); + void onLoginSuccess(const QString &token, const QString websocket_url, const QString &user_uuid); void loginQuitRequested(); void on_serverDisconnected(); diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index d4811cac..53767f6d 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -24,6 +24,7 @@ WebLoginDialog::WebLoginDialog(QWidget *parent) m_webPage->setWebChannel(channel); connect(m_webPage, &QWebEnginePage::certificateError, this, &WebLoginDialog::onCertificateError); + connect(myObject, &WebLoginSharedObject::loginSuccess, this, &WebLoginDialog::loginSuccess); m_webPage->setUrl(QUrl("https://127.0.0.1:40075/login")); diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 84b44edd..2aeafe16 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -13,10 +13,20 @@ class WebLoginSharedObject : public QObject { Q_OBJECT public: - Q_INVOKABLE void handleToken(const QString &token) { - qDebug() << "Token received from web page: " << token; - // Use the token in your Qt application + + Q_INVOKABLE void debugPrint(const QString &message) { + qDebug() << "[WebLoginSharedObject::debugPrint] " << message; + } + + Q_INVOKABLE void sendLoginSuccess(const QString &token, const QString &websocket_url, const QString &user_uuid) { + qDebug() << "[WebLoginSharedObject::sendLoginSuccess] " << token << websocket_url; + emit loginSuccess(token, websocket_url, user_uuid); } + +signals: + + void loginSuccess(const QString &token, const QString &websocket_url, const QString& user_uuid); + }; namespace Ui { @@ -42,6 +52,8 @@ private slots: signals: + void loginSuccess(const QString &token, const QString &websocket_url, const QString &user_uuid); + private: Ui::WebLoginDialog *ui; QWebEngineView *m_webView; diff --git a/client/src/managers/ComManager.cpp b/client/src/managers/ComManager.cpp index 4896a8fa..114ecbc1 100644 --- a/client/src/managers/ComManager.cpp +++ b/client/src/managers/ComManager.cpp @@ -52,6 +52,29 @@ void ComManager::connectToServer(QString username, QString password) } +void ComManager::connectToServer(const QString &token, const QString &websocket_url, const QString &user_uuid) +{ + setCredentials("username", "password"); + m_loggingInProgress = true; // Indicate that a login request was sent, but not processed + QString url = websocket_url; + QString uuid = user_uuid; + if (m_enableWebsocket) + { + m_webSocketMan->connectWebSocket(url, uuid); + } + + // Set current user values + m_currentUser.setFieldValue("user_uuid", user_uuid); + setCredentials(token); + m_tokenRefreshTimer.start(); + + // Query versions informations + doGet(WEB_VERSIONSINFO_PATH); + + doUpdateCurrentUser(); + +} + void ComManager::disconnectFromServer() { doGet(QString(WEB_LOGOUT_PATH)); diff --git a/client/src/managers/ComManager.h b/client/src/managers/ComManager.h index bbaa1468..b90dc6b8 100644 --- a/client/src/managers/ComManager.h +++ b/client/src/managers/ComManager.h @@ -47,6 +47,7 @@ class ComManager : public BaseComManager ~ComManager(); void connectToServer(QString username, QString password); + void connectToServer(const QString &token, const QString &websocket_url, const QString &user_uuid); void disconnectFromServer(); bool processNetworkReply(QNetworkReply* reply); From c6280b08fd020d26dab2a41110c413dda2e9198d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Mon, 23 Sep 2024 10:11:17 -0400 Subject: [PATCH 04/25] Refs #95, weblogin now enables server selection. --- client/src/ClientApp.cpp | 15 ++--- client/src/dialogs/WebLoginDialog.cpp | 61 +++++++++++++++++++-- client/src/dialogs/WebLoginDialog.h | 16 +++--- client/src/dialogs/WebLoginDialog.ui | 3 + client/src/managers/ConfigManagerClient.cpp | 8 +++ client/src/managers/ConfigManagerClient.h | 1 + 6 files changed, 84 insertions(+), 20 deletions(-) diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index 0428944d..8ba40def 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -124,21 +124,22 @@ void ClientApp::showLogin() if (m_loginDiag == nullptr){ #ifndef OPENTERA_WEBASSEMBLY - m_loginDiag = new WebLoginDialog(); + m_loginDiag = new WebLoginDialog(&m_config); connect(m_loginDiag, &WebLoginDialog::loginSuccess, this, &ClientApp::onLoginSuccess, Qt::QueuedConnection); #else m_loginDiag = new LoginDialog(); connect(m_loginDiag, &LoginDialog::loginRequest, this, &ClientApp::loginRequested); connect(m_loginDiag, &LoginDialog::quitRequest, this, &ClientApp::loginQuitRequested); - - // Set server names - m_loginDiag->setServerNames(m_config.getServerNames()); - - // Show servers list... or not! - m_loginDiag->showServers(m_config.showServers()); #endif } + // Set server names + m_loginDiag->setServerNames(m_config.getServerNames()); + + // Show servers list... or not! + m_loginDiag->showServers(m_config.showServers()); + + // Delete main window, if present if (m_mainWindow){ m_mainWindow->deleteLater(); diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 53767f6d..6dbe4934 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -3,8 +3,8 @@ #include -WebLoginDialog::WebLoginDialog(QWidget *parent) - : QDialog(parent), ui(new Ui::WebLoginDialog) +WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) + : QDialog(parent), ui(new Ui::WebLoginDialog), m_config(config) { ui->setupUi(this); @@ -18,7 +18,6 @@ WebLoginDialog::WebLoginDialog(QWidget *parent) QWebChannel *channel = new QWebChannel(m_webPage); - WebLoginSharedObject *myObject = new WebLoginSharedObject(); channel->registerObject("qtObject", myObject); m_webPage->setWebChannel(channel); @@ -26,9 +25,7 @@ WebLoginDialog::WebLoginDialog(QWidget *parent) connect(m_webPage, &QWebEnginePage::certificateError, this, &WebLoginDialog::onCertificateError); connect(myObject, &WebLoginSharedObject::loginSuccess, this, &WebLoginDialog::loginSuccess); - m_webPage->setUrl(QUrl("https://127.0.0.1:40075/login")); - - m_webView->setPage(m_webPage); + m_webView->setPage(m_webPage); } WebLoginDialog::~WebLoginDialog() @@ -36,6 +33,36 @@ WebLoginDialog::~WebLoginDialog() delete ui; } +void WebLoginDialog::setServerNames(QStringList servers) +{ + ui->cmbServers->clear(); + foreach(QString server, servers){ + ui->cmbServers->addItem(server); + } + + // Connecting signal after will avoid calling onServerSelected when adding initial servers + connect(ui->cmbServers, &QComboBox::currentIndexChanged, this, &WebLoginDialog::onServerSelected); + + // Get last server used + QVariant current_server = TeraSettings::getGlobalSetting("last_used_server"); + + // Select server from the list if we have a setting for that + if (current_server.isValid()){ + QString server_name = current_server.toString(); + if (servers.contains(server_name)) + ui->cmbServers->setCurrentText(server_name); + } +} + + +void WebLoginDialog::showServers(bool show) +{ + if (ui->cmbServers->count() == 1) + show = false; // Never show server list if only one item. + + ui->cmbServers->setVisible(show); +} + void WebLoginDialog::onCertificateError(const QWebEngineCertificateError &certificateError) { @@ -45,3 +72,25 @@ void WebLoginDialog::onCertificateError(const QWebEngineCertificateError &certif auto mutableError = const_cast(certificateError); mutableError.acceptCertificate(); } + +void WebLoginDialog::onServerSelected(int index) +{ + QString currentServer = ui->cmbServers->itemText(index); + // Update last server + TeraSettings::setGlobalSetting("last_used_server", currentServer); + + //Get URL + if (m_config && m_webPage) + { + QUrl loginUrl = m_config->getServerLoginUrl(currentServer); + m_webPage->setUrl(loginUrl); + } +} + +QString WebLoginDialog::currentServerName() +{ + if (ui->cmbServers->currentIndex() >=0 && ui->cmbServers->isVisible()){ + return ui->cmbServers->currentText(); + } + return QString(); +} diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 2aeafe16..5afe2d67 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -3,6 +3,7 @@ #include #include "TeraSettings.h" +#include "managers/ConfigManagerClient.h" #include #include #include @@ -38,26 +39,27 @@ class WebLoginDialog : public QDialog Q_OBJECT public: - explicit WebLoginDialog(QWidget *parent = nullptr); + explicit WebLoginDialog(ConfigManagerClient *config, QWidget *parent = nullptr); ~WebLoginDialog(); - QString currentServerName() {return QString();} void setStatusMessage(const QString &message, bool error=false) {qDebug() << "Unhandled message: " << message << "error: " << error;} + void setServerNames(QStringList servers); + QString currentServerName(); + void showServers(bool show); +signals: -private: + void loginSuccess(const QString &token, const QString &websocket_url, const QString &user_uuid); private slots: void onCertificateError(const QWebEngineCertificateError &certificateError); - -signals: - - void loginSuccess(const QString &token, const QString &websocket_url, const QString &user_uuid); + void onServerSelected(int index); private: Ui::WebLoginDialog *ui; QWebEngineView *m_webView; QWebEnginePage *m_webPage; + ConfigManagerClient *m_config; }; #endif // WEBLOGINDIALOG_H diff --git a/client/src/dialogs/WebLoginDialog.ui b/client/src/dialogs/WebLoginDialog.ui index 826e7975..e7288e15 100644 --- a/client/src/dialogs/WebLoginDialog.ui +++ b/client/src/dialogs/WebLoginDialog.ui @@ -42,6 +42,9 @@ + + + diff --git a/client/src/managers/ConfigManagerClient.cpp b/client/src/managers/ConfigManagerClient.cpp index c9e00dc8..ce2235be 100644 --- a/client/src/managers/ConfigManagerClient.cpp +++ b/client/src/managers/ConfigManagerClient.cpp @@ -33,10 +33,18 @@ QUrl ConfigManagerClient::getServerUrl(const QString &server_name) QVariantMap server_info = servers[server_name].toMap(); server_url.setHost(server_info["url"].toString()); server_url.setPort(server_info["port"].toInt()); + server_url.setScheme("https"); } return server_url; } +QUrl ConfigManagerClient::getServerLoginUrl(const QString &server_name) +{ + QUrl login_url = getServerUrl(server_name); + login_url.setPath("/login"); + return login_url; +} + bool ConfigManagerClient::getLogToFile() { bool rval = false; diff --git a/client/src/managers/ConfigManagerClient.h b/client/src/managers/ConfigManagerClient.h index 3b7b854c..266306a9 100644 --- a/client/src/managers/ConfigManagerClient.h +++ b/client/src/managers/ConfigManagerClient.h @@ -13,6 +13,7 @@ class ConfigManagerClient : public ConfigManager QStringList getServerNames(); QUrl getServerUrl(const QString &server_name); + QUrl getServerLoginUrl(const QString &server_name); bool getLogToFile(); From fbf754e4de8d887c58448b77489c635d5dc0f03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Mon, 23 Sep 2024 16:39:36 -0400 Subject: [PATCH 05/25] Refs #95, weblogin now enables server selection. --- client/src/dialogs/WebLoginDialog.cpp | 1 + client/src/dialogs/WebLoginDialog.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 6dbe4934..5d3393fa 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -24,6 +24,7 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) connect(m_webPage, &QWebEnginePage::certificateError, this, &WebLoginDialog::onCertificateError); connect(myObject, &WebLoginSharedObject::loginSuccess, this, &WebLoginDialog::loginSuccess); + connect(myObject, &WebLoginSharedObject::loginFailure, this, &WebLoginDialog::loginFailure); m_webView->setPage(m_webPage); } diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 5afe2d67..0283e009 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -24,9 +24,14 @@ class WebLoginSharedObject : public QObject { emit loginSuccess(token, websocket_url, user_uuid); } + Q_INVOKABLE void sendLoginFailure(const QString &message) { + emit loginFailure(message); + } + signals: void loginSuccess(const QString &token, const QString &websocket_url, const QString& user_uuid); + void loginFailure(const QString &message); }; @@ -49,6 +54,7 @@ class WebLoginDialog : public QDialog signals: void loginSuccess(const QString &token, const QString &websocket_url, const QString &user_uuid); + void loginFailure(const QString &message); private slots: From 44a42e71d356091d73c14211e36dc60118f7ffde Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Thu, 26 Sep 2024 15:32:40 -0400 Subject: [PATCH 06/25] Refs #95. Adjusted WebLoginDialog UI. --- .gitignore | 2 +- client/resources/stylesheet.qss | 5 +- client/src/dialogs/WebLoginDialog.cpp | 33 +++- client/src/dialogs/WebLoginDialog.h | 2 + client/src/dialogs/WebLoginDialog.ui | 217 +++++++++++++++++++++++--- docs/conf.py | 4 +- 6 files changed, 230 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 8f3b334a..c0e1169c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /client/resources/translations/*.qm deploy -/build-* +/build *.user html diff --git a/client/resources/stylesheet.qss b/client/resources/stylesheet.qss index 8cd11763..85957823 100644 --- a/client/resources/stylesheet.qss +++ b/client/resources/stylesheet.qss @@ -660,11 +660,12 @@ QLabel#lblWarning, QLabel#lblWarning2, QLabel#lblDeviceRegisterKeyValue{ } -/* Customizations for LoginDialog */ +/* Customizations for LoginDialog / WebLoginDialog */ QFrame#frameLogos{background-color:rgba(200,200,200,100%);} QLabel#lblMessage{color:white;} QFrame#frameMessage{background-color: transparent;} -QFrame#frameButtons{background-color:rgba(29,29,29,50%);} +QFrame#frameButtons,QFrame#frameLoginMessages{background-color:rgba(29,29,29,50%);} +QLabel#lblError{color: orange;} /* Customizations for MainWindow */ QMainWindow{background-image: url(://TeRA_Background.png); background-color: #2c3338;} diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 5d3393fa..79501225 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -10,6 +10,8 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) //Create Web View m_webView = new QWebEngineView(ui->centralWidget); + ui->lblError->hide(); + ui->centralWidget->hide(); QVBoxLayout *layout = new QVBoxLayout(ui->centralWidget); layout->addWidget(m_webView); @@ -22,11 +24,18 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) channel->registerObject("qtObject", myObject); m_webPage->setWebChannel(channel); + auto settings = m_webPage->settings(); + settings->setAttribute(QWebEngineSettings::ShowScrollBars, false); + connect(m_webPage, &QWebEnginePage::certificateError, this, &WebLoginDialog::onCertificateError); + connect(m_webView, &QWebEngineView::loadFinished, this, &WebLoginDialog::onLoginPageLoaded); + connect(m_webView, &QWebEngineView::loadStarted, this, &WebLoginDialog::onLoginPageLoading); + connect(myObject, &WebLoginSharedObject::loginSuccess, this, &WebLoginDialog::loginSuccess); connect(myObject, &WebLoginSharedObject::loginFailure, this, &WebLoginDialog::loginFailure); - m_webView->setPage(m_webPage); + m_webPage->setBackgroundColor(QColor(0x2c3338)); + m_webView->setPage(m_webPage); } WebLoginDialog::~WebLoginDialog() @@ -55,7 +64,6 @@ void WebLoginDialog::setServerNames(QStringList servers) } } - void WebLoginDialog::showServers(bool show) { if (ui->cmbServers->count() == 1) @@ -64,7 +72,6 @@ void WebLoginDialog::showServers(bool show) ui->cmbServers->setVisible(show); } - void WebLoginDialog::onCertificateError(const QWebEngineCertificateError &certificateError) { //TODO do Something about certificates @@ -84,10 +91,30 @@ void WebLoginDialog::onServerSelected(int index) if (m_config && m_webPage) { QUrl loginUrl = m_config->getServerLoginUrl(currentServer); + loginUrl.setQuery("no_logo"); m_webPage->setUrl(loginUrl); } } +void WebLoginDialog::onLoginPageLoaded(bool ok) +{ + if (ok){ + ui->centralWidget->show(); + ui->frameLoginMessages->hide(); + }else{ + ui->lblError->show(); + ui->lblLoading->hide(); + } +} + +void WebLoginDialog::onLoginPageLoading() +{ + ui->centralWidget->hide(); + ui->lblError->hide(); + ui->lblLoading->show(); + ui->frameLoginMessages->show(); +} + QString WebLoginDialog::currentServerName() { if (ui->cmbServers->currentIndex() >=0 && ui->cmbServers->isVisible()){ diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 0283e009..0598030c 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -60,6 +60,8 @@ private slots: void onCertificateError(const QWebEngineCertificateError &certificateError); void onServerSelected(int index); + void onLoginPageLoaded(bool ok); + void onLoginPageLoading(); private: Ui::WebLoginDialog *ui; diff --git a/client/src/dialogs/WebLoginDialog.ui b/client/src/dialogs/WebLoginDialog.ui index e7288e15..b200c20c 100644 --- a/client/src/dialogs/WebLoginDialog.ui +++ b/client/src/dialogs/WebLoginDialog.ui @@ -6,45 +6,210 @@ 0 0 - 640 - 480 + 450 + 500 + + + 0 + 0 + + + + + 450 + 500 + + + + + 450 + 500 + + - Dialog + OpenTeraPlus - + + + + + + 0 + 0 + + + + + 300 + 175 + + + + + 300 + 175 + + + + + + + :/logos/LogoOpenTeraPlus.png + + + true + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop + + + + + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 20 + + + + + + + + + 10px Arial + 10 + false + true + + + + Serveur + + + + + + + + 0 + 0 + + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 20 + + + + + + + + - + 0 0 - - - 0 - 20 - - - - - 18 - true - - - - WebLogin + + QFrame::Shape::StyledPanel - - Qt::AlignmentFlag::AlignCenter + + QFrame::Shadow::Raised + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + Chargement en cours... + + + Qt::AlignmentFlag::AlignCenter + + + + + + + + 10 + true + + + + Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. + + + Qt::AlignmentFlag::AlignCenter + + + true + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + - - - @@ -57,6 +222,8 @@ - + + + diff --git a/docs/conf.py b/docs/conf.py index c5efc315..e7f746bc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,9 +7,9 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = 'OpenTeraPlus' -copyright = '2023, Simon Brière, Dominic Létourneau' +copyright = '2024, Simon Brière, Dominic Létourneau' author = 'Simon Brière, Dominic Létourneau' -release = '1.1.3' +release = '1.2.0' version = release html_logo = 'logo/LogoOpenTeraPlus.png' From 244e68398ff17eaf099c3fc44149646f88f18ac2 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Fri, 27 Sep 2024 12:41:35 -0400 Subject: [PATCH 07/25] Refs #95. Work in progress on Web Login Dialog translation. --- CMakeLists.txt | 1 + .../resources/translations/openteraplus_en.ts | 2139 ++++++++++------- .../resources/translations/openteraplus_fr.ts | 2113 +++++++++------- client/src/CMakeLists.txt | 78 +- client/src/dialogs/WebLoginDialog.cpp | 35 + client/src/dialogs/WebLoginDialog.h | 24 +- client/src/dialogs/WebLoginDialog.ui | 4 +- client/src/editors/ProjectWidget.cpp | 2 +- client/src/managers/BaseComManager.cpp | 6 +- shared/src/Utils.cpp | 13 + shared/src/Utils.h | 2 + 11 files changed, 2524 insertions(+), 1893 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b0ddfad..0023f6a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ cmake_minimum_required(VERSION 3.21) #DEFINITIONS POLICY, NEW SINCE 3.0.2 cmake_policy(SET CMP0043 NEW) +cmake_policy(SET CMP0007 NEW) # Software version SET(CPACK_PACKAGE_VERSION_MAJOR "1") diff --git a/client/resources/translations/openteraplus_en.ts b/client/resources/translations/openteraplus_en.ts index db6986c6..1028be25 100644 --- a/client/resources/translations/openteraplus_en.ts +++ b/client/resources/translations/openteraplus_en.ts @@ -1,23 +1,34 @@ - + AboutDialog - + À propos d'OpenTera... About OpenTera... - + À propos d'OpenTeraPlus... About OpenTeraPlus... - + + Clé d'enregistrement du serveur: + Server registration key: + + + Merci! Thanks! + + + + Inconnue + Unknown + AssetsWidget @@ -34,7 +45,7 @@ - + Supprimer Delete @@ -86,7 +97,7 @@ - + Tout voir See all @@ -142,57 +153,57 @@ Hide all - + Données Assets - + Actions Actions - + Durée Duration - + Taille Size - + Service Service - + Date / heure Date / time - + ... ... - + Ajouter Add - + 0 0 - + Télécharger Download - + Tout télécharger Download all @@ -200,8 +211,8 @@ BaseComManager - - + + Impossible de créer la requête Unable to create request @@ -209,12 +220,12 @@ BaseDialog - + Dialog Dialogue - + Fermer Close @@ -328,32 +339,32 @@ All you sure you want to delete all? - + Nettoyage de données... Data cleanup... - + Tout désactiver Disable all - + Tout supprimer Delete all - + Élément Item - + Action Action - + Terminer Close @@ -361,83 +372,83 @@ ClientApp - + Connexion Connection - + Bienvenue! Welcome! - + Déconnexion Disconnect - + Vous avez été déconnecté du serveur. Veuillez vous connecter à nouveau. You have been disconnected. Please connect again. - - + + La connexion a été refusée par le serveur. Connection refused by server. - + Impossible de rejoindre le serveur. Unable to reach server. - + Le serveur est introuvable. Server is unreachable. - + Impossible de se connecter (Code erreur: Unable to connect (Error code: - + Une nouvelle version ( A software update ( - + ) du logiciel est disponible. ) is available. - + Veuillez contacter votre fournisseur pour l'obtenir. Please contact your provider to update. - + Cliquez Click - + ICI HERE - + pour la télécharger. to download. - + Important: assurez-vous que le logiciel est bien fermé avant de procéder à la mise à jour. Important: please close the software before proceeding to install this update. - + Nouvelle version disponible! Software update available! @@ -445,22 +456,22 @@ ComManager - + L'utilisateur est déjà connecté. User is already logged on. - + Erreur inconnue Unknown error - + Utilisateur ou mot de passe invalide. Invalid username or password. - + La communication avec le serveur n'a pu être établie. Communication with the server couldn't be established. @@ -468,72 +479,72 @@ ConfigWidget - + Utilisateurs Users - + Groupes utilisateurs Users Groups - + Sites Sites - + Appareils Devices - + Type appareils Device Type - + Sous-types appareils Devices Sub-Types - + Types de séances Session Types - + Types évaluations Test types - + Services Services - + Erreur inconnue Unknown error - + Form Form - + Paramètres Settings - + Événements Events - + Journal d'accès Access Log @@ -577,7 +588,7 @@ - + Renommer Rename @@ -587,82 +598,82 @@ New label - + DanceWidgetConfig DanceWidgetConfig - + Aucun type de séance lié au service "Télédanse" associé à ce projet. Veuillez ajouter un type de séance approprié. No session type with service "DanceService" associated to this project. Please add an appropriate session type. - + Type de séance Session type - + Vidéos assignés Assigned videos - + Vidéo Video - + Mettre à jour Update - + Annuler Cancel - + Monter Move up - + <<< Ajouter <<< Add - + Retirer >>> Remove >>> - + Descendre Move down - + Vidéos disponibles Available videos - + Séquence Playlist - + Ajouter Add - + Supprimer Delete - + Bibliothèque Library @@ -670,171 +681,257 @@ DashboardWidget - - + + Inconnu Unknown - + Appareil: Device: - + Participant: Participant: - + Service: Service: - - + + Séances à venir Upcoming sessions - - + + Participants récents Recent participants - + participant(s) sans séance depuis au moins 6 mois participant(s) without a session since at least 6 months - - - - + + + + mois month(s) - + participant(s) sans aucune séance réalisée participant(s) without any session - - + + Créé depuis Created since - + utilisateur(s) non-connecté(s) depuis au moins 6 mois user(s) not connected since at least 6 months - + utilisateur(s) jamais connecté(s) user(s) who never logged on - - + + Attention requise Attention required - - + + Impossible de démarrer la séance Unable to start session - + Cette séance ne peut être démarrée: le type de séance est inconnu. This session could not be started: session type is unknown. - + Cette séance ne peut être démarrée: séance introuvable. Session could not be started: unknown session. - + Gérer Manage - + Dashboard Dashboard - + Aucune séance n'est prévue pour le moment. No upcoming session. - + Date Date - + Séance Session - + Type Type - + Responsable Owner - - + + Projet Project - + Invités Attendees - + Aucun participant récent. No recent participant. - + Participant Participant - + Dernière séance Last session - + Tout va bien! :-) All is fine! :-) - + Avertissement Warning - + Action Action + + DashboardsConfigWidget + + + Aucune + None + + + + Erreur HTTP + HTTP Error + + + + Erreur + Error + + + + Données sauvegardées + Data saved + + + + Suppression + Deletion + + + + Êtes-vous sûr de vouloir supprimer le tableau de bord sélectionné? + Are you sure you want to delete the selected dashboard? + + + + Dashboards Config + Dashboards Config + + + + + + + ... + ... + + + + Éditer + Edit + + + + Description + Description + + + + Nom + Name + + + + Versions + Versions + + + + Activé pour ce site / projet + Enabled for this site / project + + + + Version fixe pour ce site / project + Fixed version for this site / project + + + + Mettre à jour + Update + + + + Annuler + Cancel + + DataEditorWidget @@ -849,16 +946,26 @@ + Gestionnaire + Manager + + + + Éditeur + Editor + + + Aucun rôle No Role - + Les champs suivants doivent être complétés: The following fields must be entered: - + Champs invalides Invalid fields @@ -871,61 +978,61 @@ Unknown - + Suppression? Delete? - + Êtes-vous sûrs de vouloir supprimer Are you sure you want to delete - + Suppression de service? Service deletion? - + En supprimant le service If you delete the service - + toutes les données créées par ce service seront supprimées. Êtes-vous vraiment sûrs? all assets created by this service will be deleted. Are you sure you want to proceed? - + Form Form - + Seuls les ... ayant un lien avec ce ... sont présentement affichés. Only ... with a link with ... are displayed. - + Filtrer Filter - + Tout voir See All - + Recherche... Search... - - - + + + ... ... @@ -933,36 +1040,36 @@ Are you sure you want to proceed? DeviceAssignDialog - + Assignation d'un appareil Assign device - + L'appareil est présentement assigné au(x) participant(s) suivant(s): The device is currently assigned to the following participant(s): - + <html><head/><body><p>Souhaitez-vous <span style=" font-weight:600;">désassocier</span> cet appareil de ces participants avant de l'ajouter au participant actuel ou souhaitez-vous <span style=" font-weight:600;">ajouter</span> un participant supplémentaire à cet appareil?</p></body></html> <html><head/><body><p>Do you want to <span style=" font-weight:600;">unlink</span>this device to the actual participants or do you which to <span style=" font-weight:600;">add</span> a new participant to this device?</p></body></html> - + Déassocier puis ajouter Dissociate then add - + Ajouter sans désassocier Add without dissociating - + Annuler Cancel @@ -970,37 +1077,37 @@ dissociating DeviceSubTypeWidget - + Form Form - + Sous-type appareil Device Sub-Type - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Appareils Devices @@ -1008,59 +1115,59 @@ dissociating DeviceSummaryWidget - + Résumé appareil Device Summary - + Appareil Device - + Nouvelle Séance New Session - + Cet appareil ne peut être mis en ligne - impossible de réaliser une nouvelle séance avec celui-ci. This device isn't onlineable - can't start a new session. - - + + Séances Sessions - + Résumé Summary - - + + Informations Informations - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Journal d'accès Access Log @@ -1068,38 +1175,38 @@ dissociating DeviceTypeWidget - + Form Formulaire Form - + Type Appareil Device Type - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Appareils Devices @@ -1113,7 +1220,7 @@ dissociating - + Journal d'accès Access Log @@ -1154,57 +1261,57 @@ Si l'appareil est présentement déployé, les données ne seront plus coll If the device is currently deployed, the data will not be collected anymore and the device will not be usable during sessions. - + Form Form - + Appareil Device - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Mettre à jour les sites / projets associés à cet appareil Update sites / projects associated to this device - + Sites / Projets Sites / Projects - + Retirer cet appareil de ce participant Remove this device from the participant - + Participants Participants - + Configuration Configuration @@ -1250,27 +1357,27 @@ If the device is currently deployed, the data will not be collected anymore and Invite - New session via OpenTeraPlus - + Invitation par courriel Email invitation - + Pour le moment, aucun courriel automatisé n'est envoyé par le système. Vous êtes responsable d'envoyer ce courriel. At the moment, no automated emails are sent by the system. It is your responsability to send the email to the participants. - + Destinataire: To: - + Aucun courriel spécifié. No email specified. - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1303,17 +1410,17 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-size:10pt;">{username}</span></p></body></html> - + Copier Copy - + Envoyer (local) Send (local) - + Fermer Close @@ -1326,37 +1433,37 @@ p, li { white-space: pre-wrap; } Select the file(s) to send - + Envoi de fichier File upload - + Fichier File - + Libellé Label - + Ajouter Add - + Retirer Remove - + Envoyer Send - + Annuler Cancel @@ -1364,32 +1471,32 @@ p, li { white-space: pre-wrap; } GeneratePasswordDialog - + Générateur de mot de passe Password generator - + Mot de passe Password - + Générer Generate - + Copier Copy - + Appliquer Apply - + Annuler Cancel @@ -1405,12 +1512,12 @@ p, li { white-space: pre-wrap; } GlobalMessageBox - + Oui Yes - + Non No @@ -1418,7 +1525,7 @@ p, li { white-space: pre-wrap; } GroupWidget - + Aucun participant actif dans ce groupe No active participant in that group @@ -1427,145 +1534,150 @@ p, li { white-space: pre-wrap; } Too many active participants in that group - + Trop de participants actifs dans ce groupe pour démarrer une séance (max Too many active participants in that group to start a session (max - + participants participants - + Participants Participants - + Participants actifs Active Participants - + Séances planifiées ou réalisées Planned Session or Completed - + Actif Active - + Inactif Inactive - - + + Suppression? Deletion? - + Êtes-vous sûrs de vouloir supprimer Are you sure you want to delete - + Êtes-vous sûrs de vouloir supprimer tous les participants sélectionnés? Are you sure you want to delete all selected participants? - + Form Form - + Groupe participant Participant Group - + Démarrer Séance Start Session - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + XXXX Séances XXXX Sessions - + XXXX Participants XXXX Participants - + Participant Participant - + État State - + Séances Sessions - + Première séance First Session - + Dernière connexion Last connection - + + Afficher les participants inactifs + Show inactive participants + + + Nouveau participant New participant - + Supprimer Delete - + Informations Informations - + Dernière séance Last session - + Résumé Summary @@ -1603,58 +1715,58 @@ or Completed Stopping session... - + En attente de démarrage de séance... Waiting for the session to start... - + Déjà en séance Already in session - + vous a invité dans une séance, mais nous avons refusé l'invitation pour vous. You are invited to a session, but we denied the invitation for you. - + n'a pas répondu à did not respond to - + a refusé refused - + est occupé et ne peut répondre à is busy and cannot answer to - + l'invitation. the invitation. - + Raison: Reason: - + Service non-supporté Unsupported service - + Le service " The service " - - + + " n'est pas gérée par cette version du logiciel. Veuillez vérifier si une mise à jour existe ou contribuez au développement du logiciel! @@ -1662,87 +1774,91 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du Please update the software or contribute to the development! - + Catégorie de séance non-supportée Session category is not supported - + La catégorie de séance " The session category " - + Quitter la séance? Quit session? - + Désirez-vous quitter la séance? Do you want to qui the session? - + Répertoire où les données seront enregistrées Folder to save data - Form - Form + Form + + + + OpenTeraPlus - Séance + OpenTeraPlus - Session - + Gestion Admin - + Quitter Quit - + Terminer Close - + Invités Attendees - + Données Data - + Répertoire d'enregistrement Data recording folder - + Défaut Default - + Parcourir... Browse... - + Paramètres Parameters - + Séance inconnue Unknown session - + 00:00:00 00:00:00 @@ -1750,47 +1866,47 @@ Please update the software or contribute to the development! JoinSessionDialog - + vous invite à rejoindre une séance. invites you to join a session. - + L'invitation comporte le message suivant:<br><i> The invitation contains the following message:<br><i> - + Invitation à rejoindre une séance Join session invitation - + Invitation Invitation - + XXXX vous invite à rejoindre une séance. XXXX invites you to join the session. - + L'invitation comporte le message suivant: The invitation contains the following message: - + Joindre la séance Join session - + Refuser de joindre la séance Refuse to join session - + Désolé, je suis occupé! Sorry, I am busy! @@ -1889,88 +2005,88 @@ Please update the software or contribute to the development! Select software to launch at start - + OpenTeraPlus - Kit - Configuration OpenTeraPlus - Kit - Configuration - + Chargement en cours... Loading... - + Fermer Close - + Groupe Group - + Projet Project - + Site Site - + Service Service - + Associer ce participant à ce kit Assign this participant to this kit - + Désassocier le participant actuel Unassign current participant - + Participant Participant - + Support technique? Technical support? - + Logiciel à lancer lors de l'activation du support technique Software to launch in technical support session - - + + Parcourir... Browse... - + Autre logiciel? Other software? - + Logiciel à lancer lors de l'activation du kit Software to launch when activating kit - + Sauvegarder Save - + Configuration matérielle Hardware configuration @@ -1996,17 +2112,17 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du Please update the software or contribute to the development! - + OpenTeraPlus OpenTeraPlus - + Éteindre Close - + Logiciel de séance Session software @@ -2014,47 +2130,47 @@ Please update the software or contribute to the development! KitVideoRehabWidget - + Impossible de charger la page Unable to load page - + Problème vidéo Video Problem - + Problème audio Audio Problem - + Erreur Error - + Form Form - + Titre Title - + (Erreur) (Error) - + Réessayer Retry - + Démarrage en cours... Starting... @@ -2062,61 +2178,61 @@ Please update the software or contribute to the development! LogViewWidget - + Log Viewer Log Viewer - + Début Start - + Fin End - + Aucun résultat n'est disponible. No result available. - + événements events - - + + Type Type - + Filtrer Filter - + Rafraichir Refresh - + Date Date - + Heure Time - + Message Message @@ -2277,37 +2393,37 @@ Please update the software or contribute to the development! - + Connexion en cours... Connecting... - + OpenTeraPlus - Login OpenTeraPlus -- Login - + Mot de passe Password - + Serveur Server - + Code utilisateur Username - + Connecter Connect - + Quitter Quit @@ -2414,47 +2530,47 @@ Please update the software or contribute to the development! Technical support - + OpenTeraPlus - Kit OpenTeraPlus - Kit - + Exit Exit - + Aucun participant sélectionné No selected participant - + Allumer Turn on - + Erreur Error - + Redémarrer Reboot - + Le support technique est activé Technical support is enabled - + Support Technique Technical support - + (Version) (Version) @@ -2462,59 +2578,59 @@ Please update the software or contribute to the development! MainWindow - + Erreur HTTP HTTP Error - + Erreur Error - + Suppression impossible Cannot delete - + Données sauvegardées. Data saved. - + Données supprimées. Data deleted. - + - mise à jour... - updating... - + Récupération de Retreiving - + - suppression... - deleting... - + Erreur de séance Session error - + Une erreur est survenue: The following error occured: - + La séance ne peut pas continuer. @@ -2523,154 +2639,156 @@ La séance ne peut pas continuer. The session cannot continue. - - + + + est en ligne. is online. - - + + + est hors-ligne. is offline. - + Erreur de serveur. Server error. - - - + + + Déconnexion Disconnect - + Vous serez déconnecté du logiciel. Toute donnée non enregistrée sera perdue. You'll be logged out. Unsaved data will be lost. - + Souhaitez-vous continuer? Do you want to continue? - + Votre compte You Account - + Configuration Globale Global Configuration - + Détails Details - + Séance en cours Current session - + La séance en cours empêche la fermeture du logiciel. Current session is preventing software exit. - + Veuillez la terminer avant de poursuivre. Please end the session before continuing. - + Changement de langue Change language - + En ligne ( Online ( - + La langue a été modifiée. Souhaitez-vous vous déconnecter pour appliquer les changements? The language has been modified. Would you like to disconnect to apply the changes? - + OpenTeraPlus OpenTeraPlus - + ... ... - + 0.1 0.1 - + Nom Utilisateur User Name - - + + Historique History - + Profil Profile - + Admin Admin - + Navigateur Browser - + En ligne Online - + Nom participant... Participant name... - + Cette fonctionnalité n'est pas encore disponible! This feature is not available yet! - + Recherche Search - + Heure Time - + Événement Event @@ -2678,22 +2796,22 @@ Would you like to disconnect to apply the changes? NotifyWindow - + OpenTeraPlus Notification OpenTeraPlus Notification - + (Texte de la notification) (Notification text) - + Oui Yes - + Non No @@ -2701,41 +2819,41 @@ Would you like to disconnect to apply the changes? OnlineManagerWidget - + Form Form - - - + + + 0 0 - + Filtrer appareils Filter devices - - - + + + ... ... - + Filtrer utilisateurs Filter users - + Filtrer participants Filter Participants - + Items Items @@ -2755,17 +2873,17 @@ Would you like to disconnect to apply the changes? Devices - + Déconnecter Disconnect - + Déconnecter? Disconnect? - + Êtes-vous sûrs de vouloir déconnecter Are you sure you want to disconnect @@ -2773,22 +2891,22 @@ Would you like to disconnect to apply the changes? ParticipantWidget - + Déassignation? Unassign? - + Êtes-vous sûrs de vouloir désassigner Are you sure you want to unassign - + Confirmation Confirmation - + En désactivant l'accès web, le lien sera supprimé. Si un accès est à nouveau créé, le lien sera différent et il faudra envoyer à nouveau le lien au participant. @@ -2801,92 +2919,92 @@ If a the link is re-activated, you will need the newly generated URL to the part Do you want to continue? - + Code utilisateur manquant<br/> Username missing<br/> - + Participant désactivé Participant disabled - + Participant en séance Participant already in session - + Le participant n'a pas d'accès (web ou identification) Participant doesn't have any access (web or by identification) - + Aucun type de séance associé au projet No session type associated to project - + Ce type de séance n'est pas supporté dans cette version Unsupported session type in that version - + Type de séance inconnu Unknown session type - + Impossible de démarrer cette séance Unable to start this session - + Impossible de démarrer cette séance. Unable to start this session. - + Aucun mot de passe spécifié. No specified password. - + Informations manquantes Missing information - + Les informations suivantes sont incorrectes: The following information is missing: - + existe déjà. already exists. - + a été réalisée récemment et n'a pas été terminée. has been realised lately but not finished. - + a été planifiée. has been planned. - + Reprendre une séance? Resume session? - + Un séance de ce type, A session of the type, - + Souhaitez-vous continuer cette séance? @@ -2899,161 +3017,161 @@ Would you like to continue this session? QR code for the link - + Form Form - - + + Participant Participant - + Actif Active - + Accès via lien web Web link - + Aucun lien n'a été généré No weblink generated - - + + Copier le lien Copy link - - + + ... ... - + Envoyer par courriel Send via email - + Démarrer Séance Start Session - + Générer code QR Generate QR code - + Envoyer le lien par courriel Send by email - + Afficher le lien Show link - + Accès via identification Username/password login - - + + Code utilisateur Username - - + + Mot de passe Password - + Générer mot de passe aléatoire Generate random password - - - + + + Sauvegarder Save - + Configuration Configuration - - + + Informations Informations - + Résumé Summary - + Paramètres Settings - - + + Séances Sessions - + Éditer Edit - + Annuler Cancel - + Journal d'accès Access Log - + Appareil(s) assigné(s) Assigned Device(s) - + <<< Ajouter <<< Add - + Retirer >>> Remove >>> - + Appareils disponibles Available devices - + Appareils Devices @@ -3061,58 +3179,58 @@ Would you like to continue this session? PasswordStrengthDialog - - + + Mot de passe Password - + Confirmation Confirmation - + Générer mot de passe Generate password - + ... ... - + Longueur minimale de 10 caractères Minimal length: 10 characters - + Au moins une lettre minuscule At least one lowercase letter - + Au moins une lettre majuscule At least one uppercase letter - + Au moins un chiffre At least one digit - + Au moins un caractère spécial At least one special character - + Appliquer Apply - + Annuler Cancel @@ -3135,84 +3253,88 @@ Would you like to continue this session? Participant - + Participants Participants - + Utilisateurs Users - + Appareils Devices - + Suppression? Delete? - + Êtes-vous sûrs de vouloir supprimer Are you sure you want to delete - + Form Form - + Voir le site View site - - - + + + ... ... - + Tableau de bord Dashboard - + Recherche... Find... - + Nouveau New - + Supprimer Delete - + Vue étendue Advanced view - + Avancé Advanced - + + Afficher / masquer les éléments inactifs + Show / hide disabled elements + + Afficher / masquer les participants inactifs - Show / hide inactive participants + Show / hide inactive participants - + Rafraichir Refresh @@ -3238,61 +3360,90 @@ Would you like to continue this session? ProjectWidget - + Types de séances associés Associated session types - + + Types de tests associés + Associated test types + + + + Confirmation - désactivation + Confirm - Deletion + + + Le project sera désactivé. + Project will be disabled. + + + + Le projet sera désactivé. + Project will be disabled. + + + + Tous les participants seront aussi désactivés et les appareils associés à ceux-ci seront désassociés. + All associated participants will be disabled and all associated devices will be deassociated. + + + + Êtes-vous sûrs de vouloir continuer? + Do you want to continue? + + + Utilisateurs Users - + Groupes participants Participants Groups - + Participants Participants - + Participants actifs Active Participants - + Séances planifiées ou réalisées Planned sessions or done - + Suppression de service associé Associated service deletion - + Au moins un service a été retiré de ce project. S'il y a des types de séances qui utilisent ce service, elles ne seront plus accessibles. Souhaitez-vous continuer? At least one service has been removed from this project. If there's session types who are associated to this service, they won't be available anymore. Do you want to continue? - + Seuls les groupes utilisateurs ayant un accès au projet sont affichés. Only user groups with access to this project are displayed. - + Suppression d'appareil associé Related device association - + Au moins un appareil associé à un / des participants a été retiré de ce project. Ces participants ne pourront plus utiliser cet appareil. Souhaitez-vous continuer? @@ -3301,217 +3452,232 @@ Those participants won't be able to use that device anymore. Do you want to continue? - - + + Suppression? Deletion? - + Êtes-vous sûrs de vouloir supprimer Are you sure you want to delete - + Êtes-vous sûrs de vouloir supprimer tous les participants sélectionnés? Are you sure you want to delete all selected participants? - + Seuls les utilisateurs ayant un accès au projet sont affichés. Only users with access to this project are displayed. - + Actif Active - + Inactif Inactive - + Appareils Devices - + Form Form - + Projet Project - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + XXXX Séances XXXX Sessions - + XXXX Groupes XXXX Groups - + XXXX Participants XXXX Participants - + XXXX Utilisateurs XXXX Users - + Participant Participant - + État State - + Séances Sessions - + Première séance First Session - + Dernière séance Last Session - + + Afficher les participants inactifs + Show inactive participants + + + Nouveau participant New participant - + Nouveau groupe New group - + Supprimer Delete - + Informations Informations - + Gérer les utilisateurs Manage users - + Gérer les groupes utilisateurs Manage Users Groups - + Groupes utilisateurs User groups - + Mettre à jour les types de séances associés Update associated session types - + Types de séances Session types - + + Mettre à jour les types de tests associés + Update associated test types + + + + Types de tests + Tests types + + + Mettre à jour les appareils associés Update associated devices - + Dernière connexion Last connection - + Résumé Summary - + Utilisateur User - - + + Rôle Role - - - + + + Utilisateurs Users - + Groupe Utilisateur User Group - + La modification des accès est désactivée pour les groupes utilisateurs dont l'accès au projet provient du site (i.e. administrateurs du site associé au projet) Access modification is disabled for users groups which project access is specified in the site (i.e. project's administrators) - + Mettre à jour les rôles Update roles - + Groupes Utilisateurs Users Groups - + Mettre à jour les services associés Updated associated services - - + + Services Services @@ -3529,22 +3695,22 @@ Do you want to continue? Images - + Code QR QR Code - + Copier Copy - + Enregistrer Save - + Fermer Close @@ -3552,17 +3718,17 @@ Do you want to continue? ResultMessageWidget - + Form Form - + (Message) (Message) - + ... ... @@ -3570,47 +3736,47 @@ Do you want to continue? ServiceConfigWidget - + Configuration - Service Configuration - Service - + Configuration Configuration - + Configuration: Configuration: - + Sauvegarder Save - + Annuler Cancel - + Field service_config_config can't be set. Field service_config_config can't be set. - + Globale Global - + Les champs suivants doivent être complétés: The following fields must be entered: - + Champs invalides Invalid fields @@ -3618,89 +3784,89 @@ Do you want to continue? ServiceWidget - + Nouveau rôle New Role - - + + Code du rôle: Role Code: - + Supprimer ce rôle? Delete this role? - + Êtes-vous sûrs de vouloir supprimer le rôle: Are you shure you want to delete this role: - + Édition du rôle Edit Role - + Form Form - + Service Service - + Attention! Ces paramètres sont pour des utilisateurs avancés - modifiez à vos propres risques! Warning! Those parameters are for advanced users - change at your own risks! - - + + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Mettre à jour les sites / projets associés Update associated sites / projects - + Sites / Projets Sites / Projects - + Nouveau Rôle New Role - + Supprimer Delete - + Rôles Roles @@ -3708,90 +3874,90 @@ Do you want to continue? SessionInviteWidget - + Filtrer participants Filter Participants - - - - + + + + ... ... - + Utilisateurs Users - + Invitations à la séance Session's invitations - + Appareils Devices - + Ajouter des invités à la séance Add attendees to the session - + Éléments disponibles Available elements - + Filtrer Utilisateurs Filter Users - + Filtrer Appareils Filter Devices - + En ligne / Hors ligne Online / Offline - + Recherche... Search... - + Inviter Invite - + Invités dans la séance Invited to the session - + 1 1 - + Participants Participants - + 0 / 7 0 / 7 - + Retirer de la séance Remove from session @@ -3824,22 +3990,22 @@ Do you want to continue? SessionLobbyDialog - + Vestibule Lobby - + (Type de séance) (Session Type) - + Démarrer la séance Start Session - + Annuler Cancel @@ -3864,52 +4030,52 @@ Vous devez associer au moins un site. You must select at least one site. - + Form Form - + Type de séance Session Type - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Mettre à jour les sites / projets associés Update associated sites / projects - + Sites / Projets Sites / Projects - + Mettre à jour la configuration Update configuration - + Paramètres Settings @@ -3964,112 +4130,112 @@ You must select at least one site. Tests - + Form Form - + Séance Session - + État de la séance Session Status - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Invités Attendees - + XXXX Évaluations XXXX Tests - + XXX Appareils XXXX Devices - + XXXX Participants XXXX Participants - + XXXX Utilisateurs XXXX Users - + XXXX Données XXXX Data - + XXXX Événements XXXX Events - + Résumé Summary - + Données Data - + Évaluations Evaluations - + Type Type - + Date / Heure Date / Hour - + Contexte Context - + Description Description - + Événements Events @@ -4093,147 +4259,147 @@ You must select at least one site. Are you sure you want to delete all selected sessions ? - + Nouvelle séance New session - - - + + + Séance Session - + Ouvrir Open - - + + Supprimer Delete - + Voir les données View assets - + Voir les évaluations View tests - + Continuer la séance Continue session - + Appareil: Device: - + Participant: Participant: - + Service: Service: - + Inconnu Unknown - - + + Explorateur de données Assets explorer - - + + Explorateur d'évaluations Tests explorer - + Liste des séances Sessions list - + Chargement des séances: %p% Loading sessions: %p% - + Mois 1 Month 1 - + Mois 2 Month 2 - + Mois 3 Month 3 - + Tout cocher Select All - + Tout décocher Deselect All - + Date Date - + Type Type - + État State - + Durée Duration - + Responsable Owner - + Actions Actions - + Filtrer les séances Filter sessions - + Nouvelle New @@ -4241,253 +4407,285 @@ You must select at least one site. SiteWidget - + Utilisateurs Users - + Projets Projects - + Groupes participants Participants Groups - + Participants Participants - + Participants actifs Active Participants - + Suppression de service associé Associated service deletion - + Au moins un service a été retiré de ce site. S'il y a des projets qui utilisent ce service, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? At least one service was removed from this site. If there's projects using that service, they won't be able to use it anymore. Do you want to continue? - + Suppression d'appareil associé Device association deletion - + Au moins un appareil a été retiré de ce site. S'il y a des projets qui utilisent cet appareil, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? At least one device was removed from this site. If there is projects using that device, they won't be able to use it anymore. Do you want to continue? - + Suppression de types de séances associés Associated session types deletion - + Au moins un type de séance a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? At least one session type was removed from this site. If there are projects using that type, they won't be able to use it anymore. Do you want to continue? - + Seuls les types de séances associés au site sont affichés. Only session types related to the site are displayed. - - + + Types de séances Session types - + + Suppression de types de tests associés + Deleting associated test types + + + + Au moins un type de test a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. +Souhaitez-vous continuer? + At least one test type has been removed from this site. If any project are using this type, they won't be able to use it anymore.\nDo you want to continue? + + + Séances planifiées ou réalisées Planned or realized sessions - + Appareils Devices - + Seuls les appareils associés au site sont affichés. Only associated devices are displayed. - + Seuls les utilisateurs ayant un accès au site sont affichés. Only users with site access are displayed. - + Seuls les groupes utilisateurs ayant un accès au site sont affichés. Only users groups with site access are displayed. - + Groupes Utilisateurs Users Groups - + Form Form - + Site Site - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + XXXX Groupes XXXX Groups - + + Pour modifier les types de séances associés à ce site, veuillez contacter votre administrateur + To modify associated session types for this site, please contact your administrator + + + Gestion des types de séances Session types management - + Mettre à jour les types de séances associés Update associated session types - + + Pour modifier les types de tests associés à ce site, veuillez contacter votre administrateur + To modify associated test types for this site, please contact your administrator + + + + Mettre à jour les types de tests associés + Update associated test types + + + + Types de tests + Test types + + + Appareil à rechercher Device to search - + Gestion des appareils Devices management - + Mettre à jour les appareils associés Update associated devices - + Mettre à jour les services associés Updated associated services - + + Services Services - + XXX Appareils XXXX Devices - + XXXX Projets XXXX Projects - + XXXX Utilisateurs XXXX Users - + XXXX Séances XXXX Sessions - + XXXX Participants XXXX Participants - + Informations Informations - + Gestion des groupes utilisateurs User groups management - + Mettre à jour les rôles des groupes utilisateurs Update user groups access - + Résumé Summary - - + + Utilisateurs Users - + <html><head/><body><p>Il n'est pas possible de spécifier &quot;Aucun rôle&quot; aux groupes utilisateurs qui ont au moins un accès (Administrateur ou Utilisateur) à un projet du groupe.</p></body></html> <html><head/><body><p>You cannot specify &quot;Any Role&quot; to users groups that have (Administrator or User) access to a project.</p></body></html> - + Groupe utilisateur User Group - + Rôle Role - + Hérité? Inherited? - + Groupes utilisateurs Users Groups - - + + Appareils Devices @@ -4495,22 +4693,22 @@ realized sessions StartSessionDialog - + Démarrage de séance... Starting session... - + 10 10 - + Démarrage de la séance en cours... Starting session... - + Annuler Cancel @@ -4523,183 +4721,196 @@ realized sessions Unknown - + Utilisateur User - + Groupe utilisateur User group - + Utilisateurs: Groupe Users: group - + Utilisateurs: Préférences Users: Preferences - + Site Site - + Type de séance Session type - - + + Évaluation Test - + Évaluation: projet Test: project - + Évaluation: site Test: site - + Projet Project - + Appareil Device - + Participant Participant - + Groupe participant Participant group - + Accès: site Access: site - + Accès: projet Access: project - + Séance Session - + Appareil: site Device: site - + Appareil: projet Device: project - + Appareil: participant Device: participant - + Appareil: sous-type Device: sub-type - + Appareil: type Device: type - + Type de séance: projet Session type: project - + Type de séance: site Session type: site - + Séance: événement Session: event - + Service Service - + Service: projet Service: project - + Service: site Service: site - + + Service: accès + Service: access + + + + Service: configuration + Service: configuration + + + + Service: rôle + Service: role + + Service: Accès - Service: Access + Service: Access - Service: Configuration - Service: Configuration + Service: Configuration - + Statistiques Statistics - + Appareil: état Device: status - + Participant: état Participant: status - + Utilisateur: état User: status - + Donnée Asset - + Journal: Connexion Log: Access - + Journal: Général Log: General @@ -4707,19 +4918,23 @@ realized sessions TeraForm - + + Afficher + Show + + + Choisir la couleur Chose a color - + Form Form - Ce formulaire ne contient aucune information. - This form does not contain any information. + This form does not contain any information. @@ -4909,42 +5124,42 @@ Vous devez associer au moins un site. You must select at least one site. - + Type Évaluation Test test - + Type d'évaluation Test type - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Mettre à jour les sites / projets associés Update associated sites / projects - + Sites / Projets Sites / Projects @@ -4993,115 +5208,124 @@ You must select at least one site. item - - + + Suppression? Delete? - + Êtes-vous sûrs de vouloir supprimer Are you sure you want to delete - + Êtes-vous sûrs de vouloir supprimer toutes les évaluations sélectionnées? Are you sure you want to delete all selected tests? - + Fichier à enregistrer File to save - + Erreur d'exportation Data export error - + Impossible d'exporter les données dans le fichier. Unable to export data in file. - + Le fichier est peut-être ouvert dans une autre application? The file might be open in another software? - + Exportation terminée Data export completed - + L'exportation des données a été complétée avec succès. Data export completed with success. - + Données Data - + Évaluation Test - + Séance Session - + Type d'évaluation Test type - + État State - + Date / Heure Date / Hour - + Répondant Surveyee - + Item Item - + Résultat Result - + Ajouter Add - + Supprimer Delete - + 0 0 - + + Exporter la sélection + Export selection + + + + Tout exporter + Export all + + Exporter - Export + Export @@ -5110,7 +5334,7 @@ You must select at least one site. - + En cours In progress @@ -5126,13 +5350,13 @@ You must select at least one site. - + Complétés Completed - + Erreurs Errors @@ -5143,33 +5367,33 @@ You must select at least one site. - + Annuler Cancel - + Transferts Transfers - + Transferts en cours Transfers in progress - + Progression Progress - - + + Fichier File - + Erreur Error @@ -5198,91 +5422,107 @@ You must select at least one site. UserGroupWidget - - + + Accès - Sites Access - Sites - - + + Accès - Projets Access - Projects - + Form Form - + Groupe utilisateur User group - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + <html><head/><body><p>Il n'est pas possible de spécifier &quot;Aucun rôle&quot; aux groupes utilisateurs qui ont au moins un accès (Administrateur ou Utilisateur) à un projet du groupe.</p><p>Vous ne pouvez pas spécifier un rôle pour les sites dont vous n'est pas Administrateur.</p></body></html> <html><head/><body><p>It is not possible to specify &quot;Any role&quot; to user groups that have a least one acces (Admin or User) to a project of the group.</p><p>You cannot specify a role for sites which you are not Administrator.</p></body></html> - - + + Site Site - - + + + Rôle Role - + Mettre à jour les rôles des sites Update sites' roles - + <html><head/><body><p>Vous ne pouvez pas spécifier un rôle pour les projets dont vous n'est pas Administrateur.</p></body></html> <html><head/><body><p>You cannot specify a role for a project which you are not Administrator.</p></body></html> - + Projet Project - + Mettre à jour les rôles des projets Update projects' roles - + + Service + Service + + + + Mettre à jour les rôles des services + Update services roles + + + + Accès - Services + Service Access + + + Mettre à jour les utilisateurs membres de ce groupe Update users members of the group - + Utilisateurs Users @@ -5290,54 +5530,54 @@ You must select at least one site. UserSummaryWidget - + Résumé Utilisateur User Summary - + Utilisateur User - + Nouvelle Séance New Session - - + + Séances Sessions - + Résumé Summary - + Sauvegarder Save - + Annuler Cancel - + Journal d'accès Access Log - + Éditer Edit - - + + Informations Information @@ -5345,138 +5585,154 @@ You must select at least one site. UserWidget - + Groupes utilisateurs User's groups - - + + Journal d'accès Access Log - + Langue de l'interface Application language - + Français French - + Anglais English - + Sons lors des notifications Notification sounds - + Attention Warning - + Aucun groupe utilisateur n'a été spécifié. Vous devez spécifier au moins un groupe utilisateur You should specify at least one user group - - + + Utilisateur User - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Mettre à jour les groupes de cet utilisateur Update this user groups - + Groupes Groups - + Rôles effectifs Effective roles - + Sites Sites - - + + Site Site - + Projets Projects - + Projet Project - - + + + Rôle Role - + <html><head/><body><p>Cet utilisateur est un super administrateur.</p><p>Il est donc impossible de lui assigner des groupes utiilsateurs.</p></body></html> <html><head/><body><p>This user is a super administrator.</p><p>It is impossible to add user groups to a super administrator.</p></body></html> - + + Services + Services + + + + Cet utilisateur est un super-administrateur. + This user is a super administrator. + + + + Service + Service + + + Rôles Roles - + Mettre à jour les préférences Update Preferences - - + + Préférences Preferences - + Configuration Configuration @@ -5492,53 +5748,53 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabPTZDialog - + Configuration Caméra PTZ PTZ Camera Settings - + Type de contrôle: Control type: - - + + admin admin - + Vivotek Vivotek - + Adresse (URL): Address (URL): - + Utilisateur: User: - + Mot de passe: Password: - + Port: Port: - + Appliquer Apply - + Annuler Cancel @@ -5546,93 +5802,93 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabSetupWidget - + VideoRehabSetup VideoRehabSetup - + Titre Title - + (Erreur) (Error) - + Réessayer Retry - + Chargement en cours... Loading... - + Définir par défaut Define as default - + Configuration avancée Advanced Configuration - - + + Caméra PTZ PTZ Camera - + Type de caméra PTZ non-supporté Unsupported PTZ camera type - + Impossible de charger la page de prévisualisation de la caméra Unable to load camera preview - + Problème vidéo Video Problem - + Problème audio Audio Problem - + Erreur Error - + Erreur de caméra Camera error - + Impossible de se connecter à la source vidéo. Unable to connect to video source. - + Caméra PTZ: Impossible de se connecter. PTZ camera: unable to connect. - + Caméra PTZ: Erreur de communication. PTZ camera: Communication error. - + Caméra PTZ: Authentification refusée. PTZ camera: authenfication denied. @@ -5640,17 +5896,17 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabToolsWidget - + Form Form - + Reconnecter Reconnect - + Pause Pause @@ -5686,7 +5942,7 @@ Vous devez spécifier au moins un groupe utilisateur - + Enregistrer Save @@ -5724,58 +5980,58 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabVirtualCamSetupDialog - + Configuration - Caméra virtuelle Virtual camera - Configuration - + Configuration assistée? Configuration wizard? - + Source de la caméra Camera source - + Utilisateur: User: - + Type de source: Source type: - + Adresse (URL): Address (URL): - + Vivotek Vivotek - - + + admin admin - + Mot de passe: Password: - + Appliquer Apply - + Annuler Cancel @@ -5783,70 +6039,93 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabWidget - + Form Form - + Titre Title - + (Erreur) (Error) - + Réessayer Retry - + Établissement de la connexion... Connecting... - + Fichier disponible File available - + Le fichier File - + est disponible dans le répertoire is available in the folder - + Impossible de charger la page Unable to load page - + Problème vidéo Video Problem - + Problème audio Audio Problem - + Erreur Error + + WebLoginDialog + + + OpenTeraPlus + OpenTeraPlus + + + + Serveur + Server + + + + Chargement en cours... + Loading... + + + + Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. + Unable to reach server. Please check your Internet connection, your network settings and your firewall, then try again. + + WebSocketManager - + Le serveur ne répond pas. The server is not responding. diff --git a/client/resources/translations/openteraplus_fr.ts b/client/resources/translations/openteraplus_fr.ts index d2024629..74b51ac6 100644 --- a/client/resources/translations/openteraplus_fr.ts +++ b/client/resources/translations/openteraplus_fr.ts @@ -4,20 +4,31 @@ AboutDialog - + À propos d'OpenTera... - + À propos d'OpenTeraPlus... - + + Clé d'enregistrement du serveur: + + + + Merci! + + + + Inconnue + + AssetsWidget @@ -34,7 +45,7 @@ - + Supprimer @@ -86,7 +97,7 @@ - + Tout voir @@ -142,57 +153,57 @@ - + Données - + Actions - + Durée - + Taille - + Service - + Date / heure - + ... - + Ajouter - + 0 - + Télécharger - + Tout télécharger @@ -200,8 +211,8 @@ BaseComManager - - + + Impossible de créer la requête @@ -209,12 +220,12 @@ BaseDialog - + Dialog - + Fermer @@ -328,32 +339,32 @@ - + Nettoyage de données... - + Tout désactiver - + Tout supprimer - + Élément - + Action - + Terminer @@ -361,83 +372,83 @@ ClientApp - + Connexion - + Bienvenue! - + Déconnexion - + Vous avez été déconnecté du serveur. Veuillez vous connecter à nouveau. - - + + La connexion a été refusée par le serveur. - + Impossible de rejoindre le serveur. - + Le serveur est introuvable. - + Impossible de se connecter (Code erreur: - + Une nouvelle version ( - + ) du logiciel est disponible. - + Veuillez contacter votre fournisseur pour l'obtenir. - + Cliquez - + ICI - + pour la télécharger. - + Important: assurez-vous que le logiciel est bien fermé avant de procéder à la mise à jour. - + Nouvelle version disponible! @@ -445,22 +456,22 @@ ComManager - + L'utilisateur est déjà connecté. - + Erreur inconnue - + Utilisateur ou mot de passe invalide. - + La communication avec le serveur n'a pu être établie. @@ -468,72 +479,72 @@ ConfigWidget - + Utilisateurs - + Groupes utilisateurs - + Sites - + Appareils - + Type appareils - + Sous-types appareils - + Types de séances - + Types évaluations - + Services - + Erreur inconnue - + Form - + Paramètres - + Événements - + Journal d'accès @@ -577,7 +588,7 @@ - + Renommer @@ -587,82 +598,82 @@ - + DanceWidgetConfig - + Aucun type de séance lié au service "Télédanse" associé à ce projet. Veuillez ajouter un type de séance approprié. - + Type de séance - + Vidéos assignés - + Vidéo - + Mettre à jour - + Annuler - + Monter - + <<< Ajouter - + Retirer >>> - + Descendre - + Vidéos disponibles - + Séquence - + Ajouter - + Supprimer - + Bibliothèque @@ -670,171 +681,257 @@ DashboardWidget - - + + Inconnu - + Appareil: - + Participant: - + Service: - - + + Séances à venir - - + + Participants récents - + participant(s) sans séance depuis au moins 6 mois - - - - + + + + mois - + participant(s) sans aucune séance réalisée - - + + Créé depuis - + utilisateur(s) non-connecté(s) depuis au moins 6 mois - + utilisateur(s) jamais connecté(s) - - + + Attention requise - - + + Impossible de démarrer la séance - + Cette séance ne peut être démarrée: le type de séance est inconnu. - + Cette séance ne peut être démarrée: séance introuvable. - + Gérer - + Dashboard - + Aucune séance n'est prévue pour le moment. - + Date - + Séance - + Type - + Responsable - - + + Projet - + Invités - + Aucun participant récent. - + Participant - + Dernière séance - + Tout va bien! :-) - + Avertissement - + Action + + DashboardsConfigWidget + + + Aucune + + + + + Erreur HTTP + + + + + Erreur + + + + + Données sauvegardées + + + + + Suppression + + + + + Êtes-vous sûr de vouloir supprimer le tableau de bord sélectionné? + + + + + Dashboards Config + + + + + + + + ... + + + + + Éditer + + + + + Description + + + + + Nom + + + + + Versions + + + + + Activé pour ce site / projet + + + + + Version fixe pour ce site / project + + + + + Mettre à jour + + + + + Annuler + + + DataEditorWidget @@ -849,16 +946,26 @@ + Gestionnaire + + + + + Éditeur + + + + Aucun rôle - + Les champs suivants doivent être complétés: - + Champs invalides @@ -871,60 +978,60 @@ - + Suppression? - + Êtes-vous sûrs de vouloir supprimer - + Suppression de service? - + En supprimant le service - + toutes les données créées par ce service seront supprimées. Êtes-vous vraiment sûrs? - + Form - + Seuls les ... ayant un lien avec ce ... sont présentement affichés. - + Filtrer - + Tout voir - + Recherche... - - - + + + ... @@ -932,34 +1039,34 @@ DeviceAssignDialog - + Assignation d'un appareil - + L'appareil est présentement assigné au(x) participant(s) suivant(s): - + <html><head/><body><p>Souhaitez-vous <span style=" font-weight:600;">désassocier</span> cet appareil de ces participants avant de l'ajouter au participant actuel ou souhaitez-vous <span style=" font-weight:600;">ajouter</span> un participant supplémentaire à cet appareil?</p></body></html> - + Déassocier puis ajouter - + Ajouter sans désassocier - + Annuler @@ -967,37 +1074,37 @@ désassocier DeviceSubTypeWidget - + Form - + Sous-type appareil - + Éditer - + Sauvegarder - + Annuler - + Informations - + Appareils @@ -1005,59 +1112,59 @@ désassocier DeviceSummaryWidget - + Résumé appareil - + Appareil - + Nouvelle Séance - + Cet appareil ne peut être mis en ligne - impossible de réaliser une nouvelle séance avec celui-ci. - - + + Séances - + Résumé - - + + Informations - + Éditer - + Sauvegarder - + Annuler - + Journal d'accès @@ -1065,37 +1172,37 @@ désassocier DeviceTypeWidget - + Form - + Type Appareil - + Éditer - + Sauvegarder - + Annuler - + Informations - + Appareils @@ -1109,7 +1216,7 @@ désassocier - + Journal d'accès @@ -1147,57 +1254,57 @@ Si l'appareil est présentement déployé, les données ne seront plus coll - + Form - + Appareil - + Éditer - + Sauvegarder - + Annuler - + Informations - + Mettre à jour les sites / projets associés à cet appareil - + Sites / Projets - + Retirer cet appareil de ce participant - + Participants - + Configuration @@ -1243,27 +1350,27 @@ Si l'appareil est présentement déployé, les données ne seront plus coll - + Invitation par courriel - + Pour le moment, aucun courriel automatisé n'est envoyé par le système. Vous êtes responsable d'envoyer ce courriel. - + Destinataire: - + Aucun courriel spécifié. - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1282,17 +1389,17 @@ p, li { white-space: pre-wrap; } - + Copier - + Envoyer (local) - + Fermer @@ -1305,37 +1412,37 @@ p, li { white-space: pre-wrap; } - + Envoi de fichier - + Fichier - + Libellé - + Ajouter - + Retirer - + Envoyer - + Annuler @@ -1343,32 +1450,32 @@ p, li { white-space: pre-wrap; } GeneratePasswordDialog - + Générateur de mot de passe - + Mot de passe - + Générer - + Copier - + Appliquer - + Annuler @@ -1384,12 +1491,12 @@ p, li { white-space: pre-wrap; } GlobalMessageBox - + Oui - + Non @@ -1397,149 +1504,154 @@ p, li { white-space: pre-wrap; } GroupWidget - + Aucun participant actif dans ce groupe - + Trop de participants actifs dans ce groupe pour démarrer une séance (max - + participants - + Participants - + Participants actifs - + Séances planifiées ou réalisées - + Actif - + Inactif - - + + Suppression? - + Êtes-vous sûrs de vouloir supprimer - + Êtes-vous sûrs de vouloir supprimer tous les participants sélectionnés? - + Form - + Groupe participant - + Démarrer Séance - + Éditer - + Sauvegarder - + Annuler - + XXXX Séances - + XXXX Participants - + Participant - + État - + Séances - + Première séance - + Dernière connexion - + + Afficher les participants inactifs + + + + Nouveau participant - + Supprimer - + Informations - + Dernière séance - + Résumé @@ -1577,145 +1689,145 @@ ou réalisées - + En attente de démarrage de séance... - + Déjà en séance - + vous a invité dans une séance, mais nous avons refusé l'invitation pour vous. - + n'a pas répondu à - + a refusé - + est occupé et ne peut répondre à - + l'invitation. - + Raison: - + Service non-supporté - + Le service " - - + + " n'est pas gérée par cette version du logiciel. Veuillez vérifier si une mise à jour existe ou contribuez au développement du logiciel! - + Catégorie de séance non-supportée - + La catégorie de séance " - + Quitter la séance? - + Désirez-vous quitter la séance? - + Répertoire où les données seront enregistrées - - Form + + OpenTeraPlus - Séance - + Gestion - + Quitter - + Terminer - + Invités - + Données - + Répertoire d'enregistrement - + Défaut - + Parcourir... - + Paramètres - + Séance inconnue - + 00:00:00 @@ -1723,47 +1835,47 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du JoinSessionDialog - + vous invite à rejoindre une séance. - + L'invitation comporte le message suivant:<br><i> - + Invitation à rejoindre une séance - + Invitation - + XXXX vous invite à rejoindre une séance. - + L'invitation comporte le message suivant: - + Joindre la séance - + Refuser de joindre la séance - + Désolé, je suis occupé! @@ -1862,88 +1974,88 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du - + OpenTeraPlus - Kit - Configuration - + Chargement en cours... - + Fermer - + Groupe - + Projet - + Site - + Service - + Associer ce participant à ce kit - + Désassocier le participant actuel - + Participant - + Support technique? - + Logiciel à lancer lors de l'activation du support technique - - + + Parcourir... - + Autre logiciel? - + Logiciel à lancer lors de l'activation du kit - + Sauvegarder - + Configuration matérielle @@ -1968,17 +2080,17 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du - + OpenTeraPlus - + Éteindre - + Logiciel de séance @@ -1986,47 +2098,47 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du KitVideoRehabWidget - + Impossible de charger la page - + Problème vidéo - + Problème audio - + Erreur - + Form - + Titre - + (Erreur) - + Réessayer - + Démarrage en cours... @@ -2034,61 +2146,61 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du LogViewWidget - + Log Viewer - + Début - + Fin - + Aucun résultat n'est disponible. - + événements - - + + Type - + Filtrer - + Rafraichir - + Date - + Heure - + Message @@ -2249,37 +2361,37 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du - + Connexion en cours... - + OpenTeraPlus - Login - + Mot de passe - + Serveur - + Code utilisateur - + Connecter - + Quitter @@ -2386,47 +2498,47 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du - + OpenTeraPlus - Kit - + Exit - + Aucun participant sélectionné - + Allumer - + Erreur - + Redémarrer - + Le support technique est activé - + Support Technique - + (Version) @@ -2434,211 +2546,213 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du MainWindow - + Erreur HTTP - + Erreur - + Suppression impossible - + Données sauvegardées. - + Données supprimées. - + - mise à jour... - + Récupération de - + - suppression... - + Erreur de séance - + Une erreur est survenue: - + La séance ne peut pas continuer. - - + + + est en ligne. - - + + + est hors-ligne. - + Erreur de serveur. - - - + + + Déconnexion - + Vous serez déconnecté du logiciel. Toute donnée non enregistrée sera perdue. - + Souhaitez-vous continuer? - + Votre compte - + Configuration Globale - + Détails - + Séance en cours - + La séance en cours empêche la fermeture du logiciel. - + Veuillez la terminer avant de poursuivre. - + Changement de langue - + En ligne ( - + La langue a été modifiée. Souhaitez-vous vous déconnecter pour appliquer les changements? - + OpenTeraPlus - + ... - + 0.1 - + Nom Utilisateur - - + + Historique - + Profil - + Admin - + Navigateur - + En ligne - + Nom participant... - + Cette fonctionnalité n'est pas encore disponible! - + Recherche - + Heure - + Événement @@ -2646,22 +2760,22 @@ Souhaitez-vous vous déconnecter pour appliquer les changements? NotifyWindow - + OpenTeraPlus Notification - + (Texte de la notification) - + Oui - + Non @@ -2669,41 +2783,41 @@ Souhaitez-vous vous déconnecter pour appliquer les changements? OnlineManagerWidget - + Form - - - + + + 0 - + Filtrer appareils - - - + + + ... - + Filtrer utilisateurs - + Filtrer participants - + Items @@ -2723,17 +2837,17 @@ Souhaitez-vous vous déconnecter pour appliquer les changements? - + Déconnecter - + Déconnecter? - + Êtes-vous sûrs de vouloir déconnecter @@ -2741,62 +2855,62 @@ Souhaitez-vous vous déconnecter pour appliquer les changements? ParticipantWidget - + Déassignation? - + Êtes-vous sûrs de vouloir désassigner - + Participant désactivé - + Participant en séance - + Le participant n'a pas d'accès (web ou identification) - + Aucun type de séance associé au projet - + Ce type de séance n'est pas supporté dans cette version - + Type de séance inconnu - + Impossible de démarrer cette séance - + Impossible de démarrer cette séance. - + Confirmation - + En désactivant l'accès web, le lien sera supprimé. Si un accès est à nouveau créé, le lien sera différent et il faudra envoyer à nouveau le lien au participant. @@ -2805,213 +2919,213 @@ Souhaitez-vous continuer? - + Code utilisateur manquant<br/> - + Aucun mot de passe spécifié. - + Informations manquantes - + Les informations suivantes sont incorrectes: - + existe déjà. - + a été réalisée récemment et n'a pas été terminée. - + a été planifiée. - + Reprendre une séance? - + Un séance de ce type, - + Souhaitez-vous continuer cette séance? - + Form - - + + Participant - + Actif - + Accès via lien web - + Aucun lien n'a été généré - - + + Copier le lien - - + + ... - + Envoyer par courriel - + Démarrer Séance - + Générer code QR - + Envoyer le lien par courriel - + Afficher le lien - + Accès via identification - - + + Code utilisateur - - + + Mot de passe - + Générer mot de passe aléatoire - - - + + + Sauvegarder - + Configuration - - + + Informations - + Résumé - + Paramètres - - + + Séances - + Éditer - + Annuler - + Journal d'accès - + Appareil(s) assigné(s) - + <<< Ajouter - + Retirer >>> - + Appareils disponibles - + Appareils @@ -3019,58 +3133,58 @@ Souhaitez-vous continuer cette séance? PasswordStrengthDialog - - + + Mot de passe - + Confirmation - + Générer mot de passe - + ... - + Longueur minimale de 10 caractères - + Au moins une lettre minuscule - + Au moins une lettre majuscule - + Au moins un chiffre - + Au moins un caractère spécial - + Appliquer - + Annuler @@ -3093,84 +3207,84 @@ Souhaitez-vous continuer cette séance? - + Participants - + Utilisateurs - + Appareils - + Suppression? - + Êtes-vous sûrs de vouloir supprimer - + Form - + Voir le site - - - + + + ... - + Tableau de bord - + Recherche... - + Nouveau - + Supprimer - + Vue étendue - + Avancé - - Afficher / masquer les participants inactifs + + Afficher / masquer les éléments inactifs - + Rafraichir @@ -3196,276 +3310,316 @@ Souhaitez-vous continuer cette séance? ProjectWidget - + Types de séances associés - + + Le projet sera désactivé. + + + + Utilisateurs - + Groupes participants - + Participants - + Participants actifs - + Séances planifiées ou réalisées - + Actif - + Inactif - + + Types de tests associés + + + + + Confirmation - désactivation + + + + + Tous les participants seront aussi désactivés et les appareils associés à ceux-ci seront désassociés. + + + + + Êtes-vous sûrs de vouloir continuer? + + + + Suppression de service associé - + Au moins un service a été retiré de ce project. S'il y a des types de séances qui utilisent ce service, elles ne seront plus accessibles. Souhaitez-vous continuer? - + Seuls les groupes utilisateurs ayant un accès au projet sont affichés. - + Suppression d'appareil associé - + Au moins un appareil associé à un / des participants a été retiré de ce project. Ces participants ne pourront plus utiliser cet appareil. Souhaitez-vous continuer? - - + + Suppression? - + Êtes-vous sûrs de vouloir supprimer - + Êtes-vous sûrs de vouloir supprimer tous les participants sélectionnés? - + Seuls les utilisateurs ayant un accès au projet sont affichés. - + Appareils - + Form - + Projet - + Éditer - + Sauvegarder - + Annuler - + XXXX Séances - + XXXX Groupes - + XXXX Participants - + XXXX Utilisateurs - + Participant - + État - + Séances - + Première séance - + Dernière séance - + Dernière connexion - + Résumé - + + Afficher les participants inactifs + + + + Nouveau participant - + Nouveau groupe - + Supprimer - + Informations - + Gérer les utilisateurs - + Groupes utilisateurs - + Mettre à jour les types de séances associés - + Types de séances - + + Mettre à jour les types de tests associés + + + + + Types de tests + + + + Mettre à jour les appareils associés - + Utilisateur - - + + Rôle - - - + + + Utilisateurs - + Gérer les groupes utilisateurs - + Groupe Utilisateur - + La modification des accès est désactivée pour les groupes utilisateurs dont l'accès au projet provient du site (i.e. administrateurs du site associé au projet) - + Mettre à jour les rôles - + Groupes Utilisateurs - + Mettre à jour les services associés - - + + Services @@ -3483,22 +3637,22 @@ Souhaitez-vous continuer? - + Code QR - + Copier - + Enregistrer - + Fermer @@ -3506,17 +3660,17 @@ Souhaitez-vous continuer? ResultMessageWidget - + Form - + (Message) - + ... @@ -3524,47 +3678,47 @@ Souhaitez-vous continuer? ServiceConfigWidget - + Configuration - Service - + Configuration - + Configuration: - + Sauvegarder - + Annuler - + Field service_config_config can't be set. - + Globale - + Les champs suivants doivent être complétés: - + Champs invalides @@ -3572,89 +3726,89 @@ Souhaitez-vous continuer? ServiceWidget - + Nouveau rôle - - + + Code du rôle: - + Supprimer ce rôle? - + Êtes-vous sûrs de vouloir supprimer le rôle: - + Édition du rôle - + Form - + Service - + Attention! Ces paramètres sont pour des utilisateurs avancés - modifiez à vos propres risques! - - + + Éditer - + Sauvegarder - + Annuler - + Informations - + Mettre à jour les sites / projets associés - + Sites / Projets - + Nouveau Rôle - + Supprimer - + Rôles @@ -3662,90 +3816,90 @@ Souhaitez-vous continuer? SessionInviteWidget - + Filtrer participants - - - - + + + + ... - + Utilisateurs - + Invitations à la séance - + Appareils - + Ajouter des invités à la séance - + Éléments disponibles - + Filtrer Utilisateurs - + Filtrer Appareils - + En ligne / Hors ligne - + Recherche... - + Inviter - + Invités dans la séance - + 1 - + Participants - + 0 / 7 - + Retirer de la séance @@ -3778,22 +3932,22 @@ Souhaitez-vous continuer? SessionLobbyDialog - + Vestibule - + (Type de séance) - + Démarrer la séance - + Annuler @@ -3817,52 +3971,52 @@ Vous devez associer au moins un site. - + Form - + Type de séance - + Éditer - + Sauvegarder - + Annuler - + Informations - + Mettre à jour les sites / projets associés - + Sites / Projets - + Mettre à jour la configuration - + Paramètres @@ -3917,112 +4071,112 @@ Vous devez associer au moins un site. - + Form - + Séance - + État de la séance - + Éditer - + Sauvegarder - + Annuler - + Informations - + Invités - + XXXX Évaluations - + XXX Appareils - + XXXX Participants - + XXXX Utilisateurs - + XXXX Données - + XXXX Événements - + Résumé - + Données - + Évaluations - + Type - + Date / Heure - + Contexte - + Description - + Événements @@ -4046,147 +4200,147 @@ Vous devez associer au moins un site. - + Nouvelle séance - - - + + + Séance - + Ouvrir - - + + Supprimer - + Voir les données - + Voir les évaluations - + Continuer la séance - + Appareil: - + Participant: - + Service: - + Inconnu - - + + Explorateur de données - - + + Explorateur d'évaluations - + Liste des séances - + Chargement des séances: %p% - + Mois 1 - + Mois 2 - + Mois 3 - + Tout cocher - + Tout décocher - + Date - + Type - + État - + Durée - + Responsable - + Actions - + Filtrer les séances - + Nouvelle @@ -4194,249 +4348,281 @@ Vous devez associer au moins un site. SiteWidget - + Utilisateurs - + Projets - + Groupes participants - + Participants - + Participants actifs - + Séances planifiées ou réalisées - + Appareils - + Suppression de service associé - + Au moins un service a été retiré de ce site. S'il y a des projets qui utilisent ce service, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? - + Suppression d'appareil associé - + Au moins un appareil a été retiré de ce site. S'il y a des projets qui utilisent cet appareil, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? - + Suppression de types de séances associés - + Au moins un type de séance a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? - + Seuls les types de séances associés au site sont affichés. - - + + Types de séances - + + Suppression de types de tests associés + + + + + Au moins un type de test a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. +Souhaitez-vous continuer? + + + + Seuls les appareils associés au site sont affichés. - + Seuls les utilisateurs ayant un accès au site sont affichés. - + Seuls les groupes utilisateurs ayant un accès au site sont affichés. - + Groupes Utilisateurs - + Form - + Site - + Éditer - + Sauvegarder - + Annuler - + XXXX Groupes - + Informations - + + Pour modifier les types de séances associés à ce site, veuillez contacter votre administrateur + + + + Gestion des types de séances - + Mettre à jour les types de séances associés - + + Pour modifier les types de tests associés à ce site, veuillez contacter votre administrateur + + + + + Mettre à jour les types de tests associés + + + + + Types de tests + + + + Appareil à rechercher - + Gestion des appareils - + Mettre à jour les appareils associés - + Mettre à jour les services associés - + + Services - + XXX Appareils - + XXXX Projets - + XXXX Utilisateurs - + XXXX Séances - + XXXX Participants - + Mettre à jour les rôles des groupes utilisateurs - + Résumé - - + + Utilisateurs - + Gestion des groupes utilisateurs - + <html><head/><body><p>Il n'est pas possible de spécifier &quot;Aucun rôle&quot; aux groupes utilisateurs qui ont au moins un accès (Administrateur ou Utilisateur) à un projet du groupe.</p></body></html> - + Groupe utilisateur - + Rôle - + Hérité? - + Groupes utilisateurs - - + + Appareils @@ -4444,22 +4630,22 @@ Souhaitez-vous continuer? StartSessionDialog - + Démarrage de séance... - + 10 - + Démarrage de la séance en cours... - + Annuler @@ -4472,183 +4658,188 @@ Souhaitez-vous continuer? - + Utilisateur - + Groupe utilisateur - + Utilisateurs: Groupe - + Utilisateurs: Préférences - + Site - + Type de séance - - + + Évaluation - + Évaluation: projet - + Évaluation: site - + Projet - + Appareil - + Participant - + Groupe participant - + Accès: site - + Accès: projet - + Séance - + Appareil: site - + Appareil: projet - + Appareil: participant - + Appareil: sous-type - + Appareil: type - + Type de séance: projet - + Type de séance: site - + Séance: événement - + Service - + Service: projet - + Service: site - - Service: Accès + + Service: accès - - Service: Configuration + + Service: configuration - + + Service: rôle + + + + Statistiques - + Appareil: état - + Participant: état - + Utilisateur: état - + Donnée - + Journal: Connexion - + Journal: Général @@ -4656,18 +4847,18 @@ Souhaitez-vous continuer? TeraForm - - Choisir la couleur + + Afficher - - Form + + Choisir la couleur - - Ce formulaire ne contient aucune information. + + Form @@ -4857,42 +5048,42 @@ Vous devez associer au moins un site. - + Type Évaluation - + Type d'évaluation - + Éditer - + Sauvegarder - + Annuler - + Informations - + Mettre à jour les sites / projets associés - + Sites / Projets @@ -4941,114 +5132,119 @@ Vous devez associer au moins un site. - - + + Suppression? - + Êtes-vous sûrs de vouloir supprimer - + Êtes-vous sûrs de vouloir supprimer toutes les évaluations sélectionnées? - + Fichier à enregistrer - + Erreur d'exportation - + Impossible d'exporter les données dans le fichier. - + Le fichier est peut-être ouvert dans une autre application? - + Exportation terminée - + L'exportation des données a été complétée avec succès. - + Données - + Évaluation - + Séance - + Type d'évaluation - + État - + Date / Heure - + Répondant - + Item - + Résultat - + Ajouter - + Supprimer - + 0 - - Exporter + + Exporter la sélection + + + + + Tout exporter @@ -5058,7 +5254,7 @@ Vous devez associer au moins un site. - + En cours @@ -5074,13 +5270,13 @@ Vous devez associer au moins un site. - + Complétés - + Erreurs @@ -5091,33 +5287,33 @@ Vous devez associer au moins un site. - + Annuler - + Transferts - + Transferts en cours - + Progression - - + + Fichier - + Erreur @@ -5146,91 +5342,107 @@ Vous devez associer au moins un site. UserGroupWidget - - + + Accès - Sites - - + + Accès - Projets - + Form - + Groupe utilisateur - + Éditer - + Sauvegarder - + Annuler - + Informations - + <html><head/><body><p>Il n'est pas possible de spécifier &quot;Aucun rôle&quot; aux groupes utilisateurs qui ont au moins un accès (Administrateur ou Utilisateur) à un projet du groupe.</p><p>Vous ne pouvez pas spécifier un rôle pour les sites dont vous n'est pas Administrateur.</p></body></html> - - + + Site - - + + + Rôle - + Mettre à jour les rôles des sites - + <html><head/><body><p>Vous ne pouvez pas spécifier un rôle pour les projets dont vous n'est pas Administrateur.</p></body></html> - + Projet - + Mettre à jour les rôles des projets - + + Service + + + + + Mettre à jour les rôles des services + + + + + Accès - Services + + + + Mettre à jour les utilisateurs membres de ce groupe - + Utilisateurs @@ -5238,54 +5450,54 @@ Vous devez associer au moins un site. UserSummaryWidget - + Utilisateur - + Nouvelle Séance - - + + Séances - + Résumé - + Sauvegarder - + Annuler - + Journal d'accès - + Éditer - + Résumé Utilisateur - - + + Informations @@ -5293,138 +5505,154 @@ Vous devez associer au moins un site. UserWidget - + Groupes utilisateurs - - + + Journal d'accès - + Langue de l'interface - + Français - + Anglais - + Sons lors des notifications - + Attention - + Aucun groupe utilisateur n'a été spécifié. Vous devez spécifier au moins un groupe utilisateur - - + + Utilisateur - + Éditer - + Sauvegarder - + Annuler - + Informations - + Mettre à jour les groupes de cet utilisateur - + Groupes - + Rôles effectifs - + Sites - - + + Site - + Projets - + Projet - - + + + Rôle - + <html><head/><body><p>Cet utilisateur est un super administrateur.</p><p>Il est donc impossible de lui assigner des groupes utiilsateurs.</p></body></html> - + + Services + + + + + Cet utilisateur est un super-administrateur. + + + + + Service + + + + Rôles - + Mettre à jour les préférences - - + + Préférences - + Configuration @@ -5440,53 +5668,53 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabPTZDialog - + Configuration Caméra PTZ - + Type de contrôle: - - + + admin - + Vivotek - + Adresse (URL): - + Utilisateur: - + Mot de passe: - + Port: - + Appliquer - + Annuler @@ -5494,93 +5722,93 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabSetupWidget - + VideoRehabSetup - + Titre - + (Erreur) - + Réessayer - + Chargement en cours... - + Définir par défaut - + Configuration avancée - - + + Caméra PTZ - + Type de caméra PTZ non-supporté - + Impossible de charger la page de prévisualisation de la caméra - + Problème vidéo - + Problème audio - + Erreur - + Erreur de caméra - + Impossible de se connecter à la source vidéo. - + Caméra PTZ: Impossible de se connecter. - + Caméra PTZ: Erreur de communication. - + Caméra PTZ: Authentification refusée. @@ -5588,17 +5816,17 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabToolsWidget - + Form - + Reconnecter - + Pause @@ -5634,7 +5862,7 @@ Vous devez spécifier au moins un groupe utilisateur - + Enregistrer @@ -5672,58 +5900,58 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabVirtualCamSetupDialog - + Configuration - Caméra virtuelle - + Configuration assistée? - + Source de la caméra - + Utilisateur: - + Type de source: - + Adresse (URL): - + Vivotek - - + + admin - + Mot de passe: - + Appliquer - + Annuler @@ -5731,70 +5959,93 @@ Vous devez spécifier au moins un groupe utilisateur VideoRehabWidget - + Form - + Titre - + (Erreur) - + Réessayer - + Établissement de la connexion... - + Fichier disponible - + Le fichier - + est disponible dans le répertoire - + Impossible de charger la page - + Problème vidéo - + Problème audio - + Erreur + + WebLoginDialog + + + OpenTeraPlus + + + + + Serveur + + + + + Chargement en cours... + + + + + Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. + + + WebSocketManager - + Le serveur ne répond pas. diff --git a/client/src/CMakeLists.txt b/client/src/CMakeLists.txt index c6ed1fcd..c079dc1d 100755 --- a/client/src/CMakeLists.txt +++ b/client/src/CMakeLists.txt @@ -16,6 +16,11 @@ endif (MSVC) find_package(Qt6 REQUIRED COMPONENTS LinguistTools Multimedia WebSockets Network) +qt_standard_project_setup( + I18N_SOURCE_LANGUAGE fr + I18N_TRANSLATED_LANGUAGES en fr +) + # Drivers first add_subdirectory(drivers) @@ -351,31 +356,62 @@ set(translation_files_srcs ) -#Translation files, this is done manually to avoid removing the file when doing make clean -# Add -noobsolete parameter to remove obsoleted translations -add_custom_target(openteraplus_en_ts - COMMAND ${Qt6_LUPDATE_EXECUTABLE} -target-language en ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${moc_uis} +# #Translation files, this is done manually to avoid removing the file when doing make clean +# # Add -noobsolete parameter to remove obsoleted translations +# add_custom_target(openteraplus_en_ts +# COMMAND ${Qt6_LUPDATE_EXECUTABLE} -target-language en ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts +# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +# DEPENDS ${moc_uis} +# ) + +# add_custom_target(openteraplus_fr_ts +# COMMAND ${Qt6_LUPDATE_EXECUTABLE} -target-language fr ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts +# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +# DEPENDS ${moc_uis} +# ) + +# #set qm files output directory +# set_source_files_properties(${translation_files_srcs} PROPERTIES OUTPUT_LOCATION ${TERACLIENT_RES_INCLUDES}/translations/) + +# #Build this target to update translations +# add_custom_target(translations DEPENDS openteraplus_en_ts openteraplus_fr_ts) +# add_custom_target(translation_files SOURCES ${translation_files_srcs}) + +# #Generate qm files from .ts files +# qt6_add_translation(qm_files +# ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts +# ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts) + +# Translations +# if (Qt6_VERSION VERSION_GREATER_EQUAL 6.7) +# qt_add_translations(TARGETS OpenTeraPlus +# SOURCE_TARGETS ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} +# TS_FILES ${translation_files_srcs} + +# ) +# else() +# qt_add_translations(OpenTeraPlus +# TS_FILES +# ${translation_files_srcs} +# ) +# endif() +qt_add_lupdate( + TS_FILES + ${translation_files_srcs} + + SOURCES + ${srcs} + ${headers} + ${moc_uis} + + SOURCE_TARGETS opentera_shared ) -add_custom_target(openteraplus_fr_ts - COMMAND ${Qt6_LUPDATE_EXECUTABLE} -target-language fr ${srcs} ${OPENTERA_SHARED_INCLUDES} ${headers} ${moc_uis} -ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${moc_uis} +qt_add_lrelease( + TS_FILES + ${translation_files_srcs} ) -#set qm files output directory -set_source_files_properties(${translation_files_srcs} PROPERTIES OUTPUT_LOCATION ${TERACLIENT_RES_INCLUDES}/translations/) - -#Build this target to update translations -add_custom_target(translations DEPENDS openteraplus_en_ts openteraplus_fr_ts) -add_custom_target(translation_files SOURCES ${translation_files_srcs}) - -#Generate qm files from .ts files -qt6_add_translation(qm_files ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts) - - message(STATUS "qm_files : ${qm_files}") include_directories( diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 79501225..b3dd8841 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -1,7 +1,10 @@ #include "WebLoginDialog.h" #include "ui_WebLoginDialog.h" + #include +#include "Utils.h" +#include "TeraSettings.h" WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) : QDialog(parent), ui(new Ui::WebLoginDialog), m_config(config) @@ -16,7 +19,10 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) QVBoxLayout *layout = new QVBoxLayout(ui->centralWidget); layout->addWidget(m_webView); + m_requestInterceptor = new WebLoginRequestInterceptor(this); + m_webPage = new QWebEnginePage(m_webView); + m_webPage->setUrlRequestInterceptor(m_requestInterceptor); QWebChannel *channel = new QWebChannel(m_webPage); @@ -101,6 +107,7 @@ void WebLoginDialog::onLoginPageLoaded(bool ok) if (ok){ ui->centralWidget->show(); ui->frameLoginMessages->hide(); + m_webView->setFocus(); }else{ ui->lblError->show(); ui->lblLoading->hide(); @@ -122,3 +129,31 @@ QString WebLoginDialog::currentServerName() } return QString(); } + + +WebLoginRequestInterceptor::WebLoginRequestInterceptor(QObject *p) : QWebEngineUrlRequestInterceptor(p) +{ + // Cache OS information + m_osName = Utils::getOsName(); + m_osVersion = Utils::getOsVersion(); +} + +WebLoginRequestInterceptor::~WebLoginRequestInterceptor() +{ + +} + +void WebLoginRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) +{ + // Inject client name and version + info.setHttpHeader("X-Client-Name", QByteArray(OPENTERAPLUS_CLIENT_NAME)); + info.setHttpHeader("X-Client-Version", QByteArray(OPENTERAPLUS_VERSION)); + info.setHttpHeader("X-OS-Name", m_osName.toUtf8()); + info.setHttpHeader("X-OS-Version", m_osVersion.toUtf8()); + + // Inject required language + QString localeString = QLocale().bcp47Name(); + //qDebug() << "localeString : " << localeString; + info.setHttpHeader(QByteArray("Accept-Language"), localeString.toUtf8()); +} + diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 0598030c..2c94276b 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -2,12 +2,13 @@ #define WEBLOGINDIALOG_H #include -#include "TeraSettings.h" + #include "managers/ConfigManagerClient.h" #include #include #include #include +#include #include @@ -39,6 +40,19 @@ namespace Ui { class WebLoginDialog; } + +class WebLoginRequestInterceptor : public QWebEngineUrlRequestInterceptor { + + // QWebEngineUrlRequestInterceptor interface +public: + WebLoginRequestInterceptor(QObject *p = nullptr); + ~WebLoginRequestInterceptor(); + void interceptRequest(QWebEngineUrlRequestInfo &info) override; +private: + QString m_osName; + QString m_osVersion; +}; + class WebLoginDialog : public QDialog { Q_OBJECT @@ -64,10 +78,12 @@ private slots: void onLoginPageLoading(); private: - Ui::WebLoginDialog *ui; - QWebEngineView *m_webView; - QWebEnginePage *m_webPage; + Ui::WebLoginDialog *ui; + QWebEngineView *m_webView; + QWebEnginePage *m_webPage; + WebLoginRequestInterceptor *m_requestInterceptor; ConfigManagerClient *m_config; }; + #endif // WEBLOGINDIALOG_H diff --git a/client/src/dialogs/WebLoginDialog.ui b/client/src/dialogs/WebLoginDialog.ui index b200c20c..4788e520 100644 --- a/client/src/dialogs/WebLoginDialog.ui +++ b/client/src/dialogs/WebLoginDialog.ui @@ -6,7 +6,7 @@ 0 0 - 450 + 500 500 @@ -18,7 +18,7 @@ - 450 + 500 500 diff --git a/client/src/editors/ProjectWidget.cpp b/client/src/editors/ProjectWidget.cpp index b3138501..06eaebaa 100644 --- a/client/src/editors/ProjectWidget.cpp +++ b/client/src/editors/ProjectWidget.cpp @@ -660,7 +660,7 @@ bool ProjectWidget::validateData() if (!editedProjectEnabled && m_data->getFieldValue("project_enabled").toBool()){ // We changed from "enabled" to "disabled". User confirmation required before proceeding. GlobalMessageBox msg; - GlobalMessageBox::StandardButton rval = msg.showYesNo(tr("Confirmation - désactivation"), tr("Le project sera désactivé.") + "\n\r" + + GlobalMessageBox::StandardButton rval = msg.showYesNo(tr("Confirmation - désactivation"), tr("Le projet sera désactivé.") + "\n\r" + tr("Tous les participants seront aussi désactivés et les appareils associés à ceux-ci seront désassociés.") + "\n\r" + tr("Êtes-vous sûrs de vouloir continuer?")); if (rval != GlobalMessageBox::Yes){ diff --git a/client/src/managers/BaseComManager.cpp b/client/src/managers/BaseComManager.cpp index 38f34582..cb6e0f21 100644 --- a/client/src/managers/BaseComManager.cpp +++ b/client/src/managers/BaseComManager.cpp @@ -1,5 +1,4 @@ #include "BaseComManager.h" -#include BaseComManager::BaseComManager(QUrl serverUrl, QObject *parent) : QObject{parent}, @@ -10,9 +9,8 @@ BaseComManager::BaseComManager(QUrl serverUrl, QObject *parent) m_loggingInProgress = false; // Get Operating system information to send to server for logging - QOperatingSystemVersion os = QOperatingSystemVersion::current(); - m_osName = os.name(); - m_osVersion = QString::number(os.majorVersion()) + "." + QString::number(os.minorVersion()) + "." + QString::number(os.microVersion()); + m_osName = Utils::getOsName(); + m_osVersion = Utils::getOsVersion(); // Create correct server url m_serverUrl.setUrl("https://" + serverUrl.host() + ":" + QString::number(serverUrl.port())); diff --git a/shared/src/Utils.cpp b/shared/src/Utils.cpp index bfa6447f..29196b00 100644 --- a/shared/src/Utils.cpp +++ b/shared/src/Utils.cpp @@ -1,5 +1,6 @@ #include "Utils.h" #include +#include Utils::Utils(QObject *parent) : QObject(parent) { @@ -81,6 +82,18 @@ QString Utils::getMachineUniqueId() return machine_id; } +QString Utils::getOsName() +{ + QOperatingSystemVersion os = QOperatingSystemVersion::current(); + return os.name(); +} + +QString Utils::getOsVersion() +{ + QOperatingSystemVersion os = QOperatingSystemVersion::current(); + return QString::number(os.majorVersion()) + "." + QString::number(os.minorVersion()) + "." + QString::number(os.microVersion()); +} + void Utils::inStringUnicodeConverter(QString *str) { if (str->contains("\\u")) { diff --git a/shared/src/Utils.h b/shared/src/Utils.h index 4e6be93c..cfe70d61 100644 --- a/shared/src/Utils.h +++ b/shared/src/Utils.h @@ -28,6 +28,8 @@ class SHAREDLIB_EXPORT Utils : public QObject static QList validatePassword(const QString& password); static QString getMachineUniqueId(); + static QString getOsName(); + static QString getOsVersion(); static void inStringUnicodeConverter(QString* str); From 949f89d13afa93b04507acd1d7725f09e9079576 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Mon, 30 Sep 2024 10:13:46 -0400 Subject: [PATCH 08/25] Refs #95. Fixed translations and login sequence with WebLoginDialog --- client/src/CMakeLists.txt | 10 ++--- client/src/ClientApp.cpp | 62 ++++++++++++++++++--------- client/src/ClientApp.h | 2 +- client/src/dialogs/WebLoginDialog.cpp | 3 +- client/src/dialogs/WebLoginDialog.h | 6 ++- client/src/main/MainWindow.cpp | 1 + shared/src/data/TeraPreferences.cpp | 2 +- 7 files changed, 55 insertions(+), 31 deletions(-) diff --git a/client/src/CMakeLists.txt b/client/src/CMakeLists.txt index c079dc1d..e9f05848 100755 --- a/client/src/CMakeLists.txt +++ b/client/src/CMakeLists.txt @@ -370,9 +370,6 @@ set(translation_files_srcs # DEPENDS ${moc_uis} # ) -# #set qm files output directory -# set_source_files_properties(${translation_files_srcs} PROPERTIES OUTPUT_LOCATION ${TERACLIENT_RES_INCLUDES}/translations/) - # #Build this target to update translations # add_custom_target(translations DEPENDS openteraplus_en_ts openteraplus_fr_ts) # add_custom_target(translation_files SOURCES ${translation_files_srcs}) @@ -395,6 +392,10 @@ set(translation_files_srcs # ${translation_files_srcs} # ) # endif() + +# #set qm files output directory +set_source_files_properties(${translation_files_srcs} PROPERTIES OUTPUT_LOCATION ${TERACLIENT_RES_INCLUDES}/translations/) + qt_add_lupdate( TS_FILES ${translation_files_srcs} @@ -408,8 +409,7 @@ qt_add_lupdate( ) qt_add_lrelease( - TS_FILES - ${translation_files_srcs} + TS_FILES ${translation_files_srcs} ) message(STATUS "qm_files : ${qm_files}") diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index 8ba40def..ee2d2036 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -17,8 +17,8 @@ ClientApp::ClientApp(int &argc, char **argv) m_mainKitWindow = nullptr; #endif - m_translator = new QTranslator(); - m_qt_translator = new QTranslator(); + m_translator = new QTranslator(this); + m_qt_translator = new QTranslator(this); // Translations QString last_lang = TeraSettings::getGlobalSetting(SETTINGS_LASTLANGUAGE).toString(); @@ -63,9 +63,6 @@ ClientApp::~ClientApp() m_comMan->deleteLater(); } - delete m_translator; - delete m_qt_translator; - } ComManager *ClientApp::getComManager() @@ -131,14 +128,12 @@ void ClientApp::showLogin() connect(m_loginDiag, &LoginDialog::loginRequest, this, &ClientApp::loginRequested); connect(m_loginDiag, &LoginDialog::quitRequest, this, &ClientApp::loginQuitRequested); #endif - } - - // Set server names - m_loginDiag->setServerNames(m_config.getServerNames()); - - // Show servers list... or not! - m_loginDiag->showServers(m_config.showServers()); + // Set server names + m_loginDiag->setServerNames(m_config.getServerNames()); + // Show servers list... or not! + m_loginDiag->showServers(m_config.showServers()); + } // Delete main window, if present if (m_mainWindow){ @@ -227,12 +222,12 @@ void ClientApp::setTranslation(QString language) m_currentLocale = QLocale(); // Use system locale by default lang_changed = true; } - if (language.toLower() == "en" && m_currentLocale != QLocale::English){ + if (language.toLower() == "en" && m_currentLocale.language() != QLocale::English){ m_currentLocale = QLocale(QLocale::English); lang_changed = true; } - if (language.toLower() == "fr" && m_currentLocale != QLocale::French){ + if (language.toLower() == "fr" && m_currentLocale.language() != QLocale::French){ m_currentLocale = QLocale(QLocale::French); lang_changed = true; } @@ -246,15 +241,23 @@ void ClientApp::setTranslation(QString language) QLocale::setDefault(m_currentLocale); // Install Qt translator for default widgets - if (m_qt_translator->load("qt_" + m_currentLocale.name(), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) + if (m_qt_translator->load(m_currentLocale, QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) { - this->installTranslator(m_qt_translator); + if(!this->installTranslator(m_qt_translator)){ + //qWarning() << "Unable to install Qt translator..."; + }else{ + //qDebug() << "Installed Qt translator"; + } } - // Install app specific translator + // Install app specific translator if (m_translator->load(m_currentLocale, QLatin1String("openteraplus"), QLatin1String("_"), QLatin1String(":/translations"))) { - this->installTranslator(m_translator); - //qDebug() << "Installed translator"; + //qDebug() << m_translator->filePath() << m_translator->language() << m_translator->isEmpty(); + if (!this->installTranslator(m_translator)){ + //qWarning() << "Unable to install translator..."; + }else{ + //qDebug() << "Installed translator"; + } } // Save last used language @@ -319,10 +322,27 @@ void ClientApp::onLoginSuccess(const QString &token, const QString websocket_url if (m_comMan){ m_comMan->deleteLater(); } - m_comMan = new ComManager(QUrl("https://127.0.0.1:40075")); + + // Find server url for that server + QUrl server; + if (m_loginDiag) + server = m_config.getServerUrl(m_loginDiag->currentServerName()); + + m_comMan = new ComManager(server); + + connect(m_comMan, &ComManager::socketError, this, &ClientApp::on_serverError); + connect(m_comMan, &ComManager::serverDisconnected, this, &ClientApp::on_serverDisconnected); + connect(m_comMan, &ComManager::loginResult, this, &ClientApp::on_loginResult); + connect(m_comMan, &ComManager::networkError, this, &ClientApp::on_networkError); + connect(m_comMan, &ComManager::preferencesUpdated, this, &ClientApp::preferencesUpdated); + connect(m_comMan, &ComManager::newVersionAvailable, this, &ClientApp::on_newVersionAvailable); + connect(m_comMan, &ComManager::currentUserUpdated, this, &ClientApp::on_currentUserUpdated); + + connect(m_comMan->getWebSocketManager(), &WebSocketManager::genericEventReceived, this, &ClientApp::ws_genericEventReceived); + m_comMan->connectToServer(token, websocket_url, user_uuid); - showMainWindow(); + //showMainWindow(); } void ClientApp::loginQuitRequested() diff --git a/client/src/ClientApp.h b/client/src/ClientApp.h index e9979060..e320cf42 100755 --- a/client/src/ClientApp.h +++ b/client/src/ClientApp.h @@ -50,7 +50,7 @@ class ClientApp : public QApplication ConfigManagerClient m_config; #ifndef OPENTERA_WEBASSEMBLY - WebLoginDialog *m_loginDiag; + WebLoginDialog* m_loginDiag; #else LoginDialog* m_loginDiag; #endif diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index b3dd8841..bc3f7ba3 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -90,6 +90,7 @@ void WebLoginDialog::onCertificateError(const QWebEngineCertificateError &certif void WebLoginDialog::onServerSelected(int index) { QString currentServer = ui->cmbServers->itemText(index); + // Update last server TeraSettings::setGlobalSetting("last_used_server", currentServer); @@ -130,7 +131,7 @@ QString WebLoginDialog::currentServerName() return QString(); } - +/////////////////////////////////////////////////////////////////////////////////////////////////////// WebLoginRequestInterceptor::WebLoginRequestInterceptor(QObject *p) : QWebEngineUrlRequestInterceptor(p) { // Cache OS information diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 2c94276b..8cb0c7f7 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -21,7 +21,7 @@ class WebLoginSharedObject : public QObject { } Q_INVOKABLE void sendLoginSuccess(const QString &token, const QString &websocket_url, const QString &user_uuid) { - qDebug() << "[WebLoginSharedObject::sendLoginSuccess] " << token << websocket_url; + //qDebug() << "[WebLoginSharedObject::sendLoginSuccess] " << token << websocket_url; emit loginSuccess(token, websocket_url, user_uuid); } @@ -60,7 +60,9 @@ class WebLoginDialog : public QDialog public: explicit WebLoginDialog(ConfigManagerClient *config, QWidget *parent = nullptr); ~WebLoginDialog(); - void setStatusMessage(const QString &message, bool error=false) {qDebug() << "Unhandled message: " << message << "error: " << error;} + void setStatusMessage(const QString &message, bool error=false) { + /*qDebug() << "Unhandled message: " << message << "error: " << error;*/ + } void setServerNames(QStringList servers); QString currentServerName(); void showServers(bool show); diff --git a/client/src/main/MainWindow.cpp b/client/src/main/MainWindow.cpp index 3b775caa..25e8ba9f 100644 --- a/client/src/main/MainWindow.cpp +++ b/client/src/main/MainWindow.cpp @@ -730,6 +730,7 @@ void MainWindow::com_downloadCompleted(DownloadingFile *file) void MainWindow::com_preferencesUpdated() { + qDebug() << m_currentLanguage << m_comManager->getCurrentPreferences().getLanguage(); if (m_currentLanguage != m_comManager->getCurrentPreferences().getLanguage()){ // Filter initial language change GlobalMessageBox msg; if (msg.showYesNo(tr("Changement de langue"), tr("La langue a été modifiée.\nSouhaitez-vous vous déconnecter pour appliquer les changements?")) == QMessageBox::Yes){ diff --git a/shared/src/data/TeraPreferences.cpp b/shared/src/data/TeraPreferences.cpp index 8a9da40c..63a6c9ed 100644 --- a/shared/src/data/TeraPreferences.cpp +++ b/shared/src/data/TeraPreferences.cpp @@ -34,7 +34,7 @@ void TeraPreferences::load(const TeraData &pref_obj) void TeraPreferences::clear() { // Reset default values - m_language = "fr"; + m_language = ""; m_notifySounds = true; m_isSet = false; From 7951aef0aebb1716fa6469862b796a1d668976ca Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Mon, 30 Sep 2024 15:13:22 -0400 Subject: [PATCH 09/25] Refs #95. Working 2FA setup flow on login --- client/src/dialogs/WebLoginDialog.cpp | 63 ++++++++++- client/src/dialogs/WebLoginDialog.h | 31 +++++- client/src/dialogs/WebLoginDialog.ui | 149 +++++++++++++++----------- 3 files changed, 174 insertions(+), 69 deletions(-) diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index bc3f7ba3..882ec762 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -2,6 +2,7 @@ #include "ui_WebLoginDialog.h" #include +#include #include "Utils.h" #include "TeraSettings.h" @@ -10,6 +11,7 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) : QDialog(parent), ui(new Ui::WebLoginDialog), m_config(config) { ui->setupUi(this); + showLargeView(false); //Create Web View m_webView = new QWebEngineView(ui->centralWidget); @@ -38,7 +40,9 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) connect(m_webView, &QWebEngineView::loadStarted, this, &WebLoginDialog::onLoginPageLoading); connect(myObject, &WebLoginSharedObject::loginSuccess, this, &WebLoginDialog::loginSuccess); - connect(myObject, &WebLoginSharedObject::loginFailure, this, &WebLoginDialog::loginFailure); + connect(myObject, &WebLoginSharedObject::loginFailure, this, &WebLoginDialog::onLoginFailed); + connect(myObject, &WebLoginSharedObject::mfaCheckInProgress, this, &WebLoginDialog::onMfaCheckInProgress); + connect(myObject, &WebLoginSharedObject::mfaSetupInProgress, this, &WebLoginDialog::onMfaSetupInProgress); m_webPage->setBackgroundColor(QColor(0x2c3338)); m_webView->setPage(m_webPage); @@ -73,9 +77,11 @@ void WebLoginDialog::setServerNames(QStringList servers) void WebLoginDialog::showServers(bool show) { if (ui->cmbServers->count() == 1) - show = false; // Never show server list if only one item. + m_showServers = false; // Never show server list if only one item. + else + m_showServers = show; - ui->cmbServers->setVisible(show); + ui->cmbServers->setVisible(m_showServers); } void WebLoginDialog::onCertificateError(const QWebEngineCertificateError &certificateError) @@ -123,9 +129,50 @@ void WebLoginDialog::onLoginPageLoading() ui->frameLoginMessages->show(); } +void WebLoginDialog::onMfaSetupInProgress() +{ + qDebug() << "WebLoginDialog::onMfaSetupInProgress"; + showLargeView(true); +} + +void WebLoginDialog::onMfaCheckInProgress() +{ + qDebug() << "WebLoginDialog::onMfaCheckInProgress()"; + showLargeView(true); +} + +void WebLoginDialog::onLoginFailed(const QString &message) +{ + showLargeView(false); + emit loginFailure(message); +} + +void WebLoginDialog::showLargeView(const bool &large) +{ + ui->lblLogo->setVisible(!large); + ui->btnCancel->setVisible(large); + + if (m_showServers){ + ui->frameServers->setVisible(!large); + } + if (large){ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + setFixedSize(768, 768); + + }else{ + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + setFixedSize(550, 500); + } + + // Recenter on screen + this->setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, + this->size(), + QGuiApplication::primaryScreen()->availableGeometry())); +} + QString WebLoginDialog::currentServerName() { - if (ui->cmbServers->currentIndex() >=0 && ui->cmbServers->isVisible()){ + if (ui->cmbServers->currentIndex() >=0/* && ui->cmbServers->isVisible()*/){ return ui->cmbServers->currentText(); } return QString(); @@ -158,3 +205,11 @@ void WebLoginRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info info.setHttpHeader(QByteArray("Accept-Language"), localeString.toUtf8()); } + +void WebLoginDialog::on_btnCancel_clicked() +{ + showLargeView(false); + // Return to login page + onServerSelected(ui->cmbServers->currentIndex()); +} + diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index 8cb0c7f7..a754fbff 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -29,10 +29,20 @@ class WebLoginSharedObject : public QObject { emit loginFailure(message); } + Q_INVOKABLE void sendSetupInProgress() { + emit mfaSetupInProgress(); + } + + Q_INVOKABLE void sendCheckInProgress() { + emit mfaCheckInProgress(); + } + signals: void loginSuccess(const QString &token, const QString &websocket_url, const QString& user_uuid); void loginFailure(const QString &message); + void mfaSetupInProgress(); + void mfaCheckInProgress(); }; @@ -79,12 +89,23 @@ private slots: void onLoginPageLoaded(bool ok); void onLoginPageLoading(); + void onMfaSetupInProgress(); + void onMfaCheckInProgress(); + void onLoginFailed(const QString &message); + + void on_btnCancel_clicked(); + private: - Ui::WebLoginDialog *ui; - QWebEngineView *m_webView; - QWebEnginePage *m_webPage; - WebLoginRequestInterceptor *m_requestInterceptor; - ConfigManagerClient *m_config; + Ui::WebLoginDialog *ui; + QWebEngineView *m_webView; + QWebEnginePage *m_webPage; + WebLoginRequestInterceptor *m_requestInterceptor; + ConfigManagerClient *m_config; + + bool m_showServers = false; + + + void showLargeView(const bool& large); }; diff --git a/client/src/dialogs/WebLoginDialog.ui b/client/src/dialogs/WebLoginDialog.ui index 4788e520..fea9c968 100644 --- a/client/src/dialogs/WebLoginDialog.ui +++ b/client/src/dialogs/WebLoginDialog.ui @@ -24,7 +24,7 @@ - 450 + 500 500 @@ -71,65 +71,67 @@ - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Fixed - - - - 20 - 20 - - - - - - - - - 10px Arial - 10 - false - true - - - - Serveur - - - - - - - - 0 - 0 - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Fixed - - - - 20 - 20 - - - - - + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 20 + + + + + + + + + 10px Arial + 10 + false + true + + + + Serveur + + + + + + + + 0 + 0 + + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Fixed + + + + 20 + 20 + + + + + + @@ -220,6 +222,33 @@ + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + PointingHandCursor + + + Annuler + + + + + From c40da13388df47aa5ea52e6cdf84fc776f011d32 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Tue, 1 Oct 2024 14:24:04 -0400 Subject: [PATCH 10/25] Refs #95. Improved WebLoginDialog experience --- client/src/ClientApp.cpp | 3 +- client/src/dialogs/WebLoginDialog.cpp | 55 ++++++++++++++++++--------- client/src/dialogs/WebLoginDialog.h | 13 ++++++- client/src/dialogs/WebLoginDialog.ui | 35 ++++++++++++++++- 4 files changed, 85 insertions(+), 21 deletions(-) diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index ee2d2036..8dc8a62b 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -60,7 +60,8 @@ ClientApp::~ClientApp() if (m_comMan){ m_comMan->disconnectFromServer(); - m_comMan->deleteLater(); + //m_comMan->deleteLater(); + delete m_comMan; } } diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 882ec762..d8176ca7 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -11,6 +11,7 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) : QDialog(parent), ui(new Ui::WebLoginDialog), m_config(config) { ui->setupUi(this); + ui->btnRetry->hide(); showLargeView(false); //Create Web View @@ -36,13 +37,13 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) settings->setAttribute(QWebEngineSettings::ShowScrollBars, false); connect(m_webPage, &QWebEnginePage::certificateError, this, &WebLoginDialog::onCertificateError); - connect(m_webView, &QWebEngineView::loadFinished, this, &WebLoginDialog::onLoginPageLoaded); - connect(m_webView, &QWebEngineView::loadStarted, this, &WebLoginDialog::onLoginPageLoading); + connect(m_webPage, &QWebEnginePage::loadingChanged, this, &WebLoginDialog::onLoginPageLoadingChanged); connect(myObject, &WebLoginSharedObject::loginSuccess, this, &WebLoginDialog::loginSuccess); connect(myObject, &WebLoginSharedObject::loginFailure, this, &WebLoginDialog::onLoginFailed); connect(myObject, &WebLoginSharedObject::mfaCheckInProgress, this, &WebLoginDialog::onMfaCheckInProgress); connect(myObject, &WebLoginSharedObject::mfaSetupInProgress, this, &WebLoginDialog::onMfaSetupInProgress); + connect(myObject, &WebLoginSharedObject::redirectToLogin, this, &WebLoginDialog::onRedirectToLoginRequest); m_webPage->setBackgroundColor(QColor(0x2c3338)); m_webView->setPage(m_webPage); @@ -106,39 +107,49 @@ void WebLoginDialog::onServerSelected(int index) QUrl loginUrl = m_config->getServerLoginUrl(currentServer); loginUrl.setQuery("no_logo"); m_webPage->setUrl(loginUrl); + showLargeView(false); } } -void WebLoginDialog::onLoginPageLoaded(bool ok) +void WebLoginDialog::onLoginPageLoadingChanged(const QWebEngineLoadingInfo &loadingInfo) { - if (ok){ + qDebug() << loadingInfo.status(); + if (loadingInfo.status() == QWebEngineLoadingInfo::LoadStartedStatus){ + // Page is loading... + ui->centralWidget->hide(); + ui->btnRetry->hide(); + ui->lblError->hide(); + ui->lblLoading->show(); + ui->frameLoginMessages->show(); + return; + } + + if (loadingInfo.status() == QWebEngineLoadingInfo::LoadSucceededStatus){ ui->centralWidget->show(); ui->frameLoginMessages->hide(); m_webView->setFocus(); }else{ + // Manage specific error messages + if (loadingInfo.errorCode() == 404) { + // Not found error + ui->lblError->setText(tr("Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau.")); + }else{ + ui->lblError->setText(tr("Une erreur est survenue") + ": \n" + QString::number(loadingInfo.errorCode()) + " - " + loadingInfo.errorString()); + } ui->lblError->show(); ui->lblLoading->hide(); + ui->btnRetry->show(); } } -void WebLoginDialog::onLoginPageLoading() -{ - ui->centralWidget->hide(); - ui->lblError->hide(); - ui->lblLoading->show(); - ui->frameLoginMessages->show(); -} - void WebLoginDialog::onMfaSetupInProgress() { - qDebug() << "WebLoginDialog::onMfaSetupInProgress"; showLargeView(true); } void WebLoginDialog::onMfaCheckInProgress() { - qDebug() << "WebLoginDialog::onMfaCheckInProgress()"; - showLargeView(true); + ui->btnCancel->setVisible(true); } void WebLoginDialog::onLoginFailed(const QString &message) @@ -147,6 +158,11 @@ void WebLoginDialog::onLoginFailed(const QString &message) emit loginFailure(message); } +void WebLoginDialog::onRedirectToLoginRequest() +{ + onServerSelected(ui->cmbServers->currentIndex()); +} + void WebLoginDialog::showLargeView(const bool &large) { ui->lblLogo->setVisible(!large); @@ -157,8 +173,7 @@ void WebLoginDialog::showLargeView(const bool &large) } if (large){ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - setFixedSize(768, 768); - + setFixedSize(768, 500); }else{ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setFixedSize(550, 500); @@ -213,3 +228,9 @@ void WebLoginDialog::on_btnCancel_clicked() onServerSelected(ui->cmbServers->currentIndex()); } + +void WebLoginDialog::on_btnRetry_clicked() +{ + m_webPage->load(m_webPage->url()); +} + diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index a754fbff..b605f261 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -37,10 +38,16 @@ class WebLoginSharedObject : public QObject { emit mfaCheckInProgress(); } + Q_INVOKABLE void sendRedirectToLogin(){ + emit redirectToLogin(); + } + signals: void loginSuccess(const QString &token, const QString &websocket_url, const QString& user_uuid); void loginFailure(const QString &message); + void redirectToLogin(); + void mfaSetupInProgress(); void mfaCheckInProgress(); @@ -86,15 +93,17 @@ private slots: void onCertificateError(const QWebEngineCertificateError &certificateError); void onServerSelected(int index); - void onLoginPageLoaded(bool ok); - void onLoginPageLoading(); + void onLoginPageLoadingChanged(const QWebEngineLoadingInfo &loadingInfo); void onMfaSetupInProgress(); void onMfaCheckInProgress(); void onLoginFailed(const QString &message); + void onRedirectToLoginRequest(); void on_btnCancel_clicked(); + void on_btnRetry_clicked(); + private: Ui::WebLoginDialog *ui; QWebEngineView *m_webView; diff --git a/client/src/dialogs/WebLoginDialog.ui b/client/src/dialogs/WebLoginDialog.ui index fea9c968..eb517453 100644 --- a/client/src/dialogs/WebLoginDialog.ui +++ b/client/src/dialogs/WebLoginDialog.ui @@ -186,7 +186,7 @@ - Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. + (Erreur) Qt::AlignmentFlag::AlignCenter @@ -209,6 +209,39 @@ + + + + + + + 32 + 32 + + + + PointingHandCursor + + + Réessayer + + + + :/icons/refresh.png:/icons/refresh.png + + + + 32 + 32 + + + + Qt::ToolButtonStyle::ToolButtonTextBesideIcon + + + + + From e25f505821523cf3669ecd60ce4ecdcbaddeb1d7 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Tue, 1 Oct 2024 14:58:40 -0400 Subject: [PATCH 11/25] Refs #95. Updated translations --- .../resources/translations/openteraplus_en.ts | 108 +++++++++++------- .../resources/translations/openteraplus_fr.ts | 106 ++++++++++------- 2 files changed, 127 insertions(+), 87 deletions(-) diff --git a/client/resources/translations/openteraplus_en.ts b/client/resources/translations/openteraplus_en.ts index 1028be25..1db4e5cd 100644 --- a/client/resources/translations/openteraplus_en.ts +++ b/client/resources/translations/openteraplus_en.ts @@ -372,83 +372,83 @@ ClientApp - + Connexion Connection - + Bienvenue! Welcome! - + Déconnexion Disconnect - + Vous avez été déconnecté du serveur. Veuillez vous connecter à nouveau. You have been disconnected. Please connect again. - - + + La connexion a été refusée par le serveur. Connection refused by server. - + Impossible de rejoindre le serveur. Unable to reach server. - + Le serveur est introuvable. Server is unreachable. - + Impossible de se connecter (Code erreur: Unable to connect (Error code: - + Une nouvelle version ( A software update ( - + ) du logiciel est disponible. ) is available. - + Veuillez contacter votre fournisseur pour l'obtenir. Please contact your provider to update. - + Cliquez Click - + ICI HERE - + pour la télécharger. to download. - + Important: assurez-vous que le logiciel est bien fermé avant de procéder à la mise à jour. Important: please close the software before proceeding to install this update. - + Nouvelle version disponible! Software update available! @@ -2618,19 +2618,19 @@ Please update the software or contribute to the development! - deleting... - + Erreur de séance Session error - + Une erreur est survenue: The following error occured: - + La séance ne peut pas continuer. @@ -2639,73 +2639,73 @@ La séance ne peut pas continuer. The session cannot continue. - - - + + + est en ligne. is online. - - - + + + est hors-ligne. is offline. - + Erreur de serveur. Server error. - - + + Déconnexion - Disconnect + Logout - + Vous serez déconnecté du logiciel. Toute donnée non enregistrée sera perdue. You'll be logged out. Unsaved data will be lost. - + Souhaitez-vous continuer? Do you want to continue? - + Votre compte You Account - + Configuration Globale Global Configuration - + Détails Details - + Séance en cours Current session - + La séance en cours empêche la fermeture du logiciel. Current session is preventing software exit. - + Veuillez la terminer avant de poursuivre. Please end the session before continuing. - + Changement de langue Change language @@ -2715,7 +2715,7 @@ The session cannot continue. Online ( - + La langue a été modifiée. Souhaitez-vous vous déconnecter pour appliquer les changements? The language has been modified. @@ -6102,25 +6102,45 @@ Vous devez spécifier au moins un groupe utilisateur WebLoginDialog - + OpenTeraPlus OpenTeraPlus - + Serveur Server - + Chargement en cours... Loading... - + + (Erreur) + (Error) + + + + Réessayer + Retry + + + + Annuler + Cancel + + + Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. Unable to reach server. Please check your Internet connection, your network settings and your firewall, then try again. + + + Une erreur est survenue + An error occured + WebSocketManager diff --git a/client/resources/translations/openteraplus_fr.ts b/client/resources/translations/openteraplus_fr.ts index 74b51ac6..b9ab6858 100644 --- a/client/resources/translations/openteraplus_fr.ts +++ b/client/resources/translations/openteraplus_fr.ts @@ -372,83 +372,83 @@ ClientApp - + Connexion - + Bienvenue! - + Déconnexion - + Vous avez été déconnecté du serveur. Veuillez vous connecter à nouveau. - - + + La connexion a été refusée par le serveur. - + Impossible de rejoindre le serveur. - + Le serveur est introuvable. - + Impossible de se connecter (Code erreur: - + Une nouvelle version ( - + ) du logiciel est disponible. - + Veuillez contacter votre fournisseur pour l'obtenir. - + Cliquez - + ICI - + pour la télécharger. - + Important: assurez-vous que le logiciel est bien fermé avant de procéder à la mise à jour. - + Nouvelle version disponible! @@ -2586,91 +2586,91 @@ Veuillez vérifier si une mise à jour existe ou contribuez au développement du - + Erreur de séance - + Une erreur est survenue: - + La séance ne peut pas continuer. - - - + + + est en ligne. - - - + + + est hors-ligne. - + Erreur de serveur. - - + + Déconnexion - + Vous serez déconnecté du logiciel. Toute donnée non enregistrée sera perdue. - + Souhaitez-vous continuer? - + Votre compte - + Configuration Globale - + Détails - + Séance en cours - + La séance en cours empêche la fermeture du logiciel. - + Veuillez la terminer avant de poursuivre. - + Changement de langue @@ -2680,7 +2680,7 @@ La séance ne peut pas continuer. - + La langue a été modifiée. Souhaitez-vous vous déconnecter pour appliquer les changements? @@ -6022,25 +6022,45 @@ Vous devez spécifier au moins un groupe utilisateur WebLoginDialog - + OpenTeraPlus - + Serveur - + Chargement en cours... - + + (Erreur) + + + + + Réessayer + + + + + Annuler + + + + Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. + + + Une erreur est survenue + + WebSocketManager From 541b286fd8a13795777b07b24389e6189775cb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Wed, 2 Oct 2024 11:40:10 -0400 Subject: [PATCH 12/25] Refs #95, fix translations on Mac. --- client/src/Info.plist.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/Info.plist.in b/client/src/Info.plist.in index e62fb6e0..1cad1465 100644 --- a/client/src/Info.plist.in +++ b/client/src/Info.plist.in @@ -30,6 +30,11 @@ ???? CFBundleVersion ${MACOSX_BUNDLE_BUNDLE_VERSION} + CFBundleLocalizations + + en + fr + CSResourcesFileMapped NSHumanReadableCopyright From b16149a34347147c7d3a02a8912d616ca06428f3 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Wed, 2 Oct 2024 14:50:57 -0400 Subject: [PATCH 13/25] Refs #95. Updated editors for 2FA authentication --- client/src/dialogs/WebLoginDialog.cpp | 6 +- client/src/editors/SiteWidget.cpp | 21 +++++++ client/src/editors/SiteWidget.h | 5 +- client/src/editors/SiteWidget.ui | 80 +++++++++++++-------------- client/src/editors/TeraForm.cpp | 2 - client/src/editors/UserWidget.cpp | 50 ++++++++++++++++- client/src/editors/UserWidget.h | 3 +- client/src/editors/UserWidget.ui | 73 ++++++++++++++++++------ client/src/managers/ComManager.cpp | 3 +- 9 files changed, 176 insertions(+), 67 deletions(-) diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index d8176ca7..afe7ef31 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "Utils.h" #include "TeraSettings.h" @@ -113,7 +114,7 @@ void WebLoginDialog::onServerSelected(int index) void WebLoginDialog::onLoginPageLoadingChanged(const QWebEngineLoadingInfo &loadingInfo) { - qDebug() << loadingInfo.status(); + //qDebug() << loadingInfo.status(); if (loadingInfo.status() == QWebEngineLoadingInfo::LoadStartedStatus){ // Page is loading... ui->centralWidget->hide(); @@ -134,7 +135,8 @@ void WebLoginDialog::onLoginPageLoadingChanged(const QWebEngineLoadingInfo &load // Not found error ui->lblError->setText(tr("Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau.")); }else{ - ui->lblError->setText(tr("Une erreur est survenue") + ": \n" + QString::number(loadingInfo.errorCode()) + " - " + loadingInfo.errorString()); + QString message = QTextDocumentFragment::fromHtml(loadingInfo.errorString()).toPlainText(); + ui->lblError->setText(tr("Une erreur est survenue") + ": \n" + QString::number(loadingInfo.errorCode()) + " - " + message); } ui->lblError->show(); ui->lblLoading->hide(); diff --git a/client/src/editors/SiteWidget.cpp b/client/src/editors/SiteWidget.cpp index 0f36dfa5..2a2feb20 100644 --- a/client/src/editors/SiteWidget.cpp +++ b/client/src/editors/SiteWidget.cpp @@ -4,6 +4,8 @@ #include "editors/DataListWidget.h" #include "services/DashboardsService/DashboardsConfigWidget.h" +#include "GlobalMessageBox.h" + SiteWidget::SiteWidget(ComManager *comMan, const TeraData *data, const bool configMode, QWidget *parent) : DataEditorWidget(comMan, data, parent), ui(new Ui::SiteWidget) @@ -86,6 +88,8 @@ void SiteWidget::connectSignals() connect(ui->btnUpdateRoles, &QPushButton::clicked, this, &SiteWidget::btnUpdateAccess_clicked); + connect(ui->wdgSite, &TeraForm::widgetValueHasChanged, this, &SiteWidget::siteValueHasChanged); + } void SiteWidget::updateUserGroupSiteAccess(const TeraData *access) @@ -149,6 +153,9 @@ void SiteWidget::updateControlsState() bool is_super_admin = m_comManager->isCurrentUserSuperAdmin(); bool is_site_admin = isSiteAdmin() || is_super_admin; + if (!is_site_admin) + ui->wdgSite->hideField("site_2fa_required"); + ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabUsersDetails), is_site_admin); ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabDevices), is_site_admin /*(is_site_admin && m_devicesCount>0) || is_super_admin*/); ui->tabNav->setTabVisible(ui->tabNav->indexOf(ui->tabServices), is_site_admin); @@ -414,6 +421,20 @@ void SiteWidget::processStatsReply(TeraData stats, QUrlQuery reply_query) } +void SiteWidget::siteValueHasChanged(QWidget *widget, QVariant value) +{ + if (widget == ui->wdgSite->getWidgetForField("site_2fa_required")){ + if (value.toBool()){ + GlobalMessageBox msgbox; + if (msgbox.showYesNo(tr("Authentification multi-facteurs"), + tr("Activer l'authentification multi-facteurs forcera les utilisateurs ayant accès au site à utiliser cette authentification.\n\n" + "Cette action sera difficilement réversible - il faudra désactiver l'authentification pour chacun des utilisateurs individuellement.\n\nVoulez-vous continuer?")) == GlobalMessageBox::No){ + ui->wdgSite->setFieldValue("site_2fa_required", false); + } + } + } +} + void SiteWidget::updateServiceSite(const TeraData *service_site) { int id_site = service_site->getFieldValue("id_site").toInt(); diff --git a/client/src/editors/SiteWidget.h b/client/src/editors/SiteWidget.h index 327a3a68..da9a4cf5 100644 --- a/client/src/editors/SiteWidget.h +++ b/client/src/editors/SiteWidget.h @@ -6,7 +6,6 @@ #include #include "DataEditorWidget.h" -#include "GlobalMessageBox.h" #include "dialogs/BaseDialog.h" namespace Ui { @@ -31,7 +30,9 @@ private slots: void processDeviceSiteAccessReply(QListdevice_sites, QUrlQuery reply_query); void processSessionTypeSiteAccessReply(QListst_sites, QUrlQuery reply_query); void processTestTypeSiteAccessReply(QListtt_sites, QUrlQuery reply_query); - void processStatsReply(TeraData stats, QUrlQuery reply_query); + void processStatsReply(TeraData stats, QUrlQuery reply_query); + + void siteValueHasChanged(QWidget* widget, QVariant value); void processPostOKReply(QString path); diff --git a/client/src/editors/SiteWidget.ui b/client/src/editors/SiteWidget.ui index 794a4b7e..55b2dc16 100644 --- a/client/src/editors/SiteWidget.ui +++ b/client/src/editors/SiteWidget.ui @@ -79,7 +79,7 @@ - 5 + 0 @@ -114,7 +114,7 @@ - + @@ -142,7 +142,7 @@ - + @@ -224,14 +224,14 @@ 15 - + XXX Appareils - + @@ -262,7 +262,7 @@ - + @@ -293,7 +293,7 @@ - + @@ -305,11 +305,11 @@ XXXX Séances - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - + @@ -321,11 +321,11 @@ XXXX Utilisateurs - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - + @@ -356,7 +356,7 @@ - + @@ -387,14 +387,14 @@ - + XXXX Groupes - + @@ -437,11 +437,11 @@ XXXX Projets - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter - + @@ -472,7 +472,7 @@ - + @@ -484,7 +484,7 @@ XXXX Participants - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -494,7 +494,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -521,7 +521,7 @@ - QTabWidget::West + QTabWidget::TabPosition::West 1 @@ -581,7 +581,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -648,7 +648,7 @@ <html><head/><body><p>Il n'est pas possible de spécifier &quot;Aucun rôle&quot; aux groupes utilisateurs qui ont au moins un accès (Administrateur ou Utilisateur) à un projet du groupe.</p></body></html> - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter true @@ -658,7 +658,7 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers false @@ -667,10 +667,10 @@ false - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -775,7 +775,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -816,16 +816,16 @@ - Qt::NoFocus + Qt::FocusPolicy::NoFocus - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -895,16 +895,16 @@ - Qt::NoFocus + Qt::FocusPolicy::NoFocus - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -1030,10 +1030,10 @@ - Qt::NoFocus + Qt::FocusPolicy::NoFocus - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers false @@ -1042,10 +1042,10 @@ false - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -1095,7 +1095,7 @@ - QTabWidget::West + QTabWidget::TabPosition::West 0 @@ -1118,7 +1118,7 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers diff --git a/client/src/editors/TeraForm.cpp b/client/src/editors/TeraForm.cpp index aa0958d0..899890c6 100644 --- a/client/src/editors/TeraForm.cpp +++ b/client/src/editors/TeraForm.cpp @@ -47,7 +47,6 @@ void TeraForm::buildUiFromStructure(const QString &structure) } ui->toolboxMain->show(); - QJsonObject struct_object = struct_info.object(); //qDebug() << struct_info.object().keys(); if (struct_object.contains("objecttype")) @@ -91,7 +90,6 @@ void TeraForm::buildUiFromStructure(const QString &structure) buildFormFromStructure(m_mainWidget, section_data["items"].toList()); } } - } } } diff --git a/client/src/editors/UserWidget.cpp b/client/src/editors/UserWidget.cpp index 389f1abc..654c4e68 100644 --- a/client/src/editors/UserWidget.cpp +++ b/client/src/editors/UserWidget.cpp @@ -8,6 +8,8 @@ #include #include "dialogs/PasswordStrengthDialog.h" +#include "ServiceConfigWidget.h" +#include "GlobalMessageBox.h" UserWidget::UserWidget(ComManager *comMan, const TeraData *data, QWidget *parent) : @@ -129,10 +131,17 @@ void UserWidget::updateControlsState(){ // Enable access editing bool allow_access_edit = !m_limited; + bool is_editing_current_user = m_data->getId() == m_comManager->getCurrentUser().getId(); if (m_data){ bool user_is_superadmin = m_data->getFieldValue("user_superadmin").toBool(); // Super admin can't be changed - they have access to everything! allow_access_edit &= !user_is_superadmin; + + if (is_editing_current_user){ + ui->wdgUser->hideFields(QStringList() << "user_force_password_change" << "user_2fa_otp_enabled" << "user_2fa_email_enabled"); + ui->wdgUser->setFieldEnabled("user_2fa_enabled", !m_data->getFieldValue("user_2fa_enabled").toBool()); + } + } ui->frameGroups->setEnabled(allow_access_edit); @@ -155,7 +164,7 @@ void UserWidget::updateControlsState(){ }else{ if (ui->tabMain->indexOf(ui->tabLogins) < 0){ // Check if current user is site admin in at least a site of that user... or is self! - bool has_site_admin_access = m_comManager->getCurrentUser().getId() == m_data->getId() || m_comManager->isCurrentUserSuperAdmin(); + bool has_site_admin_access = is_editing_current_user || m_comManager->isCurrentUserSuperAdmin(); if (!has_site_admin_access){ // Check if we are admin in a list one site QList id_sites = m_userSitesRole.keys(); @@ -169,6 +178,13 @@ void UserWidget::updateControlsState(){ if (has_site_admin_access){ ui->tabMain->addTab(ui->tabLogins, QIcon(":/icons/password.png"), tr("Journal d'accès")); + }else{ + ui->wdgUser->hideFields(QStringList() << "user_force_password_change" << "user_2fa_otp_enabled" << "user_2fa_email_enabled"); + ui->wdgUser->setFieldEnabled("user_2fa_enabled", false); + } + + if (m_data){ + ui->btnReset2FA->setVisible(m_data->getFieldValue("user_2fa_enabled").toBool()); } } @@ -694,6 +710,18 @@ void UserWidget::userFormValueChanged(QWidget *widget, QVariant value) m_passwordJustGenerated = false; } } + + if (widget == ui->wdgUser->getWidgetForField("user_2fa_otp_enabled")){ + if (m_data){ + if (!value.toBool() && m_data->getFieldValue("user_2fa_otp_enabled").toBool()){ + GlobalMessageBox msgbox; + if (msgbox.showYesNo(tr("Authentification multi-facteurs"), + tr("Désactiver l'authentification par OTP forcera une reconfiguration de l'utilisateur lors de la prochaine connexion.\n\nVoulez-vous continuer?")) == GlobalMessageBox::No){ + ui->wdgUser->setFieldValue("user_2fa_otp_enabled", true); + } + } + } + } } void UserWidget::userFormValueHasFocus(QWidget *widget) @@ -771,3 +799,23 @@ void UserWidget::undoButtonClicked() DataEditorWidget::undoButtonClicked(); } + +void UserWidget::on_btnReset2FA_clicked() +{ + GlobalMessageBox msg; + if (msg.showYesNo(tr("Réinitialiser code authentification"), tr("Cette action forcera l'utilisateur à reconfigurer ses paramètres d'authentification.\n\nVoulez-vous continuer?")) == GlobalMessageBox::Yes){ + QJsonDocument document; + QJsonObject data_obj; + QJsonObject base_obj; + + data_obj.insert("id_user", QJsonValue::fromVariant(ui->wdgUser->getFieldValue("id_user"))); + data_obj.insert("user_2fa_otp_secret", QJsonValue::fromVariant("")); + + base_obj.insert(TeraData::getDataTypeName(TERADATA_USER), data_obj); + document.setObject(base_obj); + + postDataRequest(WEB_USERINFO_PATH, document.toJson()); + + } +} + diff --git a/client/src/editors/UserWidget.h b/client/src/editors/UserWidget.h index cea5644d..81207c0f 100644 --- a/client/src/editors/UserWidget.h +++ b/client/src/editors/UserWidget.h @@ -14,8 +14,6 @@ #include #include "DataEditorWidget.h" -#include "ServiceConfigWidget.h" -#include "GlobalMessageBox.h" namespace Ui { class UserWidget; @@ -95,6 +93,7 @@ private slots: void saveButtonClicked() override; void undoButtonClicked() override; + void on_btnReset2FA_clicked(); }; diff --git a/client/src/editors/UserWidget.ui b/client/src/editors/UserWidget.ui index 855d1681..61a141de 100644 --- a/client/src/editors/UserWidget.ui +++ b/client/src/editors/UserWidget.ui @@ -104,9 +104,21 @@ + + + 0 + 0 + + + + + 0 + 0 + + true @@ -120,6 +132,9 @@ + + 10 + 0 @@ -134,10 +149,36 @@ + + + + + 300 + 32 + + + + PointingHandCursor + + + Réinitialiser code authentification + + + + :/icons/password.png:/icons/password.png + + + + 24 + 24 + + + + - Qt::Horizontal + Qt::Orientation::Horizontal @@ -261,7 +302,7 @@ Groupes - + <html><head/><body><p>Cet utilisateur est un super administrateur.</p><p>Il est donc impossible de lui assigner des groupes utiilsateurs.</p></body></html> @@ -271,10 +312,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -298,16 +339,16 @@ - Qt::NoFocus + Qt::FocusPolicy::NoFocus - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers false - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection @@ -418,13 +459,13 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -505,13 +546,13 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows @@ -604,10 +645,10 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::NoSelection @@ -689,7 +730,7 @@ - Qt::Vertical + Qt::Orientation::Vertical diff --git a/client/src/managers/ComManager.cpp b/client/src/managers/ComManager.cpp index 114ecbc1..06bb25ff 100644 --- a/client/src/managers/ComManager.cpp +++ b/client/src/managers/ComManager.cpp @@ -1,5 +1,4 @@ #include "ComManager.h" -#include #include ComManager::ComManager(QUrl serverUrl, bool connectWebsocket, QObject *parent) : @@ -602,7 +601,7 @@ bool ComManager::handleDataReply(const QString& reply_path, const QString &reply TeraDataTypes items_type = TeraData::getDataTypeFromPath(reply_path); if (data_list.isArray()){ const QJsonArray data_array = data_list.array(); - for (const QJsonValue data:data_array){ + for (const QJsonValue &data:data_array){ TeraData item_data(items_type, data); // Check if the currently connected user was updated and not requesting a list (limited information) From b40389cf2ca0313a375c1830dd04e3856f6d699a Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Fri, 4 Oct 2024 11:44:38 -0400 Subject: [PATCH 14/25] Refs #95. Added support for password change on login --- client/src/dialogs/WebLoginDialog.cpp | 6 ++++++ client/src/dialogs/WebLoginDialog.h | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index afe7ef31..5b43b547 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -44,6 +44,7 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) connect(myObject, &WebLoginSharedObject::loginFailure, this, &WebLoginDialog::onLoginFailed); connect(myObject, &WebLoginSharedObject::mfaCheckInProgress, this, &WebLoginDialog::onMfaCheckInProgress); connect(myObject, &WebLoginSharedObject::mfaSetupInProgress, this, &WebLoginDialog::onMfaSetupInProgress); + connect(myObject, &WebLoginSharedObject::passwordChangeInProgress, this, &WebLoginDialog::onPasswordChangeInProgress); connect(myObject, &WebLoginSharedObject::redirectToLogin, this, &WebLoginDialog::onRedirectToLoginRequest); m_webPage->setBackgroundColor(QColor(0x2c3338)); @@ -154,6 +155,11 @@ void WebLoginDialog::onMfaCheckInProgress() ui->btnCancel->setVisible(true); } +void WebLoginDialog::onPasswordChangeInProgress() +{ + showLargeView(true); +} + void WebLoginDialog::onLoginFailed(const QString &message) { showLargeView(false); diff --git a/client/src/dialogs/WebLoginDialog.h b/client/src/dialogs/WebLoginDialog.h index b605f261..f851b987 100644 --- a/client/src/dialogs/WebLoginDialog.h +++ b/client/src/dialogs/WebLoginDialog.h @@ -38,6 +38,10 @@ class WebLoginSharedObject : public QObject { emit mfaCheckInProgress(); } + Q_INVOKABLE void sendPasswordChangeInProgress(){ + emit passwordChangeInProgress(); + } + Q_INVOKABLE void sendRedirectToLogin(){ emit redirectToLogin(); } @@ -51,6 +55,8 @@ class WebLoginSharedObject : public QObject { void mfaSetupInProgress(); void mfaCheckInProgress(); + void passwordChangeInProgress(); + }; namespace Ui { @@ -97,6 +103,8 @@ private slots: void onMfaSetupInProgress(); void onMfaCheckInProgress(); + void onPasswordChangeInProgress(); + void onLoginFailed(const QString &message); void onRedirectToLoginRequest(); From 25b4c910f712d0ac20936bf6dc922368d354f25f Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Mon, 7 Oct 2024 14:35:43 -0400 Subject: [PATCH 15/25] Refs #95. Bumped version to 1.3.0 --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0023f6a7..11b6518a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,6 @@ +#Look for minimum cmake version +cmake_minimum_required(VERSION 3.21) + if (APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum OS X deployment version") endif(APPLE) @@ -8,17 +11,14 @@ project(OpenTeraPlus) #enable_testing() #include(CheckFunctionExists) -#Look for minimum cmake version -cmake_minimum_required(VERSION 3.21) - #DEFINITIONS POLICY, NEW SINCE 3.0.2 cmake_policy(SET CMP0043 NEW) cmake_policy(SET CMP0007 NEW) # Software version SET(CPACK_PACKAGE_VERSION_MAJOR "1") -SET(CPACK_PACKAGE_VERSION_MINOR "2") -SET(CPACK_PACKAGE_VERSION_PATCH "1") +SET(CPACK_PACKAGE_VERSION_MINOR "3") +SET(CPACK_PACKAGE_VERSION_PATCH "0") SET(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}) add_definitions(-DOPENTERAPLUS_VERSION="${CPACK_PACKAGE_VERSION}" ) add_definitions(-DOPENTERAPLUS_VERSION_MAJOR="${CPACK_PACKAGE_VERSION_MAJOR}" ) From 572d2a7246b4cba7b3064aecf160fbcfb6734c1f Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Mon, 7 Oct 2024 15:02:53 -0400 Subject: [PATCH 16/25] Refs #95. Added warning when enabled 2FA in user editor --- client/src/editors/TeraForm.cpp | 8 ++++---- client/src/editors/UserWidget.cpp | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/client/src/editors/TeraForm.cpp b/client/src/editors/TeraForm.cpp index 899890c6..25eb83aa 100644 --- a/client/src/editors/TeraForm.cpp +++ b/client/src/editors/TeraForm.cpp @@ -256,10 +256,10 @@ void TeraForm::hideField(const QString &field) setWidgetVisibility(widget, nullptr, false); checkConditions(widget); // Disable condition - if (widget->property("condition").isValid() && !hasHookCondition(widget)){ + /*if (widget->property("condition").isValid() && !hasHookCondition(widget)){ widget->setProperty("_condition", widget->property("condition")); widget->setProperty("condition", QVariant()); - } + }*/ } } @@ -269,10 +269,10 @@ void TeraForm::showField(const QString &field) if (widget){ setWidgetVisibility(widget, nullptr, true); // Enable condition - if (widget->property("_condition").isValid()){ + /*if (widget->property("_condition").isValid()){ widget->setProperty("condition", widget->property("_condition")); widget->setProperty("_condition", QVariant()); - } + }*/ checkConditions(widget); } } diff --git a/client/src/editors/UserWidget.cpp b/client/src/editors/UserWidget.cpp index 654c4e68..ae86412c 100644 --- a/client/src/editors/UserWidget.cpp +++ b/client/src/editors/UserWidget.cpp @@ -711,6 +711,17 @@ void UserWidget::userFormValueChanged(QWidget *widget, QVariant value) } } + if (widget == ui->wdgUser->getWidgetForField("user_2fa_enabled")){ + if (m_data){ + if (value.toBool() && !m_data->getFieldValue("user_2fa_enabled").toBool()){ + GlobalMessageBox msgbox; + if (msgbox.showYesNo(tr("Authentification multi-facteurs"), + tr("Activer la double authentification forcera une configuration de l'utilisateur lors de la prochaine connexion.\n\nVoulez-vous continuer?")) == GlobalMessageBox::No){ + ui->wdgUser->setFieldValue("user_2fa_enabled", false); + } + } + } + } if (widget == ui->wdgUser->getWidgetForField("user_2fa_otp_enabled")){ if (m_data){ if (!value.toBool() && m_data->getFieldValue("user_2fa_otp_enabled").toBool()){ From e090b5ce4b679fd20b1e1a39ab28458e4cd83ca4 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Mon, 7 Oct 2024 15:17:37 -0400 Subject: [PATCH 17/25] Refs #95. Updated translations --- .../resources/translations/openteraplus_en.ts | 187 ++++++++++++------ .../resources/translations/openteraplus_fr.ts | 177 +++++++++++------ 2 files changed, 234 insertions(+), 130 deletions(-) diff --git a/client/resources/translations/openteraplus_en.ts b/client/resources/translations/openteraplus_en.ts index 1db4e5cd..0ec05906 100644 --- a/client/resources/translations/openteraplus_en.ts +++ b/client/resources/translations/openteraplus_en.ts @@ -456,22 +456,22 @@ ComManager - + L'utilisateur est déjà connecté. User is already logged on. - + Erreur inconnue Unknown error - + Utilisateur ou mot de passe invalide. Invalid username or password. - + La communication avec le serveur n'a pu être établie. Communication with the server couldn't be established. @@ -4407,117 +4407,135 @@ You must select at least one site. SiteWidget - + Utilisateurs Users - + Projets Projects - + Groupes participants Participants Groups - + Participants Participants - + Participants actifs Active Participants - + + Authentification multi-facteurs + Multi-factor Authentication + + + + Activer l'authentification multi-facteurs forcera les utilisateurs ayant accès au site à utiliser cette authentification. + +Cette action sera difficilement réversible - il faudra désactiver l'authentification pour chacun des utilisateurs individuellement. + +Voulez-vous continuer? + Enabling multi-factor authentication (MFA) will force users with access to this site to configure and use MFA + +This action will be hard to reverse - manual MFA disabling will be required for each user. + +Do you still want to proceed? + + + Suppression de service associé Associated service deletion - + Au moins un service a été retiré de ce site. S'il y a des projets qui utilisent ce service, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? At least one service was removed from this site. If there's projects using that service, they won't be able to use it anymore. Do you want to continue? - + Suppression d'appareil associé Device association deletion - + Au moins un appareil a été retiré de ce site. S'il y a des projets qui utilisent cet appareil, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? At least one device was removed from this site. If there is projects using that device, they won't be able to use it anymore. Do you want to continue? - + Suppression de types de séances associés Associated session types deletion - + Au moins un type de séance a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? At least one session type was removed from this site. If there are projects using that type, they won't be able to use it anymore. Do you want to continue? - + Seuls les types de séances associés au site sont affichés. Only session types related to the site are displayed. - + Types de séances Session types - + Suppression de types de tests associés Deleting associated test types - + Au moins un type de test a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? At least one test type has been removed from this site. If any project are using this type, they won't be able to use it anymore.\nDo you want to continue? - + Séances planifiées ou réalisées Planned or realized sessions - + Appareils Devices - + Seuls les appareils associés au site sont affichés. Only associated devices are displayed. - + Seuls les utilisateurs ayant un accès au site sont affichés. Only users with site access are displayed. - + Seuls les groupes utilisateurs ayant un accès au site sont affichés. Only users groups with site access are displayed. - + Groupes Utilisateurs Users Groups @@ -4684,7 +4702,7 @@ realized sessions Users Groups - + Appareils Devices @@ -4918,12 +4936,12 @@ realized sessions TeraForm - + Afficher Show - + Choisir la couleur Chose a color @@ -5585,154 +5603,193 @@ You must select at least one site. UserWidget - + Groupes utilisateurs User's groups - - + + Journal d'accès Access Log - + Langue de l'interface Application language - + Français French - + Anglais English - + Sons lors des notifications Notification sounds - + Attention Warning - + Aucun groupe utilisateur n'a été spécifié. Vous devez spécifier au moins un groupe utilisateur You should specify at least one user group - - + + + Authentification multi-facteurs + Multi-factor authentication + + + + Activer la double authentification forcera une configuration de l'utilisateur lors de la prochaine connexion. + +Voulez-vous continuer? + Enabling multi-factor authentication will force a configuration from the user on next login. + +Do you want to continue? + + + + Désactiver l'authentification par OTP forcera une reconfiguration de l'utilisateur lors de la prochaine connexion. + +Voulez-vous continuer? + Disabling OTP authentication will force a user configuration on next login. + +Do you want to continue? + + + + + Réinitialiser code authentification + Reset authentication code + + + + Cette action forcera l'utilisateur à reconfigurer ses paramètres d'authentification. + +Voulez-vous continuer? + This action will force the user to reconfigure authentication parameters. + +Do you want to continue? + + + + Utilisateur User - + Éditer Edit - + Sauvegarder Save - + Annuler Cancel - + Informations Informations - + Mettre à jour les groupes de cet utilisateur Update this user groups - + Groupes Groups - + Rôles effectifs Effective roles - + Sites Sites - - + + Site Site - + Projets Projects - + Projet Project - - - + + + Rôle Role - + <html><head/><body><p>Cet utilisateur est un super administrateur.</p><p>Il est donc impossible de lui assigner des groupes utiilsateurs.</p></body></html> <html><head/><body><p>This user is a super administrator.</p><p>It is impossible to add user groups to a super administrator.</p></body></html> - + Services Services - + Cet utilisateur est un super-administrateur. This user is a super administrator. - + Service Service - + Rôles Roles - + Mettre à jour les préférences Update Preferences - - + + Préférences Preferences - + Configuration Configuration @@ -6132,12 +6189,12 @@ Vous devez spécifier au moins un groupe utilisateur Cancel - + Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. Unable to reach server. Please check your Internet connection, your network settings and your firewall, then try again. - + Une erreur est survenue An error occured diff --git a/client/resources/translations/openteraplus_fr.ts b/client/resources/translations/openteraplus_fr.ts index b9ab6858..656ee26c 100644 --- a/client/resources/translations/openteraplus_fr.ts +++ b/client/resources/translations/openteraplus_fr.ts @@ -456,22 +456,22 @@ ComManager - + L'utilisateur est déjà connecté. - + Erreur inconnue - + Utilisateur ou mot de passe invalide. - + La communication avec le serveur n'a pu être établie. @@ -4348,113 +4348,127 @@ Vous devez associer au moins un site. SiteWidget - + Utilisateurs - + Projets - + Groupes participants - + Participants - + Participants actifs - + Séances planifiées ou réalisées - + Appareils - + + Authentification multi-facteurs + + + + + Activer l'authentification multi-facteurs forcera les utilisateurs ayant accès au site à utiliser cette authentification. + +Cette action sera difficilement réversible - il faudra désactiver l'authentification pour chacun des utilisateurs individuellement. + +Voulez-vous continuer? + + + + Suppression de service associé - + Au moins un service a été retiré de ce site. S'il y a des projets qui utilisent ce service, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? - + Suppression d'appareil associé - + Au moins un appareil a été retiré de ce site. S'il y a des projets qui utilisent cet appareil, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? - + Suppression de types de séances associés - + Au moins un type de séance a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? - + Seuls les types de séances associés au site sont affichés. - + Types de séances - + Suppression de types de tests associés - + Au moins un type de test a été retiré de ce site. S'il y a des projets qui utilisent ce type, ils ne pourront plus l'utiliser. Souhaitez-vous continuer? - + Seuls les appareils associés au site sont affichés. - + Seuls les utilisateurs ayant un accès au site sont affichés. - + Seuls les groupes utilisateurs ayant un accès au site sont affichés. - + Groupes Utilisateurs @@ -4621,7 +4635,7 @@ Souhaitez-vous continuer? - + Appareils @@ -4847,12 +4861,12 @@ Souhaitez-vous continuer? TeraForm - + Afficher - + Choisir la couleur @@ -5505,154 +5519,187 @@ Vous devez associer au moins un site. UserWidget - + Groupes utilisateurs - - + + Journal d'accès - + Langue de l'interface - + Français - + Anglais - + Sons lors des notifications - + Attention - + Aucun groupe utilisateur n'a été spécifié. Vous devez spécifier au moins un groupe utilisateur - - + + + Authentification multi-facteurs + + + + + Activer la double authentification forcera une configuration de l'utilisateur lors de la prochaine connexion. + +Voulez-vous continuer? + + + + + Désactiver l'authentification par OTP forcera une reconfiguration de l'utilisateur lors de la prochaine connexion. + +Voulez-vous continuer? + + + + + + Réinitialiser code authentification + + + + + Cette action forcera l'utilisateur à reconfigurer ses paramètres d'authentification. + +Voulez-vous continuer? + + + + + Utilisateur - + Éditer - + Sauvegarder - + Annuler - + Informations - + Mettre à jour les groupes de cet utilisateur - + Groupes - + Rôles effectifs - + Sites - - + + Site - + Projets - + Projet - - - + + + Rôle - + <html><head/><body><p>Cet utilisateur est un super administrateur.</p><p>Il est donc impossible de lui assigner des groupes utiilsateurs.</p></body></html> - + Services - + Cet utilisateur est un super-administrateur. - + Service - + Rôles - + Mettre à jour les préférences - - + + Préférences - + Configuration @@ -6052,12 +6099,12 @@ Vous devez spécifier au moins un groupe utilisateur - + Impossible de rejoindre le serveur. Vérifiez votre connexion Internet, vos paramètres et votre pare-feu, puis essayez de nouveau. - + Une erreur est survenue From 858803e946242eb34973c72cd8bb90b7d03dde0b Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Tue, 8 Oct 2024 15:01:44 -0400 Subject: [PATCH 18/25] Refs #95. Fixed issues when only 1 server in config file --- client/src/dialogs/WebLoginDialog.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 5b43b547..ffcfa902 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -72,8 +72,17 @@ void WebLoginDialog::setServerNames(QStringList servers) // Select server from the list if we have a setting for that if (current_server.isValid()){ QString server_name = current_server.toString(); - if (servers.contains(server_name)) - ui->cmbServers->setCurrentText(server_name); + if (servers.contains(server_name)){ + if (ui->cmbServers->currentText() != server_name) + ui->cmbServers->setCurrentText(server_name); + else + onServerSelected(0); + } + }else{ + if (ui->cmbServers->count() > 0){ + ui->cmbServers->setCurrentIndex(0); + onServerSelected(0); + } } } @@ -178,6 +187,8 @@ void WebLoginDialog::showLargeView(const bool &large) if (m_showServers){ ui->frameServers->setVisible(!large); + }else{ + ui->frameServers->hide(); } if (large){ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); From 88c926dea3ff6c95d3ffb373de4e528fbcdcff29 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Tue, 8 Oct 2024 15:04:12 -0400 Subject: [PATCH 19/25] Refs #95. Fixed bad display on Weblogin when not showing servers --- client/src/dialogs/WebLoginDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 5b43b547..aae8a0b3 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -84,7 +84,7 @@ void WebLoginDialog::showServers(bool show) else m_showServers = show; - ui->cmbServers->setVisible(m_showServers); + ui->frameServers->setVisible(m_showServers); } void WebLoginDialog::onCertificateError(const QWebEngineCertificateError &certificateError) From 05e2e07db85503cd6993484ffea169a788804340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Tue, 8 Oct 2024 16:32:11 -0400 Subject: [PATCH 20/25] Refs #95, Fixed translation. To be validated. --- client/resources/CMakeLists.txt | 7 +++ .../resources/translations/openteraplus_fr.ts | 4 +- client/src/CMakeLists.txt | 52 +++++++++++-------- client/src/ClientApp.cpp | 16 +++--- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/client/resources/CMakeLists.txt b/client/resources/CMakeLists.txt index 841c4a3b..02b5ce04 100755 --- a/client/resources/CMakeLists.txt +++ b/client/resources/CMakeLists.txt @@ -1 +1,8 @@ set(TERACLIENT_RES_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "doc string") + +set(translations + translations/openteraplus_en.ts + translations/openteraplus_fr.ts +) + +add_custom_target(translation_files SOURCES ${translations}) diff --git a/client/resources/translations/openteraplus_fr.ts b/client/resources/translations/openteraplus_fr.ts index b9ab6858..7dfc25ad 100644 --- a/client/resources/translations/openteraplus_fr.ts +++ b/client/resources/translations/openteraplus_fr.ts @@ -1,12 +1,12 @@ - + AboutDialog À propos d'OpenTera... - + À propos d'OpenTera... diff --git a/client/src/CMakeLists.txt b/client/src/CMakeLists.txt index e9f05848..e367e249 100755 --- a/client/src/CMakeLists.txt +++ b/client/src/CMakeLists.txt @@ -345,15 +345,40 @@ QT6_WRAP_UI(moc_uis ${uis}) #This will generate moc_* for Qt QT6_WRAP_CPP(moc_srcs ${headers}) +set(translation_files_srcs + ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts + ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts +) + +# #set qm files output directory +set_source_files_properties(${translation_files_srcs} PROPERTIES OUTPUT_LOCATION ${TERACLIENT_RES_INCLUDES}/translations/) + +qt_add_lupdate( + TS_FILES + ${translation_files_srcs} + + SOURCES + ${srcs} + ${headers} + ${moc_uis} + + SOURCE_TARGETS opentera_shared +) + +qt_add_lrelease( + TS_FILES ${translation_files_srcs} QM_FILES_OUTPUT_VARIABLE qm_files +) + +message(STATUS "qm_files : ${qm_files}") + + # generate rules for building source files from the resources QT6_ADD_RESOURCES(client_qrc ${qrcs}) -set(translation_files_srcs - ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_fr.ts - ${TERACLIENT_RES_INCLUDES}/translations/openteraplus_en.ts -) +# Make client_qrc target depends on qm_files + # #Translation files, this is done manually to avoid removing the file when doing make clean @@ -393,26 +418,7 @@ set(translation_files_srcs # ) # endif() -# #set qm files output directory -set_source_files_properties(${translation_files_srcs} PROPERTIES OUTPUT_LOCATION ${TERACLIENT_RES_INCLUDES}/translations/) - -qt_add_lupdate( - TS_FILES - ${translation_files_srcs} - - SOURCES - ${srcs} - ${headers} - ${moc_uis} - - SOURCE_TARGETS opentera_shared -) - -qt_add_lrelease( - TS_FILES ${translation_files_srcs} -) -message(STATUS "qm_files : ${qm_files}") include_directories( ${TERACLIENT_RES_INCLUDES} diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index 8dc8a62b..52cb5457 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -242,27 +242,27 @@ void ClientApp::setTranslation(QString language) QLocale::setDefault(m_currentLocale); // Install Qt translator for default widgets - if (m_qt_translator->load(m_currentLocale, QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) + if (m_qt_translator->load(QLocale(m_currentLocale.language()), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) { if(!this->installTranslator(m_qt_translator)){ - //qWarning() << "Unable to install Qt translator..."; + qWarning() << "Unable to install Qt translator..."; }else{ - //qDebug() << "Installed Qt translator"; + qDebug() << "Installed Qt translator"; } } // Install app specific translator - if (m_translator->load(m_currentLocale, QLatin1String("openteraplus"), QLatin1String("_"), QLatin1String(":/translations"))) { - //qDebug() << m_translator->filePath() << m_translator->language() << m_translator->isEmpty(); + if (m_translator->load(QLocale(m_currentLocale.language()), QLatin1String("openteraplus"), QLatin1String("_"), QLatin1String(":/translations"))) { + qDebug() << m_translator->filePath() << m_translator->language() << m_translator->isEmpty(); if (!this->installTranslator(m_translator)){ - //qWarning() << "Unable to install translator..."; + qWarning() << "Unable to install translator..."; }else{ - //qDebug() << "Installed translator"; + qDebug() << "Installed translator"; } } // Save last used language - TeraSettings::setGlobalSetting(SETTINGS_LASTLANGUAGE, language.toLower()); + TeraSettings::setGlobalSetting(SETTINGS_LASTLANGUAGE, m_currentLocale.bcp47Name()); } } From f6c048d83af3ac0f599073b306ea6bce49e7f16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20Le=CC=81tourneau?= Date: Tue, 8 Oct 2024 16:43:28 -0400 Subject: [PATCH 21/25] Refs #95, Fixed translation. To be validated. --- client/src/ClientApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index 52cb5457..27c17a00 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -262,7 +262,7 @@ void ClientApp::setTranslation(QString language) } // Save last used language - TeraSettings::setGlobalSetting(SETTINGS_LASTLANGUAGE, m_currentLocale.bcp47Name()); + TeraSettings::setGlobalSetting(SETTINGS_LASTLANGUAGE, QLocale(m_currentLocale.language()).bcp47Name()); } } From dd66a77cdcd6051ac4c4fc6e6efa7c96bd2396e5 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Wed, 9 Oct 2024 09:37:27 -0400 Subject: [PATCH 22/25] Refs #95. Revised app closing paths and fixed possible issues --- client/src/ClientApp.cpp | 13 +++++++++++-- client/src/main.cpp | 4 +++- client/src/main/MainWindow.cpp | 4 +++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/client/src/ClientApp.cpp b/client/src/ClientApp.cpp index 8dc8a62b..36136620 100755 --- a/client/src/ClientApp.cpp +++ b/client/src/ClientApp.cpp @@ -59,11 +59,18 @@ ClientApp::~ClientApp() delete m_loginDiag; if (m_comMan){ - m_comMan->disconnectFromServer(); + //m_comMan->disconnect(); + //m_comMan->disconnectFromServer(); //m_comMan->deleteLater(); delete m_comMan; } + if (m_mainWindow){ + delete m_mainWindow; + } + if (m_mainKitWindow) + delete m_mainKitWindow; + } ComManager *ClientApp::getComManager() @@ -124,6 +131,7 @@ void ClientApp::showLogin() #ifndef OPENTERA_WEBASSEMBLY m_loginDiag = new WebLoginDialog(&m_config); connect(m_loginDiag, &WebLoginDialog::loginSuccess, this, &ClientApp::onLoginSuccess, Qt::QueuedConnection); + connect(m_loginDiag, &WebLoginDialog::finished, this, &ClientApp::loginQuitRequested); #else m_loginDiag = new LoginDialog(); connect(m_loginDiag, &LoginDialog::loginRequest, this, &ClientApp::loginRequested); @@ -297,7 +305,7 @@ void ClientApp::loginRequested(QString username, QString password, QString serve void ClientApp::logoutRequested() { m_comMan->disconnectFromServer(); - showLogin(); + //showLogin(); } void ClientApp::on_loginResult(bool logged, QString log_msg) @@ -355,6 +363,7 @@ void ClientApp::on_serverDisconnected() { LOG_DEBUG("Disconnected from server.", "ClientApp::on_serverDisconnected"); showLogin(); + } void ClientApp::on_serverError(QAbstractSocket::SocketError error, QString error_str) diff --git a/client/src/main.cpp b/client/src/main.cpp index 3bf1a8a3..6a5923d7 100755 --- a/client/src/main.cpp +++ b/client/src/main.cpp @@ -29,5 +29,7 @@ int main(int argc, char* argv[]) //QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); //QWebEngineSettings::defaultSettings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); - return app.exec(); + int rval = app.exec(); + qDebug() << "Bye!"; + return rval; } diff --git a/client/src/main/MainWindow.cpp b/client/src/main/MainWindow.cpp index 25e8ba9f..fdf87ff8 100644 --- a/client/src/main/MainWindow.cpp +++ b/client/src/main/MainWindow.cpp @@ -252,7 +252,7 @@ void MainWindow::showDashboard(const bool &show) } if (!m_dashboard){ - m_dashboard = new DashboardWidget(m_comManager, ui->projNavigator->getCurrentSiteId()); + m_dashboard = new DashboardWidget(m_comManager, ui->projNavigator->getCurrentSiteId(), this); connect(m_dashboard, &DashboardWidget::dataDisplayRequest, this, &MainWindow::dataDisplayRequested); ui->wdgMainTop->layout()->addWidget(m_dashboard); }else{ @@ -1058,6 +1058,8 @@ void MainWindow::closeEvent(QCloseEvent *event) } } #endif + m_comManager->disconnect(); + //QApplication::quit(); event->accept(); } From 2d6519ade5ea78fba0a092d183b9c44afce8dfe5 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Wed, 9 Oct 2024 10:07:02 -0400 Subject: [PATCH 23/25] Refs #95. Removed context menu from WebLoginDialog (and others). --- client/src/dialogs/AboutDialog.cpp | 9 +++++++-- client/src/dialogs/AboutDialog.h | 1 + client/src/dialogs/AboutDialog.ui | 10 +++++----- client/src/dialogs/AboutDialogPage.cpp | 13 +++++++++++++ client/src/dialogs/AboutDialogPage.h | 4 ++++ client/src/dialogs/WebLoginDialog.cpp | 1 + client/src/kit/KitVideoRehabWidget.cpp | 1 + .../VideoRehabService/VideoRehabSetupWidget.cpp | 1 + .../services/VideoRehabService/VideoRehabWidget.cpp | 1 + 9 files changed, 34 insertions(+), 7 deletions(-) diff --git a/client/src/dialogs/AboutDialog.cpp b/client/src/dialogs/AboutDialog.cpp index 591c7b1d..d0630de8 100644 --- a/client/src/dialogs/AboutDialog.cpp +++ b/client/src/dialogs/AboutDialog.cpp @@ -9,6 +9,7 @@ AboutDialog::AboutDialog(ComManager* comManager, QWidget *parent) : // Initialize web engine view m_webEngine = new QWebEngineView(ui->wdgWebView); + m_webEngine->setContextMenuPolicy(Qt::NoContextMenu); m_webPage = new AboutDialogPage(); m_webEngine->setPage(m_webPage); @@ -53,11 +54,14 @@ void AboutDialog::on_lblAbout_clicked() { if (m_webEngine){ m_webEngine->setUrl(QUrl("chrome://dino")); - ui->wdgWebView->setFocus(); - } } +void AboutDialog::onPageLoaded() +{ + ui->wdgWebView->setFocus(); +} + void AboutDialog::processServerSettings(QVariantHash settings) { if (settings.contains(WEB_QUERY_DEVICE_REGISTER_KEY)){ @@ -69,5 +73,6 @@ void AboutDialog::processServerSettings(QVariantHash settings) void AboutDialog::connectSignals() { + connect(m_webEngine, &QWebEngineView::loadFinished, this, &AboutDialog::onPageLoaded); connect(m_comManager, &ComManager::serverSettingsReceived, this, &AboutDialog::processServerSettings); } diff --git a/client/src/dialogs/AboutDialog.h b/client/src/dialogs/AboutDialog.h index 512b4140..7ab854f2 100644 --- a/client/src/dialogs/AboutDialog.h +++ b/client/src/dialogs/AboutDialog.h @@ -23,6 +23,7 @@ class AboutDialog : public QDialog private slots: void on_btnOk_clicked(); void on_lblAbout_clicked(); + void onPageLoaded(); void processServerSettings(QVariantHash settings); diff --git a/client/src/dialogs/AboutDialog.ui b/client/src/dialogs/AboutDialog.ui index 46b45e19..750c3b0e 100644 --- a/client/src/dialogs/AboutDialog.ui +++ b/client/src/dialogs/AboutDialog.ui @@ -10,6 +10,9 @@ 300 + + Qt::FocusPolicy::StrongFocus + À propos d'OpenTera... @@ -33,9 +36,6 @@ 0 - - Qt::StrongFocus - @@ -64,14 +64,14 @@ Inconnue - Qt::TextSelectableByMouse + Qt::TextInteractionFlag::TextSelectableByMouse - Qt::Horizontal + Qt::Orientation::Horizontal diff --git a/client/src/dialogs/AboutDialogPage.cpp b/client/src/dialogs/AboutDialogPage.cpp index d473e1ac..35643ff2 100644 --- a/client/src/dialogs/AboutDialogPage.cpp +++ b/client/src/dialogs/AboutDialogPage.cpp @@ -1,5 +1,6 @@ #include "AboutDialogPage.h" #include +#include AboutDialogPage::AboutDialogPage() { @@ -15,3 +16,15 @@ void AboutDialogPage::onCertificateError(const QWebEngineCertificateError &certi auto mutableError = const_cast(certificateError); mutableError.acceptCertificate(); } + +bool AboutDialogPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) +{ + if (type == NavigationTypeLinkClicked){ + // Open links in external browser + QDesktopServices::openUrl(url); + + return false; + } + + return true; +} diff --git a/client/src/dialogs/AboutDialogPage.h b/client/src/dialogs/AboutDialogPage.h index c8bb73c8..5e01769c 100644 --- a/client/src/dialogs/AboutDialogPage.h +++ b/client/src/dialogs/AboutDialogPage.h @@ -13,6 +13,10 @@ class AboutDialogPage : public QWebEnginePage protected slots: void onCertificateError(const QWebEngineCertificateError &certificateError); + + // QWebEnginePage interface +protected: + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override; }; #endif // ABOUTDIALOGPAGE_H diff --git a/client/src/dialogs/WebLoginDialog.cpp b/client/src/dialogs/WebLoginDialog.cpp index 61e23bf2..1e1632f7 100644 --- a/client/src/dialogs/WebLoginDialog.cpp +++ b/client/src/dialogs/WebLoginDialog.cpp @@ -17,6 +17,7 @@ WebLoginDialog::WebLoginDialog(ConfigManagerClient *config, QWidget *parent) //Create Web View m_webView = new QWebEngineView(ui->centralWidget); + m_webView->setContextMenuPolicy(Qt::NoContextMenu); ui->lblError->hide(); ui->centralWidget->hide(); diff --git a/client/src/kit/KitVideoRehabWidget.cpp b/client/src/kit/KitVideoRehabWidget.cpp index 95d58e0e..040b579a 100644 --- a/client/src/kit/KitVideoRehabWidget.cpp +++ b/client/src/kit/KitVideoRehabWidget.cpp @@ -54,6 +54,7 @@ void KitVideoRehabWidget::initUi() m_loadingIcon->start(); m_webEngine = new QWebEngineView(ui->wdgWebEngine); + m_webEngine->setContextMenuPolicy(Qt::NoContextMenu); connect(m_webEngine, &QWebEngineView::loadFinished, this, &KitVideoRehabWidget::webPageLoaded); // Create a new page diff --git a/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp b/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp index b380e992..b6b73274 100644 --- a/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp +++ b/client/src/services/VideoRehabService/VideoRehabSetupWidget.cpp @@ -51,6 +51,7 @@ void VideoRehabSetupWidget::initUI() //// Web engine setup m_webEngine = new QWebEngineView(ui->wdgWebEngine); + m_webEngine->setContextMenuPolicy(Qt::NoContextMenu); connect(m_webEngine, &QWebEngineView::loadFinished, this, &VideoRehabSetupWidget::webPageLoaded); //Create a new page diff --git a/client/src/services/VideoRehabService/VideoRehabWidget.cpp b/client/src/services/VideoRehabService/VideoRehabWidget.cpp index 94fe7767..d525abd0 100644 --- a/client/src/services/VideoRehabService/VideoRehabWidget.cpp +++ b/client/src/services/VideoRehabService/VideoRehabWidget.cpp @@ -52,6 +52,7 @@ void VideoRehabWidget::initUI() m_loadingIcon->start(); m_webEngine = new QWebEngineView(/*ui->wdgWebEngine*/); + m_webEngine->setContextMenuPolicy(Qt::NoContextMenu); connect(m_webEngine, &QWebEngineView::loadFinished, this, &VideoRehabWidget::webPageLoaded); // Create a new page From 14150beb436e9ade8304737d87bf56004857a5f4 Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Thu, 10 Oct 2024 08:15:06 -0400 Subject: [PATCH 24/25] Refs #95. Fixed crash on Mac OS on language change --- client/src/main/MainWindow.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/main/MainWindow.cpp b/client/src/main/MainWindow.cpp index fdf87ff8..41bcd844 100644 --- a/client/src/main/MainWindow.cpp +++ b/client/src/main/MainWindow.cpp @@ -730,13 +730,18 @@ void MainWindow::com_downloadCompleted(DownloadingFile *file) void MainWindow::com_preferencesUpdated() { - qDebug() << m_currentLanguage << m_comManager->getCurrentPreferences().getLanguage(); + // qDebug() << m_currentLanguage << m_comManager->getCurrentPreferences().getLanguage(); if (m_currentLanguage != m_comManager->getCurrentPreferences().getLanguage()){ // Filter initial language change + m_currentLanguage = m_comManager->getCurrentPreferences().getLanguage(); GlobalMessageBox msg; if (msg.showYesNo(tr("Changement de langue"), tr("La langue a été modifiée.\nSouhaitez-vous vous déconnecter pour appliquer les changements?")) == QMessageBox::Yes){ + if (m_diag_editor){ + m_diag_editor->close(); + delete m_diag_editor; + m_diag_editor = nullptr; + } emit logout_request(); } - m_currentLanguage = m_comManager->getCurrentPreferences().getLanguage(); } } From 76e1fed235c4e450648677013faf36822222b2df Mon Sep 17 00:00:00 2001 From: Simon Briere Date: Thu, 10 Oct 2024 11:50:13 -0400 Subject: [PATCH 25/25] Updated build action to Qt 6.7.3 --- .github/workflows/build_on_pull_request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_on_pull_request.yml b/.github/workflows/build_on_pull_request.yml index 047c9458..52796b55 100644 --- a/.github/workflows/build_on_pull_request.yml +++ b/.github/workflows/build_on_pull_request.yml @@ -15,7 +15,7 @@ jobs: - name: Install Qt uses: jurplel/install-qt-action@v3.3.0 with: - version: '6.5.3' + version: '6.7.3' host: 'windows' target: 'desktop' arch: 'win64_msvc2019_64'