Redfish: Implement new event log propety Resolved

In the new Redfish specification 2020.4,the eventlog propety "resolved"
is added.
This attribute indicates whether the log is marked as "resolved".

Tested:
Validator succeeded.
The "Modified" attribute value will also change accordingly.
This property can be changed as the "marked as resolved" is
modified on the web page, or it can be modified directly using the
redfish command.
Before marked the log as resolved:
~$ curl -i -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/Entries/1
{
  "@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1",
  "@odata.type": "#LogEntry.v1_8_0.LogEntry",
  "Created": "1970-01-01T00:01:09+00:00",
  "EntryType": "Event",
  "Id": "1",
  "Message": "xyz.openbmc_project.Common.Device.Error.ReadFailure",
  "Modified": "1970-01-01T00:01:09+00:00",
  "Name": "System Event Log Entry",
  "Resolved": false,
  "Severity": "Critical"
}%
after marked the log as resolved on webpage OR use the redfish commond:
~$ curl -k -H "X-Auth-Token: $token" -X PATCH -d '{"Resolved": true}' https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/Entries/1
~$ curl -i -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Systems/system/LogServices/EventLog/Entries/1
{
"@odata.id": "/redfish/v1/Systems/system/LogServices/EventLog/Entries/1",
"@odata.type": "#LogEntry.v1_8_0.LogEntry",
"Created": "1970-01-01T00:00:57+00:00",
"EntryType": "Event",
"Id": "1",
"Message": "xyz.openbmc_project.Common.Device.Error.ReadFailure",
"Modified": "1970-01-01T00:03:05+00:00",
"Name": "System Event Log Entry",
"Resolved": true,
"Severity": "Critical"
}

Signed-off-by: Xiaochao Ma <maxiaochao@inspur.com>
Change-Id: Idd0cc0ca61ad56703303f90ba2bd1a372c321d94
diff --git a/redfish-core/lib/log_services.hpp b/redfish-core/lib/log_services.hpp
index a4e483e..883fc69 100644
--- a/redfish-core/lib/log_services.hpp
+++ b/redfish-core/lib/log_services.hpp
@@ -30,6 +30,7 @@
 #include <error_messages.hpp>
 
 #include <filesystem>
+#include <optional>
 #include <string_view>
 #include <variant>
 
@@ -1405,6 +1406,7 @@
                         std::time_t updateTimestamp{};
                         std::string* severity = nullptr;
                         std::string* message = nullptr;
+                        bool resolved = false;
 
                         for (auto& propertyMap : interfaceMap.second)
                         {
@@ -1443,6 +1445,17 @@
                                 message = std::get_if<std::string>(
                                     &propertyMap.second);
                             }
+                            else if (propertyMap.first == "Resolved")
+                            {
+                                bool* resolveptr =
+                                    std::get_if<bool>(&propertyMap.second);
+                                if (resolveptr == nullptr)
+                                {
+                                    messages::internalError(asyncResp->res);
+                                    return;
+                                }
+                                resolved = *resolveptr;
+                            }
                         }
                         if (id == nullptr || message == nullptr ||
                             severity == nullptr)
@@ -1451,7 +1464,7 @@
                             return;
                         }
                         thisEntry = {
-                            {"@odata.type", "#LogEntry.v1_6_0.LogEntry"},
+                            {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
                             {"@odata.id",
                              "/redfish/v1/Systems/system/LogServices/EventLog/"
                              "Entries/" +
@@ -1459,6 +1472,7 @@
                             {"Name", "System Event Log Entry"},
                             {"Id", std::to_string(*id)},
                             {"Message", *message},
+                            {"Resolved", resolved},
                             {"EntryType", "Event"},
                             {"Severity",
                              translateSeverityDbusToRedfish(*severity)},
@@ -1533,6 +1547,7 @@
                 std::time_t updateTimestamp{};
                 std::string* severity = nullptr;
                 std::string* message = nullptr;
+                bool resolved = false;
 
                 for (auto& propertyMap : resp)
                 {
@@ -1569,6 +1584,17 @@
                     {
                         message = std::get_if<std::string>(&propertyMap.second);
                     }
+                    else if (propertyMap.first == "Resolved")
+                    {
+                        bool* resolveptr =
+                            std::get_if<bool>(&propertyMap.second);
+                        if (resolveptr == nullptr)
+                        {
+                            messages::internalError(asyncResp->res);
+                            return;
+                        }
+                        resolved = *resolveptr;
+                    }
                 }
                 if (id == nullptr || message == nullptr || severity == nullptr)
                 {
@@ -1576,7 +1602,7 @@
                     return;
                 }
                 asyncResp->res.jsonValue = {
-                    {"@odata.type", "#LogEntry.v1_6_0.LogEntry"},
+                    {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
                     {"@odata.id",
                      "/redfish/v1/Systems/system/LogServices/EventLog/"
                      "Entries/" +
@@ -1584,6 +1610,7 @@
                     {"Name", "System Event Log Entry"},
                     {"Id", std::to_string(*id)},
                     {"Message", *message},
+                    {"Resolved", resolved},
                     {"EntryType", "Event"},
                     {"Severity", translateSeverityDbusToRedfish(*severity)},
                     {"Created", crow::utility::getDateTime(timestamp)},
@@ -1595,6 +1622,47 @@
             "xyz.openbmc_project.Logging.Entry");
     }
 
+    void doPatch(crow::Response& res, const crow::Request& req,
+                 const std::vector<std::string>& params) override
+    {
+        std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+
+        if (params.size() != 1)
+        {
+            messages::internalError(asyncResp->res);
+            return;
+        }
+        std::string entryId = params[0];
+
+        std::optional<bool> resolved;
+
+        if (!json_util::readJson(req, res, "Resolved", resolved))
+        {
+            return;
+        }
+
+        if (resolved)
+        {
+            BMCWEB_LOG_DEBUG << "Set Resolved";
+
+            crow::connections::systemBus->async_method_call(
+                [asyncResp, resolved,
+                 entryId](const boost::system::error_code ec) {
+                    if (ec)
+                    {
+                        BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+                        messages::internalError(asyncResp->res);
+                        return;
+                    }
+                },
+                "xyz.openbmc_project.Logging",
+                "/xyz/openbmc_project/logging/entry/" + entryId,
+                "org.freedesktop.DBus.Properties", "Set",
+                "xyz.openbmc_project.Logging.Entry", "Resolved",
+                std::variant<bool>(*resolved));
+        }
+    }
+
     void doDelete(crow::Response& res, const crow::Request&,
                   const std::vector<std::string>& params) override
     {