From 004e0fa12dff041f84c72a44d063e7e342aba162 Mon Sep 17 00:00:00 2001 From: Wonkeun No Date: Fri, 2 Dec 2022 19:42:53 -0500 Subject: [PATCH] Add script converting image and committing to repo --- .eslintrc.js | 44 ++-- package-lock.json | 189 +++++++++++++----- package.json | 3 +- src/App.js | 19 +- src/AuthDialog.js | 19 +- src/UploadInterface.js | 161 ++++++++++++--- src/image-optimizer.js | 57 ++++++ src/resource/loading-gear.gif | Bin 0 -> 18486 bytes src/worker/functions/commit-files.js | 109 ++++++++++ .../worker}/functions/create-repo.js | 7 +- {worker => src/worker}/functions/get-user.js | 0 .../worker}/functions/handle-post-req.js | 0 .../worker}/functions/on-req-post.js | 0 {worker => src/worker}/functions/response.js | 0 .../worker}/functions/validate-input.js | 0 src/worker/index.js | 28 +++ {worker => src/worker}/index.test.js | 0 {worker => src/worker}/wrangler.toml | 0 worker/.eslintrc.json | 13 -- worker/.gitignore | 1 - worker/index.js | 24 --- 21 files changed, 508 insertions(+), 166 deletions(-) create mode 100644 src/image-optimizer.js create mode 100644 src/resource/loading-gear.gif create mode 100644 src/worker/functions/commit-files.js rename {worker => src/worker}/functions/create-repo.js (80%) rename {worker => src/worker}/functions/get-user.js (100%) rename {worker => src/worker}/functions/handle-post-req.js (100%) rename {worker => src/worker}/functions/on-req-post.js (100%) rename {worker => src/worker}/functions/response.js (100%) rename {worker => src/worker}/functions/validate-input.js (100%) create mode 100644 src/worker/index.js rename {worker => src/worker}/index.test.js (100%) rename {worker => src/worker}/wrangler.toml (100%) delete mode 100644 worker/.eslintrc.json delete mode 100644 worker/.gitignore delete mode 100644 worker/index.js diff --git a/.eslintrc.js b/.eslintrc.js index c02fc66..4ab840a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,25 +1,25 @@ module.exports = { - env: { - browser: true, - node: true, - commonjs: true, - es2021: true, - jest: true, + env: { + browser: true, + node: true, + commonjs: true, + es2021: true, + jest: true, + serviceworker: true, + }, + extends: ['eslint:recommended', 'plugin:react/recommended'], + overrides: [], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + ecmaFeatures: { + jsx: true, }, - extends: ['eslint:recommended', 'plugin:react/recommended'], - overrides: [], - parserOptions: { - ecmaVersion: 'latest', - sourceType: "module", - ecmaFeatures: { - jsx: true - } + }, + rules: {}, + settings: { + react: { + version: 'detect', }, - rules: {}, - settings: { - react: { - version: "detect" - } - }, - - }; \ No newline at end of file + }, +}; diff --git a/package-lock.json b/package-lock.json index d02fc02..cd43fc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@fontsource/poppins": "^4.5.10", "@octokit/rest": "^19.0.5", "bootstrap": "^5.2.2", + "compressorjs": "^1.1.1", "eslint": "^8.27.0", "http-status-codes": "^2.2.0", "octokit": "^2.0.10", @@ -6219,6 +6220,25 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@typescript-eslint/utils": { "version": "5.43.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz", @@ -7224,6 +7244,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "node_modules/blueimp-canvas-to-blob": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz", + "integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==" + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -7785,6 +7810,15 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/compressorjs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.1.1.tgz", + "integrity": "sha512-SysRuUPfmUNoq+RviE0iMFVUmoX2q/x+7PkEPUmk6NGkd85hDrmvujx0Qtp8UCGA6KMe5kuodsylPQcNaLf60w==", + "dependencies": { + "blueimp-canvas-to-blob": "^3.29.0", + "is-blob": "^2.1.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -10650,19 +10684,6 @@ } ] }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", @@ -10870,25 +10891,6 @@ "node": ">=4" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -11476,6 +11478,17 @@ "node": ">=8" } }, + "node_modules/is-blob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz", + "integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -17398,6 +17411,25 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/react-dev-utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/react-dev-utils/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -17599,6 +17631,19 @@ } } }, + "node_modules/react-scripts/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/react-scripts/node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -24847,6 +24892,21 @@ "is-glob": "^4.0.3", "semver": "^7.3.7", "tsutils": "^3.21.0" + }, + "dependencies": { + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + } } }, "@typescript-eslint/utils": { @@ -25626,6 +25686,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "blueimp-canvas-to-blob": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz", + "integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==" + }, "body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -26051,6 +26116,15 @@ } } }, + "compressorjs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.1.1.tgz", + "integrity": "sha512-SysRuUPfmUNoq+RviE0iMFVUmoX2q/x+7PkEPUmk6NGkd85hDrmvujx0Qtp8UCGA6KMe5kuodsylPQcNaLf60w==", + "requires": { + "blueimp-canvas-to-blob": "^3.29.0", + "is-blob": "^2.1.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -28004,16 +28078,6 @@ "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==" }, - "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, "fs-monkey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", @@ -28159,19 +28223,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -28587,6 +28638,11 @@ "binary-extensions": "^2.0.0" } }, + "is-blob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz", + "integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==" + }, "is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -32611,6 +32667,19 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -32745,6 +32814,16 @@ "source-map": "^0.7.3" } }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, "react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", diff --git a/package.json b/package.json index 8202e8c..6490335 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "build": "react-scripts build", "test": "jest --", "eject": "react-scripts eject", - "auth-worker": "wrangler dev ./worker/index", + "auth-worker": "wrangler dev ./src/worker/index", "auth-worker:login": "wrangler login", "lint": "eslint src/**/*.js", "format": "npx prettier --write .", @@ -28,6 +28,7 @@ "@fontsource/poppins": "^4.5.10", "@octokit/rest": "^19.0.5", "bootstrap": "^5.2.2", + "compressorjs": "^1.1.1", "eslint": "^8.27.0", "http-status-codes": "^2.2.0", "octokit": "^2.0.10", diff --git a/src/App.js b/src/App.js index a3be9ac..ec24214 100644 --- a/src/App.js +++ b/src/App.js @@ -1,13 +1,13 @@ -import React from "react"; -import NavigationBar from "./NavigationBar"; -import AuthDialog from "./AuthDialog"; -import UploadInterface from "./UploadInterface"; +import React from 'react'; +import NavigationBar from './NavigationBar'; +import AuthDialog from './AuthDialog'; +import UploadInterface from './UploadInterface'; function App() { const [token, setToken] = React.useState(null); const [repository, setRepository] = React.useState(null); const [show, setShow] = React.useState(true); - const isAuthorized = token && repository; + const isAuthorized = Boolean(token && repository); return ( <> @@ -19,14 +19,9 @@ function App() { }} /> - + - + ); } diff --git a/src/AuthDialog.js b/src/AuthDialog.js index 1f6ef66..9792e04 100644 --- a/src/AuthDialog.js +++ b/src/AuthDialog.js @@ -1,5 +1,5 @@ -import React, { useRef } from "react"; -import { Button, Form, Modal } from "react-bootstrap"; +import React, { useRef } from 'react'; +import { Button, Form, Modal } from 'react-bootstrap'; import PropTypes from 'prop-types'; function AuthDialog({ show, setShow, setToken, setRepository }) { @@ -23,7 +23,7 @@ function AuthDialog({ show, setShow, setToken, setRepository }) { - Repository (username/repository_name) + Repository Name @@ -43,13 +43,12 @@ function AuthDialog({ show, setShow, setToken, setRepository }) { let token = tokenEl.current; let repo = repoEl.current; - const validRepo = - /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}\/[a-zA-Z0-9_.-]+$/i; + const validRepo = /^[a-zA-Z0-9_.-]+$/i; - if (token.value === "") { + if (token.value === '') { token.focus(); return; - } else if (repo.value === "" || !repo.value.match(validRepo)) { + } else if (repo.value === '' || !repo.value.match(validRepo)) { repo.focus(); return; } @@ -69,7 +68,7 @@ AuthDialog.propTypes = { show: PropTypes.bool, setToken: PropTypes.func, setRepository: PropTypes.func, - setShow: PropTypes.func -} + setShow: PropTypes.func, +}; -export default AuthDialog \ No newline at end of file +export default AuthDialog; diff --git a/src/UploadInterface.js b/src/UploadInterface.js index 1edbe47..c33334c 100644 --- a/src/UploadInterface.js +++ b/src/UploadInterface.js @@ -1,23 +1,132 @@ -import React, { useRef, useState } from "react"; -import "./App.css"; -import "bootstrap/dist/css/bootstrap.min.css"; -import { FileUploader } from "react-drag-drop-files"; -import { Button, OverlayTrigger, Tooltip } from "react-bootstrap"; +import React, { useRef, useState } from 'react'; +import './App.css'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import { FileUploader } from 'react-drag-drop-files'; +import { Alert, Button, Image, OverlayTrigger, Tooltip } from 'react-bootstrap'; import PropTypes from 'prop-types'; +import { Octokit } from '@octokit/rest'; +import getUser from './worker/functions/get-user'; +import createRepo from './worker/functions/create-repo'; +import { + getCurrentCommit, + createBlobForFile, + createNewTree, + getPathNamesFromFile, + createNewCommit, + setBranchToCommit, +} from './worker/functions/commit-files'; +import { createOptimizedImages } from './image-optimizer'; +import loadingGif from './resource/loading-gear.gif'; -const fileTypes = ["jpg", "jpeg", "png", "bmp", "gif"]; +const fileTypes = ['jpg', 'jpeg', 'png', 'bmp', 'gif']; -function UploadInterface({ isAuthorized }) { - const [image, setImage] = useState(null); +function UploadInterface({ isAuthorized, token, repository }) { + const [images, setImages] = useState([]); + const [userMessage, setUserMessage] = useState(''); + const [errorOccurred, setErrorOccurred] = useState(false); + const [loading, setLoading] = useState(false); const imgPreviewEl = useRef(null); + async function uploadBtnClicked() { + setUserMessage('MyPhotoHub is validating user token...'); + setLoading(true); + setErrorOccurred(false); + + const octokit = new Octokit({ auth: token }); + let username, repoCreated; + try { + username = await getUser(octokit); + } catch (err) { + console.error('Invalid PAT token'); + setUserMessage('Sorry, could not find a user with the token'); + setErrorOccurred(true); + setLoading(false); + return; + } + + setUserMessage('User validated! MyPhotoHub is creating a GitHub repository...'); + repoCreated = await createRepo(octokit, username, repository); + + if (repoCreated) { + setUserMessage('GitHub repository has been created! Creating optimized images...'); + + const convertedFiles = await createOptimizedImages(images); + if (!convertedFiles) { + setUserMessage('Something went wrong while converting images...'); + setLoading(false); + return; + } + const pathNames = getPathNamesFromFile(convertedFiles); + + setUserMessage('Images optimized! Preparing image files for a new commit...'); + try { + const listOfBlob = await createBlobForFile(octokit, username, repository, convertedFiles); + + const currentCommit = await getCurrentCommit(octokit, username, repository, 'main'); + + const newTree = await createNewTree( + octokit, + username, + repository, + listOfBlob, + pathNames, + currentCommit.treeSha + ); + + setUserMessage('Now creating a commit to repo...'); + const commitMessage = 'Add my photos to repo'; + const newCommit = await createNewCommit( + octokit, + username, + repository, + commitMessage, + newTree.sha, + currentCommit.commitSha + ); + + await setBranchToCommit(octokit, username, repository, 'main', newCommit.sha); + + setUserMessage( + `Process complete. You can check out https://github.com/${username}/${repository}` + ); + setLoading(false); + } catch (err) { + setLoading(false); + setErrorOccurred(true); + setUserMessage(`Something went wrong while creating a commit`); + console.error('Error occurred while creating a commit'); + } + } else { + console.error('Error occurred while creating a repo'); + setUserMessage('Sorry, something went wrong while creating a repository'); + setErrorOccurred(true); + setLoading(false); + } + } + return (
+ {!userMessage ? ( + <> + ) : loading ? ( + + + {userMessage} + + ) : !errorOccurred ? ( + + {userMessage} + + ) : ( + + {userMessage} + + )} Selected file preview

