diff --git a/extension/bwcontest/src/SidebarProvider.ts b/extension/bwcontest/src/SidebarProvider.ts index 4631dfb..a6a4dbe 100644 --- a/extension/bwcontest/src/SidebarProvider.ts +++ b/extension/bwcontest/src/SidebarProvider.ts @@ -27,7 +27,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider { switch (data.type) { case 'onTestAndSubmit': { if (this._context) { - BWPanel.createOrShow(this._context?.extensionUri, this._context); + BWPanel.createOrShow(this._context); } break; } diff --git a/extension/bwcontest/src/extension.ts b/extension/bwcontest/src/extension.ts index fc1fd1a..b8a3fd5 100644 --- a/extension/bwcontest/src/extension.ts +++ b/extension/bwcontest/src/extension.ts @@ -98,7 +98,7 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand('bwcontest.helloWorld', () => { - BWPanel.createOrShow(context.extensionUri, context); + BWPanel.createOrShow(context); }) ); diff --git a/extension/bwcontest/src/problemPanel.ts b/extension/bwcontest/src/problemPanel.ts index ac4dffe..7e09e6c 100644 --- a/extension/bwcontest/src/problemPanel.ts +++ b/extension/bwcontest/src/problemPanel.ts @@ -3,6 +3,7 @@ import { getNonce } from './getNonce'; import { runJava } from './run/java'; import { extensionSettings } from './extension'; import { join } from 'path'; +import { submitProblem } from './submit'; export class BWPanel { /** @@ -17,7 +18,7 @@ export class BWPanel { private _disposables: vscode.Disposable[] = []; private static _context?: vscode.ExtensionContext; - public static createOrShow(extensionUri: vscode.Uri, context: vscode.ExtensionContext) { + public static createOrShow(context: vscode.ExtensionContext) { this._context = context; const column = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn @@ -26,7 +27,6 @@ export class BWPanel { // If we already have a panel, show it. if (BWPanel.currentPanel) { BWPanel.currentPanel._panel.reveal(column); - BWPanel.currentPanel._update(); return; } @@ -43,13 +43,13 @@ export class BWPanel { // And restrict the webview to only loading content from our extension's `media` directory. localResourceRoots: [ - vscode.Uri.joinPath(extensionUri, 'media'), - vscode.Uri.joinPath(extensionUri, 'out/compiled') + vscode.Uri.joinPath(context.extensionUri, 'media'), + vscode.Uri.joinPath(context.extensionUri, 'out/compiled') ] } ); - BWPanel.currentPanel = new BWPanel(panel, extensionUri); + BWPanel.currentPanel = new BWPanel(panel, context.extensionUri); } public static kill() { @@ -64,34 +64,13 @@ export class BWPanel { private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) { this._panel = panel; this._extensionUri = extensionUri; - - // Set the webview's initial html content this._update(); - - // Listen for when the panel is disposed - // This happens when the user closes the panel or when the panel is closed programatically this._panel.onDidDispose(() => this.dispose(), null, this._disposables); - - // // Handle messages from the webview - // this._panel.webview.onDidReceiveMessage( - // (message) => { - // switch (message.command) { - // case "alert": - // vscode.window.showErrorMessage(message.text); - // return; - // } - // }, - // null, - // this._disposables - // ); } public dispose() { BWPanel.currentPanel = undefined; - - // Clean up our resources this._panel.dispose(); - while (this._disposables.length) { const x = this._disposables.pop(); if (x) { @@ -106,12 +85,39 @@ export class BWPanel { this._panel.webview.html = this._getHtmlForWebview(webview); webview.onDidReceiveMessage(async (data) => { switch (data.type) { + case 'onSubmit': { + if (!data.value) { + return; + } + const ans = await vscode.window.showInformationMessage( + `Are you sure you want to submit ${data.value.problemName}?`, + 'Yes', + 'No' + ); + if (ans !== 'Yes') { + break; + } + try { + await submitProblem( + data.value.sessionToken, + data.value.contestId, + data.value.teamId, + data.value.problemId + ); + } catch (reason) { + vscode.window.showErrorMessage('Unable to submit'); + console.error(reason); + break; + } + vscode.window.showInformationMessage('Submitted!'); + break; + } case 'onRun': { if (!data.value) { return; } const repoDir = extensionSettings().repoClonePath; - const output = await runJava( + runJava( join( repoDir, 'BWContest', @@ -129,8 +135,9 @@ export class BWPanel { ), data.value.problemPascalName, data.value.input - ); - this._panel.webview.postMessage({ type: 'onOutput', value: output }); + ).then((output) => { + this._panel.webview.postMessage({ type: 'onOutput', value: output }); + }); break; } case 'onStartup': { diff --git a/extension/bwcontest/src/submit.ts b/extension/bwcontest/src/submit.ts new file mode 100644 index 0000000..614df6b --- /dev/null +++ b/extension/bwcontest/src/submit.ts @@ -0,0 +1,63 @@ +import { extensionSettings } from './extension'; +import { exec } from 'child_process'; +import util = require('node:util'); +import axios from 'axios'; + +const execPromise = util.promisify(exec); + +export async function submitProblem( + sessionToken: string, + contestId: number, + teamId: number, + problemId: number +) { + const repoClonePath = extensionSettings().repoClonePath; + console.log(repoClonePath); + + const clonedRepoPath = `${repoClonePath}/BWContest/${contestId.toString()}/${teamId.toString()}`; + + let output: { stdout: string; stderr: string }; + output = await execPromise(`git add .`, { + cwd: clonedRepoPath + }); + + if (output.stderr) { + console.error(output.stderr); + } + + output = await execPromise(`git commit -m "Submit problem ${problemId}"`, { + cwd: clonedRepoPath + }); + + if (output.stderr) { + console.error(output.stderr); + } + + output = await execPromise(`git push`, { + cwd: clonedRepoPath + }); + + if (output.stderr) { + console.error(output.stderr); + } + + output = await execPromise(`git rev-parse HEAD`, { + cwd: clonedRepoPath + }); + + if (output.stderr) { + console.error(output.stderr); + } + + const commitHash = output.stdout.toString().replace('\n', ''); + const res = await axios.post(`http://localhost:5173/api/team/${sessionToken}/submit`, { + commitHash: commitHash, + problemId: problemId + }); + if (res.status !== 200) { + throw Error('Failed to post submission'); + } + if (!res.data.success) { + throw Error('Submission post unsuccessful'); + } +} diff --git a/extension/bwcontest/webviews/components/ProblemPanel.svelte b/extension/bwcontest/webviews/components/ProblemPanel.svelte index 4c15cd2..04b14c0 100644 --- a/extension/bwcontest/webviews/components/ProblemPanel.svelte +++ b/extension/bwcontest/webviews/components/ProblemPanel.svelte @@ -55,6 +55,12 @@ } } + function onSubmit() { + if (teamId && contestId && sessionToken) { + postMessage({type: 'onSubmit', value: {sessionToken: sessionToken, contestId: contestId, teamId: teamId, problemId: activeProblem.id, problemName: activeProblem.pascalName}}) + } + } + async function fetchProblemData() { if (sessionToken) { const res = await fetch(`http://localhost:5173/api/contest/${sessionToken}`); @@ -122,6 +128,7 @@ + {/if}