SettingsFlow.cpp (7765B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "Resources.h" 5 #include "SettingsFlow.h" 6 #include <AppInstallerStrings.h> 7 #include <winget/UserSettings.h> 8 #include <winget/AdminSettings.h> 9 10 namespace AppInstaller::CLI::Workflow 11 { 12 using namespace AppInstaller::Settings; 13 using namespace AppInstaller::Utility; 14 15 namespace 16 { 17 struct ExportSettingsJson 18 { 19 ExportSettingsJson() 20 { 21 root["$schema"] = "https://aka.ms/winget-settings-export.schema.json"; 22 root["adminSettings"] = Json::ValueType::objectValue; 23 root["userSettingsFile"] = UserSettings::SettingsFilePath().u8string(); 24 } 25 26 void AddAdminSetting(BoolAdminSetting setting) 27 { 28 auto str = std::string{ Settings::AdminSettingToString(setting) }; 29 root["adminSettings"][str] = Settings::IsAdminSettingEnabled(setting); 30 } 31 32 void AddAdminSetting(StringAdminSetting setting) 33 { 34 auto name = std::string{ Settings::AdminSettingToString(setting) }; 35 auto value = Settings::GetAdminSetting(setting); 36 if (value) 37 { 38 root["adminSettings"][name] = value.value(); 39 } 40 } 41 42 std::string ToJsonString() const 43 { 44 Json::StreamWriterBuilder writerBuilder; 45 writerBuilder.settings_["indentation"] = ""; 46 return Json::writeString(writerBuilder, root); 47 } 48 49 private: 50 Json::Value root{ Json::ValueType::objectValue }; 51 }; 52 } 53 54 void EnableAdminSetting(Execution::Context& context) 55 { 56 auto adminSettingString = context.Args.GetArg(Execution::Args::Type::AdminSettingEnable); 57 BoolAdminSetting adminSetting = Settings::StringToBoolAdminSetting(adminSettingString); 58 if (Settings::EnableAdminSetting(adminSetting)) 59 { 60 context.Reporter.Info() << Resource::String::AdminSettingEnabled(AdminSettingToString(adminSetting)) << std::endl; 61 } 62 else 63 { 64 context.Reporter.Error() << Resource::String::EnableAdminSettingFailed(AdminSettingToString(adminSetting)) << std::endl; 65 } 66 } 67 68 void DisableAdminSetting(Execution::Context& context) 69 { 70 auto adminSettingString = context.Args.GetArg(Execution::Args::Type::AdminSettingDisable); 71 BoolAdminSetting adminSetting = Settings::StringToBoolAdminSetting(adminSettingString); 72 if (Settings::DisableAdminSetting(adminSetting)) 73 { 74 context.Reporter.Info() << Resource::String::AdminSettingDisabled(AdminSettingToString(adminSetting)) << std::endl; 75 } 76 else 77 { 78 context.Reporter.Error() << Resource::String::DisableAdminSettingFailed(AdminSettingToString(adminSetting)) << std::endl; 79 } 80 } 81 82 void SetAdminSetting(Execution::Context& context) 83 { 84 auto adminSettingName = context.Args.GetArg(Execution::Args::Type::SettingName); 85 auto adminSettingValue = context.Args.GetArg(Execution::Args::Type::SettingValue); 86 StringAdminSetting adminSetting = Settings::StringToStringAdminSetting(adminSettingName); 87 if (Settings::SetAdminSetting(adminSetting, adminSettingValue)) 88 { 89 context.Reporter.Info() << Resource::String::SetAdminSettingSucceeded(LocIndString{ adminSettingName }, LocIndString{ adminSettingValue }) << std::endl; 90 } 91 else 92 { 93 context.Reporter.Error() << Resource::String::SetAdminSettingFailed(LocIndString{ adminSettingName }) << std::endl; 94 } 95 } 96 97 void ResetAdminSetting(Execution::Context& context) 98 { 99 auto adminSettingName = context.Args.GetArg(Execution::Args::Type::SettingName); 100 101 // Try as both bool and string setting as we don't know the type 102 auto boolAdminSetting = Settings::StringToBoolAdminSetting(adminSettingName); 103 auto stringAdminSetting = Settings::StringToStringAdminSetting(adminSettingName); 104 105 if ((boolAdminSetting != Settings::BoolAdminSetting::Unknown && Settings::DisableAdminSetting(boolAdminSetting)) 106 || (stringAdminSetting != Settings::StringAdminSetting::Unknown && Settings::ResetAdminSetting(stringAdminSetting))) 107 { 108 context.Reporter.Info() << Resource::String::ResetAdminSettingSucceeded(LocIndString{ adminSettingName }) << std::endl; 109 } 110 else 111 { 112 context.Reporter.Error() << Resource::String::ResetAdminSettingFailed(LocIndString{ adminSettingName }) << std::endl; 113 } 114 } 115 116 void ResetAllAdminSettings(Execution::Context& context) 117 { 118 Settings::ResetAllAdminSettings(); 119 context.Reporter.Info() << Resource::String::ResetAllAdminSettingsSucceeded << std::endl; 120 } 121 122 void OpenUserSetting(Execution::Context& context) 123 { 124 // Show warnings only when the setting command is executed. 125 if (!User().GetWarnings().empty()) 126 { 127 context.Reporter.Warn() << Resource::String::SettingLoadFailure << std::endl; 128 for (const auto& warning : User().GetWarnings()) 129 { 130 auto warn = context.Reporter.Warn(); 131 warn << warning.Message; 132 if (!warning.Path.empty()) 133 { 134 if (warning.IsFieldWarning) 135 { 136 warn << ' ' << Resource::String::SettingsWarningField(warning.Path); 137 } 138 else 139 { 140 warn << ' ' << warning.Path; 141 } 142 } 143 144 if (!warning.Data.empty()) 145 { 146 if (warning.IsFieldWarning) 147 { 148 warn << ' ' << Resource::String::SettingsWarningValue(warning.Data); 149 } 150 else 151 { 152 warn << 153 std::endl << 154 warning.Data; 155 } 156 } 157 158 warn << std::endl; 159 } 160 } 161 162 User().PrepareToShellExecuteFile(); 163 164 auto filePathUTF16 = UserSettings::SettingsFilePath().wstring(); 165 166 // Some versions of windows will fail if no file extension association exists, other will pop up the dialog 167 // to make the user pick their default. 168 // Kudos to the terminal team for this workaround. 169 HINSTANCE res = ShellExecuteW(nullptr, nullptr, filePathUTF16.c_str(), nullptr, nullptr, SW_SHOW); 170 if (static_cast<int>(reinterpret_cast<uintptr_t>(res)) <= 32) 171 { 172 // User doesn't have file type association. Default to notepad 173 AICLI_LOG(CLI, Info, << "Json file type association not found, using notepad.exe"); 174 ShellExecuteW(nullptr, nullptr, L"notepad", filePathUTF16.c_str(), nullptr, SW_SHOW); 175 } 176 } 177 178 void ExportSettings(Execution::Context& context) 179 { 180 ExportSettingsJson exportSettingsJson; 181 182 for (const auto& setting : GetAllBoolAdminSettings()) 183 { 184 exportSettingsJson.AddAdminSetting(setting); 185 } 186 187 for (const auto& setting : GetAllStringAdminSettings()) 188 { 189 exportSettingsJson.AddAdminSetting(setting); 190 } 191 192 context.Reporter.Info() << exportSettingsJson.ToJsonString() << std::endl; 193 } 194 }