Skip to content

Commit

Permalink
CLDR-14745 First steps for WHAT_GETROW to modern api (#1658)
Browse files Browse the repository at this point in the history
-New boolean cldrTable.TABLE_USES_NEW_API to test calling api/voting instead of SurveyAjax.getRow

-Keep cldrTable.TABLE_USES_NEW_API false until new api works correctly

-Enable old-fashioned sendXhr request to use modern session header for api

-Encapsulate X-SurveyTool-Session, and adding session header, in cldrAjax.js

-Minor refactoring of cldrAjax.js, more subroutines

-Make ST_AJAX_DEBUG false; debugging should be off unless specifically needed

-Fix VoteAPIHelper to call getErrorOnPath as when required by front end

-Add convenience functions VoteAPIHelper.handleGetOneRow/handleGetOnePage

-Add convenience class VoteAPIHelper.ArgsForGet, shorten parameter lists

-Remove dead deprecated CheckCLDR.get/setHTMLMessage

-Fix deprecation warnings for SurveyLog.logException

-Formatting

-Comments
  • Loading branch information
btangmu authored Dec 13, 2021
1 parent 89c1cd7 commit 8334c30
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 99 deletions.
85 changes: 68 additions & 17 deletions tools/cldr-apps/js/src/esm/cldrAjax.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
*/
import * as cldrStatus from "./cldrStatus.js";

const ST_AJAX_DEBUG = true;
const ST_AJAX_DEBUG = false;

const SURVEY_TOOL_SESSION_HEADER = "X-SurveyTool-Session";

const SLASH_API_SLASH = "/api/";

/**
* Call the standard js fetch function, possibly with additional handling suitable
Expand All @@ -19,13 +23,29 @@ function doFetch(resource, init) {
if (ST_AJAX_DEBUG) {
console.log("cldrAjax.doFetch: " + resource);
}
init = init || {};
init.headers = cldrStatus.sessionHeaders(init?.headers);
init = addSessionHeader(init);
return fetch(resource, init);
}

/**
* Send a request
* If the current user has a session id, add it to the fetch headers, creating
* init and/or init.headers if not already defined
*
* @param {Object} init an object containing any custom settings for the request; or null
* @returns {Object} init, possibly newly created if the parameter was null and id exists
*/
function addSessionHeader(init) {
const id = cldrStatus.getSessionId();
if (id) {
init = init || {};
init.headers = init.headers || {};
init.headers[SURVEY_TOOL_SESSION_HEADER] = id;
}
return init;
}

/**
* Send a request the old-fashioned, low-level way
*
* It will be a GET *unless* either postData or content are set.
*
Expand All @@ -42,30 +62,36 @@ function doFetch(resource, init) {
* }
*/
function sendXhr(xhrArgs) {
const options = newOptionsFromXhrArgs(xhrArgs);
const request = new XMLHttpRequest();
request.open(options.method, xhrArgs.url);
request.responseType = options.handleAs ? options.handleAs : "text";
request.timeout = xhrArgs.timeout ? xhrArgs.timeout : 0;
addSessionHeaderIfApi(request, xhrArgs.url);
request.onreadystatechange = function () {
onChange(request, xhrArgs);
};
if (options.method === "POST") {
setPostDataAndHeader(request, options);
}
request.send(options.data);
}

function newOptionsFromXhrArgs(xhrArgs) {
let options = {};
if (xhrArgs.handleAs) {
options.handleAs = xhrArgs.handleAs;
}
if (xhrArgs.postData || xhrArgs.content) {
options.method = "POST";
options.data = xhrArgs.postData ? xhrArgs.postData : xhrArgs.content;
if (typeof options.data === "object" && xhrArgs.url.includes("api/")) {
if (typeof options.data === "object" && isApiUrl(xhrArgs.url)) {
options.makeJsonPost = true;
}
} else {
options.method = "GET";
}
const request = new XMLHttpRequest();
request.open(options.method, xhrArgs.url);
request.responseType = options.handleAs ? options.handleAs : "text";
request.timeout = xhrArgs.timeout ? xhrArgs.timeout : 0;
request.onreadystatechange = function () {
onChange(request, xhrArgs);
};
if (options.method === "POST") {
setPostDataAndHeader(request, options);
}
request.send(options.data);
return options;
}

function onChange(request, xhrArgs) {
Expand Down Expand Up @@ -180,7 +206,32 @@ function makeUrl(p) {
*/
function makeApiUrl(api, p) {
const queryString = p ? "?" + p.toString() : "";
return cldrStatus.getContextPath() + "/api/" + api + queryString;
return cldrStatus.getContextPath() + SLASH_API_SLASH + api + queryString;
}

/**
* If the current user has a session id, add it to the http request,
* but only if the url is for the modern api
*
* This enables calling modern api urls with old-fashioned sendXhr
* Avoid adding the session header for legacy (non-api) urls,
* since the back end may not recognize it or may be confused between
* it and legacy "s" or "ss" query parameters.
*
* @param {Object} request the http request, to be modified
* @param {String} url
*/
function addSessionHeaderIfApi(request, url) {
if (isApiUrl(url)) {
const id = cldrStatus.getSessionId();
if (id) {
request.setRequestHeader(SURVEY_TOOL_SESSION_HEADER, id);
}
}
}

function isApiUrl(url) {
return url.includes(SLASH_API_SLASH);
}

export { doFetch, makeApiUrl, makeUrl, mediumTimeout, sendXhr };
22 changes: 16 additions & 6 deletions tools/cldr-apps/js/src/esm/cldrLoad.js
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ function loadExclamationPoint() {
}

function loadAllRows(itemLoadInfo, theDiv) {
// TODO: curId (aka strid) appears to be ignored by the server; if so, remove it from the request
const curId = cldrStatus.getCurrentId();
const curPage = cldrStatus.getCurrentPage();
const curLocale = cldrStatus.getCurrentLocale();
Expand All @@ -832,7 +833,19 @@ function loadAllRows(itemLoadInfo, theDiv) {
locmap.getLocaleName(curLocale) + "/" + curPage + "/" + curId
)
);
const url =
const url = getPageUrl(curLocale, curPage, curId);
$("#nav-page").show(); // make top "Prev/Next" buttons visible while loading, cf. '#nav-page-footer' below
myLoad(url, "section", function (json) {
loadAllRowsFromJson(json, theDiv);
});
}

function getPageUrl(curLocale, curPage, curId) {
if (cldrTable.TABLE_USES_NEW_API) {
const api = "voting/" + curLocale + "/page/" + curPage;
return cldrAjax.makeApiUrl(api, null);
}
return (
cldrStatus.getContextPath() +
"/SurveyAjax?what=getrow&_=" +
curLocale +
Expand All @@ -842,11 +855,8 @@ function loadAllRows(itemLoadInfo, theDiv) {
curId +
"&s=" +
cldrStatus.getSessionId() +
cldrSurvey.cacheKill();
$("#nav-page").show(); // make top "Prev/Next" buttons visible while loading, cf. '#nav-page-footer' below
myLoad(url, "section", function (json) {
loadAllRowsFromJson(json, theDiv);
});
cldrSurvey.cacheKill()
);
}

function loadAllRowsFromJson(json, theDiv) {
Expand Down
14 changes: 0 additions & 14 deletions tools/cldr-apps/js/src/esm/cldrStatus.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,19 +277,6 @@ function getSessionId() {
return sessionId;
}

/**
* Return header needed for login.
* @param {Object} h headers to append to
* @returns {Object} header map for fetch
*/
function sessionHeaders(h) {
h = h || {};
if (getSessionId()) {
h["X-SurveyTool-Session"] = getSessionId();
}
return h;
}

function setSessionId(i) {
if (i !== sessionId) {
sessionId = i;
Expand Down Expand Up @@ -457,7 +444,6 @@ export {
logoIcon,
on,
runningStampChanged,
sessionHeaders,
setAutoImportBusy,
setContextPath,
setCurrentId,
Expand Down
16 changes: 15 additions & 1 deletion tools/cldr-apps/js/src/esm/cldrTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import * as cldrVote from "./cldrVote.js";
import * as cldrXPathUtils from "./cldrXpathUtils.js";

const CLDR_TABLE_DEBUG = false;

const TABLE_USES_NEW_API = false;

/*
* ALWAYS_REMOVE_ALL_CHILD_NODES and NEVER_REUSE_TABLE should both be false for efficiency,
* but if necessary they can be made true to revert to old less efficient behavior.
Expand Down Expand Up @@ -375,8 +378,18 @@ function singleRowErrHandler(err, tr, onFailure) {
}

function getSingleRowUrl(tr, theRow) {
if (TABLE_USES_NEW_API) {
const loc = cldrStatus.getCurrentLocale();
const xpath = tr.rowHash;
const api = "voting/" + loc + "/row/" + xpath;
let p = null;
if (cldrGui.dashboardIsVisible()) {
p = new URLSearchParams();
p.append("dashboard", "true");
}
return cldrAjax.makeApiUrl(api, p);
}
const p = new URLSearchParams();
// TODO: switch to new API; WHAT_GETROW is deprecated
p.append("what", "getrow"); // cf. WHAT_GETROW in SurveyAjax.java
p.append("_", cldrStatus.getCurrentLocale());
p.append("xpath", theRow.xpathId);
Expand Down Expand Up @@ -1291,6 +1304,7 @@ function getValidWinningValue(theRow) {

export {
NO_WINNING_VALUE,
TABLE_USES_NEW_API,
appendExample,
getRowApprovalStatusClass,
insertRows,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
//
// Created by Steven R. Loomis on 18/11/2005.
// Copyright 2005-2014 IBM. All rights reserved.
//

// "Section" is now a misnomer, since this class now handles one "page" at a time, not one "section".
// A section is like "Locale Display Names"; a page is like "Languages (A-D)". Generally one section
// contains multiple pages.

// TODO: this class now has lots of knowledge about specific data types.. so does SurveyMain
// Probably, it should be concentrated in one side or another- perhaps SurveyMain should call this
Expand Down Expand Up @@ -1717,8 +1720,6 @@ public static CheckCLDR.Options getOptions(WebContext ctx, CookieSession session
* @param matcher
*
* Called only by DataSection.make
*
* Old parameter ptype was always "comprehensive"
*/
DataSection(PageId pageId, SurveyMain sm, CLDRLocale loc, String prefix, XPathMatcher matcher) {
this.locale = loc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2453,11 +2453,11 @@ public List<CheckStatus> getCheckStatusList() {
* @throws IOException
* @throws JSONException
*
* @deprecated - use /api/vote instead
* @deprecated - use /api/voting instead
*
* TODO: in spite of being deprecated, this is used constantly in Survey Tool. Its intended
* replacement in /api/vote is not actually used yet, and isn't ready to be used since it
* fails to implement the "dashboard=true" query parameter for calling Dashboard.getErrorOnPath.
* replacement in /api/voting is not actually used yet, and isn't ready to be used since it
* does not produce json compatible with the front end
* Reference: https://unicode-org.atlassian.net/browse/CLDR-14745
*/
@Deprecated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ public static JSONObject wrap(CheckStatus status) throws JSONException {
return new JSONObject() {
{
put("message", cs.getMessage());
put("htmlMessage", cs.getHTMLMessage());
put("type", cs.getType());
if (cs.getCause() != null) {
put("cause", wrap(cs.getCause()));
Expand Down
22 changes: 11 additions & 11 deletions tools/cldr-apps/src/main/java/org/unicode/cldr/web/api/VoteAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

Expand All @@ -22,6 +23,7 @@
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.json.JSONArray;
import org.unicode.cldr.test.CheckCLDR;
import org.unicode.cldr.test.CheckCLDR.CheckStatus;
import org.unicode.cldr.test.CheckCLDR.CheckStatus.Subtype;
Expand Down Expand Up @@ -50,7 +52,7 @@ public class VoteAPI {
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Get row info",
description = "Get info for a row")
description = "Get info for a single xpath")
@APIResponses(
value = {
@APIResponse(
Expand All @@ -73,23 +75,25 @@ public class VoteAPI {
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = STError.class))),
})
public Response getRows(
public Response getRow(
@Parameter(required = true, example = "br",
schema = @Schema(type = SchemaType.STRING)) @PathParam("locale") String loc,

@Parameter(example = "132345490064d839",
schema = @Schema(type = SchemaType.STRING)) @PathParam("xpath") String xpath,

@QueryParam("dashboard") @Schema(required = false, description = "Whether to get dashboard info") Boolean getDashboard,

@HeaderParam(Auth.SESSION_HEADER) String session) {
return VoteAPIHelper.handleGetRows(loc, session, xpath, null);
return VoteAPIHelper.handleGetOneRow(loc, session, xpath, getDashboard);
}

@GET
@Path("/{locale}/page/{page}")
@Produces(MediaType.APPLICATION_JSON)
@Operation(
summary = "Get section data",
description = "Get all xpaths in a page")
summary = "Get page info",
description = "Get all info for all xpaths in a page")
@APIResponses(
value = {
@APIResponse(
Expand Down Expand Up @@ -120,22 +124,20 @@ public Response getPage(
schema = @Schema(type = SchemaType.STRING)) @PathParam("page") String page,

@HeaderParam(Auth.SESSION_HEADER) String session) {
return VoteAPIHelper.handleGetRows(loc, session, null, page);
return VoteAPIHelper.handleGetOnePage(loc, session, page);
}

public static final class RowResponse {

public static final class Row {

public static final class Candidate {

public String value;
public String displayValue;
public String pClass;
public String example;
public boolean isBaselineValue;
public VoteEntry[] votes;

}

public Candidate[] items;
Expand All @@ -155,7 +157,6 @@ public static final class Candidate {
public String inheritedLocale;
public String winningValue;
public String inheritedXpath;

}

public String localeDisplayName;
Expand All @@ -164,6 +165,7 @@ public static final class Candidate {
@Schema(description = "If set, row is not available because there is a Default Content parent. See the specified locale instead.")
public String dcParent;
public Row[] rows;
public JSONArray issues;
}

@POST
Expand Down Expand Up @@ -237,7 +239,6 @@ void setResults(List<CheckStatus> results) {

final static public class CheckStatusSummary {
public String message;
public String htmlMessage;
public Type type;
public Subtype subType;
public String subTypeUrl;
Expand All @@ -248,7 +249,6 @@ final static public class CheckStatusSummary {

public CheckStatusSummary(CheckStatus checkStatus) {
this.message = checkStatus.getMessage();
this.htmlMessage = checkStatus.getHTMLMessage();
this.type = checkStatus.getType();
// cause
CheckCLDR cause = checkStatus.getCause();
Expand Down
Loading

0 comments on commit 8334c30

Please sign in to comment.