From 5ef7c1c634824cec1b810ede9b18707f958491b7 Mon Sep 17 00:00:00 2001 From: Kyle Sullivan Date: Thu, 4 May 2023 15:28:13 -0300 Subject: [PATCH 1/4] Add start of script --- scripts/downgrade-users/downgradeUsers.js | 113 ++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 scripts/downgrade-users/downgradeUsers.js diff --git a/scripts/downgrade-users/downgradeUsers.js b/scripts/downgrade-users/downgradeUsers.js new file mode 100644 index 0000000000..f012781579 --- /dev/null +++ b/scripts/downgrade-users/downgradeUsers.js @@ -0,0 +1,113 @@ +const AUTH_TOKEN = ""; +const TRACKER_GRAPHQL_URI = ""; + +if (!AUTH_TOKEN) { + console.error("You must enter your auth token!"); +} + +if (!TRACKER_GRAPHQL_URI) { + console.error("You must enter the Tracker graphql URI!"); +} + +const csv2json = (str, delimiter = ",") => { + const titles = str + .slice(0, str.indexOf("\n")) + .replace(/["']/g, "") + .split(delimiter) + .map((str) => str.trim()); + const rows = str.slice(str.indexOf("\n") + 1).split("\n"); + return rows.map((row) => { + const values = row.split(delimiter); + return titles.reduce((object, curr, i) => { + object[curr] = values[i].replace(/["']/g, "").trim(); + return object; + }, {}); + }); +}; + +const getOrg = async (orgSlug) => { + const res = await fetch(TRACKER_GRAPHQL_URI, { + body: JSON.stringify({ + query: `query { + findOrganizationBySlug(orgSlug: "${orgSlug}") { + id + name + slug + } + }`, + }), + headers: { + Accept: "application/json", + Authorization: AUTH_TOKEN, + "Content-Type": "application/json", + }, + method: "POST", + }); + return (await res.json()).data; +}; + +const changeUserRole = async ({ email, role = "USER", orgId }) => { + const res = await fetch(TRACKER_GRAPHQL_URI, { + body: JSON.stringify({ + query: `mutation { + updateUserRole(input: { + userName: "${email}", + role: ${role}, + orgId: "${orgId}", + }) { + result { + ...on UpdateUserRoleResult { + status + } + ...on AffiliationError { + code + description + } + __typename + } + } + }`, + }), + headers: { + Accept: "application/json", + Authorization: AUTH_TOKEN, + "Content-Type": "application/json", + }, + method: "POST", + }); + + return await res.json(); +}; + +const [fileHandle] = await window.showOpenFilePicker(); +const file = await fileHandle.getFile(); +const content = (await file.text()).trim(); +const downgradeUserList = csv2json(content, ","); + +// for await (const [key, inv] of downgradeUserList.entries()) { +// try { +// const data = await getOrg(inv.orgSlug); +// downgradeUserList[key].orgId = data.findOrganizationBySlug.id; +// const inviteRes = await inviteUser({ email: inv.email, orgId: inv.orgId, role: inv.role }); +// if (inviteRes.data.inviteUserToOrg.result["__typename"] === "AffiliationError") { +// console.error(`Error while inviting ${inv.email} to ${inv.orgSlug}: `, inv); +// downgradeUserList[key].success = false; +// downgradeUserList[key].error = inviteRes.data.inviteUserToOrg.result.description; +// continue; +// } +// } catch (e) { +// console.error(`Error while inviting ${inv.email} to ${inv.orgSlug}: `, inv); +// downgradeUserList[key].success = false; +// downgradeUserList[key].error = e; +// } +// downgradeUserList[key].success = true; +// console.log(`Successfully invited ${inv.email} to ${inv.orgSlug}: `, inv); +// } +// +// for (const inv of downgradeUserList) { +// if (inv.error) { +// console.error(`Error while inviting ${inv.email} to ${inv.orgSlug}: `, inv); +// } +// } +// +// console.table(downgradeUserList.filter((inv) => inv.success === false)); From bd4ec7863a296b361ef053afdc1d10f5906abbcc Mon Sep 17 00:00:00 2001 From: Kyle Sullivan <47400288+FestiveKyle@users.noreply.github.com> Date: Thu, 4 May 2023 14:30:30 -0400 Subject: [PATCH 2/4] Include example downgrade list csv --- scripts/downgrade-users/exampleDowngradeList.csv | 1 + 1 file changed, 1 insertion(+) create mode 100644 scripts/downgrade-users/exampleDowngradeList.csv diff --git a/scripts/downgrade-users/exampleDowngradeList.csv b/scripts/downgrade-users/exampleDowngradeList.csv new file mode 100644 index 0000000000..6c78bd685d --- /dev/null +++ b/scripts/downgrade-users/exampleDowngradeList.csv @@ -0,0 +1 @@ +userId,displayName,userName,totalCount,affiliationId,permission,organizationId,acronym,name,slug From 9fc17de50794339a53e0a1041ca98330748627bd Mon Sep 17 00:00:00 2001 From: Kyle Sullivan Date: Thu, 4 May 2023 15:33:33 -0300 Subject: [PATCH 3/4] Add example users to example csv --- scripts/downgrade-users/exampleDowngradeList.csv | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/downgrade-users/exampleDowngradeList.csv b/scripts/downgrade-users/exampleDowngradeList.csv index 6c78bd685d..f1ec6cf5a1 100644 --- a/scripts/downgrade-users/exampleDowngradeList.csv +++ b/scripts/downgrade-users/exampleDowngradeList.csv @@ -1 +1,3 @@ -userId,displayName,userName,totalCount,affiliationId,permission,organizationId,acronym,name,slug +userId,displayName,userName,totalCount,affiliationId,permission,organizationId,acronym,name,slug +exampleIdqd2a=,example name ,example1@example.com,2,e21e12eaw,ADMIN,2e21e12e,EO,Example Org,example-org +exampleIdqd2a=,example name ,example1@example.com,2,e21e12eaw,ADMIN,anrk30a=,AEO,Another Example,another-example From 18ec12a2340324040e3854f45289128d8d3dca72 Mon Sep 17 00:00:00 2001 From: Kyle Sullivan Date: Thu, 4 May 2023 16:49:39 -0300 Subject: [PATCH 4/4] Add logic for downgradeUsers script --- scripts/downgrade-users/README.md | 10 +++ scripts/downgrade-users/downgradeUsers.js | 85 ++++++++----------- .../{exampleDowngradeList.csv => example.csv} | 0 3 files changed, 47 insertions(+), 48 deletions(-) create mode 100644 scripts/downgrade-users/README.md rename scripts/downgrade-users/{exampleDowngradeList.csv => example.csv} (100%) diff --git a/scripts/downgrade-users/README.md b/scripts/downgrade-users/README.md new file mode 100644 index 0000000000..d3a5560b33 --- /dev/null +++ b/scripts/downgrade-users/README.md @@ -0,0 +1,10 @@ +Use in Chromium-based browsers (Chrome, Edge, etc.): +1. Open the console (F12) +2. Copy the code from the file `downgradeUsers.js` and paste it into the console +3. Enter auth token into `AUTH_TOKEN`. The token can be obtained from a Tracker browser request. Log into Tracker, open the console (F12), go to the Network tab, refresh the page, find the latest request with the name `graphql`, go to the Headers tab, copy the value of the `Authorization` header. +4. Enter the URI for the Tracker instance into `TRACKER_URI` +5. Press Enter +6. Wait for the script to finish +7. Enjoy + +CSV file format given in the example file `example.csv`. diff --git a/scripts/downgrade-users/downgradeUsers.js b/scripts/downgrade-users/downgradeUsers.js index f012781579..fb733649ec 100644 --- a/scripts/downgrade-users/downgradeUsers.js +++ b/scripts/downgrade-users/downgradeUsers.js @@ -25,27 +25,6 @@ const csv2json = (str, delimiter = ",") => { }); }; -const getOrg = async (orgSlug) => { - const res = await fetch(TRACKER_GRAPHQL_URI, { - body: JSON.stringify({ - query: `query { - findOrganizationBySlug(orgSlug: "${orgSlug}") { - id - name - slug - } - }`, - }), - headers: { - Accept: "application/json", - Authorization: AUTH_TOKEN, - "Content-Type": "application/json", - }, - method: "POST", - }); - return (await res.json()).data; -}; - const changeUserRole = async ({ email, role = "USER", orgId }) => { const res = await fetch(TRACKER_GRAPHQL_URI, { body: JSON.stringify({ @@ -84,30 +63,40 @@ const file = await fileHandle.getFile(); const content = (await file.text()).trim(); const downgradeUserList = csv2json(content, ","); -// for await (const [key, inv] of downgradeUserList.entries()) { -// try { -// const data = await getOrg(inv.orgSlug); -// downgradeUserList[key].orgId = data.findOrganizationBySlug.id; -// const inviteRes = await inviteUser({ email: inv.email, orgId: inv.orgId, role: inv.role }); -// if (inviteRes.data.inviteUserToOrg.result["__typename"] === "AffiliationError") { -// console.error(`Error while inviting ${inv.email} to ${inv.orgSlug}: `, inv); -// downgradeUserList[key].success = false; -// downgradeUserList[key].error = inviteRes.data.inviteUserToOrg.result.description; -// continue; -// } -// } catch (e) { -// console.error(`Error while inviting ${inv.email} to ${inv.orgSlug}: `, inv); -// downgradeUserList[key].success = false; -// downgradeUserList[key].error = e; -// } -// downgradeUserList[key].success = true; -// console.log(`Successfully invited ${inv.email} to ${inv.orgSlug}: `, inv); -// } -// -// for (const inv of downgradeUserList) { -// if (inv.error) { -// console.error(`Error while inviting ${inv.email} to ${inv.orgSlug}: `, inv); -// } -// } -// -// console.table(downgradeUserList.filter((inv) => inv.success === false)); +for await (const [key, val] of downgradeUserList.entries()) { + try { + const updateRoleRes = await changeUserRole({ email: val.userName, orgId: val.organizationId, role: "USER" }); + if (updateRoleRes.data.updateUserRole.result["__typename"] === "AffiliationError") { + console.error( + `Error while updating "${val.email}" permission for organization "${val.organizationId}" to "USER": `, + val + ); + downgradeUserList[key].success = false; + downgradeUserList[key].error = updateRoleRes.data.updateUserRole.result.description; + continue; + } + } catch (e) { + console.error( + `Error while updating "${val.email}" permission for organization "${val.organizationId}" to "USER": `, + val + ); + downgradeUserList[key].success = false; + downgradeUserList[key].error = e; + } + downgradeUserList[key].success = true; + console.log( + `Successfully changed "${val.email}" permission for organization "${val.organizationId}" to "USER": `, + val + ); +} + +for (const val of downgradeUserList) { + if (val.error) { + console.error( + `Error while updating "${val.email}" permission for organization "${val.organizationId}" to "USER": `, + val + ); + } +} + +console.table(downgradeUserList.filter((val) => val.success === false)); diff --git a/scripts/downgrade-users/exampleDowngradeList.csv b/scripts/downgrade-users/example.csv similarity index 100% rename from scripts/downgrade-users/exampleDowngradeList.csv rename to scripts/downgrade-users/example.csv