Skip to content

Commit ad3fa61

Browse files
author
Giovanni D'Andrea
authored
Merge pull request #3 from Exifly:feature/CDS-64-authentication
feat: added snippet authentication
2 parents d252c73 + 756f2e2 commit ad3fa61

8 files changed

Lines changed: 299 additions & 72 deletions

File tree

codeishot_extension/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ out/
33
./out/*
44

55
./out
6-
out
6+
out
7+
8+
## Testing
9+
.vscode-test

codeishot_extension/package.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,23 @@
1919
"main": "./out/extension.js",
2020
"contributes": {
2121
"commands": [
22+
{
23+
"command": "extension.login",
24+
"title": "Login to Codeishot ✨"
25+
},
2226
{
2327
"command": "extension.postSnippet",
2428
"title": "Share on Codeishot ✨"
2529
}
30+
2631
],
2732
"menus": {
2833
"editor/context": [
2934
{
3035
"command": "extension.postSnippet"
36+
},
37+
{
38+
"command": "extension.login"
3139
}
3240
]
3341
},
@@ -38,7 +46,18 @@
3846
"mac": "ctrl+shift+c",
3947
"when": "editorTextFocus"
4048
}
41-
]
49+
],
50+
"configuration": {
51+
"type": "string",
52+
"title": "Codeishot",
53+
"properties": {
54+
"jwt": {
55+
"type": "string",
56+
"default": "",
57+
"description": "Token to login into codeishot."
58+
}
59+
}
60+
}
4261
},
4362
"scripts": {
4463
"vscode:prepublish": "npm run compile",
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Ported from vue axios plugin.
3+
* Needs to:
4+
* - Use the extension configuration instead of authStore
5+
* - Change the import.meta
6+
*/
7+
8+
import axios from "axios";
9+
import { getTokenFromConfiguration } from "./login";
10+
11+
const fetch = axios.create({
12+
baseURL: process.env.API_BASE_URL || "https://api.codeishot.com",
13+
timeout: 10000,
14+
headers: {
15+
"Content-Type": "application/json",
16+
Accept: "application/json",
17+
},
18+
withCredentials: false,
19+
responseType: "json",
20+
});
21+
22+
// Interceptor
23+
fetch.interceptors.request.use(
24+
(config) => {
25+
// Check if the user tokens are stored to apply the bearer on the headers,
26+
// Otherwise the request is not authenticated.
27+
const token = getTokenFromConfiguration();
28+
29+
if (token) {
30+
config.headers.Authorization = `Bearer ${token}`;
31+
}
32+
return config;
33+
},
34+
(error) => {
35+
console.error(`Error in request ${error}`);
36+
return Promise.reject(error);
37+
}
38+
);
39+
40+
export default { fetch };

codeishot_extension/src/config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const headers = {
2+
accept: "application/json",
3+
contentType: "application/json",
4+
userAgent: "codeishot/1.0.0",
5+
// 'X-CSRFTOKEN': csrfToken,
6+
};
7+
8+
export { headers };

codeishot_extension/src/customs.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type {
2+
AxiosResponse,
3+
InternalAxiosRequestConfig,
4+
AxiosError,
5+
} from "axios";
6+
7+
export interface CustomResponse {
8+
config: InternalAxiosRequestConfig;
9+
data: object;
10+
status_code: number;
11+
status_text: string;
12+
}
13+
14+
export interface CustomError {
15+
code?: string;
16+
message: string;
17+
data: any; // FIXME: not any
18+
status_code?: number;
19+
status_text?: string;
20+
}
21+
22+
/**
23+
*
24+
* @param {AxiosResponse} r
25+
* @returns Custom Axios response object
26+
*/
27+
const CustomAxiosResponse = (r: AxiosResponse): CustomResponse => {
28+
return {
29+
config: r.config,
30+
data: r.data,
31+
status_code: r.status,
32+
status_text: r.statusText,
33+
};
34+
};
35+
36+
/**
37+
*
38+
* @param {AxiosError} er
39+
* @returns Custom Axios error object
40+
*/
41+
const CustomAxiosError = (er: AxiosError): CustomError => {
42+
return {
43+
code: er.code,
44+
message: er.message,
45+
data: er.response?.data,
46+
status_code: er.response?.status,
47+
status_text: er.response?.statusText,
48+
};
49+
};
50+
51+
export { CustomAxiosResponse, CustomAxiosError };
Lines changed: 69 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import * as vscode from 'vscode';
2-
import * as path from 'path';
3-
import axios from 'axios';
1+
import * as vscode from "vscode";
2+
import * as path from "path";
3+
import { login } from "./login";
4+
import { createSnippet } from "./services/codeishotServices";
45

5-
const UI_BASE_URL: string = process.env.UI_BASE_URL || 'https://codeishot.com';
6-
const API_BASE_URL: string = process.env.API_BASE_URL || 'https://api.codeishot.com';
7-
// const csrfToken = process.env.CSRF_TOKEN;
6+
const UI_BASE_URL: string = process.env.UI_BASE_URL || "https://codeishot.com";
87

