diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bdeaa4..dd9a1c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,24 +48,3 @@ jobs: - name: VSCE Packge run: npx vsce package - - darwin: - name: macOS - runs-on: macos-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v2 - - - name: Setup Node.js environment - uses: actions/setup-node@v2 - with: - node-version: 14 - - - name: Install Node.js modules - run: npm install - - - name: Lint - run: npm run lint - - - name: VSCE Packge - run: npx vsce package diff --git a/.vscode/settings.json b/.vscode/settings.json index b5f7231..5e5ca48 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "editor.formatOnSave": true, + "editor.formatOnSave": false, "editor.insertSpaces": true, "editor.tabSize": 4, "files.insertFinalNewline": true, diff --git a/src/leetCodeManager.ts b/src/leetCodeManager.ts index 1b2d4af..16ec378 100644 --- a/src/leetCodeManager.ts +++ b/src/leetCodeManager.ts @@ -6,14 +6,14 @@ import { EventEmitter } from "events"; import * as vscode from "vscode"; import { leetCodeChannel } from "./leetCodeChannel"; import { leetCodeExecutor } from "./leetCodeExecutor"; -import { Endpoint, loginArgsMapping, urls, urlsCn, UserStatus } from "./shared"; +import { Endpoint, IQuickItemEx, loginArgsMapping, urls, urlsCn, UserStatus } from "./shared"; import { createEnvOption } from "./utils/cpUtils"; import { DialogType, openUrl, promptForOpenOutputChannel } from "./utils/uiUtils"; import * as wsl from "./utils/wslUtils"; import { getLeetCodeEndpoint } from "./commands/plugin"; import { globalState } from "./globalState"; import { queryUserData } from "./request/query-user-data"; -import { parseQuery, sleep } from "./utils/toolUtils"; +import { parseQuery } from "./utils/toolUtils"; class LeetCodeManager extends EventEmitter { private currentUser: string | undefined; @@ -42,6 +42,19 @@ class LeetCodeManager extends EventEmitter { } } + private async updateUserStatusWithCookie(cookie: string): Promise { + globalState.setCookie(cookie); + const data = await queryUserData(); + globalState.setUserStatus(data); + await this.setCookieToCli(cookie, data.username); + if (data.username) { + vscode.window.showInformationMessage(`Successfully ${data.username}.`); + this.currentUser = data.username; + this.userStatus = UserStatus.SignedIn; + this.emit("statusChanged"); + } + } + public async handleUriSignIn(uri: vscode.Uri): Promise { try { await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>) => { @@ -52,24 +65,61 @@ class LeetCodeManager extends EventEmitter { promptForOpenOutputChannel(`Failed to get cookie. Please log in again`, DialogType.error); return; } - globalState.setCookie(cookie); - const data = await queryUserData(); - globalState.setUserStatus(data); - await this.setCookieToCli(cookie, data.username); - if (data.username) { - vscode.window.showInformationMessage(`Successfully ${data.username}.`); - this.currentUser = data.username; - this.userStatus = UserStatus.SignedIn; - this.emit("statusChanged"); - } + + await this.updateUserStatusWithCookie(cookie) + }); } catch (error) { promptForOpenOutputChannel(`Failed to log in. Please open the output channel for details`, DialogType.error); } } + public async handleInputCookieSignIn(): Promise { + const cookie: string | undefined = await vscode.window.showInputBox({ + prompt: 'Enter LeetCode Cookie', + password: true, + ignoreFocusOut: true, + validateInput: (s: string): string | undefined => + s ? undefined : 'Cookie must not be empty', + }) + + await this.updateUserStatusWithCookie(cookie || '') + } + public async signIn(): Promise { - openUrl(this.getAuthLoginUrl()); + const picks: Array> = [] + picks.push( + { + label: 'Web Authorization', + detail: 'Open browser to authorize login on the website', + value: 'WebAuth', + description: '[Recommended]' + }, + { + label: 'LeetCode Cookie', + detail: 'Use LeetCode cookie copied from browser to login', + value: 'Cookie', + } + ) + + const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks) + if (!choice) { + return + } + const loginMethod: string = choice.value + + if (loginMethod === 'WebAuth') { + openUrl(this.getAuthLoginUrl()) + return + } + + try { + await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: "Fetching user data..." }, async () => { + await this.handleInputCookieSignIn() + }); + } catch (error) { + promptForOpenOutputChannel(`Failed to log in. Please open the output channel for details`, DialogType.error); + } } public async signOut(): Promise { @@ -136,15 +186,16 @@ class LeetCodeManager extends EventEmitter { } else if (data.match(this.failRegex)) { childProc.stdin?.end(); return reject(new Error("Faile to login")); + } else if (data.match(/login: /)) { + childProc.stdin?.write(`${name}\n`); + } else if (data.match(/cookie: /)) { + childProc.stdin?.write(`${cookie}\n`); } }); childProc.stderr?.on("data", (data: string | Buffer) => leetCodeChannel.append(data.toString())); childProc.on("error", reject); - childProc.stdin?.write(`${name}\n`); - await sleep(800); - childProc.stdin?.write(`${cookie}\n`); }); } } diff --git a/src/utils/httpUtils.ts b/src/utils/httpUtils.ts index aa6e205..b777173 100644 --- a/src/utils/httpUtils.ts +++ b/src/utils/httpUtils.ts @@ -16,7 +16,7 @@ export function LcAxios(path: string, settings?: AxiosRequestConfig): A } return axios(path, { headers: { - referer: referer, + referer, "content-type": "application/json", cookie, ...(settings && settings.headers), diff --git a/src/utils/toolUtils.ts b/src/utils/toolUtils.ts index 6437226..ce37e18 100644 --- a/src/utils/toolUtils.ts +++ b/src/utils/toolUtils.ts @@ -9,7 +9,7 @@ export function parseQuery(query: string): { [key: string]: string } { return queryObject; } - let keyValuePairs = query.split("&"); + const keyValuePairs = query.split("&"); keyValuePairs.forEach((pair) => { const firstEqualsIndex = pair.indexOf("="); if (firstEqualsIndex !== -1) { diff --git a/src/utils/trackingUtils.ts b/src/utils/trackingUtils.ts index 4333bfa..56b1a6f 100644 --- a/src/utils/trackingUtils.ts +++ b/src/utils/trackingUtils.ts @@ -90,7 +90,7 @@ class TrackData implements ITrackData { if (!Array.isArray(reportItems)) { reportItems = [reportItems]; } - let randomId = getRandomString(60); + const randomId = getRandomString(60); reportItems.forEach((item) => { this.reportCache.push({ ...item, diff --git a/tslint.json b/tslint.json index 34776be..a686a2c 100644 --- a/tslint.json +++ b/tslint.json @@ -1,36 +1,28 @@ { "defaultSeverity": "error", - "extends": [ - "tslint:recommended" - ], + "extends": ["tslint:recommended"], "jsRules": {}, "rules": { - "forin": false, "object-literal-sort-keys": false, - "indent": [ - true, - "spaces" - ], + "ordered-imports": [false], + "indent": [true, "spaces"], "no-string-literal": false, "no-namespace": false, - "max-line-length": [ - false, - 120 - ], - "typedef": [ - true, - "call-signature", - "arrow-call-signature", - "parameter", - "arrow-parameter", - "property-declaration", - "variable-declaration", - "member-variable-declaration" - ], - "variable-name": [ - true, - "allow-leading-underscore" - ] + "max-line-length": [false, 120], + "typedef": false, + "no-implicit-dependencies": [true, ["vscode"]], + "trailing-comma": false, + "no-any": false, + "object-literal-key-quotes": [true, "consistent-as-needed"], + "prefer-object-spread": false, + "no-unnecessary-await": false, + "semicolon": [false], + "quotemark": [false], + "member-ordering": [false], + "variable-name": [false], + "curly": false, + "interface-over-type-literal": [false], + "no-unused-expression": false }, "rulesDirectory": [] }