Merged CEO and Client App

This commit is contained in:
andrei-mihnea-cerbu
2025-02-06 10:25:13 +02:00
parent eda2e2d2a0
commit 23802acd98
186 changed files with 365 additions and 11234 deletions
@@ -0,0 +1,26 @@
// Load announcement content from the application info when the page loads
async function loadAnnouncement() {
try {
const announcementText = await window.electronAPI.readAnnouncement();
const announcementContent = document.getElementById('announcement-content');
if (announcementContent && announcementText) {
announcementContent.innerHTML = formatTextForHtml(announcementText);
}
} catch (error) {
console.error('Failed to load announcement:', error);
document.getElementById('announcement-content').textContent = 'Failed to load announcement.';
}
}
function formatTextForHtml(text) {
let formattedText = text.replace(/\n/g, '<br>');
formattedText = formattedText.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
formattedText = formattedText.replace(/ /g, ' &nbsp;');
return formattedText;
}
// Close the window when the close button is clicked
function closeWindow() {
window.electronAPI.closeAnnouncementWindow();
}
+47
View File
@@ -0,0 +1,47 @@
function fadeIn() {
document.querySelector('.container').classList.remove('fade-out');
document.querySelector('.container').classList.add('fade-in');
}
function fadeOut(destination) {
const container = document.querySelector('.container');
container.classList.remove('fade-in');
container.classList.add('fade-out');
console.log(destination);
setTimeout(() => {}, 5000);
container.addEventListener('animationend', async () => {
try {
await window.uiAPI.changeContent(destination);
console.log('Navigated to', destination);
} catch (error) {
console.error('Error navigating:', error);
}
});
}
async function waitForResponse() {
return new Promise((resolve) => {
const idResponseCheck = setInterval(async () => {
if (await window.networkAPI.hasResponseArrived()) {
clearInterval(idResponseCheck);
resolve(await window.networkAPI.getLastUcResult()); // Resolve the response or null if not available
}
}, 100); // Check every 100 milliseconds if the response has arrived
});
}
function toggleScroll(idComponent, scrollHeight = 180) {
const element = document.getElementById(idComponent); // Using getElementById
if (!element) {
console.error(`Element with ID '${idComponent}' not found.`);
return;
}
if (element.scrollHeight > scrollHeight) {
element.style.overflowY = 'auto'; // Enable scroll if content overflows
} else {
element.style.overflowY = 'hidden'; // Disable scroll if content fits
}
}
+155
View File
@@ -0,0 +1,155 @@
let codeLogin = '';
let codeFindByEmail = '';
let codeFindKeyByUser = '';
let codeOk = '';
document.addEventListener('DOMContentLoaded', async function () {
const submitButton = document.getElementById('submit');
const resetPasswordButton = document.getElementById('resetPassword');
const signUpButton = document.getElementById('signup');
await window.databaseAPI.setLoginStatus(false);
// Retrieve the operation codes via IPC
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application. Failed to retrieve operation codes.');
return;
}
codeLogin = operationCodes.LOGIN;
codeFindByEmail = operationCodes.FIND_BY_EMAIL;
codeFindKeyByUser = operationCodes.FIND_KEY_BY_USER_ID;
codeOk = operationCodes.OK;
resetPasswordButton.addEventListener('click', function (e) {
e.preventDefault();
window.uiAPI.changeContent('reset_password');
});
signUpButton.addEventListener('click', function (e) {
e.preventDefault();
window.uiAPI.changeContent('sign_up');
});
// Submit button logic (handle login)
submitButton.addEventListener('click', async function (e) {
e.preventDefault();
console.log('Submit button clicked');
const form = document.getElementById('loginForm');
const formData = new FormData(form);
const email = formData.get('email');
const password = formData.get('password');
// Open a TCP socket to the stored IP
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Internal error of the application. Unable to open socket.');
return;
}
// Attempt login
if (!await attemptLogin(email, password)) {
await window.networkAPI.closeUcSocket();
return;
}
// Fetch and store user info
if (!await fetchAndStoreUserInfo(email)) {
await window.networkAPI.closeUcSocket();
return;
}
// Fetch user info from local storage
const userInfo = await window.databaseAPI.getUserInfo('user_info');
if (!userInfo) {
await window.networkAPI.closeUcSocket();
await window.uiAPI.showAlert('Failed to fetch user info.');
return;
}
// Fetch and store encryption key
if (!await fetchAndStoreEncryptionKey(userInfo.id)) {
await window.networkAPI.closeUcSocket();
return;
}
// Close the socket and navigate to main menu after success
await window.networkAPI.closeUcSocket();
await window.workersAPI.startWorkers();
await window.databaseAPI.setLoginStatus(true);
await window.uiAPI.changeContent('main_menu');
});
});
async function attemptLogin(email, password) {
const app_type = await window.databaseAPI.getAppType();
const messageData = {email, password, app_type};
// Send the login message to the server
if (!await window.networkAPI.sendUcMessage(codeLogin, messageData)) {
await window.uiAPI.showAlert('Failed to send login request.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if (!response) {
await window.uiAPI.showAlert('No response from server.');
return false;
}
if (response.operationCode !== codeOk) {
await window.uiAPI.showAlert(response.metaInfo.message);
return false;
}
return true;
}
async function fetchAndStoreUserInfo(userEmail) {
if (!await window.networkAPI.sendUcMessage(codeFindByEmail, {email: userEmail})) {
await window.uiAPI.showAlert('Failed to send request to fetch user info.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
const userInfo = {};
userInfo.id = response.metaInfo.id;
userInfo.email = response.metaInfo.email;
userInfo.departmentId = response.metaInfo.departmentId;
userInfo.name = response.metaInfo.name || 'User';
await window.databaseAPI.writeUserInfo(userInfo);
return true;
}
await window.uiAPI.showAlert('Failed to fetch user info from server.');
return false;
}
async function fetchAndStoreEncryptionKey(userId) {
if (!await window.networkAPI.sendUcMessage(codeFindKeyByUser, {userId})) {
await window.uiAPI.showAlert('Failed to send request to fetch encryption key.');
return false;
}
// Wait for the response using waitForResponse
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
const encryptionKey = {
key: response.metaInfo.key.key,
iv: response.metaInfo.key.iv,
};
await window.databaseAPI.writeEncryptionKey(encryptionKey);
return true;
}
await window.uiAPI.showAlert('Failed to fetch encryption key from server.');
return false;
}
+173
View File
@@ -0,0 +1,173 @@
let backupDirId = '';
let shareDirId = '';
let departmentDirId = '';
document.addEventListener('DOMContentLoaded', async function () {
setInterval(loadReceivedFiles, 3000); // Call loadReceivedFiles every 3000 ms (3 seconds)
const backupButton = document.getElementById('backup-dir');
const shareButton = document.getElementById('share-dir');
const departmentButton = document.getElementById('department-dir');
const changeInfoButton = document.getElementById('change-info');
const shareFileButton = document.getElementById('share-file');
const logoutButton = document.getElementById('logout');
const restoreBackupButton = document.getElementById('restore-backup');
backupButton.addEventListener('click', async function () {
await setPath('backupDirectory');
});
shareButton.addEventListener('click', async function () {
await setPath('shareDirectory');
});
departmentButton.addEventListener('click', async function () {
await setPath('departmentDirectory');
});
changeInfoButton.addEventListener('click', function () {
fadeOut('profile');
});
shareFileButton.addEventListener('click', function () {
fadeOut('share_file');
});
logoutButton.addEventListener('click', async function () {
fadeOut('login');
});
// Add event listener for the restore backup button
restoreBackupButton.addEventListener('click', async function () {
await restoreBackup();
});
});
async function initialSetup(){
await checkAndSetAllDirectories();
await loadReceivedFiles();
await fetchUserInfo();
}
async function restoreBackup() {
const backupDirectory = await window.databaseAPI.isBackupSet();
if (backupDirectory) {
await window.uiAPI.showAlert('You have already set a backup directory. You cannot restore again.');
return;
}
// Prompt the user to choose the destination for the restored backup
const destinationPath = await window.uiAPI.selectDirectory();
if (!destinationPath) {
return; // User canceled the directory selection
}
// Call the IPC method to initiate the backup retrieval process
window.workersAPI.startBackupRetrieval(destinationPath);
// Switch the content to the 'backup_retrieve' page
fadeOut('backup_retrieve');
}
async function checkAndSetAllDirectories() {
const directorySchemes = await window.databaseAPI.getLocalResources();
backupDirId = directorySchemes.backup.id;
shareDirId = directorySchemes.shared.id;
departmentDirId = directorySchemes.department.id;
await attachNotificationButton(backupDirId, 'Set your backup directory!', 'backup_alert', 'alert');
await attachNotificationButton(shareDirId, 'Set your share directory!', 'share_alert', 'alert');
await attachNotificationButton(departmentDirId, 'Set your department directory!', 'department_alert', 'alert');
}
async function checkPathExistence(id) {
const dirInfo = await window.databaseAPI.getDirectoryInfo(id);
return dirInfo.path !== ''
}
async function setPath(id){
const path = await window.uiAPI.selectDirectory();
if (path === undefined) return false;
return await window.databaseAPI.writeDirectoryPath(id, path);
}
async function attachNotificationButton(entryId, buttonText, buttonId, buttonName) {
const path = await checkPathExistence(entryId);
if (!path) {
const notificationsDiv = document.getElementById('notifications');
const button = document.createElement('button');
button.className='alert';
button.id = buttonId;
button.name = buttonName;
button.textContent = buttonText;
button.addEventListener('click', async function () {
if(await setPath(entryId)) button.remove();
});
notificationsDiv.appendChild(button);
}
}
async function fetchUserInfo() {
const usernameField = document.getElementById('username-field');
// Read the user credentials from the userConfig
let userInfo = await window.databaseAPI.getUserInfo();
if (userInfo && userInfo.name) {
usernameField.textContent = userInfo.name;
return;
}
// Update the greeting with the fetched user's name
if (usernameField) {
usernameField.textContent = userInfo.name;
} else {
console.error("Username field is not available in the DOM.");
}
}
async function loadReceivedFiles() {
// Read the shareDirectory from applicationInfo
const shareDirData = await window.databaseAPI.getDirectoryInfo(shareDirId);
console.log('Loading received files:', shareDirData);
const notificationsDiv = document.getElementById('notifications');
const existingButtons = Array.from(notificationsDiv.children).map(button => button.getAttribute('data-filepath'));
// Iterate over each user and their files in the structure
Object.keys(shareDirData.structure).forEach(userName => {
const userFiles = shareDirData.structure[userName];
// Iterate over each file of the user
Object.keys(userFiles).forEach(fileName => {
const filePath = userFiles[fileName];
// Check if a button for this file path already exists
if (!existingButtons.includes(filePath)) {
const button = document.createElement('button');
button.setAttribute('data-filepath', filePath); // Set a custom attribute to track the file path
button.className = 'notification';
button.name = 'notification';
button.textContent = `You received a file "${fileName}" from ${userName}`; // Display the userName and file name
button.addEventListener('click', () => handleFileReceivedButtonPressed(filePath, button));
notificationsDiv.appendChild(button);
}
});
});
}
async function handleFileReceivedButtonPressed(filePath, button) {
console.log('Notification button clicked!');
// Open the file in the file explorer
await window.uiAPI.showFileInExplorer(filePath)
.then(() => console.log('File explorer opened for: ' + filePath))
.catch(error => console.error('Error opening file explorer:', error));
// Remove the button after opening the file
button.remove();
}
+86
View File
@@ -0,0 +1,86 @@
let id = '';
let departmentId = '';
document.addEventListener('DOMContentLoaded', async function () {
const {id: userId, name, email, departmentId: userDepartmentId} = await window.databaseAPI.getUserInfo();
const emailInput = document.querySelector('input[name="email"]');
const usernameInput = document.querySelector('input[name="username"]');
const passwordInput = document.querySelector('input[name="password"]');
// Pre-fill form fields with existing data
id = userId
departmentId = userDepartmentId;
usernameInput.value = name;
emailInput.value = email;
passwordInput.value = '';
const backButton = document.getElementById('back');
const submitButton = document.getElementById('submit');
// Get operation codes from the backend
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application.');
return;
}
const codeModifyUser = operationCodes.MODIFY_USER;
const codeOk = operationCodes.OK;
// Handle the back button click
backButton.addEventListener('click', async function () {
console.log('Back button clicked!');
fadeOut('main_menu');
});
// Handle the submit button click
submitButton.addEventListener('click', async function (e) {
e.preventDefault();
console.log('Submit button clicked!');
// Fetch form values
const email = emailInput.value;
const name = usernameInput.value;
const password = passwordInput.value;
const app_type = await window.databaseAPI.getAppType();
// Prepare the data to be sent via the UC socket
const messageData = {
id: id,
name: name,
email: email,
password: password,
departmentId: departmentId,
app_type: app_type
};
// Open UC socket
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Failed to open socket. Internal error of the application.');
return;
}
// Send the message to the server using the UC socket
if (!await window.networkAPI.sendUcMessage(codeModifyUser, messageData)) {
await window.uiAPI.showAlert('Failed to send message.');
return;
}
// Wait for the response
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
console.log('User update successful.');
// Save updated user info to the userConfig
await window.databaseAPI.writeUserInfo({ id: id, email: email, name: name, departmentId: departmentId });
// Navigate back to the main menu
fadeOut('main_menu');
} else {
console.log('Error updating user:', response?.metaInfo?.message || 'Unknown error');
await window.electronAPI.showAlert(response?.metaInfo?.message || 'Unknown error occurred');
}
});
});
@@ -0,0 +1,6 @@
document.addEventListener('DOMContentLoaded', async function () {
await new Promise(resolve => setTimeout(resolve, 7000));
await window.databaseAPI.resetInternalDatabase();
await window.workersAPI.stopWorkers();
await window.uiAPI.changeContent('welcome');
});
@@ -0,0 +1,66 @@
let codeResetPassword = '';
let codeOk = '';
document.addEventListener('DOMContentLoaded', async function () {
const backToLoginButton = document.getElementById('backToLogin');
const resetPasswordButton = document.getElementById('resetPassword');
// Retrieve the operation codes via IPC
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.uiAPI.showAlert('Internal error of the application.');
return;
}
codeResetPassword = operationCodes.RESET_PASSWORD;
codeOk = operationCodes.OK;
// Back to login
backToLoginButton.addEventListener('click', function (e) {
e.preventDefault();
window.uiAPI.changeContent('login');
});
// Reset password logic
resetPasswordButton.addEventListener('click', async function (e) {
e.preventDefault();
if (!await window.networkAPI.openUcSocket()) {
await window.uiAPI.showAlert('Internal error of the application.');
return;
}
const form = document.getElementById('resetPasswordForm');
const formData = new FormData(form);
const email = formData.get('email');
const newPassword = formData.get('newPassword');
// Ensure the email and new password are provided
if (!email || !newPassword) {
await window.uiAPI.showAlert('Please provide both email and new password.');
return;
}
if (!await attemptResetPassword(email, newPassword)) {
return;
}
await window.networkAPI.closeUcSocket();
await window.uiAPI.showAlert('Password reset successfully.');
await window.uiAPI.changeContent('login');
});
});
async function attemptResetPassword(email, newPassword) {
const app_type = await window.databaseAPI.getAppType();
const messageData = { email, newPassword, app_type };
if (!await window.networkAPI.sendUcMessage(codeResetPassword, messageData)) return false;
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
return true;
} else {
await window.uiAPI.showAlert(response?.metaInfo?.message || 'Error resetting password.');
return false;
}
}
+121
View File
@@ -0,0 +1,121 @@
let pathToFile = '';
let fetchUsersInterval = null;
document.addEventListener('DOMContentLoaded', async function () {
const selectFileButton = document.getElementById('selectFile');
const submitButton = document.getElementById('submitButton');
const backButton = document.getElementById('backButton');
selectFileButton.addEventListener('click', async function (event) {
event.preventDefault();
try {
pathToFile = await window.uiAPI.selectFile();
updateFileName();
} catch (error) {
console.error('Error opening file dialog:', error);
}
});
submitButton.addEventListener('click', async function (event) {
event.preventDefault();
// Check if a file was chosen
if (!pathToFile.trim()) {
await window.uiAPI.showAlert('File not chosen!');
return;
}
const user_info = await window.databaseAPI.getUserInfo();
if (!user_info) {
return;
}
const form = document.getElementById('userDestForm');
const checkboxes = form.querySelectorAll('input[name="users"]');
const selectedUserIps = Array.from(checkboxes)
.filter(checkbox => checkbox.checked)
.map(checkbox => checkbox.value); // Get IP of the selected users
if (!selectedUserIps.length) {
await window.uiAPI.showAlert('No user selected!');
return;
}
for (const selectedUserIp of selectedUserIps) {
try {
// Add task to send file to the queue
const task = {
ip: selectedUserIp, // Destination IP for the file
path: pathToFile, // File path
userName: user_info.name // Sender's username from userConfig
};
await window.databaseAPI.addTaskToSendFileQueue(task);
await window.uiAPI.showAlert('File sent to the queue.');
console.log(`Task added to send file to IP ${selectedUserIp}`);
} catch (error) {
console.error(`Error processing IP ${selectedUserIp}:`, error);
}
}
});
backButton.addEventListener('click', function (event) {
event.preventDefault();
fadeOut('main_menu');
});
setInterval(fetchUsersAndCreateCheckboxes, 5000);
});
// Function to update the file name display
function updateFileName() {
const fileNameElement = document.getElementById('selectFile');
if (!fileNameElement) {
return;
}
if (pathToFile.trim() === '') {
fileNameElement.textContent = 'No file chosen';
} else {
fileNameElement.textContent = pathToFile.split('\\').pop().split('/').pop();
}
}
async function fetchUsersAndCreateCheckboxes() {
// Step 1: Get the currently checked users before refreshing the list
const selectedUserIps = new Set(
Array.from(document.querySelectorAll('input[name="users"]:checked'))
.map(checkbox => checkbox.value)
);
const usersInfo = await window.databaseAPI.getActiveUsers();
const filteredUsers = usersInfo.filter(user => user.id !== '');
if (!filteredUsers.length === 0) {
await window.uiAPI.showAlert('No active users found.');
clearInterval(fetchUsersInterval);
fetchUsersInterval = null;
await window.uiAPI.changeContent('main_menu');
return;
}
const usersDiv = document.getElementById('choose_user_form_content');
usersDiv.innerHTML = ''; // Clear the list before updating
usersInfo.forEach(user => {
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.name = 'users';
checkbox.value = user.ip; // Store user's IP in the value
// Step 2: Check if this user was previously selected
if (selectedUserIps.has(user.ip)) {
checkbox.checked = true; // Restore checked state
}
const label = document.createElement('label');
label.innerHTML = `${user.name}`;
label.insertBefore(checkbox, label.firstChild);
usersDiv.appendChild(label);
});
toggleScroll('choose_user_form_content');
}
+136
View File
@@ -0,0 +1,136 @@
let codeOk = '';
let codeGetDepartments = '';
let codeSignUp = '';
let userData = {
email: null,
name: null,
password: null,
app_type: null,
departmentId: null
};
document.addEventListener('DOMContentLoaded', async function () {
const nextToStep2Button = document.getElementById('nextToStep2');
const backToStep1Button = document.getElementById('backToStep1');
const submitSignupButton = document.getElementById('submitSignup');
const backToLogin = document.getElementById('backToLogin');
const step1 = document.getElementById('step1');
const step2 = document.getElementById('step2');
if (!await window.networkAPI.openUcSocket()) {
alert('Internal error of the application.');
return;
}
const operationCodes = await window.networkAPI.getOperationsCodes();
if (!operationCodes) {
await window.electronAPI.showAlert('Internal error of the application.');
return;
}
codeGetDepartments = operationCodes.GET_DEPARTMENTS;
codeSignUp = operationCodes.SIGN_UP;
codeOk = operationCodes.OK;
let departments = await getDepartments();
if (departments === null) {
await window.uiAPI.showAlert('Failed to fetch departments.');
return;
}
// Handle form submission for Step 1 (Profile Information)
nextToStep2Button.addEventListener('click', async function (e) {
e.preventDefault(); // Prevent the default form submission
// Collect data from Step 1 inputs
userData.email = document.querySelector('input[name="email"]').value;
userData.name = document.querySelector('input[name="name"]').value;
userData.password = document.querySelector('input[name="password"]').value;
userData.app_type = await window.databaseAPI.getAppType();
// Move to Step 2
const departmentList = document.getElementById('departmentList');
departmentList.innerHTML = ''; // Clear existing departments
// Populate department list
departments.forEach(department => {
if (department.name !== 'CEO' && department.name !== 'ADMIN') {
const label = document.createElement('label');
label.innerHTML = `
<input type="radio" name="dept" value="${department.id}">
${department.name}
`;
departmentList.appendChild(label);
}
});
switchStep(step1, step2);
});
// Handle form submission for Step 2 (Department Selection)
submitSignupButton.addEventListener('click', async function (e) {
e.preventDefault(); // Prevent form from being submitted in the usual way
// Get the selected department
userData.departmentId = document.querySelector('input[name="dept"]:checked')?.value;
if (!userData.departmentId) {
await window.uiAPI.showAlert('Please select a department.');
return;
}
if (!await attemptSignUp()) {
switchStep(step2, step1);
return;
}
await window.uiAPI.showAlert('Signup successful!');
await window.uiAPI.changeContent('login');
});
// Back to Step 1 from Step 2
backToStep1Button.addEventListener('click', function () {
switchStep(step2, step1);
});
// Back to login
backToLogin.addEventListener('click', async function (e) {
e.preventDefault();
await window.networkAPI.closeUcSocket();
await window.uiAPI.changeContent('login');
});
});
async function getDepartments() {
if (!await window.networkAPI.sendUcMessage('GET_DEPARTMENTS')) return null;
const response = await waitForResponse();
console.log(response);
if (response && response.operationCode === codeOk) {
return response.metaInfo.departments;
}
return null;
}
async function attemptSignUp() {
if (!await window.networkAPI.sendUcMessage(codeSignUp, userData)) return false;
const response = await waitForResponse();
if (response && response.operationCode === codeOk) {
return true;
}
await window.uiAPI.showAlert(`Signup failed: ${response?.metaInfo?.message || 'Unknown error'}`);
return false;
}
// Function to switch between steps
function switchStep(fromStep, toStep) {
fromStep.classList.remove('active'); // Fade out the current step
setTimeout(() => {
fromStep.style.display = 'none'; // Hide the current step after transition
toStep.style.display = 'flex'; // Ensure display is flex for the next step
setTimeout(() => {
toStep.classList.add('active'); // Fade in the next step
}, 20); // Small delay to allow display change before applying opacity
}, 500); // Transition duration (0.5s)
}