diff --git a/tools/cldr-apps/js/src/esm/cldrCla.mjs b/tools/cldr-apps/js/src/esm/cldrCla.mjs new file mode 100644 index 00000000000..90ce7eac47a --- /dev/null +++ b/tools/cldr-apps/js/src/esm/cldrCla.mjs @@ -0,0 +1,58 @@ +import * as cldrClient from "../esm/cldrClient.mjs"; +import * as cldrNotify from "../esm/cldrNotify.mjs"; +/** + * see ClaSignature.java + * @typedef {Object} ClaSignature + * @property {boolean} corporate true if a corporate signature + * @property {string} email + * @property {string} employer + * @property {string} name + * @property {boolean} unauthorized true if cla load failed + * @property {boolean} readonly true if cla may not be modified + * @property {boolean} signed true if signed, always true when returned from getCla() + */ + +/** @return {ClaSignature} signed cla if present otherwise null if not accessible */ +export async function getCla() { + try { + const client = await cldrClient.getClient(); + const { body } = await client.apis.user.getCla(); + return body; + } catch (e) { + if (e.statusCode === 401) { + return { unauthorized: true }; + } else if (e.statusCode === 404) { + return { signed: false }; + } else { + cldrNotify.exception(e, `trying to load CLA`); + throw e; + } + } +} + +/** + * Attempt to sign. + * @throws {statusCode: 423} if the CLA may not be modified + * @throws {statusCode: 406} if there is an imput validation error + * @param {ClaSignature} cla + * @returns nothing if successful + */ +export async function signCla(cla) { + const client = await cldrClient.getClient(); + const result = await client.apis.user.signCla( + {}, + { + requestBody: cla, + } + ); +} + +/** + * Attempt to revoke. + * @throws {statusCode: 423} if the CLA may not be modified + * @throws {statusCode: 404} if the CLA was never signed + */ +export async function revokeCla() { + const client = await cldrClient.getClient(); + const result = await client.apis.user.revokeCla(); +} diff --git a/tools/cldr-apps/js/src/esm/cldrClient.mjs b/tools/cldr-apps/js/src/esm/cldrClient.mjs index ab8df8ea773..972d8659015 100644 --- a/tools/cldr-apps/js/src/esm/cldrClient.mjs +++ b/tools/cldr-apps/js/src/esm/cldrClient.mjs @@ -3,8 +3,19 @@ import { getSessionId } from "./cldrStatus.mjs"; import { SURVEY_TOOL_SESSION_HEADER } from "./cldrAjax.mjs"; const OAS3_ROOT = "/openapi"; // Path to the 'openapi' (sibling to cldr-apps). Needs to be a host-relative URL. +let client = null; // cached client object +const RESOLVED_ROOT = new URL(OAS3_ROOT, document.baseURI); // workaround relative resolution issues -const RESOLVED_ROOT = new URL(OAS3_ROOT, document.baseURI); +function makeClient() { + return SwaggerClient({ + url: RESOLVED_ROOT, + requestInterceptor: (obj) => { + // add the session header to each request + obj.headers[SURVEY_TOOL_SESSION_HEADER] = getSessionId(); + return obj; + }, + }); +} /** * Create a promise to a swagger client for ST operations. @@ -17,15 +28,11 @@ const RESOLVED_ROOT = new URL(OAS3_ROOT, document.baseURI); * * @returns {Promise} */ -async function getClient() { - return SwaggerClient({ - url: RESOLVED_ROOT, - requestInterceptor: (obj) => { - // add the session header to each request - obj.headers[SURVEY_TOOL_SESSION_HEADER] = getSessionId(); - return obj; - }, - }); +function getClient() { + if (!client) { + client = makeClient(); + } + return client; } export { getClient }; diff --git a/tools/cldr-apps/js/src/esm/cldrComponents.mjs b/tools/cldr-apps/js/src/esm/cldrComponents.mjs index 3a63971d9c3..8a70afa6838 100644 --- a/tools/cldr-apps/js/src/esm/cldrComponents.mjs +++ b/tools/cldr-apps/js/src/esm/cldrComponents.mjs @@ -14,6 +14,7 @@ import LoginButton from "../views/LoginButton.vue"; import OverallErrors from "../views/OverallErrors.vue"; import ReportResponse from "../views/ReportResponse.vue"; import SearchButton from "../views/SearchButton.vue"; +import SignCla from "../views/SignCla.vue"; // 3rd party component(s) @@ -90,6 +91,7 @@ function setup(app) { app.component("cldr-report-response", ReportResponse); app.component("cldr-searchbutton", SearchButton); app.component("cldr-value", CldrValue); + app.component("cldr-cla", SignCla); // some plugins we can pull in wholesale app.use(VueVirtualScroller); diff --git a/tools/cldr-apps/js/src/esm/cldrNotify.mjs b/tools/cldr-apps/js/src/esm/cldrNotify.mjs index f622926d3c9..8c6e0a3d86f 100644 --- a/tools/cldr-apps/js/src/esm/cldrNotify.mjs +++ b/tools/cldr-apps/js/src/esm/cldrNotify.mjs @@ -36,12 +36,14 @@ const NO_TIMEOUT = 0; * * @param {String} message the title, displayed at the top * @param {String} description the more detailed description + * @param {Function} onClick optional function called when clicking */ -function open(message, description) { +function open(message, description, onClick) { notification.open({ message: message, description: description, duration: MEDIUM_DURATION, + onClick, }); } diff --git a/tools/cldr-apps/js/src/esm/cldrText.mjs b/tools/cldr-apps/js/src/esm/cldrText.mjs index d3991685e86..1ce2ab6cd98 100644 --- a/tools/cldr-apps/js/src/esm/cldrText.mjs +++ b/tools/cldr-apps/js/src/esm/cldrText.mjs @@ -488,6 +488,7 @@ const strings = { special_add_user: "Add a Survey Tool user", special_auto_import: "Import Old Winning Votes", special_bulk_close_posts: "Bulk Close Posts", + special_cla: "Contributor License Agreement", special_createAndLogin: "Create and Login", special_default: "Missing Page", special_dashboard: "Dashboard", diff --git a/tools/cldr-apps/js/src/esm/cldrVueMap.mjs b/tools/cldr-apps/js/src/esm/cldrVueMap.mjs index 7f396abdc74..bd011a588f1 100644 --- a/tools/cldr-apps/js/src/esm/cldrVueMap.mjs +++ b/tools/cldr-apps/js/src/esm/cldrVueMap.mjs @@ -8,6 +8,7 @@ import GenerateVxml from "../views/GenerateVxml.vue"; import LockAccount from "../views/LockAccount.vue"; import LookUp from "../views/LookUp.vue"; import MainMenu from "../views/MainMenu.vue"; +import SignCla from "../views/SignCla.vue"; import TestPanel from "../views/TestPanel.vue"; import TransferVotes from "../views/TransferVotes.vue"; import UnknownPanel from "../views/UnknownPanel.vue"; @@ -37,6 +38,7 @@ const specialToComponentMap = { upload: UploadPanel, vetting_participation2: VettingParticipation2, vsummary: VettingSummary, + cla: SignCla, // If no match, end up here default: UnknownPanel, }; diff --git a/tools/cldr-apps/js/src/md/cla.md b/tools/cldr-apps/js/src/md/cla.md new file mode 100644 index 00000000000..2057b8ddf40 --- /dev/null +++ b/tools/cldr-apps/js/src/md/cla.md @@ -0,0 +1,4 @@ +# CLA not needed + +The SurveyTool is not currently requiring a CLA. +For more details about the CLA, see [policy](https://www.unicode.org/policies/licensing_policy.html) diff --git a/tools/cldr-apps/js/src/views/MainHeader.vue b/tools/cldr-apps/js/src/views/MainHeader.vue index 46b77c9e032..9582b9472aa 100644 --- a/tools/cldr-apps/js/src/views/MainHeader.vue +++ b/tools/cldr-apps/js/src/views/MainHeader.vue @@ -21,7 +21,7 @@ {{ unreadAnnouncementCount }} -
  • +
  • -
  • +