Drag and Drop or Click to Upload Images

@@ -25,27 +134,28 @@ function UploadInterface({ isAuthorized }) { name="file" accept={fileTypes} types={fileTypes} - multiple={false} + multiple={true} classes="Drop-zone" - handleChange={(file) => { - setImage(file); + handleChange={(files) => { + setImages(files); const reader = new FileReader(); reader.onload = (e) => { imgPreviewEl.current.src = e.target.result; }; - reader.readAsDataURL(file); - imgPreviewEl.current.title = file.name; + reader.readAsDataURL(files[0]); + imgPreviewEl.current.title = files[0].name; + console.log('IMAGE', images); }} - label={"Upload or drop a file right here"} + label={'Upload or drop a file right here'} /> - {!image - ? "Select Image to Upload" + {!images + ? 'Select Image to Upload' : !isAuthorized - ? "Add Token and Repository" - : "Click to Upload"} + ? 'Add Token and Repository' + : 'Click to Upload'} } placement="bottom" @@ -54,7 +164,8 @@ function UploadInterface({ isAuthorized }) { @@ -66,7 +177,9 @@ function UploadInterface({ isAuthorized }) { } UploadInterface.propTypes = { - isAuthorized:PropTypes.bool -} + isAuthorized: PropTypes.bool, + token: PropTypes.string, + repository: PropTypes.string, +}; -export default UploadInterface \ No newline at end of file +export default UploadInterface; diff --git a/src/image-optimizer.js b/src/image-optimizer.js new file mode 100644 index 0000000..87d87c7 --- /dev/null +++ b/src/image-optimizer.js @@ -0,0 +1,57 @@ +import Compressor from 'compressorjs'; + +const compressorOptions = [ + { mimeType: 'image/jpeg', width: 375 }, + { mimeType: 'image/jpeg', width: 744 }, + { mimeType: 'image/jpeg', width: 950 }, + { mimeType: 'image/jpeg', width: 1120 }, + { mimeType: 'image/webp', width: 375 }, + { mimeType: 'image/webp', width: 744 }, + { mimeType: 'image/webp', width: 950 }, + { mimeType: 'image/webp', width: 1120 }, + { mimeType: 'image/png', width: 375 }, + { mimeType: 'image/png', width: 744 }, + { mimeType: 'image/png', width: 950 }, + { mimeType: 'image/png', width: 1120 }, + { mimeType: 'image/avif', width: 375 }, + { mimeType: 'image/avif', width: 744 }, + { mimeType: 'image/avif', width: 950 }, + { mimeType: 'image/avif', width: 1120 }, +]; + +const compressImage = (file, option) => { + return new Promise((resolve, reject) => { + new Compressor(file, { + width: option.width, + quality: 0.6, + success: (result) => { + const fileName = + file.name.replace(/\.[^/.]+$/, '') + + '_' + + option.width + + '.' + + option.mimeType.substring(option.mimeType.indexOf('/') + 1); + resolve(new File([result], fileName, { type: option.mimeType })); + }, + error: (err) => { + console.error(err.message); + reject(err); + }, + }); + }); +}; + +export const createOptimizedImages = async (originalImages) => { + if (!originalImages) { + return; + } + + let compressFilesPromises = []; + compressorOptions.forEach((option) => { + for (const image of originalImages) { + compressFilesPromises.push(compressImage(image, option)); + } + }); + + return Promise.all(compressFilesPromises); +}; diff --git a/src/resource/loading-gear.gif b/src/resource/loading-gear.gif new file mode 100644 index 0000000000000000000000000000000000000000..7fc383415dce7c00c9f599bbdc25f67893c30b55 GIT binary patch literal 18486 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 s7?T { + const { data: refData } = await octokit.request( + `GET /repos/${username}/${repo}/git/ref/heads/${branch}`, + { + owner: username, + repo: repo, + ref: `heads/${branch}`, + } + ); + + const commitSha = refData.object.sha; + const { data: commitData } = await octokit.request( + `GET /repos/${username}/${repo}/git/commits/${commitSha}`, + { + owner: username, + repo: repo, + commit_sha: commitSha, + } + ); + return { + commitSha, + treeSha: commitData.tree.sha, + }; +}; + +const createBlobForFile = async (octokit, username, repoName, files) => { + let blobDataPromises = []; + for (const file of files) { + let reader = new FileReader(); + await reader.readAsArrayBuffer(file); + const promise = new Promise((resolve, reject) => { + reader.onload = async () => { + const imageBuffer = reader.result; + const byteArray = new Uint8Array(imageBuffer); + const blob = new Blob([byteArray]); + const BlobURL = URL.createObjectURL(blob); + const blobData = octokit.request(`POST /repos/${username}/${repoName}/git/blobs`, { + owner: username, + repo: repoName, + content: BlobURL, + }); + resolve(blobData); + }; + reader.onerror = reject; + }); + blobDataPromises.push(promise); + } + return Promise.all(blobDataPromises); +}; + +const createNewTree = async (octokit, username, repoName, blobs, paths, parentTreeSha) => { + const blobData = blobs.map((blob) => blob.data); + const trees = blobData.map(({ sha }, index) => ({ + path: `images/${paths[index]}`, + mode: `100644`, + type: `blob`, + sha: sha, + })); + const { data } = await octokit.request(`POST /repos/${username}/${repoName}/git/trees`, { + owner: username, + repo: repoName, + base_tree: parentTreeSha, + tree: trees, + }); + return data; +}; + +const createNewCommit = async ( + octokit, + username, + repoName, + message, + currentTreeSha, + currentCommitSha +) => + ( + await octokit.request(`POST /repos/${username}/${repoName}/git/commits`, { + owner: username, + repo: repoName, + message: message, + tree: currentTreeSha, + parents: [currentCommitSha], + }) + ).data; + +const setBranchToCommit = (octokit, username, repoName, branch = `main`, commitSha) => + octokit.request(`PATCH /repos/${username}/${repoName}/git/refs/heads/${branch}`, { + owner: username, + repo: repoName, + ref: `heads/${branch}`, + sha: commitSha, + }); + +const getPathNamesFromFile = (convertedFiles) => { + let pathNames = []; + for (const file of convertedFiles) { + pathNames.push(file.name); + } + return pathNames; +}; + +module.exports = { + getCurrentCommit, + createBlobForFile, + createNewTree, + getPathNamesFromFile, + createNewCommit, + setBranchToCommit, +}; diff --git a/worker/functions/create-repo.js b/src/worker/functions/create-repo.js similarity index 80% rename from worker/functions/create-repo.js rename to src/worker/functions/create-repo.js index 37d5eee..bca0cc1 100644 --- a/worker/functions/create-repo.js +++ b/src/worker/functions/create-repo.js @@ -1,15 +1,14 @@ const generateUniqueName = (username) => { - return `${username}-photohub-${new Date(Date.now()).toLocaleDateString( - "en-CA" - )}`; + return `${username}-photohub-${new Date(Date.now()).toLocaleDateString('en-CA')}`; }; const createRepo = async (octokit, username, repoName) => { try { await octokit.rest.repos.createForAuthenticatedUser({ name: repoName ? repoName : generateUniqueName(username), - description: "Your repository generated using my-photohub", + description: 'Your repository generated using my-photohub', private: false, + auto_init: true, }); return true; } catch (err) { diff --git a/worker/functions/get-user.js b/src/worker/functions/get-user.js similarity index 100% rename from worker/functions/get-user.js rename to src/worker/functions/get-user.js diff --git a/worker/functions/handle-post-req.js b/src/worker/functions/handle-post-req.js similarity index 100% rename from worker/functions/handle-post-req.js rename to src/worker/functions/handle-post-req.js diff --git a/worker/functions/on-req-post.js b/src/worker/functions/on-req-post.js similarity index 100% rename from worker/functions/on-req-post.js rename to src/worker/functions/on-req-post.js diff --git a/worker/functions/response.js b/src/worker/functions/response.js similarity index 100% rename from worker/functions/response.js rename to src/worker/functions/response.js diff --git a/worker/functions/validate-input.js b/src/worker/functions/validate-input.js similarity index 100% rename from worker/functions/validate-input.js rename to src/worker/functions/validate-input.js diff --git a/src/worker/index.js b/src/worker/index.js new file mode 100644 index 0000000..23abce0 --- /dev/null +++ b/src/worker/index.js @@ -0,0 +1,28 @@ +import { onRequestPost } from './functions/on-req-post'; +import { StatusCodes } from 'http-status-codes'; +import { rawHtmlResponse, loginForm } from './functions/response'; + +const handleRequest = async (request) => { + console.log('HANDLE REQUEST'); + const result = await onRequestPost(request); + if (result === StatusCodes.CONFLICT) { + const error = '

ERROR: Repo already exists

'; + return rawHtmlResponse(loginForm(error)); + } + return new Response(result); +}; + +addEventListener('fetch', (event) => { + console.log('FETCH EVENT'); + const { request } = event; + const { url } = request; + // GET request + if (new URL(url).pathname === '/' && request.method === 'GET') { + return event.respondWith(rawHtmlResponse(loginForm())); + // POST requests + } else if (request.method === 'POST') { + return event.respondWith(handleRequest(request)); + } +}); + +export default handleRequest; diff --git a/worker/index.test.js b/src/worker/index.test.js similarity index 100% rename from worker/index.test.js rename to src/worker/index.test.js diff --git a/worker/wrangler.toml b/src/worker/wrangler.toml similarity index 100% rename from worker/wrangler.toml rename to src/worker/wrangler.toml diff --git a/worker/.eslintrc.json b/worker/.eslintrc.json deleted file mode 100644 index 62a4635..0000000 --- a/worker/.eslintrc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true, - "serviceworker": true - }, - "overrides": [], - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "rules": {} -} diff --git a/worker/.gitignore b/worker/.gitignore deleted file mode 100644 index b512c09..0000000 --- a/worker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules \ No newline at end of file diff --git a/worker/index.js b/worker/index.js deleted file mode 100644 index 871051e..0000000 --- a/worker/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import { onRequestPost } from "./functions/on-req-post"; -import { StatusCodes } from "http-status-codes"; -import { rawHtmlResponse, loginForm } from "./functions/response"; - -const handleRequest = async (request) => { - const result = await onRequestPost(request); - if (result === StatusCodes.CONFLICT) { - const error = "

ERROR: Repo already exists

"; - return rawHtmlResponse(loginForm(error)); - } - return new Response(result); -}; - -addEventListener("fetch", (event) => { - const { request } = event; - const { url } = request; - // GET request - if (new URL(url).pathname === "/" && request.method === "GET") { - return event.respondWith(rawHtmlResponse(loginForm())); - // POST requests - } else if (request.method === "POST") { - return event.respondWith(handleRequest(request)); - } -});