canvaslms-cli 1.3.3 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,242 +1,239 @@
1
- /**
2
- * Config command
3
- */
4
-
5
- const {
6
- configExists,
7
- readConfig,
8
- saveConfig,
9
- deleteConfig,
10
- getConfigPath
11
- } = require('../lib/config');
12
- const { createReadlineInterface, askQuestion } = require('../lib/interactive');
13
-
14
- async function showConfig() {
15
- console.log('šŸ“‹ Canvas CLI Configuration\n');
16
-
17
- const configPath = getConfigPath();
18
- const hasConfig = configExists();
19
-
20
- console.log(`Configuration file: ${configPath}`);
21
- console.log(`Status: ${hasConfig ? 'āœ… Found' : 'āŒ Not found'}\n`);
22
-
23
- if (hasConfig) {
24
- const config = readConfig();
25
- if (config) {
26
- console.log('Current configuration:');
27
- console.log(` 🌐 Canvas Domain: ${config.domain || 'Not set'}`);
28
- console.log(` šŸ”‘ API Token: ${config.token ? config.token.substring(0, 10) + '...' : 'Not set'}`);
29
- console.log(` šŸ“… Created: ${config.createdAt ? new Date(config.createdAt).toLocaleString() : 'Unknown'}`);
30
- console.log(` šŸ”„ Last Updated: ${config.lastUpdated ? new Date(config.lastUpdated).toLocaleString() : 'Unknown'}`);
31
- } } else {
32
- console.log('āŒ No configuration found.');
33
- }
34
-
35
- console.log('\nšŸ“š Available commands:');
36
- console.log(' canvas config setup # Interactive setup wizard');
37
- console.log(' canvas config edit # Edit existing configuration');
38
- console.log(' canvas config show # Show current configuration');
39
- console.log(' canvas config delete # Delete configuration file');
40
- console.log(' canvas config path # Show configuration file path');
41
-
42
- console.log('\nšŸ”§ Manual setup:');
43
- console.log('1. Get your Canvas API token:');
44
- console.log(' - Log into your Canvas instance');
45
- console.log(' - Go to Account → Settings');
46
- console.log(' - Scroll down to "Approved Integrations"');
47
- console.log(' - Click "+ New Access Token"');
48
- console.log(' - Copy the generated token');
49
- console.log('2. Run "canvas config setup" to configure');
50
-
51
- console.log('\nšŸ“– Example usage after setup:');
52
- console.log(' canvas list # List starred courses');
53
- console.log(' canvas list -a # List all enrolled courses');
54
- console.log(' canvas submit # Interactive assignment submission');
55
- console.log(' canvas profile # Show user profile');
56
- console.log(' canvas assignments 12345 # Show assignments for course');
57
- console.log(' canvas grades # Show grades for all courses');
58
- }
59
-
60
- async function setupConfig() {
61
- const rl = createReadlineInterface();
62
-
63
- try {
64
- console.log('šŸš€ Canvas CLI Configuration Setup\n');
65
-
66
- // Check if config already exists
67
- if (configExists()) {
68
- const config = readConfig();
69
- console.log('šŸ“‹ Existing configuration found:');
70
- console.log(` Domain: ${config.domain || 'Not set'}`);
71
- console.log(` Token: ${config.token ? 'Set (hidden)' : 'Not set'}\n`);
72
-
73
- const overwrite = await askQuestion(rl, 'Do you want to overwrite the existing configuration? (y/N): ');
74
- if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {
75
- console.log('Setup cancelled.');
76
- return;
77
- }
78
- console.log('');
79
- }
80
- // Get Canvas domain
81
- const currentConfig = readConfig();
82
- let domain = await askQuestion(rl, `Enter your Canvas domain${currentConfig?.domain ? ` (${currentConfig.domain})` : ''}: `);
83
- if (!domain && currentConfig?.domain) {
84
- domain = currentConfig.domain;
85
- }
86
-
87
- if (!domain) {
88
- console.log('āŒ Canvas domain is required.');
89
- return;
90
- }
91
-
92
- // Validate and clean domain
93
- domain = domain.replace(/^https?:\/\//, '').replace(/\/$/, '');
94
- if (!domain.includes('.')) {
95
- console.log('āŒ Invalid domain format. Please enter a valid domain (e.g., school.instructure.com)');
96
- return;
97
- }
98
-
99
- console.log(`āœ… Domain set to: ${domain}\n`);
100
- // Get API token
101
- const defaultToken = currentConfig?.token || '';
102
- let token = await askQuestion(rl, `Enter your Canvas API token${defaultToken ? ' (press Enter to keep current)' : ''}: `);
103
- if (!token && defaultToken) {
104
- token = defaultToken;
105
- }
106
-
107
- if (!token) {
108
- console.log('āŒ Canvas API token is required.');
109
- console.log('\nšŸ”‘ To get your API token:');
110
- console.log('1. Log into your Canvas instance');
111
- console.log('2. Go to Account → Settings');
112
- console.log('3. Scroll down to "Approved Integrations"');
113
- console.log('4. Click "+ New Access Token"');
114
- console.log('5. Copy the generated token');
115
- return;
116
- }
117
-
118
- // Validate token format (basic check)
119
- if (token.length < 10) {
120
- console.log('āŒ API token seems too short. Please check your token.');
121
- return;
122
- }
123
-
124
- console.log('āœ… Token received\n');
125
-
126
- // Save configuration
127
- const saved = saveConfig(domain, token);
128
- if (saved) {
129
- console.log('šŸŽ‰ Configuration setup completed successfully!');
130
- console.log('\nšŸ“ Next steps:');
131
- console.log(' canvas list # Test your setup by listing courses');
132
- console.log(' canvas profile # View your profile');
133
- console.log(' canvas config show # View your configuration');
134
- }
135
-
136
- } catch (error) {
137
- console.error(`āŒ Setup failed: ${error.message}`);
138
- } finally {
139
- rl.close();
140
- }
141
- }
142
-
143
- async function editConfig() {
144
- const rl = createReadlineInterface();
145
-
146
- try {
147
- if (!configExists()) {
148
- console.log('āŒ No configuration file found. Run "canvas config setup" first.');
149
- return;
150
- }
151
-
152
- const config = readConfig();
153
- console.log('āœļø Edit Canvas CLI Configuration\n');
154
- console.log('Current values:');
155
- console.log(` Domain: ${config.domain}`);
156
- console.log(` Token: ${config.token ? config.token.substring(0, 10) + '...' : 'Not set'}\n`);
157
-
158
- // Edit domain
159
- const newDomain = await askQuestion(rl, `New Canvas domain (${config.domain}): `);
160
- const domain = newDomain.trim() || config.domain;
161
-
162
- // Edit token
163
- const changeToken = await askQuestion(rl, 'Change API token? (y/N): ');
164
- let token = config.token;
165
-
166
- if (changeToken.toLowerCase() === 'y' || changeToken.toLowerCase() === 'yes') {
167
- const newToken = await askQuestion(rl, 'New API token: ');
168
- if (newToken.trim()) {
169
- token = newToken.trim();
170
- }
171
- }
172
-
173
- // Confirm changes
174
- console.log('\nšŸ“‹ New configuration:');
175
- console.log(` Domain: ${domain}`);
176
- console.log(` Token: ${token ? token.substring(0, 10) + '...' : 'Not set'}`);
177
-
178
- const confirm = await askQuestion(rl, '\nSave changes? (Y/n): ');
179
- if (confirm.toLowerCase() === 'n' || confirm.toLowerCase() === 'no') {
180
- console.log('Changes cancelled.');
181
- return;
182
- }
183
-
184
- const saved = saveConfig(domain, token);
185
- if (saved) {
186
- console.log('āœ… Configuration updated successfully!');
187
- }
188
-
189
- } catch (error) {
190
- console.error(`āŒ Edit failed: ${error.message}`);
191
- } finally {
192
- rl.close();
193
- }
194
- }
195
-
196
- function showConfigPath() {
197
- console.log(`šŸ“ Configuration file location: ${getConfigPath()}`);
198
- console.log(`šŸ“Š Exists: ${configExists() ? 'Yes' : 'No'}`);
199
- }
200
-
201
- function deleteConfigFile() {
202
- console.log('šŸ—‘ļø Delete Configuration\n');
203
-
204
- if (!configExists()) {
205
- console.log('āŒ No configuration file found.');
206
- return;
207
- }
208
-
209
- const config = readConfig();
210
- console.log('Current configuration:');
211
- console.log(` Domain: ${config.domain}`);
212
- console.log(` Token: ${config.token ? 'Set (hidden)' : 'Not set'}`);
213
- console.log(` File: ${getConfigPath()}\n`);
214
-
215
- // For safety, require explicit confirmation
216
- console.log('āš ļø This will permanently delete your Canvas CLI configuration.');
217
- console.log('You will need to run "canvas config setup" again to use the CLI.');
218
- console.log('\nTo confirm deletion, type: DELETE');
219
-
220
- const readline = require('readline');
221
- const rl = readline.createInterface({
222
- input: process.stdin,
223
- output: process.stdout
224
- });
225
-
226
- rl.question('Confirmation: ', (answer) => {
227
- if (answer === 'DELETE') {
228
- deleteConfig();
229
- } else {
230
- console.log('Deletion cancelled.');
231
- }
232
- rl.close();
233
- });
234
- }
235
-
236
- module.exports = {
237
- showConfig,
238
- setupConfig,
239
- editConfig,
240
- showConfigPath,
241
- deleteConfigFile
242
- };
1
+ /**
2
+ * Config command
3
+ */
4
+
5
+ import { configExists, readConfig, saveConfig, deleteConfig, getConfigPath } from '../lib/config.js';
6
+ import { createReadlineInterface, askQuestion } from '../lib/interactive.js';
7
+ import chalk from 'chalk';
8
+
9
+ export async function showConfig() {
10
+ console.log(chalk.cyan.bold('\n' + '-'.repeat(60)));
11
+ console.log(chalk.cyan.bold('Canvas CLI Configuration'));
12
+ console.log(chalk.cyan('-'.repeat(60)));
13
+
14
+ const configPath = getConfigPath();
15
+ const hasConfig = configExists();
16
+
17
+ console.log(chalk.white('Configuration file: ') + configPath);
18
+ console.log(chalk.white('Status: ') + (hasConfig ? chalk.green('Found') : chalk.red('Not found')) + '\n');
19
+
20
+ if (hasConfig) {
21
+ const config = readConfig();
22
+ if (config) {
23
+ console.log(chalk.cyan('Current configuration:'));
24
+ console.log(chalk.white(' Canvas Domain: ') + (config.domain || 'Not set'));
25
+ console.log(chalk.white(' API Token: ') + (config.token ? config.token.substring(0, 10) + '...' : 'Not set'));
26
+ console.log(chalk.white(' Created: ') + (config.createdAt ? new Date(config.createdAt).toLocaleString() : 'Unknown'));
27
+ console.log(chalk.white(' Last Updated: ') + (config.lastUpdated ? new Date(config.lastUpdated).toLocaleString() : 'Unknown'));
28
+ } } else {
29
+ console.log(chalk.yellow('No configuration found.'));
30
+ }
31
+
32
+ console.log(chalk.cyan('\nAvailable commands:'));
33
+ console.log(chalk.white(' canvas config setup # Interactive setup wizard'));
34
+ console.log(chalk.white(' canvas config edit # Edit existing configuration'));
35
+ console.log(chalk.white(' canvas config show # Show current configuration'));
36
+ console.log(chalk.white(' canvas config delete # Delete configuration file'));
37
+ console.log(chalk.white(' canvas config path # Show configuration file path'));
38
+
39
+ console.log(chalk.cyan('\nManual setup:'));
40
+ console.log(chalk.white('1. Get your Canvas API token:'));
41
+ console.log(chalk.white(' - Log into your Canvas instance'));
42
+ console.log(chalk.white(' - Go to Account → Settings'));
43
+ console.log(chalk.white(' - Scroll down to "Approved Integrations"'));
44
+ console.log(chalk.white(' - Click "+ New Access Token"'));
45
+ console.log(chalk.white(' - Copy the generated token'));
46
+ console.log(chalk.white('2. Run "canvas config setup" to configure'));
47
+
48
+ console.log(chalk.cyan('\nExample usage after setup:'));
49
+ console.log(chalk.white(' canvas list # List starred courses'));
50
+ console.log(chalk.white(' canvas list -a # List all enrolled courses'));
51
+ console.log(chalk.white(' canvas submit # Interactive assignment submission'));
52
+ console.log(chalk.white(' canvas profile # Show user profile'));
53
+ console.log(chalk.white(' canvas assignments 12345 # Show assignments for course'));
54
+ console.log(chalk.white(' canvas grades # Show grades for all courses'));
55
+ }
56
+
57
+ export async function setupConfig() {
58
+ const rl = createReadlineInterface();
59
+
60
+ try {
61
+ console.log(chalk.cyan.bold('\n' + '-'.repeat(60)));
62
+ console.log(chalk.cyan.bold('Canvas CLI Configuration Setup'));
63
+ console.log(chalk.cyan('-'.repeat(60)));
64
+
65
+ // Check if config already exists
66
+ if (configExists()) {
67
+ const config = readConfig();
68
+ console.log(chalk.yellow('Existing configuration found:'));
69
+ console.log(chalk.white(' Domain: ') + (config.domain || 'Not set'));
70
+ console.log(chalk.white(' Token: ') + (config.token ? 'Set (hidden)' : 'Not set') + '\n');
71
+
72
+ const overwrite = await askQuestion(rl, 'Do you want to overwrite the existing configuration? (y/N): ');
73
+ if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {
74
+ console.log(chalk.yellow('Setup cancelled.'));
75
+ return;
76
+ }
77
+ console.log('');
78
+ }
79
+ // Get Canvas domain
80
+ const currentConfig = readConfig();
81
+ let domain = await askQuestion(rl, `Enter your Canvas domain${currentConfig?.domain ? ` (${currentConfig.domain})` : ''}: `);
82
+ if (!domain && currentConfig?.domain) {
83
+ domain = currentConfig.domain;
84
+ }
85
+
86
+ if (!domain) {
87
+ console.log(chalk.red('Canvas domain is required.'));
88
+ return;
89
+ }
90
+
91
+ // Validate and clean domain
92
+ domain = domain.replace(/^https?:\/\//, '').replace(/\/$/, '');
93
+ if (!domain.includes('.')) {
94
+ console.log(chalk.red('Invalid domain format. Please enter a valid domain (e.g., school.instructure.com)'));
95
+ return;
96
+ }
97
+
98
+ console.log(chalk.green(`Domain set to: ${domain}\n`));
99
+ // Get API token
100
+ const defaultToken = currentConfig?.token || '';
101
+ let token = await askQuestion(rl, `Enter your Canvas API token${defaultToken ? ' (press Enter to keep current)' : ''}: `);
102
+ if (!token && defaultToken) {
103
+ token = defaultToken;
104
+ }
105
+
106
+ if (!token) {
107
+ console.log(chalk.red('Canvas API token is required.'));
108
+ console.log(chalk.cyan('\nTo get your API token:'));
109
+ console.log(chalk.white('1. Log into your Canvas instance'));
110
+ console.log(chalk.white('2. Go to Account → Settings'));
111
+ console.log(chalk.white('3. Scroll down to "Approved Integrations"'));
112
+ console.log(chalk.white('4. Click "+ New Access Token"'));
113
+ console.log(chalk.white('5. Copy the generated token'));
114
+ return;
115
+ }
116
+
117
+ // Validate token format (basic check)
118
+ if (token.length < 10) {
119
+ console.log(chalk.red('API token seems too short. Please check your token.'));
120
+ return;
121
+ }
122
+
123
+ console.log('Token received\n');
124
+
125
+ // Save configuration
126
+ const saved = saveConfig(domain, token);
127
+ if (saved) {
128
+ console.log(chalk.green('Success: Configuration setup completed successfully!'));
129
+ console.log(chalk.cyan('\nNext steps:'));
130
+ console.log(chalk.white(' canvas list # Test your setup by listing courses'));
131
+ console.log(chalk.white(' canvas profile # View your profile'));
132
+ console.log(chalk.white(' canvas config show # View your configuration'));
133
+ }
134
+
135
+ } catch (error) {
136
+ console.error(chalk.red('Error: Setup failed: ') + error.message);
137
+ } finally {
138
+ rl.close();
139
+ }
140
+ }
141
+
142
+ export async function editConfig() {
143
+ const rl = createReadlineInterface();
144
+
145
+ try {
146
+ if (!configExists()) {
147
+ console.log('No configuration file found. Run "canvas config setup" first.');
148
+ return;
149
+ }
150
+
151
+ const config = readConfig();
152
+ console.log(chalk.cyan.bold('\n' + '-'.repeat(60)));
153
+ console.log(chalk.cyan.bold('Edit Canvas CLI Configuration'));
154
+ console.log(chalk.cyan('-'.repeat(60)));
155
+ console.log(chalk.cyan('Current values:'));
156
+ console.log(chalk.white(' Domain: ') + config.domain);
157
+ console.log(chalk.white(' Token: ') + (config.token ? config.token.substring(0, 10) + '...' : 'Not set') + '\n');
158
+
159
+ // Edit domain
160
+ const newDomain = await askQuestion(rl, `New Canvas domain (${config.domain}): `);
161
+ const domain = newDomain.trim() || config.domain;
162
+
163
+ // Edit token
164
+ const changeToken = await askQuestion(rl, 'Change API token? (y/N): ');
165
+ let token = config.token;
166
+
167
+ if (changeToken.toLowerCase() === 'y' || changeToken.toLowerCase() === 'yes') {
168
+ const newToken = await askQuestion(rl, 'New API token: ');
169
+ if (newToken.trim()) {
170
+ token = newToken.trim();
171
+ }
172
+ }
173
+
174
+ // Confirm changes
175
+ console.log(chalk.cyan('New configuration:'));
176
+ console.log(chalk.white(' Domain: ') + domain);
177
+ console.log(chalk.white(' Token: ') + (token ? token.substring(0, 10) + '...' : 'Not set'));
178
+
179
+ const confirm = await askQuestion(rl, '\nSave changes? (Y/n): ');
180
+ if (confirm.toLowerCase() === 'n' || confirm.toLowerCase() === 'no') {
181
+ console.log(chalk.yellow('Changes cancelled.'));
182
+ return;
183
+ }
184
+
185
+ const saved = saveConfig(domain, token);
186
+ if (saved) {
187
+ console.log(chalk.green('Success: Configuration updated successfully!'));
188
+ }
189
+
190
+ } catch (error) {
191
+ console.error(chalk.red('Error: Edit failed: ') + error.message);
192
+ } finally {
193
+ rl.close();
194
+ }
195
+ }
196
+
197
+ export function showConfigPath() {
198
+ console.log(chalk.cyan('Configuration file location: ') + getConfigPath());
199
+ console.log(chalk.white('Exists: ') + (configExists() ? chalk.green('Yes') : chalk.red('No')));
200
+ }
201
+
202
+ export function deleteConfigFile() {
203
+ console.log(chalk.cyan.bold('\n' + '-'.repeat(60)));
204
+ console.log(chalk.cyan.bold('Delete Configuration'));
205
+ console.log(chalk.cyan('-'.repeat(60)));
206
+
207
+ if (!configExists()) {
208
+ console.log(chalk.yellow('No configuration file found.'));
209
+ return;
210
+ }
211
+
212
+ const config = readConfig();
213
+ console.log(chalk.cyan('Current configuration:'));
214
+ console.log(chalk.white(' Domain: ') + config.domain);
215
+ console.log(chalk.white(' Token: ') + (config.token ? 'Set (hidden)' : 'Not set'));
216
+ console.log(chalk.white(' File: ') + getConfigPath() + '\n');
217
+
218
+ // For safety, require explicit confirmation
219
+ console.log(chalk.red('This will permanently delete your Canvas CLI configuration.'));
220
+ console.log(chalk.yellow('You will need to run "canvas config setup" again to use the CLI.'));
221
+ console.log(chalk.cyan('\nTo confirm deletion, type: DELETE'));
222
+
223
+ const readline = require('readline');
224
+ const rl = readline.createInterface({
225
+ input: process.stdin,
226
+ output: process.stdout
227
+ });
228
+
229
+ rl.question('Confirmation: ', (answer) => {
230
+ if (answer === 'DELETE') {
231
+ deleteConfig();
232
+ console.log(chalk.green('Success: Configuration deleted.'));
233
+ } else {
234
+ console.log(chalk.yellow('Deletion cancelled.'));
235
+ }
236
+ rl.close();
237
+ });
238
+ }
239
+