From d8ccb1f1a9a3c53bb8976b36ed699fa2cf90b40f Mon Sep 17 00:00:00 2001 From: deepin-ci-robot Date: Thu, 26 Oct 2023 07:23:53 +0000 Subject: [PATCH] sync: from linuxdeepin/dtkcore Synchronize source files from linuxdeepin/dtkcore. Source-pull-request: https://github.com/linuxdeepin/dtkcore/pull/390 --- docs/global/dconfigfile.zh_CN.dox | 12 +++++ include/global/dconfigfile.h | 3 +- include/util/dutil.h | 77 ++++++++++++++++++++++++++++++ src/dconfigfile.cpp | 2 + tests/data/dconf-example.meta.json | 10 ++++ tests/ut_dconfigfile.cpp | 11 +++++ 6 files changed, 114 insertions(+), 1 deletion(-) diff --git a/docs/global/dconfigfile.zh_CN.dox b/docs/global/dconfigfile.zh_CN.dox index 8bedc0b..87ae4c7 100644 --- a/docs/global/dconfigfile.zh_CN.dox +++ b/docs/global/dconfigfile.zh_CN.dox @@ -108,6 +108,16 @@ dtk_add_config_meta_files( "name": "map", "permissions": "readwrite", "visibility": "public" + }, + "publicConfig": { + "value": true, + "serial": 0, + "flags": ["user-public"], + "name": "public configure", + "name[zh_CN]": "我是公开的配置", + "description": "I am public configure", + "permissions": "readwrite", + "visibility": "private" } } } @@ -188,6 +198,8 @@ sudo ./dconfigfile-example @brief 存在此标记时,将表明则此配置项不可被覆盖(详见下述 override 机制)。反之,不存在此标记时表明此配置项允许被覆盖,对于此类配置项,如若其有界面设置入口,则当此项不可写时,应当隐藏或禁用界面的设置入口. @var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::Global @brief 当读写此类配置时,将忽略用户身份,无论程序使用哪个用户身份执行,读操作都将获取到同样的数据,写操作将对所有用户都生效。但是,如果对应的配置存储目录不存在或无权限写入,则忽略此标志 +@var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::UserPublic +@brief 该类配置项允许被其他用户访问 @enum Dtk::Core::DConfigFile::Permissions diff --git a/include/global/dconfigfile.h b/include/global/dconfigfile.h index 0593f8c..5959fd9 100644 --- a/include/global/dconfigfile.h +++ b/include/global/dconfigfile.h @@ -28,7 +28,8 @@ class LIBDTKCORESHARED_EXPORT DConfigFile : public DObject{ public: enum Flag { NoOverride = 1 << 0, - Global = 1 << 1 + Global = 1 << 1, + UserPublic = 1 << 2 }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/include/util/dutil.h b/include/util/dutil.h index 5b01f70..4790b51 100644 --- a/include/util/dutil.h +++ b/include/util/dutil.h @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include @@ -51,4 +54,78 @@ void SecureErase(T &obj) } } +inline QString escapeToObjectPath(const QString &str) +{ + if (str.isEmpty()) { + return "_"; + } + + auto ret = str; + QRegularExpression re{R"([^a-zA-Z0-9])"}; + auto matcher = re.globalMatch(ret); + while (matcher.hasNext()) { + auto replaceList = matcher.next().capturedTexts(); + replaceList.removeDuplicates(); + for (const auto &c : replaceList) { + auto hexStr = QString::number(static_cast(c.front().toLatin1()), 16); + ret.replace(c, QString{R"(_%1)"}.arg(hexStr)); + } + } + return ret; +} + +inline QString unescapeFromObjectPath(const QString &str) +{ + auto ret = str; + for (qsizetype i = 0; i < str.size(); ++i) { + if (str[i] == '_' and i + 2 < str.size()) { + auto hexStr = str.sliced(i + 1, 2); + ret.replace(QString{"_%1"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16))); + i += 2; + } + } + return ret; +} + +inline QString getAppIdFromAbsolutePath(const QString &path) +{ + decltype(auto) desktopSuffix = u8".desktop"; + const auto &appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + if (!path.endsWith(desktopSuffix) or + !std::any_of(appDirs.cbegin(), appDirs.constEnd(), [&path](const QString &dir) { return path.startsWith(dir); })) { + return {}; + } + + auto tmp = path.chopped(sizeof(desktopSuffix) - 1); + auto components = tmp.split(QDir::separator(), Qt::SkipEmptyParts); + auto location = std::find(components.cbegin(), components.cend(), "applications"); + if (location == components.cend()) { + return {}; + } + + auto appId = QStringList{location + 1, components.cend()}.join('-'); + return appId; +} + +inline QStringList getAbsolutePathFromAppId(const QString &appId) +{ + auto components = appId.split('-', Qt::SkipEmptyParts); + auto appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + + QStringList ret; + for (const auto &dirPath : appDirs) { + auto currentDir = dirPath; + for (auto it = components.cbegin(); it != components.cend(); ++it) { + auto currentName = QStringList{it, components.cend()}.join('-') + QString{".desktop"}; + QDir dir{currentDir}; + if (dir.exists(currentName)) { + ret.append(dir.filePath(currentName)); + } + + currentDir.append(QDir::separator() % *it); + } + } + + return ret; +} } diff --git a/src/dconfigfile.cpp b/src/dconfigfile.cpp index 1cc8a78..3120662 100644 --- a/src/dconfigfile.cpp +++ b/src/dconfigfile.cpp @@ -336,6 +336,8 @@ class Q_DECL_HIDDEN DConfigInfo { flags |= DConfigFile::NoOverride; } else if (flag == QLatin1String("global")) { flags |= DConfigFile::Global; + } else if (flag == QLatin1String("user-public")) { + flags |= DConfigFile::UserPublic; } } diff --git a/tests/data/dconf-example.meta.json b/tests/data/dconf-example.meta.json index d591a1c..abe786f 100755 --- a/tests/data/dconf-example.meta.json +++ b/tests/data/dconf-example.meta.json @@ -87,6 +87,16 @@ "name": "array value type", "permissions": "readwrite", "visibility": "public" + }, + "publicConfig": { + "value": true, + "serial": 0, + "flags": ["user-public"], + "name": "public configure", + "name[zh_CN]": "我是公开的配置", + "description": "I am public configure", + "permissions": "readwrite", + "visibility": "private" } } } diff --git a/tests/ut_dconfigfile.cpp b/tests/ut_dconfigfile.cpp index 8a0ab83..77d4b32 100644 --- a/tests/ut_dconfigfile.cpp +++ b/tests/ut_dconfigfile.cpp @@ -485,3 +485,14 @@ TEST_F(ut_DConfigFile, setSubpath) { ASSERT_FALSE(config.load(LocalPrefix)); } } + +TEST_F(ut_DConfigFile, userPublic) { + + FileCopyGuard guard(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME)); + { + DConfigFile config(APP_ID, FILE_NAME); + ASSERT_TRUE(config.load(LocalPrefix)); + ASSERT_TRUE(config.meta()->flags("publicConfig").testFlag(DConfigFile::UserPublic)); + ASSERT_FALSE(config.meta()->flags("canExit").testFlag(DConfigFile::UserPublic)); + } +}