98
interface PostData {
109
title: string;
@@ -28,7 +27,7 @@ function getSelectedText(editor: vscode.TextEditor): string | null {
2827
const text = editor.document.getText(selection);
2928

3029
if (!text) {
31-
vscode.window.showErrorMessage('No text selected');
30+
vscode.window.showErrorMessage("No text selected");
3231
return null;
3332
}
3433

@@ -54,50 +53,36 @@ function getLanguageIdentifier(): string | null {
5453
return null;
5554
}
5655

56+
function checkCreateSnippetStatusCode(status: number, data: PostData) {
57+
switch (status) {
58+
case 400:
59+
vscode.window.showWarningMessage(
60+
"This language is not available, sending snippet as a Plain Text"
61+
);
62+
const newRes = postSnippetWithValidatedData(data);
63+
return newRes;
64+
case 429:
65+
vscode.window.showErrorMessage("Too many requests!");
66+
break;
67+
default:
68+
break;
69+
}
70+
}
71+
5772
async function postSnippet(data: PostData): Promise<Snippet> {
58-
return await axios
59-
.post(API_BASE_URL + '/api/snippets/', data, {
60-
headers: {
61-
accept: 'application/json',
62-
contentType: 'application/json',
63-
userAgent: 'codeishot/1.0.0',
64-
// 'X-CSRFTOKEN': csrfToken,
65-
},
66-
})
67-
.then((res) => res.data)
68-
.catch((error) => {
69-
switch (error.response.status) {
70-
case 400:
71-
// TODO: Handle if status is 400 AND some other check, not only lanuage
72-
vscode.window.showWarningMessage('This language is not available, sending snippet as a Plain Text');
73-
const newRes = postSnippetWithValidatedData(data);
74-
return newRes;
75-
case 429:
76-
vscode.window.showErrorMessage('Too many requests!');
77-
break;
78-
default:
79-
vscode.window.showErrorMessage(`CODEISHOT_ERROR: ${error}`);
80-
break;
81-
}
82-
vscode.window.showWarningMessage('Please try again!');
83-
});
73+
let res = await createSnippet(data);
74+
if (res.status_code) checkCreateSnippetStatusCode(res.status_code, data);
75+
return res.data as Promise<Snippet>;
8476
}
8577

8678
async function postSnippetWithValidatedData(data: PostData): Promise<Snippet> {
8779
let plainTextData: PostData = { ...data };
8880
plainTextData.language = "plaintext";
8981

90-
return await axios
91-
.post(API_BASE_URL + '/api/snippets/', plainTextData, {
92-
headers: {
93-
accept: 'application/json',
94-
contentType: 'application/json',
95-
userAgent: 'codeishot/1.0.0',
96-
},
97-
})
82+
return await createSnippet(plainTextData)
9883
.then((res) => res.data)
9984
.catch(() => {
100-
vscode.window.showWarningMessage('Please try again!');
85+
vscode.window.showWarningMessage("Please try again!");
10186
});
10287
}
10388

@@ -106,49 +91,63 @@ async function handlePostResponse(data: Snippet) {
10691
const snippetUrl = `${UI_BASE_URL}/${data.id}`;
10792
try {
10893
await vscode.env.clipboard.writeText(snippetUrl);
109-
vscode.window.showInformationMessage('URL copied to clipboard');
94+
vscode.window.showInformationMessage("URL copied to clipboard");
11095
} catch (error) {
111-
vscode.window.showErrorMessage('Error copying URL: ' + error);
96+
vscode.window.showErrorMessage("Error copying URL: " + error);
11297
}
11398

114-
const infoMessage = await vscode.window.showInformationMessage(snippetUrl, 'Open URL');
115-
if (infoMessage === 'Open URL') {
99+
const infoMessage = await vscode.window.showInformationMessage(
100+
snippetUrl,
101+
"Open URL"
102+
);
103+
if (infoMessage === "Open URL") {
116104
vscode.env.openExternal(vscode.Uri.parse(snippetUrl));
117105
}
118106
}
119107
}
120108

121109
function activate(context: vscode.ExtensionContext) {
122-
let disposable = vscode.commands.registerCommand('extension.postSnippet', async () => {
123-
const editor = vscode.window.activeTextEditor;
124-
if (!editor) {
125-
vscode.window.showErrorMessage('No editor found');
126-
return;
127-
}
110+
let disposable = vscode.commands.registerCommand(
111+
"extension.postSnippet",
112+
async () => {
113+
const editor = vscode.window.activeTextEditor;
114+
if (!editor) {
115+
vscode.window.showErrorMessage("No editor found");
116+
return;
117+
}
128118

129-
const text = getSelectedText(editor);
130-
if (!text) {
131-
return;
132-
}
119+
const text = getSelectedText(editor);
120+
if (!text) {
121+
return;
122+
}
133123

134-
const postData: PostData = {
135-
title: getCurrentFileName() || 'untitled',
136-
code: text,
137-
language: getLanguageIdentifier() || 'python',
138-
style: 'androidstudio',
139-
};
124+
const postData: PostData = {
125+
title: getCurrentFileName() || "untitled",
126+
code: text,
127+
language: getLanguageIdentifier() || "python",
128+
style: "androidstudio",
129+
};
130+
131+
try {
132+
const data = await postSnippet(postData);
133+
await handlePostResponse(data);
134+
} catch (error: any) {
135+
vscode.window.showErrorMessage("Error: " + error.message);
136+
}
137+
}
138+
);
140139

141-
try {
142-
const data = await postSnippet(postData);
143-
await handlePostResponse(data);
144-
} catch (error: any) {
145-
vscode.window.showErrorMessage('Error: ' + error.message);
140+
const loginCommand = vscode.commands.registerCommand(
141+
"extension.login",
142+
() => {
143+
login();
146144
}
147-
});
145+
);
148146

149147
context.subscriptions.push(disposable);
148+
context.subscriptions.push(loginCommand);
150149
}
151150

152-
function deactivate() { }
151+
function deactivate() {}
153152

154-
export { activate, deactivate };
153+
export { activate, deactivate };

0 commit comments

Comments
 (0)