diff --git a/FolderManagement.gs b/FolderManagement.gs new file mode 100644 index 0000000..cd0f1a7 --- /dev/null +++ b/FolderManagement.gs @@ -0,0 +1,39 @@ +/** + * Folder Management Library + * Handles creation and management of student folders with company ID support + */ + +/** + * Creates folder manager instance + */ +function createFolderManager(config) { + return { + createStudentFolders: function(studentData) { + const results = {}; + + try { + // Format student identifiers + const formattedId = studentData.studentId.toString().padStart(4, '0'); + const formattedName = studentData.name.toLowerCase().replace(/\s+/g, '_'); + const folderName = `${studentData.companyId}+${formattedId}+${formattedName}`; + + // Create main folder structure + const companyFolder = DriveApp.getFolderById(config.COMPANIES_ROOT_ID); + const mainFolder = companyFolder.createFolder(folderName); + results.mainFolderId = mainFolder.getId(); + + // Create subfolders + const subfolders = ['slides', 'forms', 'sheets', 'docs', 'drive', 'gmail']; + subfolders.forEach(subfolder => { + const newFolder = mainFolder.createFolder(subfolder); + results[`${subfolder}FolderId`] = newFolder.getId(); + }); + + return results; + + } catch (error) { + throw new Error(`Failed to create folders: ${error.message}`); + } + } + }; +} diff --git a/LogsManagement.gs b/LogsManagement.gs new file mode 100644 index 0000000..79ba167 --- /dev/null +++ b/LogsManagement.gs @@ -0,0 +1,65 @@ +/** + * Logs Management Library + * Handles logging of operations with company ID support + */ + +/** + * Creates logs manager instance + */ +function createLogsManager(config) { + return { + logSuccess: function(studentData, folderIds, spreadsheetId) { + try { + const spreadsheet = SpreadsheetApp.openById(config.CONTROL_SPREADSHEET_ID); + const sheet = spreadsheet.getActiveSheet(); + + const formattedId = studentData.studentId.toString().padStart(4, '0'); + const formattedName = studentData.name.toLowerCase().replace(/\s+/g, '_'); + + const row = [ + new Date(), + studentData.companyId, + formattedId, + formattedName, + studentData.email, + studentData.batch, + folderIds.mainFolderId, + spreadsheetId, + 'Success' + ]; + + sheet.appendRow(row); + + } catch (error) { + console.error(`Failed to log success: ${error.message}`); + } + }, + + logError: function(studentData, error) { + try { + const spreadsheet = SpreadsheetApp.openById(config.CONTROL_SPREADSHEET_ID); + const sheet = spreadsheet.getActiveSheet(); + + const formattedId = studentData.studentId.toString().padStart(4, '0'); + const formattedName = studentData.name.toLowerCase().replace(/\s+/g, '_'); + + const row = [ + new Date(), + studentData.companyId, + formattedId, + formattedName, + studentData.email, + studentData.batch, + '', + '', + `Error: ${error.message}` + ]; + + sheet.appendRow(row); + + } catch (logError) { + console.error(`Failed to log error: ${logError.message}`); + } + } + }; +} diff --git a/SpreadsheetManagement.gs b/SpreadsheetManagement.gs new file mode 100644 index 0000000..ee213a1 --- /dev/null +++ b/SpreadsheetManagement.gs @@ -0,0 +1,38 @@ +/** + * Spreadsheet Management Library + * Handles creation and management of student spreadsheets with company ID support + */ + +/** + * Creates spreadsheet manager instance + */ +function createSpreadsheetManager(config) { + return { + createStudentSpreadsheet: function(studentData) { + try { + // Format student identifiers + const formattedId = studentData.studentId.toString().padStart(4, '0'); + const formattedName = studentData.name.toLowerCase().replace(/\s+/g, '_'); + const spreadsheetName = `${studentData.companyId}+${formattedId}+${formattedName}_scores`; + + // Create spreadsheet in company admin folder + const folder = DriveApp.getFolderById(config.COMPANY_ADMIN_ID); + const spreadsheet = SpreadsheetApp.create(spreadsheetName); + const file = DriveApp.getFileById(spreadsheet.getId()); + + // Move to correct folder + file.moveTo(folder); + + // Set up initial structure + const sheet = spreadsheet.getActiveSheet(); + sheet.setName('Scores'); + sheet.getRange('A1:D1').setValues([['Task', 'Score', 'Date', 'Comments']]); + + return spreadsheet.getId(); + + } catch (error) { + throw new Error(`Failed to create spreadsheet: ${error.message}`); + } + } + }; +} diff --git a/TaskSharingManagement.gs b/TaskSharingManagement.gs new file mode 100644 index 0000000..90960c3 --- /dev/null +++ b/TaskSharingManagement.gs @@ -0,0 +1,47 @@ +/** + * Task Sharing Management Library + * Handles task assignments and permissions with company ID support + */ + +/** + * Creates task manager instance + */ +function createTaskManager(config) { + return { + setupStudentTasks: function(studentData, folderIds) { + try { + // Validate company ID format + if (!config.COMPANY_ID_REGEX.test(studentData.companyId)) { + throw new Error('Invalid company ID format'); + } + + // Format student identifiers + const formattedId = studentData.studentId.toString().padStart(4, '0'); + const formattedName = studentData.name.toLowerCase().replace(/\s+/g, '_'); + + // Set permissions on folders + Object.values(folderIds).forEach(folderId => { + const folder = DriveApp.getFolderById(folderId); + folder.addEditor(studentData.email); + }); + + // Copy and share task templates + const taskFolder = DriveApp.getFolderById(config.TASK_PDFS_ID); + const targetFolder = DriveApp.getFolderById(folderIds.mainFolderId); + + const files = taskFolder.getFiles(); + while (files.hasNext()) { + const file = files.next(); + const newFile = file.makeCopy(targetFolder); + newFile.setName(`${studentData.companyId}+${formattedId}+${file.getName()}`); + newFile.addViewer(studentData.email); + } + + return true; + + } catch (error) { + throw new Error(`Failed to setup tasks: ${error.message}`); + } + } + }; +} diff --git a/main.gs b/main.gs new file mode 100644 index 0000000..0b32b94 --- /dev/null +++ b/main.gs @@ -0,0 +1,188 @@ +/** + * Main configuration and setup script + */ + +const CONFIG = { + // Company Information + COMPANY_NAME: 'Example Company', + COMPANY_ID: 'C001', // Company ID in C### format + COMPANY_ID_REGEX: /^C\d{3}$/, // Validation pattern for company IDs + + // Root folder IDs + TRAINING_ROOT_ID: '1XkaQRv7rwmM36QpFEzz5e_t6E5j3xG68', + COMPANIES_ROOT_ID: '19ilsru6jV9Oj9Vv5OJzwj9SWTWjci0yZ', + + // Company specific folder IDs + COMPANY_ADMIN_ID: '1csCqCxGa-8Res896uYsKKjVBOEP_ZSQJ', + TRAINER_ADMIN_ID: '1qynN7ZRDttPaaaN-jOHwGg7Q0vaHgFrO', + + // Assignment folders + ASSIGNMENT_MASTER_ID: '1iEi0ApNrECvCJJBFxPPthcXFv6mjUiww', + TASK_PDFS_ID: '17qKubT2cmTsdwyFJPEz9tRaEzqqAEb0J', + TASK_RAW_DATA_ID: '1DJgwKVLx8aBbEqVkVvH6qcPlloZsw_n8', + + // Spreadsheet IDs + STUDENT_DATABASE_ID: '1UDOOKV4pUlyKOHfwmyCq-AN31ryWAj9GHIokfZ_0swI', + CONTROL_SPREADSHEET_ID: '1yH_242vGvkM3vVmQK4SB-gizmEBgXMzMUb6TB-1BkKo' +}; + +/** + * Creates menu when spreadsheet opens + */ +function onOpen() { + const ui = SpreadsheetApp.getUi(); + ui.createMenu('Training Setup') + .addItem('Initialize Setup', 'initializeSetup') + .addItem('Create Student Resources', 'createStudentResources') + .addToUi(); +} + +/** + * Initializes the setup by checking core requirements + */ +function initializeSetup() { + const results = []; + const errors = []; + + try { + // Verify we're running from a shared drive + const activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet(); + const file = DriveApp.getFileById(activeSpreadsheet.getId()); + const parents = file.getParents(); + + if (!parents.hasNext() || !parents.next().isShareableByEditors()) { + throw new Error('This script must be run from a shared drive'); + } + + // Verify company name and ID are set + if (!CONFIG.COMPANY_NAME) { + throw new Error('Company name must be set in CONFIG'); + } + if (!CONFIG.COMPANY_ID || !CONFIG.COMPANY_ID_REGEX.test(CONFIG.COMPANY_ID)) { + throw new Error('Company ID must be set in CONFIG and match pattern C### (e.g., C001)'); + } + + // Verify critical folders exist + verifyFolderExists('Training Root', CONFIG.TRAINING_ROOT_ID, results, errors); + verifyFolderExists('Company Admin', CONFIG.COMPANY_ADMIN_ID, results, errors); + verifyFolderExists('Trainer Admin', CONFIG.TRAINER_ADMIN_ID, results, errors); + verifyFolderExists('Assignment Master', CONFIG.ASSIGNMENT_MASTER_ID, results, errors); + verifyFolderExists('Task PDFs', CONFIG.TASK_PDFS_ID, results, errors); + verifyFolderExists('Task Raw Data', CONFIG.TASK_RAW_DATA_ID, results, errors); + + // Verify spreadsheets + verifySpreadsheetExists('Student Database', CONFIG.STUDENT_DATABASE_ID, results, errors); + verifySpreadsheetExists('Control Spreadsheet', CONFIG.CONTROL_SPREADSHEET_ID, results, errors); + + displayResults('Setup Initialization', results, errors); + return errors.length === 0; + + } catch (error) { + errors.push(`Setup failed: ${error.toString()}`); + displayResults('Setup Failed', results, errors); + return false; + } +} + +/** + * Creates student resources based on database entries + */ +function createStudentResources() { + const results = []; + const errors = []; + + try { + // Initialize managers + const folderManager = createFolderManager(CONFIG); + const spreadsheetManager = createSpreadsheetManager(CONFIG); + const taskManager = createTaskManager(CONFIG); + const logsManager = createLogsManager(CONFIG); + + // Get student data from database + const studentData = getStudentData(); + + // Process each student + studentData.forEach(student => { + try { + // Create folders and resources + const folderIds = folderManager.createStudentFolders(student); + const spreadsheetId = spreadsheetManager.createStudentSpreadsheet(student); + const taskSetup = taskManager.setupStudentTasks(student, folderIds); + + // Log successful creation + logsManager.logSuccess(student, folderIds, spreadsheetId); + results.push(`✓ Created resources for ${student.name}`); + + } catch (error) { + errors.push(`Failed to process student ${student.name}: ${error.toString()}`); + logsManager.logError(student, error); + } + }); + + displayResults('Resource Creation', results, errors); + + } catch (error) { + errors.push(`Setup failed: ${error.toString()}`); + displayResults('Setup Failed', results, errors); + } +} + +/** + * Gets student data from database spreadsheet + */ +function getStudentData() { + const spreadsheet = SpreadsheetApp.openById(CONFIG.STUDENT_DATABASE_ID); + const sheet = spreadsheet.getActiveSheet(); + const data = sheet.getDataRange().getValues(); + + // Remove header row and map to student objects + return data.slice(1).map(row => ({ + companyId: CONFIG.COMPANY_ID, + studentId: row[0], + name: row[1], + email: row[2], + batch: row[3] + })); +} + +/** + * Utility function to verify folder exists and is accessible + */ +function verifyFolderExists(name, id, results, errors) { + try { + DriveApp.getFolderById(id); + results.push(`✓ ${name} folder is accessible`); + } catch (error) { + errors.push(`❌ Cannot access ${name} folder: ${error.toString()}`); + } +} + +/** + * Utility function to verify spreadsheet exists and is accessible + */ +function verifySpreadsheetExists(name, id, results, errors) { + try { + SpreadsheetApp.openById(id); + results.push(`✓ ${name} spreadsheet is accessible`); + } catch (error) { + errors.push(`❌ Cannot access ${name} spreadsheet: ${error.toString()}`); + } +} + +/** + * Displays results in UI + */ +function displayResults(title, results, errors) { + const ui = SpreadsheetApp.getUi(); + let message = '📋 Results:\n\n'; + + if (results.length > 0) { + message += '✅ Completed Successfully:\n' + results.join('\n') + '\n\n'; + } + + if (errors.length > 0) { + message += '❌ Issues Found:\n' + errors.join('\n'); + } + + ui.alert(title, message, ui.ButtonSet.OK); +}