mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-18 16:17:03 +00:00
feat(GODT-2794): Clear cached answers when report is sent.
This commit is contained in:
committed by
Romain Le Jeune
parent
c4bcc38c53
commit
3d64c5f894
@ -243,6 +243,15 @@ void QMLBackend::setQuestionAnswer(quint8 questionId, QString const &answer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \param[in] questionId The id of the question.
|
||||||
|
/// \return answer for the given question.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QString QMLBackend::getQuestionAnswer(quint8 questionId) const {
|
||||||
|
return reportFlow_.getAnswer(questionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
/// \param[in] categoryId The id of the question set.
|
/// \param[in] categoryId The id of the question set.
|
||||||
/// \return concatenate answers for set of questions.
|
/// \return concatenate answers for set of questions.
|
||||||
@ -252,6 +261,14 @@ QString QMLBackend::collectAnswers(quint8 categoryId) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
void QMLBackend::clearAnswers() {
|
||||||
|
reportFlow_.clearAnswers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
/// \return The value for the 'showOnStartup' property.
|
/// \return The value for the 'showOnStartup' property.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
|
|||||||
@ -60,7 +60,9 @@ public: // member functions.
|
|||||||
Q_INVOKABLE bool areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs) const; ///< Check if two local URL point to the same file.
|
Q_INVOKABLE bool areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs) const; ///< Check if two local URL point to the same file.
|
||||||
Q_INVOKABLE QVariantList getQuestionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category.
|
Q_INVOKABLE QVariantList getQuestionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category.
|
||||||
Q_INVOKABLE void setQuestionAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question.
|
Q_INVOKABLE void setQuestionAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question.
|
||||||
|
Q_INVOKABLE QString getQuestionAnswer(quint8 questionId) const; ///< Get the answer for a given question.
|
||||||
Q_INVOKABLE QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions.
|
Q_INVOKABLE QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions.
|
||||||
|
Q_INVOKABLE void clearAnswers(); ///< Clear all collected answers.
|
||||||
|
|
||||||
public: // Qt/QML properties. Note that the NOTIFY-er signal is required even for read-only properties (QML warning otherwise)
|
public: // Qt/QML properties. Note that the NOTIFY-er signal is required even for read-only properties (QML warning otherwise)
|
||||||
Q_PROPERTY(bool showOnStartup READ showOnStartup NOTIFY showOnStartupChanged)
|
Q_PROPERTY(bool showOnStartup READ showOnStartup NOTIFY showOnStartupChanged)
|
||||||
|
|||||||
@ -65,6 +65,13 @@ SettingsView {
|
|||||||
onAnswerChanged:{
|
onAnswerChanged:{
|
||||||
Backend.setQuestionAnswer(modelData, answer);
|
Backend.setQuestionAnswer(modelData, answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onVisibleChanged() {
|
||||||
|
setDefaultValue(Backend.getQuestionAnswer(modelData))
|
||||||
|
}
|
||||||
|
target:root
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fill height so the footer label will always be attached to the bottom
|
// fill height so the footer label will always be attached to the bottom
|
||||||
|
|||||||
@ -96,6 +96,7 @@ Item {
|
|||||||
root.showBugQuestion();
|
root.showBugQuestion();
|
||||||
}
|
}
|
||||||
onBugReportWasSent: {
|
onBugReportWasSent: {
|
||||||
|
Backend.clearAnswers();
|
||||||
root.bugReportWasSent();
|
root.bugReportWasSent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,12 @@ Item {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDefaultValue(defaultValue) {
|
||||||
|
textInput.setDefaultValue(defaultValue)
|
||||||
|
selectionRadio.setDefaultValue(defaultValue)
|
||||||
|
selectionCheckBox.setDefaultValue(defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
@ -75,6 +81,10 @@ Item {
|
|||||||
hint: mandatory ? textInput.text.length + "/" + _maxLength : ""
|
hint: mandatory ? textInput.text.length + "/" + _maxLength : ""
|
||||||
placeholderText: mandatory ? qsTr("%1... (min. %2 characters)").arg(root.text).arg(_minLength) : ""
|
placeholderText: mandatory ? qsTr("%1... (min. %2 characters)").arg(root.text).arg(_minLength) : ""
|
||||||
|
|
||||||
|
function setDefaultValue(defaultValue) {
|
||||||
|
textInput.text = root.type === QuestionItem.InputType.TextInput ? defaultValue : ""
|
||||||
|
}
|
||||||
|
|
||||||
validator: function (text) {
|
validator: function (text) {
|
||||||
if (!mandatory)
|
if (!mandatory)
|
||||||
return;
|
return;
|
||||||
@ -101,6 +111,13 @@ Item {
|
|||||||
property string text: {
|
property string text: {
|
||||||
return checkedButton ? checkedButton.text : "";
|
return checkedButton ? checkedButton.text : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDefaultValue(defaultValue) {
|
||||||
|
const values = root.type === QuestionItem.InputType.Radio ? defaultValue : [];
|
||||||
|
for (var i = 0; i < buttons.length; ++i) {
|
||||||
|
buttons[i].checked = values.includes(buttons[i].text);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.answerList
|
model: root.answerList
|
||||||
@ -115,14 +132,22 @@ Item {
|
|||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
id: selectionCheckBox
|
id: selectionCheckBox
|
||||||
exclusive: false
|
exclusive: false
|
||||||
|
property string delimitor: ", "
|
||||||
property string text: {
|
property string text: {
|
||||||
var str = "";
|
var str = "";
|
||||||
for (var i = 0; i < buttons.length; ++i) {
|
for (var i = 0; i < buttons.length; ++i) {
|
||||||
if (buttons[i].checked) {
|
if (buttons[i].checked) {
|
||||||
str += buttons[i].text + ", ";
|
str += buttons[i].text + delimitor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str.slice(0, -2);
|
return str.slice(0, -delimitor.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDefaultValue(defaultValue) {
|
||||||
|
const values = root.type === QuestionItem.InputType.Checkbox ? defaultValue.split(delimitor) : [];
|
||||||
|
for (var i = 0; i < buttons.length; ++i) {
|
||||||
|
buttons[i].checked = values.includes(buttons[i].text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Repeater {
|
Repeater {
|
||||||
|
|||||||
@ -59,9 +59,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"text": "Are you running any of these software?",
|
"text": "Can you list the software you are running?",
|
||||||
"type": 3,
|
"type": 3,
|
||||||
"answerList": ["VPN", "Antivirus", "Firewall", "Cache cleaner", "None of the above"]
|
"answerList": ["VPN", "Antivirus", "Firewall", "Cache cleaner"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,36 @@
|
|||||||
using namespace bridgepp;
|
using namespace bridgepp;
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
const QString goodJson = "{"
|
||||||
|
" \"metadata\": {"
|
||||||
|
" \"version\": \"1.0.0\""
|
||||||
|
" },"
|
||||||
|
" \"data_v1.0.0\": {"
|
||||||
|
" \"categories\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": 0,"
|
||||||
|
" \"name\": \"I can't receive mail\","
|
||||||
|
" \"questions\": [0]"
|
||||||
|
" }"
|
||||||
|
" ],"
|
||||||
|
" \"questions\": ["
|
||||||
|
" {"
|
||||||
|
" \"id\": 0,"
|
||||||
|
" \"text\": \"What happened?\","
|
||||||
|
" \"tips\": \"Expected behavior\","
|
||||||
|
" \"type\": 1"
|
||||||
|
" }"
|
||||||
|
" ]"
|
||||||
|
" }"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
//
|
//
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
@ -84,28 +114,7 @@ TEST_F(BugReportFlowFixture, emptyFile) {
|
|||||||
//
|
//
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
TEST_F(BugReportFlowFixture, validFile) {
|
TEST_F(BugReportFlowFixture, validFile) {
|
||||||
feedTempFile("{"
|
feedTempFile(goodJson);
|
||||||
" \"metadata\": {"
|
|
||||||
" \"version\": \"1.0.0\""
|
|
||||||
" },"
|
|
||||||
" \"data_v1.0.0\": {"
|
|
||||||
" \"categories\": ["
|
|
||||||
" {"
|
|
||||||
" \"id\": 0,"
|
|
||||||
" \"name\": \"I can't receive mail\","
|
|
||||||
" \"questions\": [0]"
|
|
||||||
" }"
|
|
||||||
" ],"
|
|
||||||
" \"questions\": ["
|
|
||||||
" {"
|
|
||||||
" \"id\": 0,"
|
|
||||||
" \"text\": \"What happened?\","
|
|
||||||
" \"tips\": \"Expected behavior\","
|
|
||||||
" \"type\": 1"
|
|
||||||
" }"
|
|
||||||
" ]"
|
|
||||||
" }"
|
|
||||||
"}");
|
|
||||||
|
|
||||||
EXPECT_TRUE(flow_.parse(file_.fileName()));
|
EXPECT_TRUE(flow_.parse(file_.fileName()));
|
||||||
QStringList categories = flow_.categories();
|
QStringList categories = flow_.categories();
|
||||||
@ -131,6 +140,8 @@ TEST_F(BugReportFlowFixture, validFile) {
|
|||||||
qDebug() << flow_.collectAnswers(0);
|
qDebug() << flow_.collectAnswers(0);
|
||||||
EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r - What happened?\n\rpwet\n\r");
|
EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r - What happened?\n\rpwet\n\r");
|
||||||
EXPECT_EQ(flow_.collectAnswers(1), "");
|
EXPECT_EQ(flow_.collectAnswers(1), "");
|
||||||
|
EXPECT_EQ(flow_.getAnswer(0), "pwet");
|
||||||
|
EXPECT_EQ(flow_.getAnswer(1), "");
|
||||||
flow_.clearAnswers();
|
flow_.clearAnswers();
|
||||||
EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r");
|
EXPECT_EQ(flow_.collectAnswers(0), "Category: I can't receive mail\n\r");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,6 +91,19 @@ bool BugReportFlow::setAnswer(quint8 questionId, QString const &answer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
/// \param[in] questionId The id of the question.
|
||||||
|
/// \return answer the given question.
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QString BugReportFlow::getAnswer(quint8 questionId) const {
|
||||||
|
QString answer;
|
||||||
|
if (questionId <= questions_.count() - 1) {
|
||||||
|
answer = answers_[questionId];
|
||||||
|
}
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
/// \param[in] categoryId The id of the question set.
|
/// \param[in] categoryId The id of the question set.
|
||||||
/// \return concatenate answers for set of questions.
|
/// \return concatenate answers for set of questions.
|
||||||
@ -103,7 +116,7 @@ QString BugReportFlow::collectAnswers(quint8 categoryId) const {
|
|||||||
answers += "Category: " + categories_[categoryId] + "\n\r";
|
answers += "Category: " + categories_[categoryId] + "\n\r";
|
||||||
QVariantList sets = this->questionSet(categoryId);
|
QVariantList sets = this->questionSet(categoryId);
|
||||||
for (QVariant const &var: sets) {
|
for (QVariant const &var: sets) {
|
||||||
const QString& answer = answers_[var.toInt()];
|
const QString& answer = getAnswer(var.toInt());
|
||||||
if (answer.isEmpty())
|
if (answer.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
answers += " - " + questions_[var.toInt()].toMap()["text"].toString() + "\n\r";
|
answers += " - " + questions_[var.toInt()].toMap()["text"].toString() + "\n\r";
|
||||||
@ -122,15 +135,12 @@ void BugReportFlow::clearAnswers() {
|
|||||||
|
|
||||||
|
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
//
|
/// \return true iff parsing succeed.
|
||||||
//****************************************************************************************************************************************************
|
//****************************************************************************************************************************************************
|
||||||
bool BugReportFlow::parseFile() {
|
bool BugReportFlow::parseFile() {
|
||||||
categories_.clear();
|
reset();
|
||||||
questions_.clear();
|
|
||||||
questionsSet_.clear();
|
|
||||||
|
|
||||||
QJsonObject data = getJsonDataObj(getJsonRootObj());
|
QJsonObject data = getJsonDataObj(getJsonRootObj());
|
||||||
|
|
||||||
QJsonArray categoriesJson = data.value("categories").toArray();
|
QJsonArray categoriesJson = data.value("categories").toArray();
|
||||||
for (const QJsonValueRef &v : categoriesJson) {
|
for (const QJsonValueRef &v : categoriesJson) {
|
||||||
categories_.append(v.toObject()["name"].toString());
|
categories_.append(v.toObject()["name"].toString());
|
||||||
@ -140,7 +150,22 @@ bool BugReportFlow::parseFile() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject BugReportFlow::getJsonRootObj() {
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
void BugReportFlow::reset() {
|
||||||
|
categories_.clear();
|
||||||
|
questions_.clear();
|
||||||
|
questionsSet_.clear();
|
||||||
|
answers_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QJsonObject BugReportFlow::getJsonRootObj() const {
|
||||||
QFile file(filepath_);
|
QFile file(filepath_);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
@ -152,7 +177,10 @@ QJsonObject BugReportFlow::getJsonRootObj() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QJsonObject BugReportFlow::getJsonDataObj(const QJsonObject& root) {
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QJsonObject BugReportFlow::getJsonDataObj(const QJsonObject& root) const {
|
||||||
QString version = getJsonVersion(root);
|
QString version = getJsonVersion(root);
|
||||||
if (version.isEmpty())
|
if (version.isEmpty())
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
@ -160,13 +188,15 @@ QJsonObject BugReportFlow::getJsonDataObj(const QJsonObject& root) {
|
|||||||
QJsonValue data = root.value(QString("data_v%1").arg(version));
|
QJsonValue data = root.value(QString("data_v%1").arg(version));
|
||||||
if (data == QJsonValue::Undefined || !data.isObject())
|
if (data == QJsonValue::Undefined || !data.isObject())
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
QJsonObject dataObj = data.toObject();
|
|
||||||
|
|
||||||
return migrateData(dataObj, version);
|
return migrateData(data.toObject(), version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString BugReportFlow::getJsonVersion(const QJsonObject& root) {
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QString BugReportFlow::getJsonVersion(const QJsonObject& root) const{
|
||||||
QJsonValue metadata = root.value("metadata");
|
QJsonValue metadata = root.value("metadata");
|
||||||
if (metadata == QJsonValue::Undefined || !metadata.isObject()) {
|
if (metadata == QJsonValue::Undefined || !metadata.isObject()) {
|
||||||
return QString();
|
return QString();
|
||||||
@ -179,9 +209,13 @@ QString BugReportFlow::getJsonVersion(const QJsonObject& root) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QJsonObject BugReportFlow::migrateData(const QJsonObject& data, const QString& version) {
|
//****************************************************************************************************************************************************
|
||||||
|
//
|
||||||
|
//****************************************************************************************************************************************************
|
||||||
|
QJsonObject BugReportFlow::migrateData(const QJsonObject& data, const QString& version) const{
|
||||||
if (version != currentFormatVersion)
|
if (version != currentFormatVersion)
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
|
|
||||||
// nothing to migrate now but migration should be done here.
|
// nothing to migrate now but migration should be done here.
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,23 +33,25 @@ public: // member functions.
|
|||||||
BugReportFlow(BugReportFlow &&) = delete; ///< Disabled assignment copy-constructor.
|
BugReportFlow(BugReportFlow &&) = delete; ///< Disabled assignment copy-constructor.
|
||||||
~BugReportFlow() = default; ///< Destructor.
|
~BugReportFlow() = default; ///< Destructor.
|
||||||
|
|
||||||
bool parse(const QString& filepath); ///< Initialize the Bug Report Flow.
|
[[nodiscard]] bool parse(const QString& filepath); ///< Initialize the Bug Report Flow.
|
||||||
|
|
||||||
QStringList categories() const; ///< Getter for the 'bugCategories' property.
|
[[nodiscard]] QStringList categories() const; ///< Getter for the 'bugCategories' property.
|
||||||
QVariantList questions() const; ///< Getter for the 'bugQuestions' property.
|
[[nodiscard]] QVariantList questions() const; ///< Getter for the 'bugQuestions' property.
|
||||||
QVariantList questionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category.
|
[[nodiscard]] QVariantList questionSet(quint8 categoryId) const; ///< Retrieve the set of question for a given bug category.
|
||||||
|
|
||||||
bool setAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question.
|
[[nodiscard]] bool setAnswer(quint8 questionId, QString const &answer); ///< Feed an answer for a given question.
|
||||||
QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions.
|
[[nodiscard]] QString getAnswer(quint8 questionId) const; ///< Collect answer for a given questions.
|
||||||
|
[[nodiscard]] QString collectAnswers(quint8 categoryId) const; ///< Collect answer for a given set of questions.
|
||||||
void clearAnswers(); ///< Clear all collected answers.
|
void clearAnswers(); ///< Clear all collected answers.
|
||||||
|
|
||||||
|
|
||||||
private: // member functions
|
private: // member functions
|
||||||
bool parseFile(); ///< Parse the bug report flow description file.
|
bool parseFile(); ///< Parse the bug report flow description file.
|
||||||
QJsonObject getJsonRootObj(); ///< Extract the JSON root object.
|
void reset(); ///< Reset all data.
|
||||||
QJsonObject getJsonDataObj(const QJsonObject& root); ///< Extract the JSON data object.
|
[[nodiscard]] QJsonObject getJsonRootObj() const; ///< Extract the JSON root object.
|
||||||
QString getJsonVersion(const QJsonObject& root); ///< Extract the JSON version of the file.
|
[[nodiscard]] QJsonObject getJsonDataObj(const QJsonObject& root) const; ///< Extract the JSON data object.
|
||||||
QJsonObject migrateData(const QJsonObject& data, const QString& version); ///< Migrate data if needed/possible.
|
[[nodiscard]] QString getJsonVersion(const QJsonObject& root) const; ///< Extract the JSON version of the file.
|
||||||
|
[[nodiscard]] QJsonObject migrateData(const QJsonObject& data, const QString& version) const; ///< Migrate data if needed/possible.
|
||||||
|
|
||||||
private: // data members
|
private: // data members
|
||||||
QString filepath_; ///< The file path of the BugReportFlow description file.
|
QString filepath_; ///< The file path of the BugReportFlow description file.
|
||||||
|
|||||||
Reference in New Issue
Block a user