Adding ClientId; Adding Teacher Panel to start/end event recording

main
Amēlija I 2025-04-29 20:09:41 +03:00
parent fb3d497aa3
commit 53d1767a2d
4 changed files with 266 additions and 136 deletions

3
.gitignore vendored
View File

@ -12,9 +12,6 @@ dist
# misc # misc
.DS_Store .DS_Store
# config
config.json
# local env files # local env files
.env.local .env.local
.env.development.local .env.development.local

View File

@ -6,11 +6,13 @@
"author": "Your Name", "author": "Your Name",
"permissions": [ "permissions": [
"storage" "storage",
"alarms"
], ],
"host_permissions": [ "host_permissions": [
"http://localhost:5000/*" "http://localhost:5000/*",
"https://zpdai.rkg.lv/*"
], ],
"content_security_policy": { "content_security_policy": {

View File

@ -1,3 +1,5 @@
const browserAPI = typeof browser !== 'undefined' ? browser : chrome;
function saveOptions(event) { function saveOptions(event) {
event.preventDefault(); event.preventDefault();
const serverUrl = document.querySelector("#server-url").value; const serverUrl = document.querySelector("#server-url").value;
@ -8,20 +10,62 @@ function saveOptions(event) {
return; return;
} }
browser.storage.sync.set({ serverUrl, password }).then(() => { if (typeof browser !== 'undefined') {
const status = document.querySelector("#status"); browserAPI.storage.sync.set({ serverUrl, password })
status.textContent = "Настройки сохранены!"; .then(() => {
setTimeout(() => (status.textContent = ""), 2000); showStatus("Настройки сохранены!");
})
.catch((error) => {
console.error("Ошибка сохранения настроек:", error);
showStatus("Ошибка сохранения!", true);
}); });
} else {
browserAPI.storage.sync.set({ serverUrl, password }, () => {
if (chrome.runtime.lastError) {
console.error("Ошибка сохранения настроек:", chrome.runtime.lastError);
showStatus("Ошибка сохранения!", true);
} else {
showStatus("Настройки сохранены!");
}
});
}
} }
function restoreOptions() { function restoreOptions() {
browser.storage.sync.get(["serverUrl", "password"]).then((result) => { if (typeof browser !== 'undefined') {
const serverUrl = result.serverUrl || "http://localhost:5000/submit"; browserAPI.storage.sync.get(["serverUrl", "password"])
const password = result.password || ""; .then((result) => {
document.querySelector("#server-url").value = serverUrl; updateFormFields(result);
document.querySelector("#password").value = password; })
.catch((error) => {
console.error("Ошибка загрузки настроек:", error);
updateFormFields({});
}); });
} else {
browserAPI.storage.sync.get(["serverUrl", "password"], (result) => {
if (chrome.runtime.lastError) {
console.error("Ошибка загрузки настроек:", chrome.runtime.lastError);
updateFormFields({});
} else {
updateFormFields(result);
}
});
}
}
function updateFormFields(result) {
document.querySelector("#server-url").value = result.serverUrl || "http://localhost:5000/submit";
document.querySelector("#password").value = result.password || "";
}
function showStatus(message, isError = false) {
const status = document.querySelector("#status");
status.textContent = message;
status.style.color = isError ? "red" : "green";
setTimeout(() => {
status.textContent = "";
status.style.color = "";
}, 2000);
} }
document.addEventListener("DOMContentLoaded", restoreOptions); document.addEventListener("DOMContentLoaded", restoreOptions);

View File

@ -1,8 +1,39 @@
const browserAPI = typeof browser !== 'undefined' ? browser : chrome;
let serverUrl = "http://localhost:5000/submit"; let serverUrl = "http://localhost:5000/submit";
let password = ""; let password = "";
let clientId = null;
let isRecording = false;
let checkInterval = null;
let currentSessionId = null;
function loadSettings() { function loadSettings() {
return browser.storage.sync.get(["serverUrl", "password"]).then((result) => { return new Promise((resolve) => {
if (typeof browser !== 'undefined') {
browserAPI.storage.sync.get(["serverUrl", "password"])
.then((result) => {
processSettings(result);
resolve();
})
.catch((error) => {
console.error("Ошибка загрузки настроек:", error);
resolve();
});
} else {
browserAPI.storage.sync.get(["serverUrl", "password"], (result) => {
if (chrome.runtime.lastError) {
console.error("Ошибка загрузки настроек:", chrome.runtime.lastError);
} else {
processSettings(result);
}
resolve();
});
}
});
}
function processSettings(result) {
if (result.serverUrl) { if (result.serverUrl) {
serverUrl = result.serverUrl; serverUrl = result.serverUrl;
console.log("URL сервера загружен из настроек:", serverUrl); console.log("URL сервера загружен из настроек:", serverUrl);
@ -10,30 +41,35 @@ function loadSettings() {
if (result.password) { if (result.password) {
password = result.password; password = result.password;
console.log("Пароль загружен из настроек."); console.log("Пароль загружен из настроек.");
}
}
function handleClientId() {
if (typeof browser !== 'undefined') {
browserAPI.storage.sync.get("clientId")
.then((result) => {
if (result.clientId) {
clientId = result.clientId;
console.log("ID клиента загружен:", clientId);
} else { } else {
return fetch(browser.runtime.getURL("config.json")) generateAndSaveId();
.then(response => {
if (!response.ok) {
throw new Error(`Ошибка загрузки config.json: ${response.statusText}`);
} }
return response.json();
}) })
.then(config => { .catch(console.error);
serverUrl = config.FLASK_SERVER_URL; } else {
password = config.PASSWORD || password; browserAPI.storage.sync.get("clientId", (result) => {
console.log("URL сервера успешно загружен:", serverUrl); if (chrome.runtime.lastError) {
console.error("Ошибка загрузки ID клиента:", chrome.runtime.lastError);
} else if (result.clientId) {
clientId = result.clientId;
console.log("ID клиента загружен:", clientId);
} else {
generateAndSaveId();
}
}); });
} }
}).catch((error) => {
console.error("Ошибка загрузки URL сервера:", error);
});
} }
loadSettings();
let clientId = null;
function generateUUID() { function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0; const r = (Math.random() * 16) | 0;
@ -42,20 +78,55 @@ function generateUUID() {
}); });
} }
browser.storage.sync.get("clientId").then((result) => { function generateAndSaveId() {
if (result.clientId) {
clientId = result.clientId;
console.log("ID клиента загружен:", clientId);
} else {
clientId = generateUUID(); clientId = generateUUID();
browser.storage.sync.set({ clientId }).then(() => { if (typeof browser !== 'undefined') {
browserAPI.storage.sync.set({ clientId })
.then(() => console.log("ID клиента создан и сохранен:", clientId))
.catch(console.error);
} else {
browserAPI.storage.sync.set({ clientId }, () => {
if (chrome.runtime.lastError) {
console.error("Ошибка сохранения ID клиента:", chrome.runtime.lastError);
} else {
console.log("ID клиента создан и сохранен:", clientId); console.log("ID клиента создан и сохранен:", clientId);
}
}); });
} }
}).catch((error) => { }
console.error("Ошибка загрузки ID клиента:", error);
async function checkSessionStatus() {
try {
const statusUrl = 'http://127.0.0.1:5000/api/session_status';
const response = await fetch(statusUrl, {
headers: { 'X-Password': password }
}); });
const { active, session_id } = await response.json();
if (active && !isRecording) {
startRecording(session_id);
} else if (!active && isRecording) {
stopRecording();
}
} catch (error) {
console.error('Ошибка проверки сессии:', error);
}
}
function startRecording(sessionId) {
isRecording = true;
currentSessionId = sessionId;
console.log('Запись действий начата для сессии:', sessionId);
}
function stopRecording() {
isRecording = false;
currentSessionId = null;
console.log('Запись действий остановлена');
}
function createEventJSON(eventType, data) { function createEventJSON(eventType, data) {
const timeStamp = new Date().toISOString(); const timeStamp = new Date().toISOString();
@ -71,10 +142,8 @@ function createEventJSON(eventType, data) {
async function sendDataToServer(eventData) { async function sendDataToServer(eventData) {
if (!serverUrl || !password) { if (!isRecording || !serverUrl || !password) return;
console.error("URL сервера или пароль не заданы. Проверьте настройки.");
return;
}
try { try {
const response = await fetch(serverUrl, { const response = await fetch(serverUrl, {
method: 'POST', method: 'POST',
@ -82,7 +151,10 @@ async function sendDataToServer(eventData) {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Password': password, 'X-Password': password,
}, },
body: JSON.stringify(eventData), body: JSON.stringify({
...eventData,
session_id: currentSessionId
})
}); });
const responseData = await response.json(); const responseData = await response.json();
@ -96,8 +168,24 @@ async function sendDataToServer(eventData) {
} }
} }
function debounce(func, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), delay);
};
}
async function initialize() {
await loadSettings();
handleClientId();
checkInterval = setInterval(checkSessionStatus, 5000);
checkSessionStatus();
document.addEventListener("keydown", (event) => { document.addEventListener("keydown", (event) => {
if (!isRecording) return;
const key = event.key; const key = event.key;
const code = event.code; const code = event.code;
let description; let description;
@ -119,22 +207,16 @@ document.addEventListener("keydown", (event) => {
document.addEventListener("mousedown", (event) => { document.addEventListener("mousedown", (event) => {
if (!isRecording) return;
const eventData = createEventJSON('mousedown', { button: event.button, description: `Клик мышью: ${event.button}` }); const eventData = createEventJSON('mousedown', { button: event.button, description: `Клик мышью: ${event.button}` });
console.log("Событие mousedown:", JSON.stringify(eventData)); console.log("Событие mousedown:", JSON.stringify(eventData));
sendDataToServer(eventData); sendDataToServer(eventData);
}); });
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
let accumulatedPixels = 0; let accumulatedPixels = 0;
const handleWheel = debounce((event) => { const handleWheel = debounce((event) => {
if (!isRecording) return;
const direction = accumulatedPixels > 0 ? "вниз" : "вверх"; const direction = accumulatedPixels > 0 ? "вниз" : "вверх";
const pixels = Math.abs(accumulatedPixels); const pixels = Math.abs(accumulatedPixels);
@ -145,9 +227,10 @@ const handleWheel = debounce((event) => {
accumulatedPixels = 0; accumulatedPixels = 0;
}, 200); }, 200);
document.addEventListener("wheel", (event) => { accumulatedPixels += event.deltaY; handleWheel(event);}); document.addEventListener("wheel", (event) => { if (!isRecording) return; accumulatedPixels += event.deltaY; handleWheel(event);});
document.addEventListener("click", (event) => { document.addEventListener("click", (event) => {
if (!isRecording) return;
const eventType = 'click'; const eventType = 'click';
const clickedElement = event.target; const clickedElement = event.target;
const tag = clickedElement.tagName; const tag = clickedElement.tagName;
@ -187,6 +270,7 @@ function navigateWithPromise(href) {
document.addEventListener("copy", (event) => { document.addEventListener("copy", (event) => {
if (!isRecording) return;
const selectedText = window.getSelection().toString(); const selectedText = window.getSelection().toString();
let outputText = selectedText.length > 50 ? selectedText.substring(0, 49) + '…' : selectedText; let outputText = selectedText.length > 50 ? selectedText.substring(0, 49) + '…' : selectedText;
@ -197,3 +281,6 @@ document.addEventListener("copy", (event) => {
sendDataToServer(eventData); sendDataToServer(eventData);
} }
}); });
}
initialize();