bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "GET") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "objects/query/" + type->GetName(); std::vector<String> joinAttrs; joinAttrs.push_back(""); for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if (field.Attributes & FANavigation) joinAttrs.push_back(field.Name); } Dictionary::Ptr params = HttpUtility::FetchRequestParameters(request); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector<Value> objs = FilterUtility::GetFilterTargets(qd, params, user); Array::Ptr results = new Array(); std::set<String> attrs; Array::Ptr uattrs = params->Get("attrs"); if (uattrs) { ObjectLock olock(uattrs); BOOST_FOREACH(const String& uattr, uattrs) { attrs.insert(uattr); } }
static void AddSuggestions(std::vector<String>& matches, const String& word, const String& pword, bool withFields, const Value& value) { String prefix; if (!pword.IsEmpty()) prefix = pword + "."; if (value.IsObjectType<Dictionary>()) { Dictionary::Ptr dict = value; ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { AddSuggestion(matches, word, prefix + kv.first); } } if (value.IsObjectType<Namespace>()) { Namespace::Ptr ns = value; ObjectLock olock(ns); for (const Namespace::Pair& kv : ns) { AddSuggestion(matches, word, prefix + kv.first); } } if (withFields) { Type::Ptr type = value.GetReflectionType(); for (int i = 0; i < type->GetFieldCount(); i++) { Field field = type->GetFieldInfo(i); AddSuggestion(matches, word, prefix + field.Name); } while (type) { Object::Ptr prototype = type->GetPrototype(); Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(prototype); if (dict) { ObjectLock olock(dict); for (const Dictionary::Pair& kv : dict) { AddSuggestion(matches, word, prefix + kv.first); } } type = type->GetBaseType(); } } }
BOOST_FOREACH(const ConfigObject::Ptr& obj, objs) { Dictionary::Ptr result1 = new Dictionary(); results->Add(result1); Dictionary::Ptr resultAttrs = new Dictionary(); result1->Set("attrs", resultAttrs); 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); if (!joinedObj) continue; Field field = type->GetFieldInfo(fid); prefix = field.NavigationName; } boost::algorithm::to_lower(prefix); Type::Ptr joinedType = joinedObj->GetReflectionType(); for (int fid = 0; fid < joinedType->GetFieldCount(); fid++) { Field field = joinedType->GetFieldInfo(fid); String aname = prefix + "." + field.Name; if (!attrs.empty() && attrs.find(aname) == attrs.end()) continue; Value val = joinedObj->GetField(fid); /* 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); } }
bool FilterUtility::EvaluateFilter(ScriptFrame& frame, Expression *filter, const Object::Ptr& target, const String& variableName) { if (!filter) return true; Type::Ptr type = target->GetReflectionType(); String varName; if (variableName.IsEmpty()) varName = type->GetName().ToLower(); else varName = variableName; Namespace::Ptr frameNS; if (frame.Self.IsEmpty()) { frameNS = new Namespace(); frame.Self = frameNS; } else { /* Enforce a namespace object for 'frame.self'. */ ASSERT(frame.Self.IsObjectType<Namespace>()); frameNS = frame.Self; } frameNS->Set("obj", target); frameNS->Set(varName, target); for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if ((field.Attributes & FANavigation) == 0) continue; Object::Ptr joinedObj = target->NavigateField(fid); if (field.NavigationName) frameNS->Set(field.NavigationName, joinedObj); else frameNS->Set(field.Name, joinedObj); } return Convert::ToBool(filter->Evaluate(frame)); }
bool FilterUtility::EvaluateFilter(ScriptFrame& frame, Expression *filter, const Object::Ptr& target, const String& variableName) { if (!filter) return true; Type::Ptr type = target->GetReflectionType(); String varName; if (variableName.IsEmpty()) varName = type->GetName().ToLower(); else varName = variableName; Dictionary::Ptr vars; if (frame.Self.IsEmpty()) { vars = new Dictionary(); frame.Self = vars; } else vars = frame.Self; vars->Set("obj", target); vars->Set(varName, target); for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if ((field.Attributes & FANavigation) == 0) continue; Object::Ptr joinedObj = target->NavigateField(fid); if (field.NavigationName) vars->Set(field.NavigationName, joinedObj); else vars->Set(field.Name, joinedObj); } return Convert::ToBool(filter->Evaluate(frame)); }
std::vector<String> icinga::GetFieldCompletionSuggestions(const Type::Ptr& type, const String& word) { std::vector<String> result; for (int i = 0; i < type->GetFieldCount(); i++) { Field field = type->GetFieldInfo(i); if (!(field.Attributes & FAConfig) || field.Attributes & FAInternal) continue; if (strcmp(field.TypeName, "int") != 0 && strcmp(field.TypeName, "double") != 0 && strcmp(field.TypeName, "bool") != 0 && strcmp(field.TypeName, "String") != 0) continue; String fname = field.Name; String suggestion = fname + "="; if (suggestion.Find(word) == 0) result.push_back(suggestion); } return result; }
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); for (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); for (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); } } DictionaryData resultAttrs; resultAttrs.reserve(fids.size()); for (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 && !(field.Attributes & (FAConfig | FAState))) continue; Value sval = Serialize(val, FAConfig | FAState); resultAttrs.emplace_back(field.Name, sval); } return new Dictionary(std::move(resultAttrs)); }
bool ObjectQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response, const Dictionary::Ptr& params) { if (request.RequestUrl->GetPath().size() < 3 || request.RequestUrl->GetPath().size() > 4) return false; if (request.RequestMethod != "GET") return false; Type::Ptr type = FilterUtility::TypeFromPluralName(request.RequestUrl->GetPath()[2]); if (!type) { HttpUtility::SendJsonError(response, params, 400, "Invalid type specified."); return true; } QueryDescription qd; qd.Types.insert(type->GetName()); qd.Permission = "objects/query/" + type->GetName(); Array::Ptr uattrs, ujoins, umetas; try { uattrs = params->Get("attrs"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, params, 400, "Invalid type for 'attrs' attribute specified. Array type is required."); return true; } try { ujoins = params->Get("joins"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, params, 400, "Invalid type for 'joins' attribute specified. Array type is required."); return true; } try { umetas = params->Get("meta"); } catch (const std::exception&) { HttpUtility::SendJsonError(response, params, 400, "Invalid type for 'meta' attribute specified. Array type is required."); return true; } bool allJoins = HttpUtility::GetLastParameter(params, "all_joins"); params->Set("type", type->GetName()); if (request.RequestUrl->GetPath().size() >= 4) { String attr = type->GetName(); boost::algorithm::to_lower(attr); params->Set(attr, request.RequestUrl->GetPath()[3]); } std::vector<Value> objs; try { objs = FilterUtility::GetFilterTargets(qd, params, user); } catch (const std::exception& ex) { HttpUtility::SendJsonError(response, params, 404, "No objects found.", DiagnosticInformation(ex)); return true; } ArrayData results; results.reserve(objs.size()); std::set<String> joinAttrs; std::set<String> userJoinAttrs; if (ujoins) { ObjectLock olock(ujoins); for (const String& ujoin : ujoins) { userJoinAttrs.insert(ujoin.SubStr(0, ujoin.FindFirstOf("."))); } } for (int fid = 0; fid < type->GetFieldCount(); fid++) { Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FANavigation)) continue; if (!allJoins && userJoinAttrs.find(field.NavigationName) == userJoinAttrs.end()) continue; joinAttrs.insert(field.Name); } for (const ConfigObject::Ptr& obj : objs) { DictionaryData result1{ { "name", obj->GetName() }, { "type", obj->GetReflectionType()->GetName() } }; DictionaryData metaAttrs; if (umetas) { ObjectLock olock(umetas); for (const String& meta : umetas) { if (meta == "used_by") { Array::Ptr used_by = new Array(); metaAttrs.emplace_back("used_by", used_by); for (const Object::Ptr& pobj : DependencyGraph::GetParents((obj))) { ConfigObject::Ptr configObj = dynamic_pointer_cast<ConfigObject>(pobj); if (!configObj) continue; used_by->Add(new Dictionary({ { "type", configObj->GetReflectionType()->GetName() }, { "name", configObj->GetName() } })); } } else if (meta == "location") { metaAttrs.emplace_back("location", obj->GetSourceLocation()); } else { HttpUtility::SendJsonError(response, params, 400, "Invalid field specified for meta: " + meta); return true; } } } result1.emplace_back("meta", new Dictionary(std::move(metaAttrs))); try { result1.emplace_back("attrs", SerializeObjectAttrs(obj, String(), uattrs, false, false)); } catch (const ScriptError& ex) { HttpUtility::SendJsonError(response, params, 400, ex.what()); return true; } DictionaryData joins; for (const String& joinAttr : joinAttrs) { Object::Ptr joinedObj; int fid = type->GetFieldId(joinAttr); if (fid < 0) { HttpUtility::SendJsonError(response, params, 400, "Invalid field specified for join: " + joinAttr); return true; } Field field = type->GetFieldInfo(fid); if (!(field.Attributes & FANavigation)) { HttpUtility::SendJsonError(response, params, 400, "Not a joinable field: " + joinAttr); return true; } joinedObj = obj->NavigateField(fid); if (!joinedObj) continue; String prefix = field.NavigationName; try { joins.emplace_back(prefix, SerializeObjectAttrs(joinedObj, prefix, ujoins, true, allJoins)); } catch (const ScriptError& ex) { HttpUtility::SendJsonError(response, params, 400, ex.what()); return true; } } result1.emplace_back("joins", new Dictionary(std::move(joins))); results.push_back(new Dictionary(std::move(result1))); } Dictionary::Ptr result = new Dictionary({ { "results", new Array(std::move(results)) } }); response.SetStatus(200, "OK"); HttpUtility::SendJsonBody(response, params, result); return true; }