1 /*
2 Copyright (c) 2019 Intel Corporation
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8       http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 #pragma once
17 
18 #include "app.hpp"
19 #include "query.hpp"
20 #include "registries.hpp"
21 #include "registries_selector.hpp"
22 
23 #include <boost/url/format.hpp>
24 
25 #include <array>
26 #include <format>
27 
28 namespace redfish
29 {
30 
31 inline void handleMessageRegistryFileCollectionGet(
32     crow::App& app, const crow::Request& req,
33     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
34 {
35     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
36     {
37         return;
38     }
39     // Collections don't include the static data added by SubRoute
40     // because it has a duplicate entry for members
41 
42     asyncResp->res.jsonValue["@odata.type"] =
43         "#MessageRegistryFileCollection.MessageRegistryFileCollection";
44     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Registries";
45     asyncResp->res.jsonValue["Name"] = "MessageRegistryFile Collection";
46     asyncResp->res.jsonValue["Description"] =
47         "Collection of MessageRegistryFiles";
48 
49     nlohmann::json& members = asyncResp->res.jsonValue["Members"];
50 
51     static constexpr const auto registryFiles = std::to_array(
52         {"Base", "TaskEvent", "ResourceEvent", "OpenBMC", "Telemetry",
53          "HeartbeatEvent"});
54 
55     for (const char* memberName : registryFiles)
56     {
57         nlohmann::json::object_t member;
58         member["@odata.id"] =
59             boost::urls::format("/redfish/v1/Registries/{}", memberName);
60         members.emplace_back(std::move(member));
61     }
62     asyncResp->res.jsonValue["Members@odata.count"] = members.size();
63 }
64 
65 inline void requestRoutesMessageRegistryFileCollection(App& app)
66 {
67     /**
68      * Functions triggers appropriate requests on DBus
69      */
70     BMCWEB_ROUTE(app, "/redfish/v1/Registries/")
71         .privileges(redfish::privileges::getMessageRegistryFileCollection)
72         .methods(boost::beast::http::verb::get)(std::bind_front(
73             handleMessageRegistryFileCollectionGet, std::ref(app)));
74 }
75 
76 inline void handleMessageRoutesMessageRegistryFileGet(
77     crow::App& app, const crow::Request& req,
78     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
79     const std::string& registry)
80 {
81     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
82     {
83         return;
84     }
85     std::string dmtf = "DMTF ";
86     std::optional<registries::HeaderAndUrl> headerAndUrl =
87         registries::getRegistryHeaderAndUrlFromPrefix(registry);
88 
89     if (!headerAndUrl)
90     {
91         messages::resourceNotFound(asyncResp->res, "MessageRegistryFile",
92                                    registry);
93         return;
94     }
95     if (registry == "OpenBMC")
96     {
97         dmtf.clear();
98     }
99     const registries::Header& header = headerAndUrl->header;
100     const char* url = headerAndUrl->url;
101 
102     asyncResp->res.jsonValue["@odata.id"] =
103         boost::urls::format("/redfish/v1/Registries/{}", registry);
104     asyncResp->res.jsonValue["@odata.type"] =
105         "#MessageRegistryFile.v1_1_0.MessageRegistryFile";
106     asyncResp->res.jsonValue["Name"] = registry + " Message Registry File";
107     asyncResp->res.jsonValue["Description"] =
108         dmtf + registry + " Message Registry File Location";
109     asyncResp->res.jsonValue["Id"] = header.registryPrefix;
110     asyncResp->res.jsonValue["Registry"] =
111         std::format("{}.{}.{}", header.registryPrefix, header.versionMajor,
112                     header.versionMinor);
113     nlohmann::json::array_t languages;
114     languages.emplace_back(header.language);
115     asyncResp->res.jsonValue["Languages@odata.count"] = languages.size();
116     asyncResp->res.jsonValue["Languages"] = std::move(languages);
117     nlohmann::json::array_t locationMembers;
118     nlohmann::json::object_t location;
119     location["Language"] = header.language;
120     location["Uri"] = "/redfish/v1/Registries/" + registry + "/" + registry;
121 
122     if (url != nullptr)
123     {
124         location["PublicationUri"] = url;
125     }
126     locationMembers.emplace_back(std::move(location));
127     asyncResp->res.jsonValue["Location@odata.count"] = locationMembers.size();
128     asyncResp->res.jsonValue["Location"] = std::move(locationMembers);
129 }
130 
131 inline void requestRoutesMessageRegistryFile(App& app)
132 {
133     BMCWEB_ROUTE(app, "/redfish/v1/Registries/<str>/")
134         .privileges(redfish::privileges::getMessageRegistryFile)
135         .methods(boost::beast::http::verb::get)(std::bind_front(
136             handleMessageRoutesMessageRegistryFileGet, std::ref(app)));
137 }
138 
139 inline void handleMessageRegistryGet(
140     crow::App& app, const crow::Request& req,
141     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
142     const std::string& registry, const std::string& registryMatch)
143 
144 {
145     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
146     {
147         return;
148     }
149 
150     std::optional<registries::HeaderAndUrl> headerAndUrl =
151         registries::getRegistryHeaderAndUrlFromPrefix(registry);
152     if (!headerAndUrl)
153     {
154         messages::resourceNotFound(asyncResp->res, "MessageRegistryFile",
155                                    registry);
156         return;
157     }
158 
159     const registries::Header& header = headerAndUrl->header;
160     if (registry != registryMatch)
161     {
162         messages::resourceNotFound(asyncResp->res, header.type, registryMatch);
163         return;
164     }
165 
166     asyncResp->res.jsonValue["@Redfish.Copyright"] = header.copyright;
167     asyncResp->res.jsonValue["@odata.type"] = header.type;
168     asyncResp->res.jsonValue["Id"] =
169         std::format("{}.{}.{}.{}", header.registryPrefix, header.versionMajor,
170                     header.versionMinor, header.versionPatch);
171     asyncResp->res.jsonValue["Name"] = header.name;
172     asyncResp->res.jsonValue["Language"] = header.language;
173     asyncResp->res.jsonValue["Description"] = header.description;
174     asyncResp->res.jsonValue["RegistryPrefix"] = header.registryPrefix;
175     asyncResp->res.jsonValue["RegistryVersion"] =
176         std::format("{}.{}.{}", header.versionMajor, header.versionMinor,
177                     header.versionPatch);
178     asyncResp->res.jsonValue["OwningEntity"] = header.owningEntity;
179 
180     nlohmann::json& messageObj = asyncResp->res.jsonValue["Messages"];
181 
182     // Go through the Message Registry and populate each Message
183     const std::span<const registries::MessageEntry> registryEntries =
184         registries::getRegistryFromPrefix(registry);
185 
186     for (const registries::MessageEntry& message : registryEntries)
187     {
188         nlohmann::json& obj = messageObj[message.first];
189         obj["Description"] = message.second.description;
190         obj["Message"] = message.second.message;
191         obj["Severity"] = message.second.messageSeverity;
192         obj["MessageSeverity"] = message.second.messageSeverity;
193         obj["NumberOfArgs"] = message.second.numberOfArgs;
194         obj["Resolution"] = message.second.resolution;
195         if (message.second.numberOfArgs > 0)
196         {
197             nlohmann::json& messageParamArray = obj["ParamTypes"];
198             messageParamArray = nlohmann::json::array();
199             for (const char* str : message.second.paramTypes)
200             {
201                 if (str == nullptr)
202                 {
203                     break;
204                 }
205                 messageParamArray.push_back(str);
206             }
207         }
208     }
209 }
210 
211 inline void requestRoutesMessageRegistry(App& app)
212 {
213     BMCWEB_ROUTE(app, "/redfish/v1/Registries/<str>/<str>/")
214         .privileges(redfish::privileges::getMessageRegistryFile)
215         .methods(boost::beast::http::verb::get)(
216             std::bind_front(handleMessageRegistryGet, std::ref(app)));
217 }
218 } // namespace redfish
219