System Components
Detailed breakdown of each system component.
Express Server (app.js)
The main backend server handles all HTTP requests.
Responsibilities
- Serve static files (HTML, CSS, JS)
- Handle code submissions
- Manage LTI authentication
- Serve starter code templates
Key Routes
javascript
// Static files
app.use(express.static('.'));
// Submit code to Gradescope
app.post('/submit', async (req, res) => { ... });
// Get starter code
app.get('/starter/:filename', (req, res) => { ... });
// LTI launch
app.post('/lti/launch', (req, res) => { ... });Configuration
Configured via environment variables:
PORT— Server portSECRET— Signing keyCOURSE_ID— Gradescope courseTOKEN,COOKIE— Gradescope credentials
Gradescope Module (gradescope.js)
Handles all Gradescope API communication.
Main Function
javascript
export async function submitAssg(code, course_id, stud_id, asg_id, file_name, token, cookie)Process
- Create Blob from code string
- Build FormData with file and CSRF token
- POST to Gradescope submission endpoint
- Parse response for submission URL
- Return result
Dependencies
- Native
fetchAPI FormDatafor multipart uploads
Code Editor (codemirror-demo.html)
The main student-facing interface.
Components
CodeMirror Editor
javascript
const editor = CodeMirror.fromTextArea(textarea, {
mode: "python",
theme: "material-darker",
lineNumbers: true,
indentUnit: 4
});Pyodide Runtime
javascript
const pyodide = await loadPyodide({
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.24.1/full/"
});Tab Navigation
Switches between Code and Output views in iframe mode.
Input Handler
Manages inline input() calls:
javascript
async function requestInlineInput(promptText) {
return new Promise((resolve) => {
inputArea.style.display = 'flex';
inputField.focus();
inputResolve = resolve;
});
}Event Handlers
| Button | Action |
|---|---|
| Run Code | Execute with Pyodide |
| Submit Code | POST to /submit |
| Clear | Reset editor |
| Help | Show help modal |
Starter Code System
Provides pre-filled code templates for assignments.
Server Endpoint
javascript
app.get('/starter/:filename', (req, res) => {
const filepath = path.join('starters', req.params.filename);
const code = fs.readFileSync(filepath, 'utf-8');
res.json({ code });
});Client Loading
javascript
async function loadStarterCode(filename) {
const res = await fetch('/starter/' + filename);
const data = await res.json();
editor.setValue(data.code);
}File Location
Starter files are stored in starters/ directory:
starters/
├── lab1_starter.py
├── lab2_starter.py
└── example.pyHelp System
Built-in help modal for students.
Components
- Help button (? icon)
- Modal overlay
- Sectioned content
Content Sections
- Navigation — How to use tabs
- Actions — What each button does
- Tips — Common issues and solutions
- Credits — Team information
Drag-to-Resize
Allows students to resize the editor in iframe mode.
Implementation
javascript
handle.addEventListener('mousedown', (e) => {
dragging = true;
startY = e.clientY;
startH = shell.offsetHeight;
});
document.addEventListener('mousemove', (e) => {
if (dragging) {
const newH = Math.min(maxH, Math.max(minH, startH + e.clientY - startY));
shell.style.height = newH + 'px';
}
});Constraints
- Minimum height: 200px
- Maximum height: 92% of viewport
- Default height: 420px
External Dependencies
CDN Resources
| Resource | Version | Purpose |
|---|---|---|
| CodeMirror | 5.65.16 | Code editor |
| Pyodide | 0.24.1 | Python runtime |
| Bootstrap | 5.3.3 | UI framework |
npm Packages
| Package | Purpose |
|---|---|
| express | Web server |
| dotenv | Environment variables |
| handlebars | Templates |
| node-html-parser | HTML parsing |