Loading editor/html/js/survey-manager.js +14 −3 Changes for editor/html/js/survey-manager.js: 14 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -282,6 +282,8 @@ var SurveyManager = (function() { var _surveys = []; var _current = null; // {id, name, title, xml, questions:[]} var _editingQ = null; // current question being edited var _selectMode = false; // true when opened with a callback for selection var _onSelect = null; // callback(selectedName) in select mode // ------------------------------------------------------------------------- // DOM helpers Loading @@ -297,7 +299,14 @@ var SurveyManager = (function() { item.className = 'sm-survey-item' + (_current && _current.id === s.id ? ' active' : ''); item.textContent = s.name; item.setAttribute('data-id', s.id); item.addEventListener('click', function() { loadSurvey(s.id); }); item.addEventListener('click', function() { if (_selectMode) { if (_onSelect) _onSelect(s.name); document.getElementById('survey-manager-dialog').close(); } else { loadSurvey(s.id); } }); list.appendChild(item); }); } Loading Loading @@ -782,10 +791,12 @@ var SurveyManager = (function() { // Dialog open // ------------------------------------------------------------------------- function open() { function open(initialName, onSelectCallback) { _selectMode = typeof onSelectCallback === 'function'; _onSelect = _selectMode ? onSelectCallback : null; _current = null; _selectedQId = null; el('sm-form-area').style.display = 'none'; el('sm-form-area').style.display = _selectMode ? 'none' : 'none'; loadSurveys(); document.getElementById('survey-manager-dialog').showModal(); } Loading editor/src/webedit_api.cpp +405 −0 Changes for editor/src/webedit_api.cpp: 405 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3874,3 +3874,408 @@ webedit::Api::NodeContext webedit::Api::findNodeContextInChildren( return {}; } // --------------------------------------------------------------------------- // Survey proxy handler — forwards a survey command to the connected blog // --------------------------------------------------------------------------- void webedit::Api::handleSurveyProxy(libhttppp::HttpRequest &curreq, const std::string &sessionid, const std::string &connId) { std::string authid, blogUrl; { std::lock_guard<std::mutex> lk(_connSessionMtx); auto it = _connSessions.find(connId); if (it == _connSessions.end()) { sendJsonError(curreq, 403, "Not connected"); return; } authid = it->second.authid; blogUrl = it->second.blogUrl; } std::string body = getRequestBody(curreq); json_object *cmd = json_tokener_parse(body.c_str()); if (!cmd) { sendJsonError(curreq, 400, "Invalid JSON"); return; } json_object *requestArr = json_object_new_array(); json_object *authCmd = json_object_new_object(); json_object_object_add(authCmd, "authid", json_object_new_string(authid.c_str())); json_object_array_add(requestArr, authCmd); json_object_array_add(requestArr, cmd); try { json_object *resp = blogApiCall(blogUrl, requestArr); json_object_put(requestArr); if (!resp) { sendJsonError(curreq, 502, "No response from blog"); return; } json_object *result = json_object_new_object(); if (json_object_is_type(resp, json_type_array)) { size_t rLen = json_object_array_length(resp); for (size_t i = 0; i < rLen; ++i) { json_object *item = json_object_array_get_idx(resp, i); json_object *sObj = nullptr; if (json_object_object_get_ex(item, "status", &sObj)) { json_object_get(item); json_object_put(result); result = item; break; } } } json_object_put(resp); sendJson(curreq, result); json_object_put(result); } catch (const std::exception &e) { json_object_put(requestArr); sendJsonError(curreq, 502, std::string("Survey proxy failed: ") + e.what()); } } // --------------------------------------------------------------------------- // Survey XML → blogi JSON conversion // // Editor XML format: // <Survey name="..." title="..."> // <Question id="..." parent_id="..." type="..." label="..." order_idx="0"> // <Option value="...">label text</Option> // </Question> // </Survey> // // Blogi JSON format expected by save_survey: // { "id":"", "title":"...", "description":"", // "questions":[{"id":"...","type":"...","text":"...","required":false, // "order":0, "options":[{"value":"...","label":"..."}]}] } // --------------------------------------------------------------------------- json_object* webedit::Api::surveyXmlToJson(const std::string &name, const std::string &title, const std::string &xml) { json_object *jtpl = json_object_new_object(); json_object_object_add(jtpl, "id", json_object_new_string(name.c_str())); json_object_object_add(jtpl, "title", json_object_new_string(title.c_str())); json_object_object_add(jtpl, "description", json_object_new_string("")); json_object *jquestions = json_object_new_array(); if (!xml.empty()) { tinyxml2::XMLDocument doc; if (doc.Parse(xml.c_str(), xml.size()) == tinyxml2::XML_SUCCESS) { tinyxml2::XMLElement *surveyEl = doc.FirstChildElement("Survey"); if (surveyEl) { int orderIdx = 0; for (tinyxml2::XMLElement *qEl = surveyEl->FirstChildElement("Question"); qEl; qEl = qEl->NextSiblingElement("Question")) { json_object *jq = json_object_new_object(); const char *qid = qEl->Attribute("id"); const char *qtype = qEl->Attribute("type"); const char *qlabel = qEl->Attribute("label"); int qorder = orderIdx; qEl->QueryIntAttribute("order_idx", &qorder); json_object_object_add(jq, "id", json_object_new_string(qid ? qid : "")); json_object_object_add(jq, "type", json_object_new_string(qtype ? qtype : "text")); json_object_object_add(jq, "text", json_object_new_string(qlabel ? qlabel : "")); json_object_object_add(jq, "required", json_object_new_boolean(false)); json_object_object_add(jq, "order", json_object_new_int(qorder)); json_object *jopts = json_object_new_array(); for (tinyxml2::XMLElement *optEl = qEl->FirstChildElement("Option"); optEl; optEl = optEl->NextSiblingElement("Option")) { json_object *jo = json_object_new_object(); const char *val = optEl->Attribute("value"); const char *lbl = optEl->GetText(); json_object_object_add(jo, "value", json_object_new_string(val ? val : "")); json_object_object_add(jo, "label", json_object_new_string(lbl ? lbl : "")); json_object_array_add(jopts, jo); } json_object_object_add(jq, "options", jopts); json_object_array_add(jquestions, jq); ++orderIdx; } } } } json_object_object_add(jtpl, "questions", jquestions); return jtpl; } void webedit::Api::autoPublishSurveysForDocument(const std::string &docXml, const std::string &authid, const std::string &blogUrl, const std::string &ownerUid) { if (docXml.empty() || authid.empty() || blogUrl.empty()) return; tinyxml2::XMLDocument doc; if (doc.Parse(docXml.c_str(), docXml.size()) != tinyxml2::XML_SUCCESS) return; std::vector<std::string> surveyNames; std::function<void(tinyxml2::XMLElement*)> walk = [&](tinyxml2::XMLElement *el) { if (!el) return; const char *sn = el->Attribute("survey_name"); if (sn && sn[0]) { std::string name(sn); bool found = false; for (auto &s : surveyNames) { if (s == name) { found = true; break; } } if (!found) surveyNames.push_back(name); } for (auto *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) walk(child); }; walk(doc.RootElement()); if (surveyNames.empty()) return; for (const auto &sname : surveyNames) { dbpp::SQL sql; dbpp::DBResult res; std::vector<char> eOwner, eName; sql << "SELECT id, name, title, xml FROM survey_templates WHERE owner_uid='" << dbpp::SQL::escaped(eOwner, ownerUid.c_str()) << "' AND name='" << dbpp::SQL::escaped(eName, sname.c_str()) << "' LIMIT 1;"; int rows = _db.getDb().exec(sql, res); if (rows < 1) continue; std::string sname2 = res[0][1]; std::string stitle = res[0][2]; std::string sxml = res[0][3] ? res[0][3] : ""; json_object *jsurvey = surveyXmlToJson(sname2, stitle, sxml); json_object *requestArr = json_object_new_array(); json_object *authCmd = json_object_new_object(); json_object_object_add(authCmd, "authid", json_object_new_string(authid.c_str())); json_object_array_add(requestArr, authCmd); json_object *saveCmd = json_object_new_object(); json_object_object_add(saveCmd, "command", json_object_new_string("save_survey")); json_object_object_add(saveCmd, "name", json_object_new_string(sname2.c_str())); json_object_object_add(saveCmd, "survey", jsurvey); json_object_array_add(requestArr, saveCmd); try { json_object *resp = blogApiCall(blogUrl, requestArr); if (resp) json_object_put(resp); } catch (...) { std::cerr << "autoPublishSurveys: failed to push survey '" << sname2 << "'" << std::endl; } json_object_put(requestArr); } } // --------------------------------------------------------------------------- // Survey management handlers // --------------------------------------------------------------------------- void webedit::Api::handleListSurveys(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string jsonStr = _db.listSurveys(uid); json_object *resp = json_object_new_object(); json_object *arr = json_tokener_parse(jsonStr.c_str()); json_object_object_add(resp, "surveys", arr ? arr : json_object_new_array()); sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handleListSurveyNames(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string jsonStr = _db.listSurveyNames(uid); json_object *resp = json_object_new_object(); json_object *arr = json_tokener_parse(jsonStr.c_str()); json_object_object_add(resp, "surveys", arr ? arr : json_object_new_array()); sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handleGetSurvey(libhttppp::HttpRequest &curreq, const std::string &sessionid, const std::string &surveyId) { std::string uid; _session.getData(sessionid, "uid", uid); std::string jsonStr = _db.getSurvey(uid, surveyId); json_object *resp = json_tokener_parse(jsonStr.c_str()); if (!resp) { sendJsonError(curreq, 404, "Survey not found"); return; } sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handleSaveSurvey(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string body = getRequestBody(curreq); json_object *req = json_tokener_parse(body.c_str()); if (!req) { sendJsonError(curreq, 400, "Invalid JSON"); return; } json_object *idObj = nullptr, *nameObj = nullptr, *titleObj = nullptr, *xmlObj = nullptr; json_object_object_get_ex(req, "id", &idObj); json_object_object_get_ex(req, "name", &nameObj); json_object_object_get_ex(req, "title", &titleObj); json_object_object_get_ex(req, "xml", &xmlObj); std::string name = nameObj ? json_object_get_string(nameObj) : ""; std::string title = titleObj ? json_object_get_string(titleObj) : ""; std::string xml = xmlObj ? json_object_get_string(xmlObj) : "<Survey/>"; if (name.empty()) { json_object_put(req); sendJsonError(curreq, 400, "Name is required"); return; } std::string surveyId; if (idObj && strlen(json_object_get_string(idObj)) > 0) { surveyId = json_object_get_string(idObj); _db.updateSurvey(uid, surveyId, name, title, xml); } else { surveyId = _db.saveSurvey(uid, name, title, xml); } json_object *resp = json_object_new_object(); json_object_object_add(resp, "status", json_object_new_string("ok")); json_object_object_add(resp, "id", json_object_new_string(surveyId.c_str())); sendJson(curreq, resp); json_object_put(resp); json_object_put(req); } void webedit::Api::handleDeleteSurvey(libhttppp::HttpRequest &curreq, const std::string &sessionid, const std::string &surveyId) { std::string uid; _session.getData(sessionid, "uid", uid); _db.deleteSurvey(uid, surveyId); json_object *resp = json_object_new_object(); json_object_object_add(resp, "status", json_object_new_string("ok")); sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handlePublishSurveyToConnection(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string body = getRequestBody(curreq); json_object *req = json_tokener_parse(body.c_str()); if (!req) { sendJsonError(curreq, 400, "Invalid JSON"); return; } json_object *surveyIdObj = nullptr, *connIdObj = nullptr; json_object_object_get_ex(req, "survey_id", &surveyIdObj); json_object_object_get_ex(req, "conn_id", &connIdObj); std::string surveyId = surveyIdObj ? json_object_get_string(surveyIdObj) : ""; std::string connId = connIdObj ? json_object_get_string(connIdObj) : ""; json_object_put(req); if (surveyId.empty() || connId.empty()) { sendJsonError(curreq, 400, "survey_id and conn_id required"); return; } std::string surveyJson = _db.getSurvey(uid, surveyId); json_object *surveyData = json_tokener_parse(surveyJson.c_str()); if (!surveyData) { sendJsonError(curreq, 404, "Survey not found"); return; } json_object *nameObj = nullptr, *titleObj = nullptr, *xmlObj = nullptr; json_object_object_get_ex(surveyData, "name", &nameObj); json_object_object_get_ex(surveyData, "title", &titleObj); json_object_object_get_ex(surveyData, "xml", &xmlObj); std::string sname = nameObj ? json_object_get_string(nameObj) : ""; std::string stitle = titleObj ? json_object_get_string(titleObj) : ""; std::string sxml = xmlObj ? json_object_get_string(xmlObj) : ""; json_object_put(surveyData); if (sname.empty()) { sendJsonError(curreq, 400, "Survey has no name"); return; } std::string authid, blogUrl; { std::lock_guard<std::mutex> lk(_connSessionMtx); auto it = _connSessions.find(connId); if (it == _connSessions.end()) { sendJsonError(curreq, 403, "Not connected. Bitte zuerst verbinden."); return; } authid = it->second.authid; blogUrl = it->second.blogUrl; } json_object *jsurvey = surveyXmlToJson(sname, stitle, sxml); json_object *requestArr = json_object_new_array(); json_object *authCmd = json_object_new_object(); json_object_object_add(authCmd, "authid", json_object_new_string(authid.c_str())); json_object_array_add(requestArr, authCmd); json_object *saveCmd = json_object_new_object(); json_object_object_add(saveCmd, "command", json_object_new_string("save_survey")); json_object_object_add(saveCmd, "name", json_object_new_string(sname.c_str())); json_object_object_add(saveCmd, "survey", jsurvey); json_object_array_add(requestArr, saveCmd); try { json_object *pubResp = blogApiCall(blogUrl, requestArr); json_object_put(requestArr); std::string status = "error"; std::string message = "No response"; if (pubResp && json_object_is_type(pubResp, json_type_array)) { size_t rLen = json_object_array_length(pubResp); for (size_t i = 0; i < rLen; ++i) { json_object *item = json_object_array_get_idx(pubResp, i); json_object *sObj = nullptr, *mObj = nullptr; if (json_object_object_get_ex(item, "status", &sObj)) status = json_object_get_string(sObj); if (json_object_object_get_ex(item, "message", &mObj)) message = json_object_get_string(mObj); } } if (pubResp) json_object_put(pubResp); json_object *resp = json_object_new_object(); json_object_object_add(resp, "status", json_object_new_string(status.c_str())); json_object_object_add(resp, "message", json_object_new_string(message.c_str())); sendJson(curreq, resp); json_object_put(resp); } catch (const std::exception &e) { json_object_put(requestArr); sendJsonError(curreq, 502, std::string("Publish failed: ") + e.what()); } } Loading
editor/html/js/survey-manager.js +14 −3 Changes for editor/html/js/survey-manager.js: 14 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -282,6 +282,8 @@ var SurveyManager = (function() { var _surveys = []; var _current = null; // {id, name, title, xml, questions:[]} var _editingQ = null; // current question being edited var _selectMode = false; // true when opened with a callback for selection var _onSelect = null; // callback(selectedName) in select mode // ------------------------------------------------------------------------- // DOM helpers Loading @@ -297,7 +299,14 @@ var SurveyManager = (function() { item.className = 'sm-survey-item' + (_current && _current.id === s.id ? ' active' : ''); item.textContent = s.name; item.setAttribute('data-id', s.id); item.addEventListener('click', function() { loadSurvey(s.id); }); item.addEventListener('click', function() { if (_selectMode) { if (_onSelect) _onSelect(s.name); document.getElementById('survey-manager-dialog').close(); } else { loadSurvey(s.id); } }); list.appendChild(item); }); } Loading Loading @@ -782,10 +791,12 @@ var SurveyManager = (function() { // Dialog open // ------------------------------------------------------------------------- function open() { function open(initialName, onSelectCallback) { _selectMode = typeof onSelectCallback === 'function'; _onSelect = _selectMode ? onSelectCallback : null; _current = null; _selectedQId = null; el('sm-form-area').style.display = 'none'; el('sm-form-area').style.display = _selectMode ? 'none' : 'none'; loadSurveys(); document.getElementById('survey-manager-dialog').showModal(); } Loading
editor/src/webedit_api.cpp +405 −0 Changes for editor/src/webedit_api.cpp: 405 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3874,3 +3874,408 @@ webedit::Api::NodeContext webedit::Api::findNodeContextInChildren( return {}; } // --------------------------------------------------------------------------- // Survey proxy handler — forwards a survey command to the connected blog // --------------------------------------------------------------------------- void webedit::Api::handleSurveyProxy(libhttppp::HttpRequest &curreq, const std::string &sessionid, const std::string &connId) { std::string authid, blogUrl; { std::lock_guard<std::mutex> lk(_connSessionMtx); auto it = _connSessions.find(connId); if (it == _connSessions.end()) { sendJsonError(curreq, 403, "Not connected"); return; } authid = it->second.authid; blogUrl = it->second.blogUrl; } std::string body = getRequestBody(curreq); json_object *cmd = json_tokener_parse(body.c_str()); if (!cmd) { sendJsonError(curreq, 400, "Invalid JSON"); return; } json_object *requestArr = json_object_new_array(); json_object *authCmd = json_object_new_object(); json_object_object_add(authCmd, "authid", json_object_new_string(authid.c_str())); json_object_array_add(requestArr, authCmd); json_object_array_add(requestArr, cmd); try { json_object *resp = blogApiCall(blogUrl, requestArr); json_object_put(requestArr); if (!resp) { sendJsonError(curreq, 502, "No response from blog"); return; } json_object *result = json_object_new_object(); if (json_object_is_type(resp, json_type_array)) { size_t rLen = json_object_array_length(resp); for (size_t i = 0; i < rLen; ++i) { json_object *item = json_object_array_get_idx(resp, i); json_object *sObj = nullptr; if (json_object_object_get_ex(item, "status", &sObj)) { json_object_get(item); json_object_put(result); result = item; break; } } } json_object_put(resp); sendJson(curreq, result); json_object_put(result); } catch (const std::exception &e) { json_object_put(requestArr); sendJsonError(curreq, 502, std::string("Survey proxy failed: ") + e.what()); } } // --------------------------------------------------------------------------- // Survey XML → blogi JSON conversion // // Editor XML format: // <Survey name="..." title="..."> // <Question id="..." parent_id="..." type="..." label="..." order_idx="0"> // <Option value="...">label text</Option> // </Question> // </Survey> // // Blogi JSON format expected by save_survey: // { "id":"", "title":"...", "description":"", // "questions":[{"id":"...","type":"...","text":"...","required":false, // "order":0, "options":[{"value":"...","label":"..."}]}] } // --------------------------------------------------------------------------- json_object* webedit::Api::surveyXmlToJson(const std::string &name, const std::string &title, const std::string &xml) { json_object *jtpl = json_object_new_object(); json_object_object_add(jtpl, "id", json_object_new_string(name.c_str())); json_object_object_add(jtpl, "title", json_object_new_string(title.c_str())); json_object_object_add(jtpl, "description", json_object_new_string("")); json_object *jquestions = json_object_new_array(); if (!xml.empty()) { tinyxml2::XMLDocument doc; if (doc.Parse(xml.c_str(), xml.size()) == tinyxml2::XML_SUCCESS) { tinyxml2::XMLElement *surveyEl = doc.FirstChildElement("Survey"); if (surveyEl) { int orderIdx = 0; for (tinyxml2::XMLElement *qEl = surveyEl->FirstChildElement("Question"); qEl; qEl = qEl->NextSiblingElement("Question")) { json_object *jq = json_object_new_object(); const char *qid = qEl->Attribute("id"); const char *qtype = qEl->Attribute("type"); const char *qlabel = qEl->Attribute("label"); int qorder = orderIdx; qEl->QueryIntAttribute("order_idx", &qorder); json_object_object_add(jq, "id", json_object_new_string(qid ? qid : "")); json_object_object_add(jq, "type", json_object_new_string(qtype ? qtype : "text")); json_object_object_add(jq, "text", json_object_new_string(qlabel ? qlabel : "")); json_object_object_add(jq, "required", json_object_new_boolean(false)); json_object_object_add(jq, "order", json_object_new_int(qorder)); json_object *jopts = json_object_new_array(); for (tinyxml2::XMLElement *optEl = qEl->FirstChildElement("Option"); optEl; optEl = optEl->NextSiblingElement("Option")) { json_object *jo = json_object_new_object(); const char *val = optEl->Attribute("value"); const char *lbl = optEl->GetText(); json_object_object_add(jo, "value", json_object_new_string(val ? val : "")); json_object_object_add(jo, "label", json_object_new_string(lbl ? lbl : "")); json_object_array_add(jopts, jo); } json_object_object_add(jq, "options", jopts); json_object_array_add(jquestions, jq); ++orderIdx; } } } } json_object_object_add(jtpl, "questions", jquestions); return jtpl; } void webedit::Api::autoPublishSurveysForDocument(const std::string &docXml, const std::string &authid, const std::string &blogUrl, const std::string &ownerUid) { if (docXml.empty() || authid.empty() || blogUrl.empty()) return; tinyxml2::XMLDocument doc; if (doc.Parse(docXml.c_str(), docXml.size()) != tinyxml2::XML_SUCCESS) return; std::vector<std::string> surveyNames; std::function<void(tinyxml2::XMLElement*)> walk = [&](tinyxml2::XMLElement *el) { if (!el) return; const char *sn = el->Attribute("survey_name"); if (sn && sn[0]) { std::string name(sn); bool found = false; for (auto &s : surveyNames) { if (s == name) { found = true; break; } } if (!found) surveyNames.push_back(name); } for (auto *child = el->FirstChildElement(); child; child = child->NextSiblingElement()) walk(child); }; walk(doc.RootElement()); if (surveyNames.empty()) return; for (const auto &sname : surveyNames) { dbpp::SQL sql; dbpp::DBResult res; std::vector<char> eOwner, eName; sql << "SELECT id, name, title, xml FROM survey_templates WHERE owner_uid='" << dbpp::SQL::escaped(eOwner, ownerUid.c_str()) << "' AND name='" << dbpp::SQL::escaped(eName, sname.c_str()) << "' LIMIT 1;"; int rows = _db.getDb().exec(sql, res); if (rows < 1) continue; std::string sname2 = res[0][1]; std::string stitle = res[0][2]; std::string sxml = res[0][3] ? res[0][3] : ""; json_object *jsurvey = surveyXmlToJson(sname2, stitle, sxml); json_object *requestArr = json_object_new_array(); json_object *authCmd = json_object_new_object(); json_object_object_add(authCmd, "authid", json_object_new_string(authid.c_str())); json_object_array_add(requestArr, authCmd); json_object *saveCmd = json_object_new_object(); json_object_object_add(saveCmd, "command", json_object_new_string("save_survey")); json_object_object_add(saveCmd, "name", json_object_new_string(sname2.c_str())); json_object_object_add(saveCmd, "survey", jsurvey); json_object_array_add(requestArr, saveCmd); try { json_object *resp = blogApiCall(blogUrl, requestArr); if (resp) json_object_put(resp); } catch (...) { std::cerr << "autoPublishSurveys: failed to push survey '" << sname2 << "'" << std::endl; } json_object_put(requestArr); } } // --------------------------------------------------------------------------- // Survey management handlers // --------------------------------------------------------------------------- void webedit::Api::handleListSurveys(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string jsonStr = _db.listSurveys(uid); json_object *resp = json_object_new_object(); json_object *arr = json_tokener_parse(jsonStr.c_str()); json_object_object_add(resp, "surveys", arr ? arr : json_object_new_array()); sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handleListSurveyNames(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string jsonStr = _db.listSurveyNames(uid); json_object *resp = json_object_new_object(); json_object *arr = json_tokener_parse(jsonStr.c_str()); json_object_object_add(resp, "surveys", arr ? arr : json_object_new_array()); sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handleGetSurvey(libhttppp::HttpRequest &curreq, const std::string &sessionid, const std::string &surveyId) { std::string uid; _session.getData(sessionid, "uid", uid); std::string jsonStr = _db.getSurvey(uid, surveyId); json_object *resp = json_tokener_parse(jsonStr.c_str()); if (!resp) { sendJsonError(curreq, 404, "Survey not found"); return; } sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handleSaveSurvey(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string body = getRequestBody(curreq); json_object *req = json_tokener_parse(body.c_str()); if (!req) { sendJsonError(curreq, 400, "Invalid JSON"); return; } json_object *idObj = nullptr, *nameObj = nullptr, *titleObj = nullptr, *xmlObj = nullptr; json_object_object_get_ex(req, "id", &idObj); json_object_object_get_ex(req, "name", &nameObj); json_object_object_get_ex(req, "title", &titleObj); json_object_object_get_ex(req, "xml", &xmlObj); std::string name = nameObj ? json_object_get_string(nameObj) : ""; std::string title = titleObj ? json_object_get_string(titleObj) : ""; std::string xml = xmlObj ? json_object_get_string(xmlObj) : "<Survey/>"; if (name.empty()) { json_object_put(req); sendJsonError(curreq, 400, "Name is required"); return; } std::string surveyId; if (idObj && strlen(json_object_get_string(idObj)) > 0) { surveyId = json_object_get_string(idObj); _db.updateSurvey(uid, surveyId, name, title, xml); } else { surveyId = _db.saveSurvey(uid, name, title, xml); } json_object *resp = json_object_new_object(); json_object_object_add(resp, "status", json_object_new_string("ok")); json_object_object_add(resp, "id", json_object_new_string(surveyId.c_str())); sendJson(curreq, resp); json_object_put(resp); json_object_put(req); } void webedit::Api::handleDeleteSurvey(libhttppp::HttpRequest &curreq, const std::string &sessionid, const std::string &surveyId) { std::string uid; _session.getData(sessionid, "uid", uid); _db.deleteSurvey(uid, surveyId); json_object *resp = json_object_new_object(); json_object_object_add(resp, "status", json_object_new_string("ok")); sendJson(curreq, resp); json_object_put(resp); } void webedit::Api::handlePublishSurveyToConnection(libhttppp::HttpRequest &curreq, const std::string &sessionid) { std::string uid; _session.getData(sessionid, "uid", uid); std::string body = getRequestBody(curreq); json_object *req = json_tokener_parse(body.c_str()); if (!req) { sendJsonError(curreq, 400, "Invalid JSON"); return; } json_object *surveyIdObj = nullptr, *connIdObj = nullptr; json_object_object_get_ex(req, "survey_id", &surveyIdObj); json_object_object_get_ex(req, "conn_id", &connIdObj); std::string surveyId = surveyIdObj ? json_object_get_string(surveyIdObj) : ""; std::string connId = connIdObj ? json_object_get_string(connIdObj) : ""; json_object_put(req); if (surveyId.empty() || connId.empty()) { sendJsonError(curreq, 400, "survey_id and conn_id required"); return; } std::string surveyJson = _db.getSurvey(uid, surveyId); json_object *surveyData = json_tokener_parse(surveyJson.c_str()); if (!surveyData) { sendJsonError(curreq, 404, "Survey not found"); return; } json_object *nameObj = nullptr, *titleObj = nullptr, *xmlObj = nullptr; json_object_object_get_ex(surveyData, "name", &nameObj); json_object_object_get_ex(surveyData, "title", &titleObj); json_object_object_get_ex(surveyData, "xml", &xmlObj); std::string sname = nameObj ? json_object_get_string(nameObj) : ""; std::string stitle = titleObj ? json_object_get_string(titleObj) : ""; std::string sxml = xmlObj ? json_object_get_string(xmlObj) : ""; json_object_put(surveyData); if (sname.empty()) { sendJsonError(curreq, 400, "Survey has no name"); return; } std::string authid, blogUrl; { std::lock_guard<std::mutex> lk(_connSessionMtx); auto it = _connSessions.find(connId); if (it == _connSessions.end()) { sendJsonError(curreq, 403, "Not connected. Bitte zuerst verbinden."); return; } authid = it->second.authid; blogUrl = it->second.blogUrl; } json_object *jsurvey = surveyXmlToJson(sname, stitle, sxml); json_object *requestArr = json_object_new_array(); json_object *authCmd = json_object_new_object(); json_object_object_add(authCmd, "authid", json_object_new_string(authid.c_str())); json_object_array_add(requestArr, authCmd); json_object *saveCmd = json_object_new_object(); json_object_object_add(saveCmd, "command", json_object_new_string("save_survey")); json_object_object_add(saveCmd, "name", json_object_new_string(sname.c_str())); json_object_object_add(saveCmd, "survey", jsurvey); json_object_array_add(requestArr, saveCmd); try { json_object *pubResp = blogApiCall(blogUrl, requestArr); json_object_put(requestArr); std::string status = "error"; std::string message = "No response"; if (pubResp && json_object_is_type(pubResp, json_type_array)) { size_t rLen = json_object_array_length(pubResp); for (size_t i = 0; i < rLen; ++i) { json_object *item = json_object_array_get_idx(pubResp, i); json_object *sObj = nullptr, *mObj = nullptr; if (json_object_object_get_ex(item, "status", &sObj)) status = json_object_get_string(sObj); if (json_object_object_get_ex(item, "message", &mObj)) message = json_object_get_string(mObj); } } if (pubResp) json_object_put(pubResp); json_object *resp = json_object_new_object(); json_object_object_add(resp, "status", json_object_new_string(status.c_str())); json_object_object_add(resp, "message", json_object_new_string(message.c_str())); sendJson(curreq, resp); json_object_put(resp); } catch (const std::exception &e) { json_object_put(requestArr); sendJsonError(curreq, 502, std::string("Publish failed: ") + e.what()); } }