Last active
February 7, 2025 08:16
-
-
Save pasrom/46ee95dd801a431de76b9f67480fb4e5 to your computer and use it in GitHub Desktop.
Automates fields for account information, leave request, and PZE correction requests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Account Information and Leave Request Automation | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Automates fields for account information, leave request, and PZE correction requests | |
// @author Roman Passler | |
// @match https://*/APplusProd7/time/* | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @grant GM_registerMenuCommand | |
// @require https://cdnjs.cloudflare.com/ajax/libs/sjcl/1.0.8/sjcl.min.js | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
// Store timestamps for Kommen and Gehen | |
let kommenTime = GM_getValue("kommenTime", ""); | |
let gehenTime = GM_getValue("gehenTime", ""); | |
let encryptionKey = getEncryptionKey(); | |
let username, password; | |
try { | |
username = loadOrPrompt("user", "Enter your username:"); | |
password = loadOrPrompt("password", "Enter your password:"); | |
} catch (error) { | |
console.error("Failed to load stored user and credentials, prompting for new user and password."); | |
alert("Decryption error! Please enter a new user and password."); | |
updateCredential("user", "Enter a new username:", true); | |
updateCredential("password", "Enter a new password:", true); | |
password = loadOrPrompt("password", "Enter your password:"); | |
} | |
// Register menu commands | |
GM_registerMenuCommand("Reset Encryption Key", resetEncryptionKey); | |
GM_registerMenuCommand("Change Username", () => updateCredential("user", "Enter a new username:", true)); | |
GM_registerMenuCommand("Change Password", () => updateCredential("password", "Enter a new password:", true)); | |
setupStatusField(); | |
updateStatus(); | |
// Event listener for button clicks | |
document.addEventListener('click', async (event) => { | |
const checkInButton = event.target.closest('button[accesskey="K"]'); | |
const checkOutButton = event.target.closest('button[accesskey="G"]'); | |
const accountInfoButton = event.target.closest('button[accesskey="I"]'); | |
const leaveRequestButton = event.target.closest('button[accesskey="Q"]'); | |
const pzeCorrectionButton = event.target.closest('button'); | |
if (checkInButton) { | |
console.log("Check-In button clicked!"); | |
handleFormAutomation(username, password, false); | |
if (!kommenTime) { | |
kommenTime = new Date().toLocaleString(); | |
GM_setValue("kommenTime", kommenTime); | |
console.log(`Kommen clicked. Time recorded: ${kommenTime}`); | |
} else { | |
await handleKommenClick(); | |
GM_setValue("kommenTime", kommenTime); | |
console.log(`Kommen was already clicked at: ${kommenTime}`); | |
} | |
gehenTime = ""; // Reset Gehen time when Kommen is clicked | |
GM_setValue("gehenTime", gehenTime); | |
updateStatus(); | |
} | |
if (checkOutButton) { | |
console.log("Check-Out button clicked!"); | |
handleFormAutomation(username, password, false); | |
if (!gehenTime) { | |
gehenTime = new Date().toLocaleString(); | |
GM_setValue("gehenTime", gehenTime); | |
console.log(`Gehen clicked. Time recorded: ${gehenTime}`); | |
} | |
kommenTime = "" | |
GM_setValue("kommenTime", kommenTime); | |
updateStatus(); | |
} | |
if (accountInfoButton) { | |
console.log("Account Information button clicked!"); | |
handleFormAutomation(username, password, false); | |
} | |
if (leaveRequestButton) { | |
console.log("Leave Request button clicked!"); | |
handleFormAutomation(username, password, true); | |
} | |
if (pzeCorrectionButton && pzeCorrectionButton.textContent.trim() === "PZE-Korrekturantrag") { | |
console.log("PZE Correction Request button clicked!"); | |
handleFormAutomation(username, password, true); | |
} | |
}); | |
function setupStatusField() { | |
const headerCell = document.getElementById('HEADER'); | |
if (!headerCell) { | |
console.error('Header cell not found.'); | |
return; | |
} | |
if (!document.getElementById('statusField')) { | |
const statusField = document.createElement('span'); | |
statusField.id = 'statusField'; | |
statusField.textContent = "Status Field"; // Set initial text | |
Object.assign(statusField.style, { | |
marginLeft: '10px', padding: '5px 10px', | |
fontSize: '14px', fontFamily: 'Arial, sans-serif', display: 'inline-block' | |
}); | |
headerCell.appendChild(statusField); | |
} | |
} | |
// Observe changes in the document to re-add the field if removed | |
const observer = new MutationObserver(() => { | |
setupStatusField(); | |
updateStatus(); // Ensure status is updated whenever the page changes | |
}); | |
// Start observing the entire document for changes | |
observer.observe(document.body, { childList: true, subtree: true }); | |
function extractTimeFromTextarea() { | |
const textarea = document.querySelector('#DISPLAY'); | |
return textarea?.value.match(/seit (\d{2}\.\d{2}\.\d{4} \d{2}:\d{2}:\d{2})/)?.[1] || null; | |
} | |
// Function to wait for the time extraction | |
function waitForExtractTime(timeout = 200) { | |
return new Promise((resolve) => { | |
setTimeout(() => { | |
const extractedTime = extractTimeFromTextarea(); | |
resolve(extractedTime); // Resolve the promise with the extracted time | |
}, timeout); | |
}); | |
} | |
// Async handler for "Kommen" button clicks | |
async function handleKommenClick() { | |
console.log("Waiting for time extraction..."); | |
const extractedTime = await waitForExtractTime(50); // Wait for 50 ms | |
if (extractedTime) { | |
kommenTime = extractedTime; | |
GM_setValue("kommenTime", kommenTime); | |
console.log(`Extracted time: ${kommenTime}`); | |
} else { | |
kommenTime = new Date().toLocaleString(); | |
GM_setValue("kommenTime", kommenTime); | |
console.log(`No time found. Using current time: ${kommenTime}`); | |
} | |
} | |
// Function to update the status field | |
function updateStatus() { | |
const statusField = document.getElementById('statusField'); | |
if (!statusField) return; | |
if (kommenTime && !gehenTime) { | |
statusField.textContent = `Kommen clicked at: ${kommenTime}`; | |
} else if (gehenTime) { | |
statusField.textContent = `Gehen clicked at: ${gehenTime}`; | |
} else { | |
statusField.textContent = "No actions recorded yet."; | |
} | |
} | |
// Automation function for the form | |
function handleFormAutomation(accountValue, passwordValue, isPasswordRequired) { | |
setTimeout(() => { | |
const accountField = document.querySelector('input#AUSWEIS'); | |
if (accountField) { | |
accountField.value = accountValue; | |
console.log(`Account field value set to ${accountValue}`); | |
} else { | |
console.error("Account field not found!"); | |
} | |
const passwordField = document.querySelector('input#PASSWORT'); | |
if (passwordField) { | |
if (isPasswordRequired && passwordValue !== "") { | |
passwordField.value = passwordValue; | |
console.log("Password field value set."); | |
} else if (isPasswordRequired) { | |
console.warn("Password required but no value provided."); | |
} else { | |
console.log("Password field left empty."); | |
} | |
} else { | |
console.error("Password field not found!"); | |
} | |
const submitButton = document.querySelector('button#melden'); | |
if (submitButton) { | |
console.log("Submit button found, clicking..."); | |
submitButton.click(); | |
} else { | |
console.error("Submit button not found!"); | |
} | |
}, 5); | |
} | |
// Helper functions | |
function loadOrPrompt(key, message) { | |
let encryptedData = GM_getValue(key, ""); | |
if (!encryptedData) { | |
let value = prompt(message, ""); | |
if (value) { | |
GM_setValue(key, encrypt(value)); | |
} | |
return value; | |
} | |
return decrypt(encryptedData); | |
} | |
function resetEncryptionKey() { | |
encryptionKey = generateEncryptionKey(); | |
GM_setValue("encryptionKey", encryptionKey); | |
console.log("Encryption key reset. Re-enter username and password."); | |
updateCredential("user", "Enter a new username:"); | |
updateCredential("password", "Enter a new password:"); | |
location.reload(); | |
} | |
function updateCredential(key, message, reload = false) { | |
let value = prompt(message, ""); | |
if (value) { | |
GM_setValue(key, encrypt(value)); | |
console.log(`${key} successfully updated.`); | |
if (reload) location.reload(); | |
} | |
} | |
function encrypt(data) { | |
return sjcl.encrypt(encryptionKey, data); | |
} | |
function decrypt(data) { | |
return sjcl.decrypt(encryptionKey, data); | |
} | |
function generateEncryptionKey() { | |
const array = new Uint8Array(16); | |
window.crypto.getRandomValues(array); | |
return Array.from(array, byte => byte.toString(16).padStart(2, "0")).join(""); | |
} | |
function getEncryptionKey() { | |
let key = GM_getValue("encryptionKey", ""); | |
if (!key) { | |
key = generateEncryptionKey(); | |
GM_setValue("encryptionKey", key); | |
} | |
return key; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Account Automation Script for APplus Terminal
This Tampermonkey script automates account login, leave requests, and PZE correction requests in the APplus terminal, making check-ins and check-outs faster and more efficient.
🔧 Installation & Setup
Step 1: Install Tampermonkey
To run this script, install Tampermonkey, a browser extension for managing custom scripts:
Step 2: Install the Script
Step 3: Initial Setup
🚀 How to Use
✅ Reset Encryption Key
✅ Change Username
✅ Change Password