Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions .github/workflows/collect_commits.yml

This file was deleted.

17 changes: 10 additions & 7 deletions .github/workflows/release_attacher.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Minimize client code
run: |
sudo apt install -y nodejs npm jq
npm install -g terser
cd client
for i in */*.js; do terser $i --compress -o $i; done
jq -c < settings.json > tmp.json
rm settings.json && mv tmp.json settings.json
cd -

- name: Create archive client
run: zip -r client_${{ github.event.release.tag_name }}.zip client/*

- name: Create archive server
run: zip -r server_${{ github.event.release.tag_name }}.zip server/*

- name: Attach archives to GitHub Release
uses: softprops/action-gh-release@v2
# Для softprops/action-gh-release@v2 токен по умолчанию не нужен
# env:
# GITHUB_TOKEN: ${{ github.token }}
with:
files: |
client_${{ github.event.release.tag_name }}.zip
server_${{ github.event.release.tag_name }}.zip
7 changes: 5 additions & 2 deletions client/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Local proctoring",
"description": "Local recording tool containing screen, microphone and camera.",
"version": "2.0.0",
"version": "2.0.2",
"manifest_version": 3,
"permissions": [
"storage",
Expand Down Expand Up @@ -34,5 +34,8 @@
"16": "assets/icons/icon.png",
"48": "assets/icons/icon.png",
"128": "assets/icons/icon.png"
}
},
"host_permissions": [
"https://proctoring.moevm.pro/"
]
}
6 changes: 3 additions & 3 deletions client/pages/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ <h1 class="page__title">Локальный прокторинг</h1>
<input type="checkbox" id="no_patronymic_checkbox" class="no-patronymic-checkbox">
<span class="no-patronymic-text">Нет отчества</span>
</div>
<label for="link_input" class="user-inputs__label">Ссылка:</label>
<input type="text" name="link" id="link_input" class="user-inputs__input" placeholder="Введите ссылку" required minlength="2" maxlength="2048">
<label for="title" class="user-inputs__label">Название работы:</label>
<input type="text" name="title" id="title_input" class="user-inputs__input" placeholder="Введите название работы" required minlength="2" maxlength="2048">
<span class="message"></span>
</div>
<div class="stats-section">
Expand All @@ -35,7 +35,7 @@ <h1 class="page__title">Локальный прокторинг</h1>
</div>
<div class="record-section">
<button class="record-section__button record-section__button_permissions">Разрешения</button>
<button class="record-section__button record-section__button_upload">Отправить</button>
<button class="record-section__button record-section__button_upload">Сохранить</button>
</div>
<div class="record-section">
<button class="record-section__button record-section__button_record-start">Начать запись</button>
Expand Down
2 changes: 1 addition & 1 deletion client/pages/media.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</head>
<body class="mediatab">
<section class="main">
<h1 class="main__header">Не закрывайте, не обновляйте эту вкладку! Служебная вкладка!</h1>
<h1 class="main__header">Не закрывайте, не обновляйте эту вкладку! Служебная вкладка для работы локального прокторинга!</h1>
<div class="preview-toggle-block">
<label for="preview-toggle-btn" class="preview-label">Предпросмотр записи: </label>
<button id="preview-toggle-btn" disabled>Включить</button>
Expand Down
59 changes: 58 additions & 1 deletion client/scripts/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,63 @@ export async function showModalNotify(messages, title = "Уведомление"
}
}

export async function showModalConfirm(messages, title = "Подтверждение", showOnActiveTab = false, mediaIntependent = false) {
chrome.runtime.sendMessage({ action: "closePopup" });
logClientAction({ action: "showModalConfirm", showOnActiveTab });

if (!Array.isArray(messages)) {
messages = [messages];
}

return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({
action: "gotoMediaTab",
mediaExtensionUrl: chrome.runtime.getURL("pages/media.html")
}, (response) => {
if (chrome.runtime.lastError) {
console.error('Error send gotoMediaTab', chrome.runtime.lastError.message);
logClientAction({ action: "Error send gotoMediaTab", message: chrome.runtime.lastError.message });
} else {
logClientAction({ action: "Response gotoMediaTab", response });
}
});

const existingOverlay = document.getElementById('custom-modal-overlay');
if (existingOverlay) existingOverlay.remove();

const overlay = document.createElement('div');
overlay.id = 'custom-modal-overlay';

const modal = document.createElement('div');
modal.id = 'custom-modal';

modal.innerHTML = `
<h2>${title}</h2>
<div class="modal-content">
${messages.map(msg => `<p>${msg}</p>`).join('')}
</div>
<div class="modal-buttons">
<button id="modal-confirm-yes">Да</button>
<button id="modal-confirm-no">Нет</button>
</div>
`;

const closeModal = (result) => {
overlay.remove();
document.body.style.overflow = '';
resolve(result);
};

modal.querySelector('#modal-confirm-yes').addEventListener('click', () => closeModal(true));
modal.querySelector('#modal-confirm-no').addEventListener('click', () => closeModal(false));

document.body.style.overflow = 'hidden';
overlay.appendChild(modal);
document.body.appendChild(overlay);

});
}

function sendModalNotifyToActiveTab(messages, title) {
return new Promise((resolve, reject) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
Expand Down Expand Up @@ -289,7 +346,7 @@ export function setReadyToUploadContainer(container, files) {

const titleElement = document.createElement("div");
titleElement.id = "ready-to-upload-container-title";
titleElement.innerHTML = `Файлов, доступных для выгрузки: ${files.length}`;
titleElement.innerHTML = `<br><br><br><br><br>Файлов, доступных для выгрузки: ${files.length}`;

container.appendChild(titleElement);

Expand Down
34 changes: 18 additions & 16 deletions client/scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const inputElements = {
name: document.querySelector('#name_input'),
surname: document.querySelector('#surname_input'),
patronymic: document.querySelector('#patronymic_input'),
link: document.querySelector('#link_input')
title: document.querySelector('#title_input')
};

const buttonElements = {
Expand Down Expand Up @@ -74,26 +74,28 @@ const bStates = {
}
}

const validationStringRegExp = /^[А-ЯЁ][а-яёА-ЯЁ -]*$/;

const validationRules = {
group: {
regex: /^\d{4}$/,
message: "Группа должна содержать ровно 4 цифры. Пример: '1234'"
},
name: {
regex: /^[A-ZА-ЯЁ][a-zа-яёA-ZА-ЯЁ-]*$/,
message: "Имя должно начинаться с заглавной буквы и содержать только русские/латинские буквы и тире. Пример: 'Иван'"
regex: validationStringRegExp,
message: "Имя должно начинаться с заглавной буквы и содержать только кириллицу и тире/пробел. Пример: 'Иван'"
},
surname: {
regex: /^[A-ZА-ЯЁ][a-zа-яёA-ZА-ЯЁ-]*$/,
message: "Фамилия должна начинаться с заглавной буквы и содержать только русские/латинские буквы и тире. Пример: 'Иванов'"
regex: validationStringRegExp,
message: "Фамилия должна начинаться с заглавной буквы и содержать только кириллицу и тире/пробел. Пример: 'Иванов'"
},
patronymic: {
regex: /^[A-ZА-ЯЁ][a-zа-яёA-ZА-ЯЁ-]*$/,
message: "Отчество должно начинаться с заглавной буквы и содержать только русские/латинские буквы и тире. Пример: 'Иванович'"
regex: validationStringRegExp,
message: "Отчество должно начинаться с заглавной буквы и содержать только кириллицу и тире/пробел. Пример: 'Иванович'"
},
link: {
title: {
regex: /.+/,
message: "Ссылка на комнату не должна быть пустой."
message: "Название работы не должно быть пустым."
}
};

Expand Down Expand Up @@ -165,7 +167,7 @@ async function saveInputValues() {
surname: inputElements.surname.value,
patronymic: inputElements.patronymic.value,
noPatronymicChecked: noPatronymicCheckbox.checked,
link: inputElements.link.value
title: inputElements.title.value
}
});
logClientAction({ action: "Save input values" });
Expand Down Expand Up @@ -474,7 +476,7 @@ async function startRecCallback() {
name: inputElements.name.value,
surname: inputElements.surname.value,
patronymic: noPatronymicCheckbox.checked ? "Без_отчества" : inputElements.patronymic.value.trim(),
link: inputElements.link.value
title: inputElements.title.value
};

chrome.runtime.sendMessage({
Expand Down Expand Up @@ -604,7 +606,7 @@ async function saveFormDataFilesLocally(formData, sessionId) {
async function uploadFormDataToServer(formData, sessionId) {
logClientAction({ action: "Send upload request", sessionId: sessionId, messageType: "upload_video" });

const eventSource = new EventSource(`http://127.0.0.1:5000/progress/${sessionId}`);
const eventSource = new EventSource(`${session_settings.server_url}/progress/${sessionId}`);

const steps = 7;

Expand Down Expand Up @@ -634,7 +636,7 @@ async function uploadFormDataToServer(formData, sessionId) {
};

try {
const response = await fetch('http://127.0.0.1:5000/upload_video', {
const response = await fetch(`${session_settings.server_url}/upload_video`, {
method: "POST",
body: formData,
});
Expand Down Expand Up @@ -699,10 +701,10 @@ async function uploadVideo(files) {
await chrome.storage.local.remove("metadata");
await chrome.storage.local.set({"session_status" : "need_init"});

inputElements.link.value = "";
inputElements.link.classList.remove('input-valid', 'input-invalid');
inputElements.title.value = "";
inputElements.title.classList.remove('input-valid', 'input-invalid');
await saveInputValues();
logClientAction("Clear link field");
logClientAction("Clear work title field");
}
});
}
Loading
Loading