UNPKG

canvaslms-cli

Version:

A command line tool for interacting with Canvas LMS API

240 lines (201 loc) 9.65 kB
/** * Config command */ import { configExists, readConfig, saveConfig, deleteConfig, getConfigPath } from '../lib/config.js'; import { createReadlineInterface, askQuestion } from '../lib/interactive.js'; import chalk from 'chalk'; export async function showConfig() { console.log(chalk.cyan.bold('\n' + '-'.repeat(60))); console.log(chalk.cyan.bold('Canvas CLI Configuration')); console.log(chalk.cyan('-'.repeat(60))); const configPath = getConfigPath(); const hasConfig = configExists(); console.log(chalk.white('Configuration file: ') + configPath); console.log(chalk.white('Status: ') + (hasConfig ? chalk.green('Found') : chalk.red('Not found')) + '\n'); if (hasConfig) { const config = readConfig(); if (config) { console.log(chalk.cyan('Current configuration:')); console.log(chalk.white(' Canvas Domain: ') + (config.domain || 'Not set')); console.log(chalk.white(' API Token: ') + (config.token ? config.token.substring(0, 10) + '...' : 'Not set')); console.log(chalk.white(' Created: ') + (config.createdAt ? new Date(config.createdAt).toLocaleString() : 'Unknown')); console.log(chalk.white(' Last Updated: ') + (config.lastUpdated ? new Date(config.lastUpdated).toLocaleString() : 'Unknown')); } } else { console.log(chalk.yellow('No configuration found.')); } console.log(chalk.cyan('\nAvailable commands:')); console.log(chalk.white(' canvas config setup # Interactive setup wizard')); console.log(chalk.white(' canvas config edit # Edit existing configuration')); console.log(chalk.white(' canvas config show # Show current configuration')); console.log(chalk.white(' canvas config delete # Delete configuration file')); console.log(chalk.white(' canvas config path # Show configuration file path')); console.log(chalk.cyan('\nManual setup:')); console.log(chalk.white('1. Get your Canvas API token:')); console.log(chalk.white(' - Log into your Canvas instance')); console.log(chalk.white(' - Go to Account → Settings')); console.log(chalk.white(' - Scroll down to "Approved Integrations"')); console.log(chalk.white(' - Click "+ New Access Token"')); console.log(chalk.white(' - Copy the generated token')); console.log(chalk.white('2. Run "canvas config setup" to configure')); console.log(chalk.cyan('\nExample usage after setup:')); console.log(chalk.white(' canvas list # List starred courses')); console.log(chalk.white(' canvas list -a # List all enrolled courses')); console.log(chalk.white(' canvas submit # Interactive assignment submission')); console.log(chalk.white(' canvas profile # Show user profile')); console.log(chalk.white(' canvas assignments 12345 # Show assignments for course')); console.log(chalk.white(' canvas grades # Show grades for all courses')); } export async function setupConfig() { const rl = createReadlineInterface(); try { console.log(chalk.cyan.bold('\n' + '-'.repeat(60))); console.log(chalk.cyan.bold('Canvas CLI Configuration Setup')); console.log(chalk.cyan('-'.repeat(60))); // Check if config already exists if (configExists()) { const config = readConfig(); console.log(chalk.yellow('Existing configuration found:')); console.log(chalk.white(' Domain: ') + (config.domain || 'Not set')); console.log(chalk.white(' Token: ') + (config.token ? 'Set (hidden)' : 'Not set') + '\n'); const overwrite = await askQuestion(rl, 'Do you want to overwrite the existing configuration? (y/N): '); if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') { console.log(chalk.yellow('Setup cancelled.')); return; } console.log(''); } // Get Canvas domain const currentConfig = readConfig(); let domain = await askQuestion(rl, `Enter your Canvas domain${currentConfig?.domain ? ` (${currentConfig.domain})` : ''}: `); if (!domain && currentConfig?.domain) { domain = currentConfig.domain; } if (!domain) { console.log(chalk.red('Canvas domain is required.')); return; } // Validate and clean domain domain = domain.replace(/^https?:\/\//, '').replace(/\/$/, ''); if (!domain.includes('.')) { console.log(chalk.red('Invalid domain format. Please enter a valid domain (e.g., school.instructure.com)')); return; } console.log(chalk.green(`Domain set to: ${domain}\n`)); // Get API token const defaultToken = currentConfig?.token || ''; let token = await askQuestion(rl, `Enter your Canvas API token${defaultToken ? ' (press Enter to keep current)' : ''}: `); if (!token && defaultToken) { token = defaultToken; } if (!token) { console.log(chalk.red('Canvas API token is required.')); console.log(chalk.cyan('\nTo get your API token:')); console.log(chalk.white('1. Log into your Canvas instance')); console.log(chalk.white('2. Go to Account → Settings')); console.log(chalk.white('3. Scroll down to "Approved Integrations"')); console.log(chalk.white('4. Click "+ New Access Token"')); console.log(chalk.white('5. Copy the generated token')); return; } // Validate token format (basic check) if (token.length < 10) { console.log(chalk.red('API token seems too short. Please check your token.')); return; } console.log('Token received\n'); // Save configuration const saved = saveConfig(domain, token); if (saved) { console.log(chalk.green('Success: Configuration setup completed successfully!')); console.log(chalk.cyan('\nNext steps:')); console.log(chalk.white(' canvas list # Test your setup by listing courses')); console.log(chalk.white(' canvas profile # View your profile')); console.log(chalk.white(' canvas config show # View your configuration')); } } catch (error) { console.error(chalk.red('Error: Setup failed: ') + error.message); } finally { rl.close(); } } export async function editConfig() { const rl = createReadlineInterface(); try { if (!configExists()) { console.log('No configuration file found. Run "canvas config setup" first.'); return; } const config = readConfig(); console.log(chalk.cyan.bold('\n' + '-'.repeat(60))); console.log(chalk.cyan.bold('Edit Canvas CLI Configuration')); console.log(chalk.cyan('-'.repeat(60))); console.log(chalk.cyan('Current values:')); console.log(chalk.white(' Domain: ') + config.domain); console.log(chalk.white(' Token: ') + (config.token ? config.token.substring(0, 10) + '...' : 'Not set') + '\n'); // Edit domain const newDomain = await askQuestion(rl, `New Canvas domain (${config.domain}): `); const domain = newDomain.trim() || config.domain; // Edit token const changeToken = await askQuestion(rl, 'Change API token? (y/N): '); let token = config.token; if (changeToken.toLowerCase() === 'y' || changeToken.toLowerCase() === 'yes') { const newToken = await askQuestion(rl, 'New API token: '); if (newToken.trim()) { token = newToken.trim(); } } // Confirm changes console.log(chalk.cyan('New configuration:')); console.log(chalk.white(' Domain: ') + domain); console.log(chalk.white(' Token: ') + (token ? token.substring(0, 10) + '...' : 'Not set')); const confirm = await askQuestion(rl, '\nSave changes? (Y/n): '); if (confirm.toLowerCase() === 'n' || confirm.toLowerCase() === 'no') { console.log(chalk.yellow('Changes cancelled.')); return; } const saved = saveConfig(domain, token); if (saved) { console.log(chalk.green('Success: Configuration updated successfully!')); } } catch (error) { console.error(chalk.red('Error: Edit failed: ') + error.message); } finally { rl.close(); } } export function showConfigPath() { console.log(chalk.cyan('Configuration file location: ') + getConfigPath()); console.log(chalk.white('Exists: ') + (configExists() ? chalk.green('Yes') : chalk.red('No'))); } export function deleteConfigFile() { console.log(chalk.cyan.bold('\n' + '-'.repeat(60))); console.log(chalk.cyan.bold('Delete Configuration')); console.log(chalk.cyan('-'.repeat(60))); if (!configExists()) { console.log(chalk.yellow('No configuration file found.')); return; } const config = readConfig(); console.log(chalk.cyan('Current configuration:')); console.log(chalk.white(' Domain: ') + config.domain); console.log(chalk.white(' Token: ') + (config.token ? 'Set (hidden)' : 'Not set')); console.log(chalk.white(' File: ') + getConfigPath() + '\n'); // For safety, require explicit confirmation console.log(chalk.red('This will permanently delete your Canvas CLI configuration.')); console.log(chalk.yellow('You will need to run "canvas config setup" again to use the CLI.')); console.log(chalk.cyan('\nTo confirm deletion, type: DELETE')); const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question('Confirmation: ', (answer) => { if (answer === 'DELETE') { deleteConfig(); console.log(chalk.green('Success: Configuration deleted.')); } else { console.log(chalk.yellow('Deletion cancelled.')); } rl.close(); }); }