aboutsummaryrefslogtreecommitdiffstats
path: root/backend
diff options
context:
space:
mode:
authorMaksymilian Jopek <maks@jopek.eu>2023-03-28 20:14:37 +0200
committerMaksymilian Jopek <maks@jopek.eu>2023-03-28 20:14:37 +0200
commit4582aee9c51800f7b236fc9d731829c16254429f (patch)
tree057c40045beeb7db4599c1bdcf96c4040162c362 /backend
parentd44a5a6c4530691a63204b2231f04e2bcf287907 (diff)
downloadaparatus-4582aee9c51800f7b236fc9d731829c16254429f.tar.gz
aparatus-4582aee9c51800f7b236fc9d731829c16254429f.tar.zst
aparatus-4582aee9c51800f7b236fc9d731829c16254429f.zip
Add backend code to repo
Diffstat (limited to 'backend')
-rw-r--r--backend/main.js46
-rw-r--r--backend/package.json6
-rw-r--r--backend/pnpm-lock.yaml402
-rwxr-xr-xbackend/start-entr1
-rw-r--r--backend/static/index.html78
-rw-r--r--backend/static/index.js59
6 files changed, 592 insertions, 0 deletions
diff --git a/backend/main.js b/backend/main.js
new file mode 100644
index 0000000..ae330b1
--- /dev/null
+++ b/backend/main.js
@@ -0,0 +1,46 @@
+const express = require("express");
+const formidable = require('formidable');
+const fs = require("fs").promises
+
+const app = express();
+app.use(express.static('static'))
+app.use(express.json());
+const PORT = process.env.PORT || 8000;
+const uploadDir = __dirname + "/static/upload"
+
+app.get('/', () => {
+
+})
+app.post('/upload', (req, res, next) => {
+ const form = formidable({ multiples: true, uploadDir, keepExtensions: true });
+
+ form.parse(req, (err, fields, files) => {
+ if (err) {
+ next(err);
+ return;
+ }
+ res.send("ok");
+ console.log({ fields, files });
+ });
+});
+// getPathFromName
+const gpfn = name => uploadDir + "/" + name
+app.post('/delete-files', async (req, res) => {
+ for (const n of req.body.names) {
+ await fs.unlink(gpfn(n))
+ }
+ res.send("ok")
+})
+app.post('/rename-file', async (req, res) => {
+ let { nn, on } = req.body
+ if (!nn.includes('.')) nn += '.' + on.split('.').pop()
+ await fs.rename(gpfn(on), gpfn(nn))
+ res.send("ok")
+})
+app.get('/files', async (_, res) => {
+ res.json(await fs.readdir(__dirname + '/static/upload'))
+});
+app.listen(PORT, () => {
+ console.log("Server listening on port " + PORT);
+})
+
diff --git a/backend/package.json b/backend/package.json
new file mode 100644
index 0000000..27ff5c0
--- /dev/null
+++ b/backend/package.json
@@ -0,0 +1,6 @@
+{
+ "dependencies": {
+ "express": "^4.17.2",
+ "formidable": "^2.0.1"
+ }
+}
diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml
new file mode 100644
index 0000000..3a07e58
--- /dev/null
+++ b/backend/pnpm-lock.yaml
@@ -0,0 +1,402 @@
+lockfileVersion: '6.0'
+
+dependencies:
+ express:
+ specifier: ^4.17.2
+ version: 4.17.2
+ formidable:
+ specifier: ^2.0.1
+ version: 2.0.1
+
+packages:
+
+ /accepts@1.3.7:
+ resolution: {integrity: sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-types: 2.1.34
+ negotiator: 0.6.2
+ dev: false
+
+ /array-flatten@1.1.1:
+ resolution: {integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=}
+ dev: false
+
+ /asap@2.0.6:
+ resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
+ dev: false
+
+ /body-parser@1.19.1:
+ resolution: {integrity: sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.1
+ content-type: 1.0.4
+ debug: 2.6.9
+ depd: 1.1.2
+ http-errors: 1.8.1
+ iconv-lite: 0.4.24
+ on-finished: 2.3.0
+ qs: 6.9.6
+ raw-body: 2.4.2
+ type-is: 1.6.18
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /bytes@3.1.1:
+ resolution: {integrity: sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /content-disposition@0.5.4:
+ resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /content-type@1.0.4:
+ resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /cookie-signature@1.0.6:
+ resolution: {integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=}
+ dev: false
+
+ /cookie@0.4.1:
+ resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /debug@2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.0.0
+ dev: false
+
+ /depd@1.1.2:
+ resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /destroy@1.0.4:
+ resolution: {integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=}
+ dev: false
+
+ /dezalgo@1.0.3:
+ resolution: {integrity: sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==}
+ dependencies:
+ asap: 2.0.6
+ wrappy: 1.0.2
+ dev: false
+
+ /ee-first@1.1.1:
+ resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=}
+ dev: false
+
+ /encodeurl@1.0.2:
+ resolution: {integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /escape-html@1.0.3:
+ resolution: {integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=}
+ dev: false
+
+ /etag@1.8.1:
+ resolution: {integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /express@4.17.2:
+ resolution: {integrity: sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==}
+ engines: {node: '>= 0.10.0'}
+ dependencies:
+ accepts: 1.3.7
+ array-flatten: 1.1.1
+ body-parser: 1.19.1
+ content-disposition: 0.5.4
+ content-type: 1.0.4
+ cookie: 0.4.1
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 1.1.2
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 1.1.2
+ fresh: 0.5.2
+ merge-descriptors: 1.0.1
+ methods: 1.1.2
+ on-finished: 2.3.0
+ parseurl: 1.3.3
+ path-to-regexp: 0.1.7
+ proxy-addr: 2.0.7
+ qs: 6.9.6
+ range-parser: 1.2.1
+ safe-buffer: 5.2.1
+ send: 0.17.2
+ serve-static: 1.14.2
+ setprototypeof: 1.2.0
+ statuses: 1.5.0
+ type-is: 1.6.18
+ utils-merge: 1.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /finalhandler@1.1.2:
+ resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ debug: 2.6.9
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ on-finished: 2.3.0
+ parseurl: 1.3.3
+ statuses: 1.5.0
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /formidable@2.0.1:
+ resolution: {integrity: sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==}
+ dependencies:
+ dezalgo: 1.0.3
+ hexoid: 1.0.0
+ once: 1.4.0
+ qs: 6.9.3
+ dev: false
+
+ /forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /fresh@0.5.2:
+ resolution: {integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /hexoid@1.0.0:
+ resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==}
+ engines: {node: '>=8'}
+ dev: false
+
+ /http-errors@1.8.1:
+ resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ depd: 1.1.2
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 1.5.0
+ toidentifier: 1.0.1
+ dev: false
+
+ /iconv-lite@0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: false
+
+ /inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ dev: false
+
+ /ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+ dev: false
+
+ /media-typer@0.3.0:
+ resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /merge-descriptors@1.0.1:
+ resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=}
+ dev: false
+
+ /methods@1.1.2:
+ resolution: {integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /mime-db@1.51.0:
+ resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /mime-types@2.1.34:
+ resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.51.0
+ dev: false
+
+ /mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: false
+
+ /ms@2.0.0:
+ resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=}
+ dev: false
+
+ /ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ dev: false
+
+ /negotiator@0.6.2:
+ resolution: {integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /on-finished@2.3.0:
+ resolution: {integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ ee-first: 1.1.1
+ dev: false
+
+ /once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ dependencies:
+ wrappy: 1.0.2
+ dev: false
+
+ /parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /path-to-regexp@0.1.7:
+ resolution: {integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=}
+ dev: false
+
+ /proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+ dev: false
+
+ /qs@6.9.3:
+ resolution: {integrity: sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==}
+ engines: {node: '>=0.6'}
+ dev: false
+
+ /qs@6.9.6:
+ resolution: {integrity: sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==}
+ engines: {node: '>=0.6'}
+ dev: false
+
+ /range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /raw-body@2.4.2:
+ resolution: {integrity: sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.1
+ http-errors: 1.8.1
+ iconv-lite: 0.4.24
+ unpipe: 1.0.0
+ dev: false
+
+ /safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ dev: false
+
+ /safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ dev: false
+
+ /send@0.17.2:
+ resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ debug: 2.6.9
+ depd: 1.1.2
+ destroy: 1.0.4
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 0.5.2
+ http-errors: 1.8.1
+ mime: 1.6.0
+ ms: 2.1.3
+ on-finished: 2.3.0
+ range-parser: 1.2.1
+ statuses: 1.5.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /serve-static@1.14.2:
+ resolution: {integrity: sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 0.17.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ dev: false
+
+ /statuses@1.5.0:
+ resolution: {integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+ dev: false
+
+ /type-is@1.6.18:
+ resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ media-typer: 0.3.0
+ mime-types: 2.1.34
+ dev: false
+
+ /unpipe@1.0.0:
+ resolution: {integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /utils-merge@1.0.1:
+ resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=}
+ engines: {node: '>= 0.4.0'}
+ dev: false
+
+ /vary@1.1.2:
+ resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ dev: false
diff --git a/backend/start-entr b/backend/start-entr
new file mode 100755
index 0000000..7921ea4
--- /dev/null
+++ b/backend/start-entr
@@ -0,0 +1 @@
+find . -type f | rg -v "node_modules|upload|png|svg|lock|hbs" | entr -r node main.js
diff --git a/backend/static/index.html b/backend/static/index.html
new file mode 100644
index 0000000..afa1954
--- /dev/null
+++ b/backend/static/index.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <title></title>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <style>
+ body {
+ background-color: black;
+ color: white;
+ }
+
+ #container {
+ display: flex;
+ flex-wrap: wrap;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .dImg {
+ background-color: darkgray;
+ /* width: fit-content; */
+ width: 12rem;
+ padding: 10px;
+ border-radius: 20px;
+ margin-right: 25px;
+ margin-bottom: 25px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ @media all and (max-width: 960px) {
+ .dImg {
+ width: 9rem;
+ }
+ }
+
+ .dImg * {
+ margin: 5px;
+ }
+
+ .dImg p {
+ overflow-wrap: anywhere;
+ }
+
+ .dImg input[type='checkbox'] {
+ width: 20px;
+ height: 20px;
+ display: inline;
+ }
+
+ .dImg img {
+ border-radius: 30px;
+ aspect-ratio: 1 / 1;
+ }
+
+ .dImg label {
+ display: flex;
+ align-items: center;
+ }
+ </style>
+ <script src="index.js" defer></script>
+</head>
+
+<body>
+ <header>
+ <h2>Uploaded Images:</h2>
+ <button type="button" onclick="getFiles()">Reload</button>
+ <button type="button" onclick="selectAll()">Select all</button>
+ <button type="button" onclick="removeAllSel()">Remove selected</button>
+ </header><br>
+ <div id="container"></div>
+</body>
+
+</html>
diff --git a/backend/static/index.js b/backend/static/index.js
new file mode 100644
index 0000000..07f4c89
--- /dev/null
+++ b/backend/static/index.js
@@ -0,0 +1,59 @@
+const newDiv = `<!-- <div class="dImg"> -->
+ <p>$name</p><br>
+ <img src="upload/$name" alt="$name" width="120" height="120"/>
+ <button type="button" onclick="deleteFiles(['$name'])">Delete</button>
+ <button type="button" onclick="renameFile('$name')">Rename</button><br>
+ <label>
+ Select:
+ <input type="checkbox" name="$name" />
+ </label>
+ <!-- </div> -->`
+
+function selectAll() {
+ for (const c of document.querySelectorAll("input[type='checkbox']")) {
+ c.checked = !c.checked
+ }
+}
+async function deleteFiles(names) {
+ if (!confirm("Are you sure about that file deleting thingy?")) return;
+ await fetch("/delete-files", {
+ method: "POST",
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ names }),
+ })
+ getFiles()
+}
+async function removeAllSel() {
+ const names = []
+ for (const c of [...document.querySelectorAll("input[type='checkbox']")].filter(i => i.checked)) {
+ names.push(c.name)
+ }
+ deleteFiles(names)
+}
+async function renameFile(on) {
+ const nn = prompt("What will be the new name of this beautiful picture?")
+ if (!nn) return;
+ await fetch("/rename-file", {
+ method: "POST",
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ nn, on }),
+ })
+ getFiles()
+}
+const cont = document.getElementById("container");
+async function getFiles() {
+ const files = await fetch("/files").then(res => res.json());
+ for (const d of document.querySelectorAll(".dImg")) d.remove()
+ for (const f of files) {
+ const div = document.createElement("div")
+ div.className = "dImg"
+ div.innerHTML = newDiv.replaceAll("$name", f);
+ cont.appendChild(div)
+ }
+}
+getFiles()
+