From 9cacef61daba83d5eee522844bcae047b95edbbc Mon Sep 17 00:00:00 2001 From: Khushraj Rathod Date: Tue, 27 Oct 2020 23:07:26 +0530 Subject: [PATCH 1/5] Closes #1, add separate endpoint for uploading files --- api/new.ts | 60 ++++++++++++++++-------------------------------- api/newSingle.ts | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 40 deletions(-) create mode 100644 api/newSingle.ts diff --git a/api/new.ts b/api/new.ts index 78d1036..be596ce 100644 --- a/api/new.ts +++ b/api/new.ts @@ -1,6 +1,4 @@ -import { ServerRequest } from 'https://deno.land/std@0.61.0/http/server.ts' -import { Hash } from "https://deno.land/x/checksum@1.4.0/mod.ts" -import { urlParse } from 'https://deno.land/x/url_parse/mod.ts'; +import { ServerRequest } from 'https://deno.land/std@0.75.0/http/server.ts' const endpoint = (path: string) => { // https://vercel.com/docs/api#api-basics/authentication/accessing-resources-owned-by-a-team @@ -11,36 +9,7 @@ const endpoint = (path: string) => { return url } -// Vercel protects against env tokens starting with `VERCEL_`, so we're calling -// it the ZEIT_TOKEN - -const uploadFile = async (url: string, index: number) => { - const req = await fetch(url) - const data = new Uint8Array(await req.arrayBuffer()) - const sha = new Hash('sha1').digest(data).hex() - const size = data.byteLength - const { pathname } = urlParse(url) - const filename = index + pathname.substr(pathname.lastIndexOf('/') + 1) - - const uploadedFile = await fetch(endpoint('v2/now/files'), { - method: 'POST', - headers: { - 'Content-Length': size.toString(), - 'x-now-digest': sha, - 'Authorization': `Bearer ${Deno.env.get('ZEIT_TOKEN')}` - }, - body: data.buffer, - }) - - return { - sha, - size, - file: 'public/' + filename, - path: filename - } -} - -const deploy = async (files: {sha: string, file: string, path: string, size: number}[]) => { +const deploy = async (files: { sha: string, file: string, path: string, size: number }[]) => { const req = await fetch(endpoint('v12/now/deployments'), { method: 'POST', headers: { @@ -68,26 +37,37 @@ const deploy = async (files: {sha: string, file: string, path: string, size: num export default async (req: ServerRequest) => { if (req.method == 'OPTIONS') { - return req.respond({status: 204, body: JSON.stringify({ status: "YIPPE YAY. YOU HAVE CLEARANCE TO PROCEED." })}) + return req.respond({ status: 204, body: JSON.stringify({ status: "YIPPE YAY. YOU HAVE CLEARANCE TO PROCEED." }) }) } if (req.method == 'GET') { - return req.respond({status: 405, body: JSON.stringify({ error: '*GET outta here!* (Method not allowed, use POST)' })}) + return req.respond({ status: 405, body: JSON.stringify({ error: '*GET outta here!* (Method not allowed, use POST)' }) }) } if (req.method == 'PUT') { - return req.respond({status: 405, body: JSON.stringify({ error: '*PUT that request away!* (Method not allowed, use POST)' })}) + return req.respond({ status: 405, body: JSON.stringify({ error: '*PUT that request away!* (Method not allowed, use POST)' }) }) } if (req.method != 'POST') { - return req.respond({status: 405, body: JSON.stringify({ error: 'Method not allowed, use POST' })}) + return req.respond({ status: 405, body: JSON.stringify({ error: 'Method not allowed, use POST' }) }) } const decoder = new TextDecoder() const buf = await Deno.readAll(req.body) const fileURLs = JSON.parse(decoder.decode(buf)) if (!Array.isArray(fileURLs) || fileURLs.length < 1) { - return req.respond({status: 422, body: JSON.stringify({ error: 'Empty file array' })}) + return req.respond({ status: 422, body: JSON.stringify({ error: 'Empty file array' }) }) } - const uploadedFiles = await Promise.all(fileURLs.map(uploadFile)) - const result = await deploy(uploadedFiles) + + let uploadedURLs = await Promise.all(fileURLs.map(async (url) => { + const res = await fetch("https://cdn.hackclub.com/api/newSingle", { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: url + }) + return JSON.parse(await res.json()) + })) + + const result = await deploy(uploadedURLs) req.respond({ status: result.status, diff --git a/api/newSingle.ts b/api/newSingle.ts new file mode 100644 index 0000000..9ef85e7 --- /dev/null +++ b/api/newSingle.ts @@ -0,0 +1,47 @@ +import { ServerRequest } from 'https://deno.land/std@0.75.0/http/server.ts' +import { Hash } from "https://deno.land/x/checksum@1.4.0/mod.ts" +import { urlParse } from 'https://deno.land/x/url_parse/mod.ts'; + +const uploadFile = async (url: string) => { + const req = await fetch(url) + const data = new Uint8Array(await req.arrayBuffer()) + const sha = new Hash('sha1').digest(data).hex() + const size = data.byteLength + const { pathname } = urlParse(url) + const filename = pathname.substr(pathname.lastIndexOf('/') + 1) + + await fetch(endpoint('v2/now/files'), { + method: 'POST', + headers: { + 'Content-Length': size.toString(), + 'x-now-digest': sha, + 'Authorization': `Bearer ${Deno.env.get('ZEIT_TOKEN')}` + }, + body: data.buffer, + }) + + return { + sha, + size, + file: 'public/' + filename, + path: filename + } +} + +export default async (req: ServerRequest) => { + if (req.method != 'POST') { + return req.respond({ status: 405, body: JSON.stringify({ error: 'Method not allowed, use POST' }) }) + } + + const decoder = new TextDecoder() + const buf = await Deno.readAll(req.body) + const singleFileURL = JSON.parse(decoder.decode(buf)) + if (typeof singleFileURL != 'string') { + return req.respond({ status: 422, body: JSON.stringify({ error: 'newSingle only accepts a single URL' }) }) + } + const uploadedFileURL = await uploadFile(singleFileURL) + + req.respond({ + body: JSON.stringify(uploadedFileURL) + }) +} From 5d229106f3bf6d2fd5e9f6c86072fd627608d15d Mon Sep 17 00:00:00 2001 From: Khushraj Rathod Date: Sat, 31 Oct 2020 00:13:35 +0530 Subject: [PATCH 2/5] Add endpoint to newSingle.ts, add index --- .vscode/settings.json | 6 ++++++ api/new.ts | 16 ++++++++++++---- api/newSingle.ts | 17 +++++++++++------ 3 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7d61b6f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "deno.enable": true, + "deno.import_intellisense_origins": { + "https://deno.land": true + }, +} \ No newline at end of file diff --git a/api/new.ts b/api/new.ts index be596ce..9b48734 100644 --- a/api/new.ts +++ b/api/new.ts @@ -1,4 +1,5 @@ import { ServerRequest } from 'https://deno.land/std@0.75.0/http/server.ts' +import { urlParse } from 'https://deno.land/x/url_parse/mod.ts'; const endpoint = (path: string) => { // https://vercel.com/docs/api#api-basics/authentication/accessing-resources-owned-by-a-team @@ -56,15 +57,22 @@ export default async (req: ServerRequest) => { return req.respond({ status: 422, body: JSON.stringify({ error: 'Empty file array' }) }) } - let uploadedURLs = await Promise.all(fileURLs.map(async (url) => { - const res = await fetch("https://cdn.hackclub.com/api/newSingle", { + let uploadedURLs = await Promise.all(fileURLs.map(async (url, index) => { + const { pathname } = urlParse(url) + const filename = index + pathname.substr(pathname.lastIndexOf('/') + 1) + + const res = JSON.parse(await (await fetch("https://cdn.hackclub.com/api/newSingle", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: url - }) - return JSON.parse(await res.json()) + })).json()) + + res.file = 'public/' + filename + res.path = filename + + return res })) const result = await deploy(uploadedURLs) diff --git a/api/newSingle.ts b/api/newSingle.ts index 9ef85e7..56abb51 100644 --- a/api/newSingle.ts +++ b/api/newSingle.ts @@ -2,14 +2,21 @@ import { ServerRequest } from 'https://deno.land/std@0.75.0/http/server.ts' import { Hash } from "https://deno.land/x/checksum@1.4.0/mod.ts" import { urlParse } from 'https://deno.land/x/url_parse/mod.ts'; +const endpoint = (path: string) => { + // https://vercel.com/docs/api#api-basics/authentication/accessing-resources-owned-by-a-team + let url = 'https://api.vercel.com/' + path + if (Deno.env.get('ZEIT_TEAM')) { + url += ('?teamId=' + Deno.env.get('ZEIT_TEAM')) + } + return url +} + const uploadFile = async (url: string) => { const req = await fetch(url) const data = new Uint8Array(await req.arrayBuffer()) const sha = new Hash('sha1').digest(data).hex() const size = data.byteLength - const { pathname } = urlParse(url) - const filename = pathname.substr(pathname.lastIndexOf('/') + 1) - + await fetch(endpoint('v2/now/files'), { method: 'POST', headers: { @@ -22,9 +29,7 @@ const uploadFile = async (url: string) => { return { sha, - size, - file: 'public/' + filename, - path: filename + size } } From 35cdee72a1122ed10512a7d6eb52e454dcad59db Mon Sep 17 00:00:00 2001 From: Max Wofford Date: Fri, 30 Oct 2020 14:46:00 -0400 Subject: [PATCH 3/5] Delete vscode settings --- .vscode/settings.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 7d61b6f..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "deno.enable": true, - "deno.import_intellisense_origins": { - "https://deno.land": true - }, -} \ No newline at end of file From 3103294d0ed0b54f88baf323ef42f7bb12340d38 Mon Sep 17 00:00:00 2001 From: Khushraj Rathod Date: Sat, 31 Oct 2020 00:30:57 +0530 Subject: [PATCH 4/5] Update newSingle.ts --- api/newSingle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/newSingle.ts b/api/newSingle.ts index 56abb51..393c1b5 100644 --- a/api/newSingle.ts +++ b/api/newSingle.ts @@ -40,7 +40,7 @@ export default async (req: ServerRequest) => { const decoder = new TextDecoder() const buf = await Deno.readAll(req.body) - const singleFileURL = JSON.parse(decoder.decode(buf)) + const singleFileURL = decoder.decode(buf) if (typeof singleFileURL != 'string') { return req.respond({ status: 422, body: JSON.stringify({ error: 'newSingle only accepts a single URL' }) }) } From 1a9e5923264c1399c2ae370ea144db527dd6a4a9 Mon Sep 17 00:00:00 2001 From: Khushraj Rathod Date: Sat, 31 Oct 2020 10:06:37 +0530 Subject: [PATCH 5/5] Remove rogue JSON.parse --- .gitignore | 3 ++- api/new.ts | 4 ++-- api/newSingle.ts | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d558dbc..edaaef5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .env -.vercel \ No newline at end of file +.vercel +.vscode diff --git a/api/new.ts b/api/new.ts index 9b48734..97add8b 100644 --- a/api/new.ts +++ b/api/new.ts @@ -61,13 +61,13 @@ export default async (req: ServerRequest) => { const { pathname } = urlParse(url) const filename = index + pathname.substr(pathname.lastIndexOf('/') + 1) - const res = JSON.parse(await (await fetch("https://cdn.hackclub.com/api/newSingle", { + const res = await (await fetch("https://cdn.hackclub.com/api/newSingle", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: url - })).json()) + })).json() res.file = 'public/' + filename res.path = filename diff --git a/api/newSingle.ts b/api/newSingle.ts index 393c1b5..1f2cd3a 100644 --- a/api/newSingle.ts +++ b/api/newSingle.ts @@ -1,6 +1,5 @@ import { ServerRequest } from 'https://deno.land/std@0.75.0/http/server.ts' import { Hash } from "https://deno.land/x/checksum@1.4.0/mod.ts" -import { urlParse } from 'https://deno.land/x/url_parse/mod.ts'; const endpoint = (path: string) => { // https://vercel.com/docs/api#api-basics/authentication/accessing-resources-owned-by-a-team