mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-03 09:14:12 +02:00
Merge pull request #984 from ispyisail/feature/scripting-opt-in
Scripting off by default, with a prompt and a setting to turn it on
This commit is contained in:
@@ -58,6 +58,7 @@
|
||||
#include "ui/backupdialog.h"
|
||||
#include "ui/dialogwaiting.h"
|
||||
#include "undocommand/addelementtextcommand.h"
|
||||
#include "utils/qetsettings.h"
|
||||
#include "utils/qetutils.h"
|
||||
#include "undocommand/rotateselectioncommand.h"
|
||||
#include "undocommand/rotatetextscommand.h"
|
||||
@@ -3168,6 +3169,29 @@ void QETDiagramEditor::slot_runScript() {
|
||||
QETProject *project = currentProject();
|
||||
if (!project) return;
|
||||
|
||||
// Scripting is off until somebody says otherwise, so the first use has
|
||||
// to ask. Asking here rather than greying the action out keeps the
|
||||
// feature discoverable: a disabled menu entry tells a user that
|
||||
// something exists and nothing about how to have it.
|
||||
if (!QetSettings::scriptingEnabled()) {
|
||||
const QMessageBox::StandardButton answer = QET::QetMessageBox::question(
|
||||
this,
|
||||
tr("Exécuter un script"),
|
||||
tr("Les scripts sont désactivés.\n\n"
|
||||
"Un script s'exécute avec vos droits : il peut lire et "
|
||||
"modifier le projet ouvert et écrire des fichiers. "
|
||||
"N'exécutez que des scripts dont vous connaissez "
|
||||
"l'origine.\n\n"
|
||||
"Activer les scripts ? Ce réglage est modifiable dans "
|
||||
"Configurer QElectroTech > Général > Projets."),
|
||||
QMessageBox::Yes | QMessageBox::Cancel,
|
||||
QMessageBox::Cancel);
|
||||
if (answer != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
QetSettings::setScriptingEnabled(true);
|
||||
}
|
||||
|
||||
const QString script_path = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
tr("Exécuter un script"),
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "qetscriptapi.h"
|
||||
#include "../qetmessagebox.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../utils/qetsettings.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
@@ -48,8 +49,33 @@ bool isRunRequest(const QStringList &args)
|
||||
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
|
||||
namespace {
|
||||
/**
|
||||
@brief refusalMessage
|
||||
What to tell somebody whose script was not run, and how to change
|
||||
that. Written once because the command line and the graphical
|
||||
editor both need to say it, and an explanation that names only one
|
||||
of the two ways out sends half the people down the wrong path.
|
||||
*/
|
||||
QString refusalMessage()
|
||||
{
|
||||
return QObject::tr(
|
||||
"Les scripts sont désactivés.\n\n"
|
||||
"Un script a accès à l'ensemble du projet et peut écrire des "
|
||||
"fichiers, aussi cette fonction est-elle désactivée par défaut.\n\n"
|
||||
"Pour l'activer : Configurer QElectroTech > Général > Projets, "
|
||||
"ou définir la variable d'environnement QET_ENABLE_SCRIPTING=1 "
|
||||
"pour une exécution sans interface (CI, traitement par lot).");
|
||||
}
|
||||
}
|
||||
|
||||
int run(const QStringList &args)
|
||||
{
|
||||
if (!QetSettings::scriptingEnabled()) {
|
||||
err << refusalMessage() << "\n";
|
||||
return 3;
|
||||
}
|
||||
|
||||
const int idx = args.indexOf(QStringLiteral("--run"));
|
||||
const QString script_path = args.value(idx + 1);
|
||||
const QString project_path = args.value(idx + 2);
|
||||
@@ -88,6 +114,20 @@ namespace {
|
||||
|
||||
bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *view)
|
||||
{
|
||||
// Checked here as well as at each caller, deliberately: this is the
|
||||
// one function that actually evaluates JavaScript, so it is the one
|
||||
// place a future caller cannot forget to ask. The callers check first
|
||||
// only to give a better answer than this one can -- a usable exit code
|
||||
// on the command line, an offer to switch the setting on in the editor.
|
||||
if (!QetSettings::scriptingEnabled()) {
|
||||
err << refusalMessage() << "\n";
|
||||
if (view) {
|
||||
QET::QetMessageBox::warning(nullptr, QObject::tr("Script"),
|
||||
refusalMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile file(scriptPath);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
err << "Cannot open script: " << scriptPath << "\n";
|
||||
|
||||
@@ -89,6 +89,25 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
ui->m_zoom_out_beyond_folio->setChecked(settings.value("diagrameditor/zoom-out-beyond-of-folio", false).toBool());
|
||||
ui->m_use_gesture_trackpad->setChecked(settings.value("diagramview/gestures", false).toBool());
|
||||
ui->m_save_label_paste->setChecked(settings.value("diagramcommands/erase-label-on-copy", true).toBool());
|
||||
ui->m_enable_scripting->setChecked(QetSettings::scriptingEnabled());
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
if (QetSettings::scriptingForcedByEnvironment()) {
|
||||
//QET_ENABLE_SCRIPTING wins over the stored value, so let the box
|
||||
//say so rather than offer a tick that changes nothing.
|
||||
ui->m_enable_scripting->setEnabled(false);
|
||||
ui->m_enable_scripting->setToolTip(
|
||||
tr("Activé par la variable d'environnement "
|
||||
"QET_ENABLE_SCRIPTING ; ce réglage est sans effet "
|
||||
"tant qu'elle est définie."));
|
||||
}
|
||||
#else
|
||||
//Built without Qt Qml: there is no scripting to allow. Disabled as
|
||||
//well as hidden, so applyConf() leaves the stored value alone --
|
||||
//a hidden box still reports its state, and writing it here would
|
||||
//quietly clear a preference set on a build that does have Qml.
|
||||
ui->m_enable_scripting->setVisible(false);
|
||||
ui->m_enable_scripting->setEnabled(false);
|
||||
#endif
|
||||
ui->m_use_folio_label->setChecked(settings.value("genericpanel/folio", true).toBool());
|
||||
ui->m_border_0->setChecked(settings.value("border-columns_0", false).toBool());
|
||||
ui->m_autosave_sb->setValue(settings.value("diagrameditor/autosave-interval", 0).toInt());
|
||||
@@ -244,6 +263,14 @@ void GeneralConfigurationPage::applyConf()
|
||||
//DIAGRAM COMMAND
|
||||
settings.setValue("diagramcommands/erase-label-on-copy", ui->m_save_label_paste->isChecked());
|
||||
|
||||
//SCRIPTING
|
||||
//Left alone while the environment forces it on: the box is disabled
|
||||
//in that case and writing its state would silently clear the user's
|
||||
//real preference the first time this dialog is accepted.
|
||||
if (ui->m_enable_scripting->isEnabled()) {
|
||||
QetSettings::setScriptingEnabled(ui->m_enable_scripting->isChecked());
|
||||
}
|
||||
|
||||
//GENERIC PANEL
|
||||
settings.setValue("genericpanel/folio",ui->m_use_folio_label->isChecked());
|
||||
|
||||
|
||||
@@ -218,6 +218,16 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="m_enable_scripting">
|
||||
<property name="text">
|
||||
<string>Autoriser l'exécution de scripts JavaScript (Projet > Exécuter un script, et --run)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Un script s'exécute avec vos droits : il peut lire et modifier le projet ouvert et écrire des fichiers. Désactivé par défaut ; n'exécutez que des scripts dont vous connaissez l'origine.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "qetsettings.h"
|
||||
#include <QSettings>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
|
||||
namespace QetSettings
|
||||
{
|
||||
@@ -105,4 +106,50 @@ namespace QetSettings
|
||||
return default_policy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief scriptingForcedByEnvironment
|
||||
* @return true if QET_ENABLE_SCRIPTING is set to 1 in the environment.
|
||||
*
|
||||
* The way to turn scripting on where there is nobody to tick a box:
|
||||
* a headless run, a CI job, a build server. Those have no settings
|
||||
* file worth writing to -- and on a machine whose HOME is created
|
||||
* fresh for the run, writing one would not survive anyway.
|
||||
*/
|
||||
bool scriptingForcedByEnvironment()
|
||||
{
|
||||
return qgetenv("QET_ENABLE_SCRIPTING") == QByteArray("1");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief scriptingEnabled
|
||||
* @return whether QElectroTech may run a JavaScript script.
|
||||
*
|
||||
* Off unless the user turned it on. A script reaches the whole project
|
||||
* and the filesystem through the export calls, so it is capability the
|
||||
* great majority of users never asked for; leaving it on by default
|
||||
* would hand it to them anyway. @sa setScriptingEnabled
|
||||
*
|
||||
* The environment override wins over the stored value, and is checked
|
||||
* first so that a machine with no settings at all still answers.
|
||||
*/
|
||||
bool scriptingEnabled()
|
||||
{
|
||||
if (scriptingForcedByEnvironment()) {
|
||||
return true;
|
||||
}
|
||||
QSettings settings;
|
||||
return settings.value("scripting/enabled", false).toBool();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief setScriptingEnabled
|
||||
* Store whether scripting is allowed. @sa scriptingEnabled
|
||||
* @param enabled
|
||||
*/
|
||||
void setScriptingEnabled(bool enabled)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue("scripting/enabled", enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ namespace QetSettings
|
||||
void setHdpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy);
|
||||
Qt::HighDpiScaleFactorRoundingPolicy hdpiScaleFactorRoundingPolicy(
|
||||
Qt::HighDpiScaleFactorRoundingPolicy default_policy = Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
|
||||
bool scriptingEnabled();
|
||||
void setScriptingEnabled(bool enabled);
|
||||
bool scriptingForcedByEnvironment();
|
||||
}
|
||||
|
||||
#endif // QETSETTINGS_H
|
||||
|
||||
Reference in New Issue
Block a user