You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.7 KiB
149 lines
4.7 KiB
// ==UserScript== |
|
// @name kood.tech QOL |
|
// @description Buttons for managing auditor repository read access from intra |
|
// @match https://01.kood.tech/* |
|
// @grant none |
|
// @version 1.2 |
|
// @author spitko |
|
// ==/UserScript== |
|
|
|
const api = "/git/api/v1/"; |
|
|
|
function insertToggleAccessButton(auditorElement) { |
|
auditorElement.dataset.processed = true; |
|
let username = auditorElement.querySelector(".ellipsis-01").innerText; |
|
hasAccess(username).then((access) => { |
|
let button = document.createElement("button"); |
|
button.textContent = access ? "✅" : "❌"; |
|
button.onclick = function (e, newAccess) { |
|
if (e) { |
|
e.preventDefault(); |
|
} |
|
const shouldGrantAccess = |
|
newAccess !== undefined ? newAccess : button.textContent !== "✅"; |
|
if ((button.textContent === "✅") === shouldGrantAccess) { |
|
return; |
|
} |
|
if (shouldGrantAccess) { |
|
grantAccess(username).then(() => { |
|
button.textContent = "✅"; |
|
}); |
|
} else { |
|
revokeAccess(username).then(() => { |
|
button.textContent = "❌"; |
|
}); |
|
} |
|
}; |
|
button.className = "ml2-01 repo-access-button"; |
|
auditorElement.firstChild.insertAdjacentElement("beforeend", button); |
|
}); |
|
} |
|
|
|
function insertToggleAllButtons(auditRequired) { |
|
let div = document.createElement("div"); |
|
div.innerText = "Grant/revoke read access for all auditors: "; |
|
div.className = "mt3-01"; |
|
let grantButton = document.createElement("button"); |
|
grantButton.textContent = "✅"; |
|
grantButton.onclick = function () { |
|
document.querySelectorAll(".repo-access-button").forEach((button) => { |
|
button.onclick(false, true); |
|
}); |
|
}; |
|
div.appendChild(grantButton); |
|
let revokeButton = document.createElement("button"); |
|
revokeButton.textContent = "❌"; |
|
revokeButton.className = "ml1-01"; |
|
revokeButton.onclick = function () { |
|
document.querySelectorAll(".repo-access-button").forEach((button) => { |
|
button.onclick(false, false); |
|
}); |
|
}; |
|
div.appendChild(revokeButton); |
|
auditRequired.parentNode.insertAdjacentElement("beforeend", div); |
|
auditRequired.dataset.processed = true; |
|
} |
|
|
|
async function hasAccess(username) { |
|
const res = await fetch( |
|
api + `repos/${getRepo()}/collaborators/${username}`, |
|
{ headers: { Authorization: `token ${getToken()}` } } |
|
); |
|
return res.ok; |
|
} |
|
|
|
async function grantAccess(username) { |
|
return await fetch(api + `repos/${getRepo()}/collaborators/${username}`, { |
|
headers: { |
|
Authorization: `token ${getToken()}`, |
|
"Content-Type": "application/json", |
|
}, |
|
method: "PUT", |
|
body: `{"permission": "read"}`, |
|
}); |
|
} |
|
|
|
async function revokeAccess(username) { |
|
return await fetch(api + `repos/${getRepo()}/collaborators/${username}`, { |
|
headers: { Authorization: `token ${getToken()}` }, |
|
method: "DELETE", |
|
}); |
|
} |
|
|
|
function getToken() { |
|
return localStorage.getItem("token"); |
|
} |
|
|
|
function getRepo() { |
|
let repoURL = document.querySelector('a[data-test="repoLink"]').innerText; |
|
return repoURL.match(/\/git\/(.+)$/)[1]; |
|
} |
|
|
|
const observer = new MutationObserver(function (mutations) { |
|
mutations.forEach((mutation) => { |
|
if (mutation.type === "childList") { |
|
mutation.target |
|
.querySelectorAll('[data-test="audit"]:not([data-processed])') |
|
.forEach((elem) => { |
|
insertToggleAccessButton(elem); |
|
}); |
|
mutation.target |
|
.querySelectorAll('[data-test="auditRequired"]:not([data-processed])') |
|
.forEach((elem) => { |
|
insertToggleAllButtons(elem); |
|
}); |
|
mutation.target |
|
.querySelectorAll("#verificationCode-01:not([data-processed])") |
|
.forEach((elem) => { |
|
let input = elem.querySelector("input"); |
|
input.addEventListener("keyup", function (event) { |
|
if (event.keyCode === 13) { |
|
document |
|
.querySelectorAll(`input[value="true"]`) |
|
.forEach((elem) => elem.click()); |
|
document.querySelector("#submit-btn").click(); |
|
} |
|
}); |
|
elem.dataset.processed = true; |
|
}); |
|
} |
|
}); |
|
}); |
|
|
|
if (getToken()) { |
|
observer.observe(document.body, { childList: true, subtree: true }); |
|
} |
|
|
|
// Add button for saving token to localStorage |
|
// https://01.kood.tech/git/user/settings/applications |
|
if (location.href.match(/git\/user\/settings\/applications/)) { |
|
const tokenDiv = document.querySelector("div.ui.info.message.flash-info"); |
|
const button = document.createElement("button"); |
|
button.textContent = "Save to localStorage"; |
|
button.className = "ui button"; |
|
button.onclick = function () { |
|
localStorage.setItem("token", tokenDiv.firstElementChild.innerText); |
|
alert("Token saved!"); |
|
}; |
|
tokenDiv.insertAdjacentElement("beforeend", button); |
|
}
|
|
|