Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions LICENSE-THIRD-PARTY.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
Third Party Licenses
====================
# Third Party Licenses

While Submitty VSCode is made available under the [BSD "3-Clause" License](https://github.com/Submitty/Submitty-VSCode/blob/master/LICENSE.md)
While Submitty VSCode is made available under the [BSD "3-Clause" License](https://github.com/Submitty/Submitty-VSCode/blob/master/LICENSE.md)
we utilize several third-party libraries to help power various components. Below is a list of these components and their relevant copyrights, copied when the source was included/last updated within Submitty.


| Component | Copyright | Url | License |
|--------------|----------------------------------------------------------------------|-----|---------|
| vscode-git | Copyright (c) Microsoft Corporation. All rights reserved. | https://code.visualstudio.com | [MIT License](https://github.com/microsoft/vscode/blob/main/LICENSE.txt) |
| Component | Copyright | Url | License |
| ---------- | --------------------------------------------------------- | ----------------------------- | ------------------------------------------------------------------------ |
| vscode-git | Copyright (c) Microsoft Corporation. All rights reserved. | https://code.visualstudio.com | [MIT License](https://github.com/microsoft/vscode/blob/main/LICENSE.txt) |
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 54 additions & 12 deletions src/services/apiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,27 @@ export class ApiService {
this.client = new ApiClient(apiBaseUrl);
}

// set token for local api client
/**
* Sets the authorization token for the API client.
* @param token - The bearer token for authenticated requests
*/
setAuthorizationToken(token: string): void {
this.client.setToken(token);
}

// set base URL for local api client
/**
* Sets the base URL for the API client.
* @param baseUrl - The base URL of the Submitty API
*/
setBaseUrl(baseUrl: string): void {
this.client.setBaseURL(baseUrl);
}

/**
* Login to the Submitty API
* Logs in to the Submitty API and returns an auth token.
* @param userId - The user ID
* @param password - The user password
* @returns The authentication token
*/
async login(userId: string, password: string): Promise<string> {
try {
Expand All @@ -71,6 +80,10 @@ export class ApiService {
}
}

/**
* Fetches the current authenticated user's profile from the API.
* @returns The current user data
*/
async fetchMe(): Promise<any> {
try {
const response = await this.client.get<any>('/api/me');
Expand All @@ -83,20 +96,26 @@ export class ApiService {
}

/**
* Fetch all courses for the authenticated user
* Fetches all courses for the authenticated user.
* @returns The course list response
*/
async fetchCourses(_token?: string): Promise<CourseResponse> {
async fetchCourses(): Promise<CourseResponse> {
try {
const response = await this.client.get<CourseResponse>('/api/courses');
return response.data;
} catch (error: unknown) {
console.error('Error fetching courses:', error);
} catch (error: any) {
throw new Error(getErrorMessage(error, 'Failed to fetch courses.'), {
cause: error,
});
}
}

/**
* Fetches all gradeables for a specific course.
* @param courseId - The course ID
* @param term - The term (e.g. "s24")
* @returns The gradeable list response
*/
async fetchGradables(
courseId: string,
term: string
Expand All @@ -114,7 +133,11 @@ export class ApiService {
}

/**
* Fetch grade details for a specific homework assignment
* Fetches grade details for a specific homework assignment.
* @param term - The term (e.g. "s24")
* @param courseId - The course ID
* @param gradeableId - The gradeable/assignment ID
* @returns The autograder details including test cases
*/
async fetchGradeDetails(
term: string,
Expand All @@ -136,9 +159,11 @@ export class ApiService {
}

/**
* Poll fetchGradeDetails until autograding_complete is true and test_cases has data.
* @param intervalMs Delay between requests (default 2000)
* @param timeoutMs Stop after this many ms (default 300000 = 5 min); 0 = no timeout
* Polls fetchGradeDetails until autograding is complete and test cases are available.
* @param term - The term (e.g. "s24")
* @param courseId - The course ID
* @param gradeableId - The gradeable/assignment ID
* @param options - Optional polling config: intervalMs (default 2000), timeoutMs (default 300000), token (cancellation)
* @returns The final AutoGraderDetails with complete data
*/
async pollGradeDetailsUntilComplete(
Expand Down Expand Up @@ -178,6 +203,13 @@ export class ApiService {
}
}

/**
* Submits a VCS (version control) gradable to trigger autograding.
* @param term - The term (e.g. "s24")
* @param courseId - The course ID
* @param gradeableId - The gradeable/assignment ID
* @returns The upload response
*/
async submitVCSGradable(
term: string,
courseId: string,
Expand All @@ -200,7 +232,11 @@ export class ApiService {
}

/**
* Fetch previous attempts for a specific homework assignment
* Fetches previous submission attempts for a specific homework assignment.
* @param term - The term (e.g. "s24")
* @param courseId - The course ID
* @param gradeableId - The gradeable/assignment ID
* @returns The list of previous attempts
*/
async fetchPreviousAttempts(
term: string,
Expand All @@ -220,6 +256,12 @@ export class ApiService {
}
}

/**
* Returns the singleton ApiService instance, creating it if necessary.
* @param context - The extension context
* @param apiBaseUrl - The base URL of the Submitty API
* @returns The ApiService instance
*/
static getInstance(
context: vscode.ExtensionContext,
apiBaseUrl: string
Expand Down
2 changes: 1 addition & 1 deletion src/services/courseRepoResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class CourseRepoResolver {
this.apiService.setAuthorizationToken(token);

// Fetch courses and match based on whether their (term, courseId) strings appear in remote URLs.
const coursesResponse = await this.apiService.fetchCourses(token);
const coursesResponse = await this.apiService.fetchCourses();
const courses = coursesResponse.data.unarchived_courses;

const remoteText = remoteUrls.join(' ');
Expand Down
84 changes: 0 additions & 84 deletions src/sidebar/login.html

This file was deleted.

10 changes: 0 additions & 10 deletions src/sidebarContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@ import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';

export function getLoginHtml(context: vscode.ExtensionContext): string {
const filePath = path.join(
context.extensionPath,
'src',
'sidebar',
'login.html'
);
return fs.readFileSync(filePath, 'utf8');
}

export function getClassesHtml(context: vscode.ExtensionContext): string {
const filePath = path.join(
context.extensionPath,
Expand Down
15 changes: 3 additions & 12 deletions src/sidebarProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,8 @@ export class SidebarProvider implements vscode.WebviewViewProvider {

this.isLoadingCourses = true;
try {
const token = await this.authService.getAuthorizationToken();
if (!token) {
return;
}

this._view.webview.html = getClassesHtml(this.context);
await this.fetchAndDisplayCourses(token, this._view);
await this.fetchAndDisplayCourses(this._view);
} catch (error: unknown) {
const err = error instanceof Error ? error.message : String(error);
console.error('Failed to load courses:', error);
Expand All @@ -106,10 +101,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
switch (msg.command) {
case MessageCommand.FETCH_AND_DISPLAY_COURSES:
try {
const token = await this.authService.getAuthorizationToken();
if (token) {
await this.fetchAndDisplayCourses(token, view);
}
await this.fetchAndDisplayCourses(view);
} catch (error: unknown) {
const err = error instanceof Error ? error.message : String(error);
console.error('Failed to fetch and display courses:', error);
Expand Down Expand Up @@ -157,11 +149,10 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
}

private async fetchAndDisplayCourses(
token: string,
view: vscode.WebviewView
): Promise<void> {
try {
const courses = await this.apiService.fetchCourses(token);
const courses = await this.apiService.fetchCourses();
const unarchived = courses.data.unarchived_courses;

const coursesWithGradables = await Promise.all(
Expand Down
Loading