File indexing completed on 2024-12-15 03:44:58
0001 /* 0002 SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include <kuserfeedback_version.h> 0008 0009 #include <jobs/handshakejob.h> 0010 #include <jobs/productexportjob.h> 0011 #include <jobs/productimportjob.h> 0012 #include <jobs/securityscanjob.h> 0013 #include <rest/restapi.h> 0014 #include <rest/restclient.h> 0015 #include <rest/serverinfo.h> 0016 #include <core/product.h> 0017 0018 #include <QCommandLineParser> 0019 #include <QCoreApplication> 0020 #include <QDir> 0021 #include <QNetworkReply> 0022 0023 #include <iostream> 0024 0025 using namespace KUserFeedback::Console; 0026 0027 static int jobCount = 0; 0028 0029 int main(int argc, char **argv) 0030 { 0031 QCoreApplication app(argc, argv); 0032 QCoreApplication::setApplicationName(QStringLiteral("userfeedbackctl")); 0033 QCoreApplication::setOrganizationName(QStringLiteral("KDE")); 0034 QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); 0035 QCoreApplication::setApplicationVersion(QStringLiteral(KUSERFEEDBACK_VERSION_STRING)); 0036 0037 QCommandLineParser parser; 0038 parser.setApplicationDescription(QStringLiteral("UserFeedback management tool")); 0039 parser.addHelpOption(); 0040 parser.addVersionOption(); 0041 QCommandLineOption serverOpt({ QStringLiteral("server"), QStringLiteral("s") }, QStringLiteral("Server Name"), QStringLiteral("name")); 0042 parser.addOption(serverOpt); 0043 QCommandLineOption outputOpt({ QStringLiteral("output"), QStringLiteral("o") }, QStringLiteral("Output path"), QStringLiteral("path")); 0044 parser.addOption(outputOpt); 0045 QCommandLineOption forceOpt({ QStringLiteral("force"), QStringLiteral("f") }, QStringLiteral("Force destructive operations")); 0046 parser.addOption(forceOpt); 0047 QCommandLineOption urlOpt({ QStringLiteral("url"), QStringLiteral("u") }, QStringLiteral("Server URL"), QStringLiteral("url")); 0048 parser.addOption(urlOpt); 0049 QCommandLineOption userOpt({ QStringLiteral("user") }, QStringLiteral("User name"), QStringLiteral("name")); 0050 parser.addOption(userOpt); 0051 QCommandLineOption passOpt({ QStringLiteral("password") }, QStringLiteral("Password"), QStringLiteral("pass")); 0052 parser.addOption(passOpt); 0053 parser.addPositionalArgument(QStringLiteral("command"), QStringLiteral("Command: add-server, delete-product, delete-server, export-all, export-product, import-product, list-products, list-servers, scan-server")); 0054 0055 parser.process(app); 0056 0057 if (parser.positionalArguments().isEmpty()) 0058 parser.showHelp(1); 0059 const auto cmd = parser.positionalArguments().at(0); 0060 if (cmd == QLatin1String("list-servers")) { 0061 const auto servers = ServerInfo::allServerInfoNames(); 0062 for (const auto &n : servers) 0063 std::cout << qPrintable(n) << std::endl; 0064 return 0; 0065 } 0066 if (!parser.isSet(serverOpt)) 0067 parser.showHelp(1); 0068 0069 if (cmd == QLatin1String("add-server")) { 0070 if (!parser.isSet(urlOpt)) 0071 parser.showHelp(1); 0072 ServerInfo s; 0073 s.setName(parser.value(serverOpt)); 0074 s.setUrl(QUrl::fromUserInput(parser.value(urlOpt))); 0075 s.setUserName(parser.value(userOpt)); 0076 s.setPassword(parser.value(passOpt)); 0077 s.save(); 0078 return 0; 0079 } else if (cmd == QLatin1String("delete-server")) { 0080 ServerInfo::remove(parser.value(serverOpt)); 0081 return 0; 0082 } 0083 0084 const auto server = ServerInfo::load(parser.value(serverOpt)); 0085 if (!server.isValid()) { 0086 std::cerr << "Invalid server information." << std::endl; 0087 return 1; 0088 } 0089 0090 QFileInfo fi(parser.value(outputOpt)); 0091 if (parser.isSet(outputOpt) && (!fi.isDir() || !fi.isWritable())) { 0092 std::cerr << "Output path does exist or is not accessible." << std::endl; 0093 return 1; 0094 } 0095 0096 RESTClient restClient; 0097 QObject::connect(&restClient, &RESTClient::errorMessage, [](const auto &msg) { 0098 std::cerr << qPrintable(msg) << std::endl; 0099 QCoreApplication::exit(1); 0100 }); 0101 restClient.setServerInfo(server); 0102 0103 if (cmd == QLatin1String("delete-product")) { 0104 jobCount = parser.positionalArguments().size() - 1; 0105 if (jobCount <= 0 || !parser.isSet(forceOpt)) 0106 parser.showHelp(1); 0107 QObject::connect(&restClient, &RESTClient::clientConnected, [&parser, &restClient]() { 0108 for (int i = 0; i < jobCount; ++i) { 0109 Product p; 0110 p.setName(parser.positionalArguments().at(i+1)); 0111 auto reply = RESTApi::deleteProduct(&restClient, p); 0112 QObject::connect(reply, &QNetworkReply::finished, [reply]() { 0113 if (reply->error() != QNetworkReply::NoError) 0114 return; 0115 --jobCount; 0116 if (jobCount == 0) 0117 qApp->quit(); 0118 }); 0119 } 0120 }); 0121 } else if (cmd == QLatin1String("export-all")) { 0122 if (parser.positionalArguments().size() != 1) 0123 parser.showHelp(1); 0124 QObject::connect(&restClient, &RESTClient::clientConnected, [&]() { 0125 auto reply = RESTApi::listProducts(&restClient); 0126 QObject::connect(reply, &QNetworkReply::finished, [reply, &parser, &outputOpt, &restClient]() { 0127 if (reply->error() != QNetworkReply::NoError) 0128 return; 0129 const auto products = Product::fromJson(reply->readAll()); 0130 for (const auto &p : products) { 0131 ++jobCount; 0132 auto job = new ProductExportJob(p, parser.value(outputOpt), &restClient); 0133 QObject::connect(job, &Job::destroyed, []() { 0134 --jobCount; 0135 if (jobCount == 0) 0136 qApp->quit(); 0137 }); 0138 QObject::connect(job, &Job::error, [](const auto &msg) { 0139 std::cerr << qPrintable(msg) << std::endl; 0140 }); 0141 } 0142 }); 0143 }); 0144 } else if (cmd == QLatin1String("export-product")) { 0145 if (parser.positionalArguments().size() != 2) 0146 parser.showHelp(1); 0147 QObject::connect(&restClient, &RESTClient::clientConnected, [&parser, &outputOpt, &restClient]() { 0148 auto job = new ProductExportJob(parser.positionalArguments().at(1), parser.value(outputOpt), &restClient); 0149 QObject::connect(job, &Job::destroyed, qApp, &QCoreApplication::quit); 0150 QObject::connect(job, &Job::error, [](const auto &msg) { 0151 std::cerr << qPrintable(msg) << std::endl; 0152 }); 0153 }); 0154 } else if (cmd == QLatin1String("import-product")) { 0155 if (parser.positionalArguments().size() != 2) 0156 parser.showHelp(1); 0157 QObject::connect(&restClient, &RESTClient::clientConnected, [&parser, &restClient]() { 0158 auto job = new ProductImportJob(parser.positionalArguments().at(1), &restClient); 0159 QObject::connect(job, &Job::destroyed, qApp, &QCoreApplication::quit); 0160 QObject::connect(job, &Job::error, [](const auto &msg) { 0161 std::cerr << qPrintable(msg) << std::endl; 0162 }); 0163 }); 0164 } else if (cmd == QLatin1String("list-products")) { 0165 if (parser.positionalArguments().size() != 1) 0166 parser.showHelp(1); 0167 QObject::connect(&restClient, &RESTClient::clientConnected, [&restClient]() { 0168 auto reply = RESTApi::listProducts(&restClient); 0169 QObject::connect(reply, &QNetworkReply::finished, [reply]() { 0170 if (reply->error() != QNetworkReply::NoError) 0171 return; 0172 const auto products = Product::fromJson(reply->readAll()); 0173 for (const auto &p : products) 0174 std::cout << qPrintable(p.name()) << std::endl; 0175 qApp->quit(); 0176 }); 0177 }); 0178 } else if (cmd == QLatin1String("scan-server")) { 0179 QObject::connect(&restClient, &RESTClient::clientConnected, [&restClient]() { 0180 auto job = new SecurityScanJob(&restClient); 0181 QObject::connect(job, &Job::destroyed, qApp, &QCoreApplication::quit); 0182 QObject::connect(job, &Job::error, [](const auto &msg) { 0183 std::cerr << qPrintable(msg) << std::endl; 0184 }); 0185 QObject::connect(job, &Job::info, [](const auto &msg) { 0186 std::cout << qPrintable(msg) << std::endl; 0187 }); 0188 }); 0189 } else { 0190 parser.showHelp(1); 0191 } 0192 0193 auto job = new HandshakeJob(&restClient); 0194 QObject::connect(job, &Job::error, [](const QString &msg) { 0195 std::cerr << qPrintable(msg) << std::endl; 0196 QCoreApplication::exit(1); 0197 }); 0198 0199 return app.exec(); 0200 }