mirror of https://github.com/Icinga/icinga2.git
parent
4cfde2d7ef
commit
a177e5e05a
|
@ -112,23 +112,15 @@ void MainForm::OnTypeSelected(wxTreeEvent& event)
|
|||
ApiType::Ptr type = m_Types[typeName.ToStdString()];
|
||||
|
||||
std::vector<String> attrs;
|
||||
attrs.push_back(type->Name.ToLower() + ".__name");
|
||||
attrs.push_back("__name");
|
||||
|
||||
m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectsCompletionHandler, this, _1, _2, true),
|
||||
std::vector<String>(), attrs);
|
||||
}
|
||||
|
||||
static bool ApiObjectLessComparer(const String& nameAttr, const ApiObject::Ptr& o1, const ApiObject::Ptr& o2)
|
||||
static bool ApiObjectLessComparer(const ApiObject::Ptr& o1, const ApiObject::Ptr& o2)
|
||||
{
|
||||
std::map<String, Value>::const_iterator it1 = o1->Attrs.find(nameAttr);
|
||||
if (it1 == o1->Attrs.end())
|
||||
return false;
|
||||
|
||||
std::map<String, Value>::const_iterator it2 = o2->Attrs.find(nameAttr);
|
||||
if (it2 == o2->Attrs.end())
|
||||
return false;
|
||||
|
||||
return it1->second < it2->second;
|
||||
return o1->Name < o2->Name;
|
||||
}
|
||||
|
||||
void MainForm::ObjectsCompletionHandler(boost::exception_ptr eptr, const std::vector<ApiObject::Ptr>& objects, bool forward)
|
||||
|
@ -151,21 +143,12 @@ void MainForm::ObjectsCompletionHandler(boost::exception_ptr eptr, const std::ve
|
|||
}
|
||||
}
|
||||
|
||||
wxTreeItemId selectedId = m_TypesTree->GetSelection();
|
||||
wxString typeName = m_TypesTree->GetItemText(selectedId);
|
||||
ApiType::Ptr type = m_Types[typeName.ToStdString()];
|
||||
|
||||
String nameAttr = type->Name.ToLower() + ".__name";
|
||||
|
||||
std::vector<ApiObject::Ptr> sortedObjects = objects;
|
||||
std::sort(sortedObjects.begin(), sortedObjects.end(), boost::bind(ApiObjectLessComparer, nameAttr, _2, _1));
|
||||
std::sort(sortedObjects.begin(), sortedObjects.end(), ApiObjectLessComparer);
|
||||
|
||||
BOOST_FOREACH(const ApiObject::Ptr& object, sortedObjects) {
|
||||
std::map<String, Value>::const_iterator it = object->Attrs.find(nameAttr);
|
||||
if (it == object->Attrs.end())
|
||||
continue;
|
||||
String name = it->second;
|
||||
m_ObjectsList->InsertItem(0, name.GetData());
|
||||
std::string name = object->Name;
|
||||
m_ObjectsList->InsertItem(0, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +173,8 @@ void MainForm::OnObjectSelected(wxListEvent& event)
|
|||
std::vector<String> names;
|
||||
names.push_back(objectName);
|
||||
|
||||
m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, _1, _2, true), names);
|
||||
m_ApiClient->GetObjects(type->PluralName, boost::bind(&MainForm::ObjectDetailsCompletionHandler, this, _1, _2, true),
|
||||
names, std::vector<String>(), std::vector<String>(), true);
|
||||
}
|
||||
|
||||
wxPGProperty *MainForm::ValueToProperty(const String& name, const Value& value)
|
||||
|
|
|
@ -105,7 +105,7 @@ void ApiClient::TypesHttpCompletionCallback(HttpRequest& request, HttpResponse&
|
|||
}
|
||||
|
||||
void ApiClient::GetObjects(const String& pluralType, const ObjectsCompletionCallback& callback,
|
||||
const std::vector<String>& names, const std::vector<String>& attrs) const
|
||||
const std::vector<String>& names, const std::vector<String>& attrs, const std::vector<String>& joins, bool all_joins) const
|
||||
{
|
||||
Url::Ptr url = new Url();
|
||||
url->SetScheme("https");
|
||||
|
@ -128,6 +128,12 @@ void ApiClient::GetObjects(const String& pluralType, const ObjectsCompletionCall
|
|||
params["attrs"].push_back(attr);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const String& join, joins) {
|
||||
params["joins"].push_back(join);
|
||||
}
|
||||
|
||||
params["all_joins"].push_back(all_joins ? "1" : "0");
|
||||
|
||||
url->SetQuery(params);
|
||||
|
||||
try {
|
||||
|
@ -169,26 +175,42 @@ void ApiClient::ObjectsHttpCompletionCallback(HttpRequest& request,
|
|||
|
||||
if (results) {
|
||||
ObjectLock olock(results);
|
||||
BOOST_FOREACH(const Dictionary::Ptr objectInfo, results)
|
||||
{
|
||||
BOOST_FOREACH(const Dictionary::Ptr objectInfo, results) {
|
||||
ApiObject::Ptr object = new ApiObject();
|
||||
|
||||
object->Name = objectInfo->Get("name");
|
||||
object->Type = objectInfo->Get("type");
|
||||
|
||||
Dictionary::Ptr attrs = objectInfo->Get("attrs");
|
||||
|
||||
{
|
||||
if (attrs) {
|
||||
ObjectLock olock(attrs);
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, attrs)
|
||||
{
|
||||
object->Attrs[kv.first] = kv.second;
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, attrs) {
|
||||
object->Attrs[object->Type.ToLower() + "." + kv.first] = kv.second;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary::Ptr joins = objectInfo->Get("joins");
|
||||
|
||||
if (joins) {
|
||||
ObjectLock olock(joins);
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv, joins) {
|
||||
Dictionary::Ptr attrs = kv.second;
|
||||
|
||||
if (attrs) {
|
||||
ObjectLock olock(attrs);
|
||||
BOOST_FOREACH(const Dictionary::Pair& kv2, attrs) {
|
||||
object->Attrs[kv.first + "." + kv2.first] = kv2.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array::Ptr used_by = objectInfo->Get("used_by");
|
||||
|
||||
{
|
||||
if (used_by) {
|
||||
ObjectLock olock(used_by);
|
||||
BOOST_FOREACH(const Dictionary::Ptr& refInfo, used_by)
|
||||
{
|
||||
BOOST_FOREACH(const Dictionary::Ptr& refInfo, used_by) {
|
||||
ApiObjectReference ref;
|
||||
ref.Name = refInfo->Get("name");
|
||||
ref.Type = refInfo->Get("type");
|
||||
|
|
|
@ -32,7 +32,9 @@ struct ApiFieldAttributes
|
|||
{
|
||||
public:
|
||||
bool Config;
|
||||
bool Internal;
|
||||
bool Navigation;
|
||||
bool NoUserModify;
|
||||
bool NouserView;
|
||||
bool Required;
|
||||
bool State;
|
||||
};
|
||||
|
@ -76,6 +78,8 @@ struct I2_REMOTE_API ApiObject : public Object
|
|||
public:
|
||||
DECLARE_PTR_TYPEDEFS(ApiObject);
|
||||
|
||||
String Name;
|
||||
String Type;
|
||||
std::map<String, Value> Attrs;
|
||||
std::vector<ApiObjectReference> UsedBy;
|
||||
};
|
||||
|
@ -94,7 +98,8 @@ public:
|
|||
typedef boost::function<void(boost::exception_ptr, const std::vector<ApiObject::Ptr>&)> ObjectsCompletionCallback;
|
||||
void GetObjects(const String& pluralType, const ObjectsCompletionCallback& callback,
|
||||
const std::vector<String>& names = std::vector<String>(),
|
||||
const std::vector<String>& attrs = std::vector<String>()) const;
|
||||
const std::vector<String>& attrs = std::vector<String>(),
|
||||
const std::vector<String>& joins = std::vector<String>(), bool all_joins = false) const;
|
||||
|
||||
typedef boost::function<void(boost::exception_ptr, const Value&)> ExecuteScriptCompletionCallback;
|
||||
void ExecuteScript(const String& session, const String& command, bool sandboxed,
|
||||
|
|
|
@ -153,7 +153,7 @@ void HttpServerConnection::ProcessMessageAsync(HttpRequest& request)
|
|||
user.reset();
|
||||
}
|
||||
|
||||
String requestUrl = request.RequestUrl->Format();
|
||||
String requestUrl = request.RequestUrl->Format();
|
||||
|
||||
Log(LogInformation, "HttpServerConnection")
|
||||
<< "Request: " << request.RequestMethod << " " << requestUrl
|
||||
|
|
|
@ -30,6 +30,84 @@ using namespace icinga;
|
|||
|
||||
REGISTER_URLHANDLER("/v1/objects", ObjectQueryHandler);
|
||||
|
||||
Dictionary::Ptr ObjectQueryHandler::SerializeObjectAttrs(const Object::Ptr& object,
|
||||
const String& attrPrefix, const Array::Ptr& attrs, bool isJoin, bool allAttrs)
|
||||
{
|
||||
Type::Ptr type = object->GetReflectionType();
|
||||
|
||||
std::vector<int> fids;
|
||||
|
||||
if (isJoin && attrs) {
|
||||
ObjectLock olock(attrs);
|
||||
BOOST_FOREACH(const String& attr, attrs) {
|
||||
if (attr == attrPrefix) {
|
||||
allAttrs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isJoin && (!attrs || attrs->GetLength() == 0))
|
||||
allAttrs = true;
|
||||
|
||||
if (allAttrs) {
|
||||
for (int fid = 0; fid < type->GetFieldCount(); fid++) {
|
||||
fids.push_back(fid);
|
||||
}
|
||||
} else if (attrs) {
|
||||
ObjectLock olock(attrs);
|
||||
BOOST_FOREACH(const String& attr, attrs) {
|
||||
String userAttr;
|
||||
|
||||
if (isJoin) {
|
||||
String::SizeType dpos = attr.FindFirstOf(".");
|
||||
if (dpos == String::NPos)
|
||||
continue;
|
||||
|
||||
String userJoinAttr = attr.SubStr(0, dpos);
|
||||
if (userJoinAttr != attrPrefix)
|
||||
continue;
|
||||
|
||||
userAttr = attr.SubStr(dpos + 1);
|
||||
} else
|
||||
userAttr = attr;
|
||||
|
||||
int fid = type->GetFieldId(userAttr);
|
||||
|
||||
if (fid < 0)
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Invalid field specified: " + userAttr));
|
||||
|
||||
fids.push_back(fid);
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary::Ptr resultAttrs = new Dictionary();
|
||||
|
||||
BOOST_FOREACH(int& fid, fids)
|
||||
{
|
||||
Field field = type->GetFieldInfo(fid);
|
||||
|
||||
Value val = object->GetField(fid);
|
||||
|
||||
/* hide attributes which shouldn't be user-visible */
|
||||
if (field.Attributes & FANoUserView)
|
||||
continue;
|
||||
|
||||
/* hide internal navigation fields */
|
||||
if (field.Attributes & FANavigation) {
|
||||
Value nval = object->NavigateField(fid);
|
||||
|
||||
if (val == nval)
|
||||
continue;
|
||||
}
|
||||
|
||||
Value sval = Serialize(val, FAConfig | FAState);
|
||||
resultAttrs->Set(field.Name, sval);
|
||||
}
|
||||
|
||||
return resultAttrs;
|
||||
}
|
||||
|
||||
bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response)
|
||||
{
|
||||
if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4)
|
||||
|
@ -51,44 +129,10 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
|||
|
||||
Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request);
|
||||
|
||||
std::set<String> userJoinAttrs;
|
||||
std::set<String> attrs;
|
||||
Array::Ptr uattrs = params->Get("attrs");
|
||||
|
||||
if (uattrs) {
|
||||
ObjectLock olock(uattrs);
|
||||
BOOST_FOREACH(const String& uattr, uattrs) {
|
||||
attrs.insert(uattr);
|
||||
|
||||
String::SizeType dpos = uattr.FindFirstOf(".");
|
||||
if (dpos == String::NPos) {
|
||||
HttpUtility::SendJsonError(response, 400, "Attribute name must contain '.'.");
|
||||
return true;
|
||||
}
|
||||
|
||||
String userJoinAttr = uattr.SubStr(0, dpos);
|
||||
|
||||
if (userJoinAttr == type->GetName().ToLower())
|
||||
userJoinAttr = "";
|
||||
|
||||
userJoinAttrs.insert(userJoinAttr);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<String> joinAttrs;
|
||||
joinAttrs.push_back("");
|
||||
|
||||
for (int fid = 0; fid < type->GetFieldCount(); fid++) {
|
||||
Field field = type->GetFieldInfo(fid);
|
||||
|
||||
if (!(field.Attributes & FANavigation))
|
||||
continue;
|
||||
|
||||
if (!userJoinAttrs.empty() && userJoinAttrs.find(field.Name) == userJoinAttrs.end())
|
||||
continue;
|
||||
|
||||
joinAttrs.push_back(field.Name);
|
||||
}
|
||||
Array::Ptr ujoins = params->Get("joins");
|
||||
Array::Ptr umetas = params->Get("meta");
|
||||
bool allJoins = HttpUtility::GetLastParameter(params, "all_joins");
|
||||
|
||||
params->Set("type", type->GetName());
|
||||
|
||||
|
@ -103,93 +147,99 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
|||
Array::Ptr results = new Array();
|
||||
results->Reserve(objs.size());
|
||||
|
||||
std::set<String> joinAttrs;
|
||||
|
||||
if (allJoins) {
|
||||
for (int fid = 0; fid < type->GetFieldCount(); fid++) {
|
||||
Field field = type->GetFieldInfo(fid);
|
||||
if (field.Attributes & FANavigation)
|
||||
joinAttrs.insert(field.Name);
|
||||
}
|
||||
} else if (ujoins) {
|
||||
ObjectLock olock(ujoins);
|
||||
BOOST_FOREACH(const String& ujoin, ujoins) {
|
||||
joinAttrs.insert(ujoin.SubStr(0, ujoin.FindFirstOf(".")));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const ConfigObject::Ptr& obj, objs) {
|
||||
Dictionary::Ptr result1 = new Dictionary();
|
||||
results->Add(result1);
|
||||
|
||||
Dictionary::Ptr resultAttrs = new Dictionary();
|
||||
result1->Set("attrs", resultAttrs);
|
||||
result1->Set("name", obj->GetName());
|
||||
result1->Set("type", obj->GetReflectionType()->GetName());
|
||||
|
||||
Dictionary::Ptr metaAttrs = new Dictionary();
|
||||
result1->Set("meta", metaAttrs);
|
||||
|
||||
if (umetas) {
|
||||
ObjectLock olock(umetas);
|
||||
BOOST_FOREACH(const String& meta, umetas) {
|
||||
if (meta == "used_by") {
|
||||
Array::Ptr used_by = new Array();
|
||||
metaAttrs->Set("used_by", used_by);
|
||||
|
||||
BOOST_FOREACH(const Object::Ptr& pobj, DependencyGraph::GetParents((obj)))
|
||||
{
|
||||
ConfigObject::Ptr configObj = dynamic_pointer_cast<ConfigObject>(pobj);
|
||||
|
||||
if (!configObj)
|
||||
continue;
|
||||
|
||||
Dictionary::Ptr refInfo = new Dictionary();
|
||||
refInfo->Set("type", configObj->GetType()->GetName());
|
||||
refInfo->Set("name", configObj->GetName());
|
||||
used_by->Add(refInfo);
|
||||
}
|
||||
} else {
|
||||
HttpUtility::SendJsonError(response, 400, "Invalid field specified for meta: " + meta);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
result1->Set("attrs", SerializeObjectAttrs(obj, String(), uattrs, false, false));
|
||||
} catch (const ScriptError& ex) {
|
||||
HttpUtility::SendJsonError(response, 400, ex.what());
|
||||
return true;
|
||||
}
|
||||
|
||||
Dictionary::Ptr joins = new Dictionary();
|
||||
result1->Set("joins", joins);
|
||||
|
||||
BOOST_FOREACH(const String& joinAttr, joinAttrs) {
|
||||
Object::Ptr joinedObj;
|
||||
String prefix;
|
||||
|
||||
if (joinAttr.IsEmpty()) {
|
||||
joinedObj = obj;
|
||||
prefix = type->GetName();
|
||||
} else {
|
||||
int fid = type->GetFieldId(joinAttr);
|
||||
joinedObj = obj->NavigateField(fid);
|
||||
int fid = type->GetFieldId(joinAttr);
|
||||
|
||||
if (!joinedObj)
|
||||
continue;
|
||||
|
||||
Field field = type->GetFieldInfo(fid);
|
||||
prefix = field.NavigationName;
|
||||
if (fid < 0) {
|
||||
HttpUtility::SendJsonError(response, 400, "Invalid field specified for join: " + joinAttr);
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::algorithm::to_lower(prefix);
|
||||
Field field = type->GetFieldInfo(fid);
|
||||
|
||||
Type::Ptr joinedType = joinedObj->GetReflectionType();
|
||||
|
||||
std::vector<int> fids;
|
||||
|
||||
if (attrs.empty()) {
|
||||
for (int fid = 0; fid < joinedType->GetFieldCount(); fid++) {
|
||||
fids.push_back(fid);
|
||||
}
|
||||
} else {
|
||||
BOOST_FOREACH(const String& aname, attrs) {
|
||||
String::SizeType dpos = aname.FindFirstOf(".");
|
||||
ASSERT(dpos != String::NPos);
|
||||
|
||||
String userJoinAttr = aname.SubStr(0, dpos);
|
||||
if (userJoinAttr != prefix)
|
||||
continue;
|
||||
|
||||
String userAttr = aname.SubStr(dpos + 1);
|
||||
|
||||
int fid = joinedType->GetFieldId(userAttr);
|
||||
fids.push_back(fid);
|
||||
}
|
||||
if (!(field.Attributes & FANavigation)) {
|
||||
HttpUtility::SendJsonError(response, 400, "Not a joinable field: " + joinAttr);
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(int& fid, fids) {
|
||||
Field field = joinedType->GetFieldInfo(fid);
|
||||
String aname = prefix + "." + field.Name;
|
||||
joinedObj = obj->NavigateField(fid);
|
||||
|
||||
Value val = joinedObj->GetField(fid);
|
||||
|
||||
/* hide attributes which shouldn't be user-visible */
|
||||
if (field.Attributes & FANoUserView)
|
||||
continue;
|
||||
|
||||
/* hide internal navigation fields */
|
||||
if (field.Attributes & FANavigation) {
|
||||
Value nval = joinedObj->NavigateField(fid);
|
||||
|
||||
if (val == nval)
|
||||
continue;
|
||||
}
|
||||
|
||||
Value sval = Serialize(val, FAConfig | FAState);
|
||||
resultAttrs->Set(aname, sval);
|
||||
}
|
||||
}
|
||||
|
||||
Array::Ptr used_by = new Array();
|
||||
result1->Set("used_by", used_by);
|
||||
|
||||
BOOST_FOREACH(const Object::Ptr& pobj, DependencyGraph::GetParents((obj))) {
|
||||
ConfigObject::Ptr configObj = dynamic_pointer_cast<ConfigObject>(pobj);
|
||||
|
||||
if (!configObj)
|
||||
if (!joinedObj)
|
||||
continue;
|
||||
|
||||
Dictionary::Ptr refInfo = new Dictionary();
|
||||
refInfo->Set("type", configObj->GetType()->GetName());
|
||||
refInfo->Set("name", configObj->GetName());
|
||||
used_by->Add(refInfo);
|
||||
prefix = field.NavigationName;
|
||||
boost::algorithm::to_lower(prefix);
|
||||
|
||||
try {
|
||||
joins->Set(prefix, SerializeObjectAttrs(joinedObj, prefix, ujoins, true, allJoins));
|
||||
} catch (const ScriptError& ex) {
|
||||
HttpUtility::SendJsonError(response, 400, ex.what());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,4 +251,3 @@ bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& re
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ public:
|
|||
DECLARE_PTR_TYPEDEFS(ObjectQueryHandler);
|
||||
|
||||
virtual bool HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) override;
|
||||
|
||||
private:
|
||||
static Dictionary::Ptr SerializeObjectAttrs(const Object::Ptr& object, const String& attrPrefix,
|
||||
const Array::Ptr& attrs, bool isJoin, bool allAttrs);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue