diff --git a/deno.json b/deno.json index 8568dc5..52a0956 100755 --- a/deno.json +++ b/deno.json @@ -23,6 +23,7 @@ "nodeModulesDir": "none", "imports": { "@bcrypt": "https://deno.land/x/bcrypt@v0.4.1/mod.ts", + "@deno-zip": "https://deno.land/x/jszip@0.11.0/mod.ts", "@mysql": "https://deno.land/x/mysql@v2.12.1/mod.ts", "@nanoid": "https://deno.land/x/nanoid@v3.0.0/mod.ts", "@std/http": "jsr:@std/http@1.0.15", diff --git a/deno.lock b/deno.lock index 983ccc5..2884008 100644 --- a/deno.lock +++ b/deno.lock @@ -9,7 +9,19 @@ } }, "redirects": { - "https://deno.land/x/bcrypt/mod.ts": "https://deno.land/x/bcrypt@v0.4.1/mod.ts" + "https://deno.land/x/bcrypt/mod.ts": "https://deno.land/x/bcrypt@v0.4.1/mod.ts", + "https://esm.sh/core-util-is@~1.0.0?target=denonext": "https://esm.sh/core-util-is@1.0.3?target=denonext", + "https://esm.sh/immediate@~3.0.5?target=denonext": "https://esm.sh/immediate@3.0.6?target=denonext", + "https://esm.sh/isarray@~1.0.0?target=denonext": "https://esm.sh/isarray@1.0.0?target=denonext", + "https://esm.sh/lie@~3.3.0?target=denonext": "https://esm.sh/lie@3.3.0?target=denonext", + "https://esm.sh/pako@~1.0.2?target=denonext": "https://esm.sh/pako@1.0.11?target=denonext", + "https://esm.sh/process-nextick-args@~2.0.0?target=denonext": "https://esm.sh/process-nextick-args@2.0.1?target=denonext", + "https://esm.sh/readable-stream@~2.3.6?target=denonext": "https://esm.sh/readable-stream@2.3.8?target=denonext", + "https://esm.sh/safe-buffer@~5.1.0?target=denonext": "https://esm.sh/safe-buffer@5.1.2?target=denonext", + "https://esm.sh/safe-buffer@~5.1.1?target=denonext": "https://esm.sh/safe-buffer@5.1.2?target=denonext", + "https://esm.sh/set-immediate-shim@~1.0.1?target=denonext": "https://esm.sh/set-immediate-shim@1.0.1?target=denonext", + "https://esm.sh/string_decoder@~1.1.1?target=denonext": "https://esm.sh/string_decoder@1.1.1?target=denonext", + "https://esm.sh/util-deprecate@~1.0.1?target=denonext": "https://esm.sh/util-deprecate@1.0.2?target=denonext" }, "remote": { "https://deno.land/std@0.104.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58", @@ -40,6 +52,18 @@ "https://deno.land/std@0.104.0/log/mod.ts": "91711789b28803082b1bdfb123d2c9685a7e01767f2e79c0a82706063ad964d8", "https://deno.land/std@0.104.0/testing/_diff.ts": "5d3693155f561d1a5443ac751ac70aab9f5d67b4819a621d4b96b8a1a1c89620", "https://deno.land/std@0.104.0/testing/asserts.ts": "e4311d45d956459d4423bc267208fe154b5294989da2ed93257b6a85cae0427e", + "https://deno.land/std@0.116.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58", + "https://deno.land/std@0.116.0/_util/os.ts": "dfb186cc4e968c770ab6cc3288bd65f4871be03b93beecae57d657232ecffcac", + "https://deno.land/std@0.116.0/fs/walk.ts": "31464d75099aa3fc7764212576a8772dfabb2692783e6eabb910f874a26eac54", + "https://deno.land/std@0.116.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853", + "https://deno.land/std@0.116.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4", + "https://deno.land/std@0.116.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b", + "https://deno.land/std@0.116.0/path/common.ts": "f41a38a0719a1e85aa11c6ba3bea5e37c15dd009d705bd8873f94c833568cbc4", + "https://deno.land/std@0.116.0/path/glob.ts": "ea87985765b977cc284b92771003b2070c440e0807c90e1eb0ff3e095911a820", + "https://deno.land/std@0.116.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12", + "https://deno.land/std@0.116.0/path/posix.ts": "34349174b9cd121625a2810837a82dd8b986bbaaad5ade690d1de75bbb4555b2", + "https://deno.land/std@0.116.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c", + "https://deno.land/std@0.116.0/path/win32.ts": "11549e8c6df8307a8efcfa47ad7b2a75da743eac7d4c89c9723a944661c8bd2e", "https://deno.land/std@0.77.0/fmt/colors.ts": "c5665c66f1a67228f21c5989bbb04b36d369b98dd7ceac06f5e26856c81c2531", "https://deno.land/x/bcrypt@v0.4.1/mod.ts": "ff09bdae282583cf5f7d87efe37ddcecef7f14f6d12e8b8066a3058db8c6c2f7", "https://deno.land/x/bcrypt@v0.4.1/src/bcrypt/base64.ts": "b8266450a4f1eb6960f60f2f7986afc4dde6b45bd2d7ee7ba10789e67e17b9f7", @@ -49,6 +73,7 @@ "https://deno.land/x/bytes_formater@v1.4.0/deps.ts": "4f98f74e21145423b873a5ca6ead66dc3e674fa81e230a0a395f9b86aafeceea", "https://deno.land/x/bytes_formater@v1.4.0/format.ts": "657c41b9f180c3ed0f934dcf75f77b09b6a610be98bb07525bffe2acfd5af4d5", "https://deno.land/x/bytes_formater@v1.4.0/mod.ts": "c6bf35303f53d74e9134eb13f666fb388fb4c62c6b12b17542bbadade250a864", + "https://deno.land/x/jszip@0.11.0/mod.ts": "5661ddc18e9ac9c07e3c5d2483bc912a7022b6af0d784bb7b05035973e640ba1", "https://deno.land/x/mysql@v2.12.1/deps.ts": "68635959a41bb08bc87db007679fb8449febc55d48202dff20b93cc23ef5820d", "https://deno.land/x/mysql@v2.12.1/mod.ts": "3246c9c259434563be69cc95d5b792f8aac7ef5d10b8a6c6589aa54ebf1bd266", "https://deno.land/x/mysql@v2.12.1/src/auth.ts": "129ea08b180d3e90e567c3f71e60432bb266304c224e17ea39d604bbcc1160d8", @@ -82,7 +107,31 @@ "https://deno.land/x/nanoid@v3.0.0/nanoid.ts": "8d119bc89a0f34e7bbe0c2dbdc280d01753e431af553d189663492310a31085d", "https://deno.land/x/nanoid@v3.0.0/random.ts": "4da71d5f72f2bfcc6a4ee79b5d4e72f48dcf4fe4c3835fd5ebab08b9f33cd598", "https://deno.land/x/nanoid@v3.0.0/urlAlphabet.ts": "8b1511deb1ecb23c66202b6000dc10fb68f9a96b5550c6c8cef5009324793431", - "https://deno.land/x/sql_builder@v1.9.1/util.ts": "b9855dc435972704cf82655019f4ec168ac83550ab4db596c5f6b6d201466384" + "https://deno.land/x/sql_builder@v1.9.1/util.ts": "b9855dc435972704cf82655019f4ec168ac83550ab4db596c5f6b6d201466384", + "https://esm.sh/core-util-is@1.0.3/denonext/core-util-is.mjs": "cfcf1ae63d56751cbe4b3b90b90b7eea577c5380c4adc272ddea4b7db2bdbbf2", + "https://esm.sh/core-util-is@1.0.3?target=denonext": "6c72958f8a1c8f42016b48c984a0f3d799ea1e0cd321f499fec0bf8db916c17f", + "https://esm.sh/immediate@3.0.6/denonext/immediate.mjs": "7148ba33cb905f7aca49affbacfa6a8257cd6b89e8c3c7c728d2d0387b4cce29", + "https://esm.sh/immediate@3.0.6?target=denonext": "fba8d9ddb37f19ff27c0b1c5b4486ab82805114b14959379d92ca05d6351c5d3", + "https://esm.sh/isarray@1.0.0/denonext/isarray.mjs": "0f26133cd58fc8580f99bbfd81f6290718328dc2a683c313c36f6b1e8c174edc", + "https://esm.sh/isarray@1.0.0?target=denonext": "00e227f6d016cb5a5f832f6f2de91dd8ab092c7ac830c551bfcf0f63284d89e6", + "https://esm.sh/jszip@3.7.1": "5161d6a228d844791a60ab58360bd3b76c4d3921b4a725616cd7403203519249", + "https://esm.sh/jszip@3.7.1/denonext/jszip.mjs": "325e8509d94e1460a8bb0bbb58b47a7b70c63b48568a60993e2880dba3a3062d", + "https://esm.sh/lie@3.3.0/denonext/lie.mjs": "20db2fef139e87d467b7cf24a9e53053e96460fefedde5910f925b1d0ddc0cba", + "https://esm.sh/lie@3.3.0?target=denonext": "74a2c724bd2fef30c46c612632dfd2ee37394f1a4540eb112e0df2ef98df0434", + "https://esm.sh/pako@1.0.11/denonext/pako.mjs": "4895feb3e2441ef725da4052a5dc93d219d065fef1decc4452bb9b7ee1477c0d", + "https://esm.sh/pako@1.0.11?target=denonext": "bc43f66ed245d58d468bf9867b3e9080c5b0590b4c14038ea308954490e0b2ea", + "https://esm.sh/process-nextick-args@2.0.1/denonext/process-nextick-args.mjs": "adffdd507c6571957aaab9d3f0a2aa54febdda1b4d546a57967fd2299505339e", + "https://esm.sh/process-nextick-args@2.0.1?target=denonext": "b80260031d83086964facc0efc6e2cc8fd878d9ce14dfcf6999e508a4d8d13d0", + "https://esm.sh/readable-stream@2.3.8/denonext/readable-stream.mjs": "ce8c7e2e7783c4487c1e9fcaf8824f0af26d48e6f5fe02fa9cbd70c34799ef98", + "https://esm.sh/readable-stream@2.3.8?target=denonext": "a8d158c470101e7518fdf293728d4cb8b2ab2cac73140940c8a9ee5542194e13", + "https://esm.sh/safe-buffer@5.1.2/denonext/safe-buffer.mjs": "848e2c2dafb98ea738399526e4396607872d1118acf8eb56eecd2a5f3be75568", + "https://esm.sh/safe-buffer@5.1.2?target=denonext": "3126988c629e3dc2d6126b26f654aceae10ad989622a21cb2a73ee72603f7df8", + "https://esm.sh/set-immediate-shim@1.0.1/denonext/set-immediate-shim.mjs": "a0fc9b90f281a6541c474dbf55184ef3a9360248f53cb3fa9479480cd24cdd40", + "https://esm.sh/set-immediate-shim@1.0.1?target=denonext": "8d30997d25a26dbcd4d79b613e6f400af85194f8e18e8e7014bc5fe3c9ffd429", + "https://esm.sh/string_decoder@1.1.1/denonext/string_decoder.mjs": "494e5a7fae95d5326e8aee93b4adfde75e389eea7a54bc1feea8549e786da032", + "https://esm.sh/string_decoder@1.1.1?target=denonext": "092c97b62b99368a40fa044c402188472658bc71529415f73c16f66c05aaf6bf", + "https://esm.sh/util-deprecate@1.0.2/denonext/util-deprecate.mjs": "083639894972cb68837eef26346c43bdd01357977149e0a4493f76192a4008b8", + "https://esm.sh/util-deprecate@1.0.2?target=denonext": "859f4df8ba771a4c33143185d3db6a7edb824fab1ed4f9a4b96ac0e6bc3ef1a4" }, "workspace": { "dependencies": [ diff --git a/mod.ts b/mod.ts index a627173..6c128e9 100644 --- a/mod.ts +++ b/mod.ts @@ -1,4 +1,5 @@ import { hash, compare } from '@bcrypt'; +import { JSZip } from '@deno-zip'; import { customAlphabet } from '@nanoid'; import { STATUS_CODE, STATUS_TEXT, StatusCode } from '@std/http/status'; @@ -82,14 +83,28 @@ Deno.serve({ port: config.api.port }, async (req) => { return genericResponse(STATUS_CODE.OK, JSON.stringify(plans)); } else if (path.startsWith('/export/')) { const userId = path.replace('/export/', ''); - const userMatch = await dbClient.query('SELECT id FROM users WHERE id = ?', [userId]).catch(() => { + const userMatch = await dbClient.query('SELECT id, name FROM users WHERE id = ?', [userId]).catch(() => { failed = true; }); if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); if (!userMatch.length) return genericResponse(STATUS_CODE.NotFound, 'User ID does not exist.'); - // WIP: export plans to zip code goes here - return genericResponse(STATUS_CODE.NotImplemented, 'Export function WIP.'); + const plans = await dbClient + .query('SELECT name, folder, data FROM plans WHERE ownerId = ? AND deleted = 0 ORDER BY folder ASC,name ASC', [userId]) + .catch(() => { + failed = true; + }); + if (failed) return genericResponse(STATUS_CODE.InternalServerError, "Couldn't read DB."); + + const zip = new JSZip(); + for (const plan of plans) { + zip.addFile(`${plan.folder}${plan.folder ? '/' : ''}${plan.name}.xivplan`, plan.data); + } + + return new Response(await zip.generateAsync({ type: 'blob' }), { + status: STATUS_CODE.OK, + statusText: STATUS_TEXT[STATUS_CODE.OK], + }); } } else if (req.method === 'POST' && path === '/enroll') { const body = await req.json(); diff --git a/ssr/buildHome.ts b/ssr/buildHome.ts index 2250b1a..65353bc 100644 --- a/ssr/buildHome.ts +++ b/ssr/buildHome.ts @@ -11,8 +11,8 @@ interface Plan { const makePlanButtons = (planId: string, deleted: boolean) => deleted - ? `` - : ``; + ? `` + : ``; const makePlanItem = (plan: Plan, deleted: boolean) => `
  • ${plan.folder}${plan.folder && '/'}${plan.name} - ${plan.lastUpdated.toLocaleString()} - ${makePlanButtons(plan.id, deleted)}
  • `; @@ -82,19 +82,6 @@ function doAction(action, planId) { } }); } -function exportPlans() { - fetch('/api/export/${userId}') - .catch((e) => { - e.text().then((text) => { - alert(text); - }); - }) - .then((r) => { - r.text().then((text) => { - alert(text); - }); - }); -} function openPlan(planId) { window.open(\`${config.api.publicDomain}share#\${planId}\`); } @@ -165,7 +152,7 @@ function deleteAccount() {

    Please note: anything modifying data will require you to enter your PIN again as both the web view you are looking at and server behind it are completely stateless for simplicity.

    DateTimeStamps on this page are all displayed in the US Eastern time zone. I don't care enough to make this extremely basic page dynamic.

    ${userName}'s Plans:

    - +download all plans @@ -173,6 +160,6 @@ ${plans.map((plan) => makePlanItem(plan, false)).join('')} - + `; }; diff --git a/ssr/buildPage.ts b/ssr/buildPage.ts index a3d12fb..487dbb8 100644 --- a/ssr/buildPage.ts +++ b/ssr/buildPage.ts @@ -20,6 +20,15 @@ a { text-decoration:none; color:white; } +.btn { +font: 13.333px Sans; +padding: 1px 6px; +border: 1px outset buttonborder; +border-radius: 3px; +color: buttontext; +background-color: buttonface; +text-decoration: none; +} li { margin:0.5rem 0; } diff --git a/start.command b/start.command index fde1ef2..6f3fe20 100644 --- a/start.command +++ b/start.command @@ -1 +1 @@ -deno run --allow-net --allow-import mod.ts \ No newline at end of file +deno run --allow-net --allow-import --allow-env mod.ts \ No newline at end of file diff --git a/xivplan-db.rc b/xivplan-db.rc index 6a57551..483eb90 100755 --- a/xivplan-db.rc +++ b/xivplan-db.rc @@ -13,7 +13,7 @@ xivplan_db_log="/var/log/xivplan_db.log" xivplan_db_chdir="${xivplan_db_root}" command="/usr/sbin/daemon" -command_args="-f -R 5 -P ${pidfile} -o ${xivplan_db_log} /usr/local/bin/deno run --allow-net --allow-import ${xivplan_db_root}/mod.ts" +command_args="-f -R 5 -P ${pidfile} -o ${xivplan_db_log} /usr/local/bin/deno run --allow-net --allow-import --allow-env ${xivplan_db_root}/mod.ts" load_rc_config xivplan-db run_rc_command "$1"