From 23eeca9ed982fe2a931bb3fa37260aa253ac70d7 Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Tue, 2 Apr 2024 19:45:12 +0300 Subject: [PATCH] UI: RuleEdit: Check for Preset Rule loops --- src/ui/conf/confmanager.cpp | 2 +- src/ui/conf/confrulemanager.cpp | 29 +++++++++++++++++++++++++++++ src/ui/conf/confrulemanager.h | 2 ++ src/ui/conf/migrations/1.sql | 1 + src/ui/model/rulesetmodel.cpp | 24 +++++++++++++++++++++--- src/ui/model/rulesetmodel.h | 2 ++ 6 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/ui/conf/confmanager.cpp b/src/ui/conf/confmanager.cpp index dd74c271..f4beae2a 100644 --- a/src/ui/conf/confmanager.cpp +++ b/src/ui/conf/confmanager.cpp @@ -34,7 +34,7 @@ namespace { const QLoggingCategory LC("conf"); -constexpr int DATABASE_USER_VERSION = 39; +constexpr int DATABASE_USER_VERSION = 40; const char *const sqlSelectAddressGroups = "SELECT addr_group_id, include_all, exclude_all," " include_zones, exclude_zones," diff --git a/src/ui/conf/confrulemanager.cpp b/src/ui/conf/confrulemanager.cpp index 45750ad3..13f78faa 100644 --- a/src/ui/conf/confrulemanager.cpp +++ b/src/ui/conf/confrulemanager.cpp @@ -60,6 +60,25 @@ const char *const sqlSelectRuleSet = "SELECT t.sub_rule_id, r.name" " WHERE t.rule_id = ?1" " ORDER BY t.order_index;"; +const char *const sqlSelectRuleSetLoop = "WITH RECURSIVE" + " parents(rule_id) AS (" + " VALUES(?1)" + " UNION ALL" + " SELECT t.rule_id" + " FROM rule_set t" + " JOIN parents p ON p.rule_id = t.sub_rule_id" + " )," + " children(rule_id) AS (" + " VALUES(?2)" + " UNION ALL" + " SELECT t.sub_rule_id" + " FROM rule_set t" + " JOIN children c ON c.rule_id = t.rule_id" + " )" + "SELECT p.rule_id" + " FROM parents p" + " JOIN children c ON c.rule_id = p.rule_id;"; + const char *const sqlUpdateRuleName = "UPDATE rule SET name = ?2 WHERE rule_id = ?1;"; const char *const sqlUpdateRuleEnabled = "UPDATE rule SET enabled = ?2 WHERE rule_id = ?1;"; @@ -142,6 +161,16 @@ void ConfRuleManager::saveRuleSet(Rule &rule) } } +bool ConfRuleManager::checkRuleSetLoop(int ruleId, int subRuleId) +{ + return DbQuery(sqliteDb()) + .sql(sqlSelectRuleSetLoop) + .vars({ ruleId, subRuleId }) + .execute() + .toInt() + > 0; +} + bool ConfRuleManager::addOrUpdateRule(Rule &rule) { bool ok = true; diff --git a/src/ui/conf/confrulemanager.h b/src/ui/conf/confrulemanager.h index 01f9315d..8707c9f5 100644 --- a/src/ui/conf/confrulemanager.h +++ b/src/ui/conf/confrulemanager.h @@ -27,6 +27,8 @@ public: void loadRuleSet(Rule &rule, QStringList &ruleSetNames); void saveRuleSet(Rule &rule); + bool checkRuleSetLoop(int ruleId, int subRuleId); + virtual bool addOrUpdateRule(Rule &rule); virtual bool deleteRule(int ruleId); virtual bool updateRuleName(int ruleId, const QString &ruleName); diff --git a/src/ui/conf/migrations/1.sql b/src/ui/conf/migrations/1.sql index ff691ecd..6bfb2d2b 100644 --- a/src/ui/conf/migrations/1.sql +++ b/src/ui/conf/migrations/1.sql @@ -114,6 +114,7 @@ CREATE TABLE rule_set( ); CREATE INDEX rule_set_rule_id_idx ON rule_set(rule_id); +CREATE INDEX rule_set_sub_rule_id_idx ON rule_set(sub_rule_id); CREATE TABLE task( task_id INTEGER PRIMARY KEY, diff --git a/src/ui/model/rulesetmodel.cpp b/src/ui/model/rulesetmodel.cpp index 4d6ca84a..2d86e1e9 100644 --- a/src/ui/model/rulesetmodel.cpp +++ b/src/ui/model/rulesetmodel.cpp @@ -1,10 +1,18 @@ #include "rulesetmodel.h" +#include + #include #include #include "rulelistmodel.h" +namespace { + +const QLoggingCategory LC("model.ruleSet"); + +} + RuleSetModel::RuleSetModel(QObject *parent) : StringListModel(parent) { } ConfRuleManager *RuleSetModel::confRuleManager() const @@ -16,6 +24,7 @@ void RuleSetModel::initialize(const RuleRow &ruleRow, const QStringList &ruleSet { setEdited(false); + m_ruleId = ruleRow.ruleId; m_ruleSet = ruleRow.ruleSet; setList(ruleSetNames); @@ -23,10 +32,19 @@ void RuleSetModel::initialize(const RuleRow &ruleRow, const QStringList &ruleSet void RuleSetModel::addRule(const RuleRow &ruleRow) { - if (m_ruleSet.contains(ruleRow.ruleId)) - return; + const int subRuleId = ruleRow.ruleId; - m_ruleSet.append(ruleRow.ruleId); + if (m_ruleSet.contains(subRuleId)) { + qCDebug(LC) << "Sub-Rule already exists"; + return; + } + + if (confRuleManager()->checkRuleSetLoop(m_ruleId, subRuleId)) { + qCDebug(LC) << "Rule Set loop detected"; + return; + } + + m_ruleSet.append(subRuleId); insert(ruleRow.ruleName); diff --git a/src/ui/model/rulesetmodel.h b/src/ui/model/rulesetmodel.h index f9812a87..d1bf07d3 100644 --- a/src/ui/model/rulesetmodel.h +++ b/src/ui/model/rulesetmodel.h @@ -30,6 +30,8 @@ public slots: private: bool m_edited = false; + int m_ruleId = 0; + RuleSetList m_ruleSet; };