Skip to content

Commit 4bc5924

Browse files
authored
CLDR-16872 Locale chooser for account creation (#5132)
1 parent c110196 commit 4bc5924

File tree

5 files changed

+752
-312
lines changed

5 files changed

+752
-312
lines changed

tools/cldr-apps/js/src/esm/cldrAccount.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,8 @@ function getHtml(json) {
256256
if (isJustMe) {
257257
html += "<h2>My Account</h2>\n";
258258
} else {
259-
const org = json.org ? orgs.shortToDisplay[json.org] : "ALL";
259+
const org =
260+
json.org && json.org != "all" ? orgs.shortToDisplay[json.org] : "ALL";
260261
html += "<h2>Users for " + org + "</h2>\n";
261262
}
262263
html += getEmailNotification(json);
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* cldrAddUser: encapsulate code for adding a new Survey Tool user.
3+
*/
4+
import * as cldrAccount from "./cldrAccount.mjs";
5+
import * as cldrAjax from "./cldrAjax.mjs";
6+
import * as cldrLoad from "./cldrLoad.mjs";
7+
import * as cldrOrganizations from "./cldrOrganizations.mjs";
8+
import * as cldrStatus from "./cldrStatus.mjs";
9+
import * as cldrUserLevels from "./cldrUserLevels.mjs";
10+
11+
const ALL_LOCALES = "*";
12+
13+
/**
14+
* Does the user have permission to add users?
15+
*/
16+
let canAdd = false;
17+
18+
/** @function */
19+
let callbackToSetData = null;
20+
21+
const errors = [];
22+
23+
function hasPermission() {
24+
return canAdd;
25+
}
26+
27+
async function viewMounted(setData) {
28+
callbackToSetData = setData;
29+
const perm = cldrStatus.getPermissions();
30+
canAdd = Boolean(perm?.userCanListUsers);
31+
if (!canAdd) {
32+
return;
33+
}
34+
await getLevelList();
35+
if (perm?.userIsAdmin) {
36+
setupOrgOptions();
37+
} else {
38+
getOrgLocales(cldrStatus.getOrganizationName());
39+
}
40+
}
41+
42+
async function getLevelList() {
43+
cldrUserLevels.getLevelList().then(loadLevelList);
44+
}
45+
46+
function loadLevelList(levelList) {
47+
if (!levelList) {
48+
addError("User-level list not received from server");
49+
} else {
50+
callbackToSetData({
51+
levelList,
52+
});
53+
}
54+
}
55+
56+
/**
57+
* Set up the organization menu, for Admin only (canChooseOrg)
58+
*/
59+
async function setupOrgOptions() {
60+
const orgObject = await cldrOrganizations.get();
61+
if (!orgObject) {
62+
addError("Organization names not received from server");
63+
} else {
64+
callbackToSetData({
65+
orgObject,
66+
});
67+
}
68+
}
69+
70+
async function getOrgLocales(orgName) {
71+
const resource = "./api/locales/org/" + orgName;
72+
await cldrAjax
73+
.doFetch(resource)
74+
.then(cldrAjax.handleFetchErrors)
75+
.then((r) => r.json())
76+
.then(setOrgLocales)
77+
.catch((e) => addError(`Error: ${e} getting org locales`));
78+
}
79+
80+
function setOrgLocales(json) {
81+
if (json.err) {
82+
cldrRetry.handleDisconnect(json.err, json, "", "Loading org locales");
83+
return;
84+
}
85+
const orgLocales =
86+
json.locales == ALL_LOCALES
87+
? Object.keys(cldrLoad.getTheLocaleMap().locmap.locales).join(" ")
88+
: json.locales;
89+
callbackToSetData({
90+
orgLocales,
91+
});
92+
}
93+
94+
function getLocaleName(loc) {
95+
if (!loc) {
96+
return null;
97+
}
98+
return cldrLoad.getTheLocaleMap()?.getLocaleName(loc);
99+
}
100+
101+
async function validateLocales(
102+
newUserOrg,
103+
newUserLocales,
104+
newUserLevel,
105+
levelList
106+
) {
107+
const skipOrg = cldrUserLevels.canVoteInNonOrgLocales(
108+
newUserLevel,
109+
levelList
110+
);
111+
const orgForValidation = skipOrg ? "" : newUserOrg;
112+
const resource =
113+
"./api/locales/normalize?" +
114+
new URLSearchParams({
115+
locs: newUserLocales,
116+
org: orgForValidation,
117+
});
118+
await cldrAjax
119+
.doFetch(resource)
120+
.then(cldrAjax.handleFetchErrors)
121+
.then((r) => r.json())
122+
.then(({ messages, normalized }) => {
123+
if (messages && newUserLocales != normalized) {
124+
// only update the warnings if the normalized value changes
125+
callbackToSetData({
126+
validatedLocales: {
127+
locWarnings: messages,
128+
newUserLocales: normalized,
129+
},
130+
});
131+
}
132+
})
133+
.catch((e) => addError(`Error: ${e} validating locale`));
134+
}
135+
136+
function add(postData) {
137+
const xhrArgs = {
138+
url: cldrAjax.makeApiUrl("adduser", null),
139+
postData: postData,
140+
handleAs: "json",
141+
load: loadHandler,
142+
error: (err) => addError(err),
143+
};
144+
cldrAjax.sendXhr(xhrArgs);
145+
}
146+
147+
function loadHandler(json) {
148+
if (json.err) {
149+
addError("Error from the server: " + translateErr(json.err));
150+
} else if (!json.userId) {
151+
addError("The server did not return a user id.");
152+
} else {
153+
const n = Math.floor(Number(json.userId));
154+
if (String(n) !== String(json.userId) || n <= 0 || !Number.isInteger(n)) {
155+
addError("The server returned an invalid id: " + json.userId);
156+
} else {
157+
// json.email is normalized, e.g., to lower case, by server
158+
callbackToSetData({
159+
newUser: { id: Number(json.userId), email: json.email },
160+
});
161+
}
162+
}
163+
}
164+
165+
function addError(message) {
166+
const index = errors.indexOf(message);
167+
if (index < 0) {
168+
errors.push(message);
169+
}
170+
callbackToSetData({ error: message });
171+
}
172+
173+
function removeError(message) {
174+
const index = errors.indexOf(message);
175+
if (index > -1) {
176+
errors.splice(index, 1);
177+
}
178+
}
179+
180+
function clearErrors() {
181+
errors.length = 0;
182+
if (errorsExist()) {
183+
console.error("clearErrors failure");
184+
}
185+
}
186+
187+
function errorsExist() {
188+
return Boolean(errors.length);
189+
}
190+
191+
function getErrors() {
192+
return errors;
193+
}
194+
195+
function translateErr(err) {
196+
const map = {
197+
BAD_NAME: "Missing or invalid name",
198+
BAD_EMAIL: "Missing or invalid e-mail",
199+
BAD_ORG: "Missing or invalid organization",
200+
BAD_LEVEL: "Missing, invalid, or forbidden user level",
201+
DUP_EMAIL: "A user with that e-mail already exists",
202+
UNKNOWN: "An unspecified error occurred",
203+
};
204+
if (!map[err]) {
205+
return err;
206+
}
207+
return map[err] + " [" + err + "]";
208+
}
209+
210+
function manageThisUser(email) {
211+
cldrAccount.zoomUser(email);
212+
}
213+
214+
export {
215+
ALL_LOCALES,
216+
add,
217+
addError,
218+
clearErrors,
219+
errorsExist,
220+
getErrors,
221+
getLocaleName,
222+
getOrgLocales,
223+
hasPermission,
224+
manageThisUser,
225+
removeError,
226+
validateLocales,
227+
viewMounted,
228+
};

tools/cldr-apps/js/src/esm/cldrComponents.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ function setup(app) {
8484
app.component("a-radio", Radio);
8585
app.component("a-row", Row);
8686
app.component("a-select", Select);
87+
app.component("a-select-option", Select.Option);
8788
app.component("a-spin", Spin);
8889
app.component("a-step", Steps.Step);
8990
app.component("a-steps", Steps);

0 commit comments

Comments
 (0)