init commit
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["@babel/env", "@babel/react"],
|
||||
"plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-object-rest-spread"]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
node_modules/
|
||||
public/dist/
|
||||
config/
|
||||
.env.development
|
||||
.env.test
|
||||
.env.production
|
||||
.well-known/
|
||||
.eslintrc.js
|
||||
.eslintrc.json
|
||||
changeEncrytionPassword/
|
||||
certificate.ca-bundle
|
||||
certificate.crt
|
||||
certificate.key
|
||||
package-lock.json
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"setupFiles": [
|
||||
"raf/polyfill",
|
||||
"<rootDir>/tests/setupTests.js"
|
||||
],
|
||||
"snapshotSerializers": [
|
||||
"enzyme-to-json/serializer"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
const prompt = require('password-prompt')
|
||||
const env = require("../src/enviroment/env")
|
||||
const crypto = require("crypto");
|
||||
|
||||
const getKey = async() => {
|
||||
|
||||
if (process.env.NODE_ENV) {
|
||||
|
||||
let password = await prompt("Enter Server Encryption Password: ", {method: "hide"});
|
||||
|
||||
password = crypto.createHash("md5").update(password).digest("hex");
|
||||
|
||||
env.key = password;
|
||||
|
||||
} else {
|
||||
|
||||
let password = "1234";
|
||||
|
||||
password = crypto.createHash("md5").update(password).digest("hex");
|
||||
|
||||
env.key = password;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = getKey;
|
||||
@@ -0,0 +1,22 @@
|
||||
const prompt = require('password-prompt')
|
||||
const env = require("../src/enviroment/env")
|
||||
const crypto = require("crypto");
|
||||
|
||||
const getKey = async() => {
|
||||
|
||||
let password = await prompt("Enter New Server Encryption Password: ", {method: "hide"});
|
||||
|
||||
let confirmPassword = await prompt("Verify New Server Encryption Password: ", {method: "hide"});
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
console.log("New Passwords do not match, exiting...");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
password = crypto.createHash("md5").update(password).digest("hex");
|
||||
|
||||
env.newKey = password;
|
||||
|
||||
}
|
||||
|
||||
module.exports = getKey;
|
||||
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"name": "my-drive",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "",
|
||||
"scripts": {
|
||||
"server": "live-server public/",
|
||||
"build:dev": "webpack",
|
||||
"build:prod": "cross-env NODE_ENV=production webpack -p --env production",
|
||||
"dev-server": "webpack-dev-server",
|
||||
"test": "cross-env NODE_ENV=test env-cmd -f ./config/test.env jest --config=jest.config.json --watchAll --runInBand",
|
||||
"start:dev": "env-cmd -f ./config/dev.env node server/serverStart.js",
|
||||
"start": "env-cmd -f ./config/prod.env node server/serverStart.js",
|
||||
"clean-database": "env-cmd -f ./config/prod.env node serverUtils/cleanDatabase.js",
|
||||
"clean-database:dev": "env-cmd -f ./config/dev.env node serverUtils/cleanDatabase.js",
|
||||
"backup-database": "env-cmd -f ./config/prod.env node serverUtils/backupDatabase.js",
|
||||
"backup-database:dev": "env-cmd -f ./config/dev.env node serverUtils/backupDatabase.js",
|
||||
"restore-database": "env-cmd -f ./config/prod.env node serverUtils/restoreDatabase.js",
|
||||
"restore-database:dev": "env-cmd -f ./config/dev.env node serverUtils/restoreDatabase.js",
|
||||
"delete-temp-database": "env-cmd -f ./config/prod.env node serverUtils/deleteTempDatabase.js",
|
||||
"delete-temp-database:dev": "env-cmd -f ./config/dev.env node serverUtils/deleteTempDatabase.js",
|
||||
"delete-database": "env-cmd -f ./config/prod.env node serverUtils/deleteDatabase.js",
|
||||
"delete-database:dev": "env-cmd -f ./config/dev.env node serverUtils/deleteDatabase.js",
|
||||
"change-password-database": "env-cmd -f ./config/prod.env node serverUtils/changeEncryptionPassword.js",
|
||||
"change-password-database:dev": "env-cmd -f ./config/dev.env node serverUtils/changeEncryptionPassword.js",
|
||||
"create-indexes-database": "env-cmd -f ./config/prod.env node serverUtils/createIndexes.js",
|
||||
"create-indexes-database:dev": "env-cmd -f ./config/dev.env node serverUtils/createIndexes.js",
|
||||
"heroku-postbuild": "yarn run build:prod"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.8.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"@babel/preset-react": "^7.8.3",
|
||||
"axios": "^0.19.2",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"bcrypt": "^3.0.8",
|
||||
"body-parser": "^1.19.0",
|
||||
"bytes": "^3.1.0",
|
||||
"cli-progress": "^3.6.0",
|
||||
"compression": "^1.7.4",
|
||||
"concat-stream": "^2.0.0",
|
||||
"connect-busboy": "0.0.2",
|
||||
"copy-text-to-clipboard": "^2.1.1",
|
||||
"core-js": "^3.6.4",
|
||||
"crypto": "^1.0.1",
|
||||
"diskusage": "^1.1.3",
|
||||
"express": "^4.17.1",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"helmet": "^3.21.2",
|
||||
"history": "^4.10.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mini-css-extract-plugin": "^0.8.2",
|
||||
"moment": "^2.24.0",
|
||||
"mongodb": "^3.5.3",
|
||||
"mongoose": "^5.9.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
"password-prompt": "^1.1.2",
|
||||
"progress-stream": "^2.0.0",
|
||||
"prompts": "^2.3.1",
|
||||
"raf": "^3.4.1",
|
||||
"react": "^16.12.0",
|
||||
"react-circular-progressbar": "^2.0.3",
|
||||
"react-contextmenu": "^2.13.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-infinite-scroller": "^1.2.4",
|
||||
"react-redux": "^7.2.0",
|
||||
"react-router-dom": "^5.1.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"sharp": "^0.23.4",
|
||||
"sweetalert2": "^9.7.2",
|
||||
"temp": "^0.9.1",
|
||||
"uuid": "^3.4.0",
|
||||
"validator": "^12.2.0",
|
||||
"webpack": "^4.41.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^2.20.0",
|
||||
"@typescript-eslint/parser": "^2.20.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"compression-webpack-plugin": "^3.1.0",
|
||||
"cross-env": "^6.0.3",
|
||||
"css-loader": "^3.4.2",
|
||||
"dart-sass": "^1.25.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"env-cmd": "^10.1.0",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.2",
|
||||
"enzyme-to-json": "^3.4.4",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-import": "^2.20.1",
|
||||
"eslint-plugin-react": "^7.18.3",
|
||||
"jest": "^24.9.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"live-server": "^1.2.1",
|
||||
"react-test-renderer": "^16.12.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"style-loader": "^1.1.3",
|
||||
"superagent-binary-parser": "^1.0.1",
|
||||
"supertest": "^4.0.2",
|
||||
"webpack-bundle-analyzer": "^3.6.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z" /></svg>
|
||||
|
After Width: | Height: | Size: 367 B |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100" height="100" viewBox="0 0 24 24"><path d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z" /></svg>
|
||||
|
After Width: | Height: | Size: 589 B |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 309 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="500" height="500" viewBox="0 0 24 24"><path d="M8,13H10.55V10H13.45V13H16L12,17L8,13M19.35,10.04C21.95,10.22 24,12.36 24,15A5,5 0 0,1 19,20H6A6,6 0 0,1 0,14C0,10.91 2.34,8.36 5.35,8.04C6.6,5.64 9.11,4 12,4C15.64,4 18.67,6.59 19.35,10.04M19,18A3,3 0 0,0 22,15C22,13.45 20.78,12.14 19.22,12.04L17.69,11.93L17.39,10.43C16.88,7.86 14.62,6 12,6C9.94,6 8.08,7.14 7.13,8.97L6.63,9.92L5.56,10.03C3.53,10.24 2,11.95 2,14A4,4 0 0,0 6,18H19Z" /></svg>
|
||||
|
After Width: | Height: | Size: 680 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" /></svg>
|
||||
|
After Width: | Height: | Size: 419 B |
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="50" height="32" viewBox="0 0 50 32">
|
||||
<image width="50" height="32" xlink:href="data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAgCAYAAABQISshAAABI0lEQVRYhc2XwQ7EIAhEp/7/P7vJJntYBZQBtHMyqDAvbZU+vXcI+gWfeeqqVF9NcNWV8VsgxvFXI8i0QImdluThL9a0CWvTCyCmuTYGDN2A2fbVnAZPwrh8SR97ZgFW7hoMCIphqNxNOpMrCy7E5nx+T+QNMDQEhlfrJkwIAsI3cgMmDAEBZFrgEGMoBQIKiLhwUyfuJNGbBqJu2FBll6B6skDMjQtZRq05S6aXnQvRTGBIMizFdrT0sHuzZ8CUQcDZokRgSiFA9Fonf31dtZim8QSMuwbb/VbCULlZELrgQnTOCAiSYUK5oiBhA1k5MkAQNJLyVLNAQBpKezUzQeA0lnpYZINg02D6iVcBgoVRa45WFYhmWIqlqBJkNF7XDQD4AMs7Mz+qUOkuAAAAAElFTkSuQmCC"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 666 B |
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="4156.000000pt" height="4156.000000pt" viewBox="0 0 4156.000000 4156.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,4156.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 443 B |
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M13,5V11H14.17L12,13.17L9.83,11H11V5H13M15,3H9V9H5L12,16L19,9H15V3M19,18H5V20H19V18Z" /></svg>
|
||||
|
After Width: | Height: | Size: 381 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="240" height="240" viewBox="0 0 24 24"><path d="M9 22C8.45 22 8 21.55 8 21V18H4C2.9 18 2 17.11 2 16L2 4C2 2.89 2.89 2 4 2H20C21.1 2 22 2.89 22 4V16C22 17.1 21.1 18 20 18L13.9 18L10.2 21.71C10 21.9 9.75 22 9.5 22L9.5 22H9M18 14V12H12.5L10.5 14H18M6 14H8.5L15.35 7.12C15.55 6.93 15.55 6.61 15.35 6.41L13.59 4.65C13.39 4.45 13.07 4.45 12.88 4.65L6 11.53V14Z" /></svg>
|
||||
|
After Width: | Height: | Size: 603 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z" /></svg>
|
||||
|
After Width: | Height: | Size: 382 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100" height="100" viewBox="0 0 24 24"><path d="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" /></svg>
|
||||
|
After Width: | Height: | Size: 390 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200" viewBox="0 0 24 24"><path d="M10,4V8H14V4H10M16,4V8H20V4H16M16,10V14H20V10H16M16,16V20H20V16H16M14,20V16H10V20H14M8,20V16H4V20H8M8,14V10H4V14H8M8,8V4H4V8H8M10,14H14V10H10V14M4,2H20A2,2 0 0,1 22,4V20A2,2 0 0,1 20,22H4C2.92,22 2,21.1 2,20V4A2,2 0 0,1 4,2Z" /></svg>
|
||||
|
After Width: | Height: | Size: 521 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M20 6H12L10 4H4A2 2 0 0 0 2 6V18A2 2 0 0 0 4 20H20A2 2 0 0 0 22 18V8A2 2 0 0 0 20 6M17 13V17H15V14H13V17H11V13H9L14 9L19 13Z" /></svg>
|
||||
|
After Width: | Height: | Size: 421 B |
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z" /></svg>
|
||||
|
After Width: | Height: | Size: 496 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200" viewBox="0 0 24 24"><path d="M7,5H21V7H7V5M7,13V11H21V13H7M4,4.5A1.5,1.5 0 0,1 5.5,6A1.5,1.5 0 0,1 4,7.5A1.5,1.5 0 0,1 2.5,6A1.5,1.5 0 0,1 4,4.5M4,10.5A1.5,1.5 0 0,1 5.5,12A1.5,1.5 0 0,1 4,13.5A1.5,1.5 0 0,1 2.5,12A1.5,1.5 0 0,1 4,10.5M7,19V17H21V19H7M4,16.5A1.5,1.5 0 0,1 5.5,18A1.5,1.5 0 0,1 4,19.5A1.5,1.5 0 0,1 2.5,18A1.5,1.5 0 0,1 4,16.5Z" /></svg>
|
||||
|
After Width: | Height: | Size: 611 B |
|
After Width: | Height: | Size: 51 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M20 18H4V8H20V18M12 6L10 4H4C2.9 4 2 4.89 2 6V18C2 19.11 2.9 20 4 20H20C21.11 20 22 19.11 22 18V8C22 6.9 21.11 6 20 6H12M11 14V12H15V9L19 13L15 17V14H11Z" /></svg>
|
||||
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M10 20H6V4H13V9H18V12.1L20 10.1V8L14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H10V20M20.2 13C20.3 13 20.5 13.1 20.6 13.2L21.9 14.5C22.1 14.7 22.1 15.1 21.9 15.3L20.9 16.3L18.8 14.2L19.8 13.2C19.9 13.1 20 13 20.2 13M20.2 16.9L14.1 23H12V20.9L18.1 14.8L20.2 16.9Z" /></svg>
|
||||
|
After Width: | Height: | Size: 558 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z" /></svg>
|
||||
|
After Width: | Height: | Size: 354 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z"/></svg>
|
||||
|
After Width: | Height: | Size: 499 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="150" height="150" viewBox="0 0 24 24"><path d="M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z" /></svg>
|
||||
|
After Width: | Height: | Size: 405 B |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
|
||||
|
||||
<title>MyDrive</title>
|
||||
<link rel="stylesheet" type="text/css" href="/dist/styles.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="app"></div>
|
||||
<!-- <script src="/socket.io/socket.io.js"></script> -->
|
||||
<script src="/dist/bundle.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
# MyDrive
|
||||
|
||||
Coming Soon :)
|
||||
|
||||
yarn install
|
||||
yarn run build:prod
|
||||
yarn start
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = __dirname
|
||||
@@ -0,0 +1,75 @@
|
||||
const express = require("express");
|
||||
const app = express();
|
||||
const path = require("path")
|
||||
const publicPath = path.join(__dirname, "..", "public");
|
||||
const userRouter = require("../src/express-routers/user")
|
||||
const fileRouter = require("../src/express-routers/file")
|
||||
const folderRouter = require("../src/express-routers/folder");
|
||||
const storageRouter = require("../src/express-routers/storage");
|
||||
const bodyParser = require('body-parser');
|
||||
const https = require("https");
|
||||
const fs = require("fs");
|
||||
const helmet = require("helmet");
|
||||
const busboy = require("connect-busboy")
|
||||
const compression = require("compression");
|
||||
|
||||
|
||||
const cert = fs.readFileSync("certificate.crt")
|
||||
const ca = fs.readFileSync("certificate.ca-bundle");
|
||||
const key = fs.readFileSync("certificate.key");
|
||||
|
||||
|
||||
const options = {
|
||||
cert,
|
||||
ca,
|
||||
key
|
||||
}
|
||||
|
||||
const http = require("http")
|
||||
|
||||
const server = http.createServer(app);
|
||||
const serverHttps = https.createServer( options, app );
|
||||
|
||||
|
||||
require("../src/db/mongoose")
|
||||
|
||||
|
||||
app.use(helmet())
|
||||
app.use(compression());
|
||||
app.use(express.json());
|
||||
app.use(express.static(publicPath));
|
||||
app.use(bodyParser.json({limit: "50mb"}));
|
||||
app.use(bodyParser.urlencoded({limit: "50mb", extended: true, parameterLimit:50000}))
|
||||
|
||||
app.use(busboy({
|
||||
highWaterMark: 2 * 1024 * 1024,
|
||||
}));
|
||||
|
||||
app.use(userRouter, fileRouter, folderRouter, storageRouter);
|
||||
|
||||
|
||||
const nodeMode = process.env.NODE_ENV ? "Production" : "Development/Testing";
|
||||
|
||||
console.log("Node Enviroment Mode:", nodeMode);
|
||||
|
||||
|
||||
app.get("*", (req, res) => {
|
||||
|
||||
res.sendFile(path.join(publicPath, "index.html"))
|
||||
})
|
||||
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
|
||||
module.exports = {server, serverHttps};
|
||||
|
||||
} else {
|
||||
|
||||
module.exports = server;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
const getKey = require("../key/getKey");
|
||||
|
||||
const serverStart = async() => {
|
||||
|
||||
await getKey();
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
|
||||
const {server, serverHttps} = require("./server");
|
||||
|
||||
server.listen(process.env.HTTP_PORT,process.env.URL, () => {
|
||||
console.log("Http Server Running On Port:", process.env.HTTP_PORT);
|
||||
})
|
||||
|
||||
serverHttps.listen(process.env.HTTPS_PORT, function () {
|
||||
console.log( 'Https Server Running On Port:', process.env.HTTPS_PORT);
|
||||
} );
|
||||
|
||||
} else {
|
||||
|
||||
const server = require("./server");
|
||||
|
||||
server.listen(process.env.HTTP_PORT,process.env.URL, () => {
|
||||
console.log("Development Server Running On Port:", process.env.HTTP_PORT);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
serverStart();
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const conn = mongoose.connection;
|
||||
const prompts = require("prompts");
|
||||
const createTempDirectory = require("./createTempDirectory");
|
||||
|
||||
const waitForDatabase = () => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (conn.readyState !== 1) {
|
||||
|
||||
conn.once("open", () => {
|
||||
|
||||
resolve();
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const copyDatabase = async() => {
|
||||
|
||||
console.log("Waiting For Database Connection...");
|
||||
await waitForDatabase();
|
||||
console.log("Connected To Database\n");
|
||||
|
||||
const userConfimation = await prompts({
|
||||
type: 'text',
|
||||
message: "Warning: This will create a new Database backup, overwriting\n" +
|
||||
"the current database backup. Only ONE Database backup\n" +
|
||||
"can Be Stored At A Time.\n" +
|
||||
"For more permanent backups, use MongoExport, or \n" +
|
||||
"Backup data manually. \n" +
|
||||
"Would you like to continue? (Yes/No)",
|
||||
name: "value"
|
||||
})
|
||||
|
||||
if (!userConfimation.value || userConfimation.value.toLowerCase() !== "yes") {
|
||||
|
||||
console.log("Exiting...")
|
||||
process.exit()
|
||||
return;
|
||||
}
|
||||
|
||||
await createTempDirectory();
|
||||
|
||||
console.log("Finished Copying Database, Exiting...");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
copyDatabase()
|
||||
@@ -0,0 +1,295 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const conn = mongoose.connection;
|
||||
const ObjectID = require('mongodb').ObjectID
|
||||
const imageChecker = require("../src/utils/imageChecker");
|
||||
const createThumbnail = require("./createThumbnailBuffer");
|
||||
const prompts = require("prompts");
|
||||
const getKey = require("../key/getKey");
|
||||
const getNewKey = require("../key/getNewKey");
|
||||
const crypto = require("crypto");
|
||||
const env = require("../src/enviroment/env");
|
||||
const cliProgress = require('cli-progress');
|
||||
const createTempDirectory = require("./createTempDirectory");
|
||||
|
||||
const waitForDatabase = () => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (conn.readyState !== 1) {
|
||||
|
||||
conn.once("open", () => {
|
||||
|
||||
resolve();
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const reencryptFile = (file, newKey, user) => {
|
||||
|
||||
return new Promise(async(resolve, reject) => {
|
||||
|
||||
const fileID = file._id;
|
||||
const filename = file.filename;
|
||||
|
||||
let decryptBucket = new mongoose.mongo.GridFSBucket(conn.db, {
|
||||
chunkSizeBytes: 1024 * 255,
|
||||
bucketName: "temp-fs"
|
||||
});
|
||||
|
||||
let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
|
||||
chunkSizeBytes: 1024 * 255
|
||||
});
|
||||
|
||||
const metadata = file.metadata;
|
||||
|
||||
const readStream = decryptBucket.openDownloadStream(ObjectID(fileID));
|
||||
|
||||
const writeStream = bucket.openUploadStream(filename, {metadata});
|
||||
|
||||
const foundOldUser = await conn.db.collection("temp-users").findOne({_id: user._id});
|
||||
|
||||
const password = getOldEncryptionKey(foundOldUser);
|
||||
|
||||
const IV = file.metadata.IV.buffer
|
||||
|
||||
const CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, IV);
|
||||
|
||||
const NEW_CIPHER_KEY = crypto.createHash('sha256').update(newKey).digest()
|
||||
|
||||
const cipher = crypto.createCipheriv('aes256', NEW_CIPHER_KEY, IV);
|
||||
|
||||
cipher.on("error", (e) => {
|
||||
console.log("de", e);
|
||||
})
|
||||
|
||||
readStream.pipe(decipher).pipe(cipher).pipe(writeStream);
|
||||
|
||||
writeStream.on("finish", async(newFile) => {
|
||||
|
||||
const imageCheck = imageChecker(filename);
|
||||
|
||||
if (file.length < 15728640 && imageCheck) {
|
||||
|
||||
try {
|
||||
await createThumbnail(newFile, filename, user, newKey);
|
||||
} catch (e) {
|
||||
console.log("Cannot create thumbnail", e);
|
||||
}
|
||||
|
||||
resolve();
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const findFiles = async() => {
|
||||
|
||||
const userListCursor = await conn.db.collection("users").find({});
|
||||
const userListCount = await conn.db.collection("users").find({}).count();
|
||||
const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
|
||||
progressBar.start(userListCount, 0);
|
||||
|
||||
for await (const currentUser of userListCursor) {
|
||||
|
||||
const currentUserID = currentUser._id;
|
||||
|
||||
const newEncrpytionKey = getEncryptionKey(currentUser);
|
||||
|
||||
const listCursor = await conn.db.collection("temp-fs.files").find({"metadata.owner": ObjectID(currentUserID)});
|
||||
|
||||
for await (const currentFile of listCursor) {
|
||||
|
||||
await reencryptFile(currentFile, newEncrpytionKey, currentUser);
|
||||
}
|
||||
|
||||
progressBar.increment()
|
||||
}
|
||||
|
||||
progressBar.stop();
|
||||
}
|
||||
|
||||
const generateEncryptionKeys = async(user) => {
|
||||
|
||||
const userPassword = user.password;
|
||||
const masterPassword = env.newKey;
|
||||
|
||||
const randomKey = crypto.randomBytes(32);
|
||||
|
||||
const iv = crypto.randomBytes(16);
|
||||
const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest();
|
||||
const cipher = crypto.createCipheriv('aes-256-cbc', USER_CIPHER_KEY, iv);
|
||||
let encryptedText = cipher.update(randomKey);
|
||||
encryptedText = Buffer.concat([encryptedText, cipher.final()]);
|
||||
|
||||
const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest();
|
||||
const masterCipher = crypto.createCipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv);
|
||||
let masterEncryptedText = masterCipher.update(encryptedText);
|
||||
masterEncryptedText = Buffer.concat([masterEncryptedText, masterCipher.final()]).toString("hex");
|
||||
|
||||
user.privateKey = masterEncryptedText;
|
||||
user.publicKey = iv.toString("hex");
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
const getOldEncryptionKey = (user) => {
|
||||
|
||||
const userPassword = user.password;
|
||||
const masterEncryptedText = user.privateKey;
|
||||
const masterPassword = env.key;
|
||||
const iv = Buffer.from(user.publicKey, "hex");
|
||||
|
||||
const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest();
|
||||
const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest();
|
||||
|
||||
const unhexMasterText = Buffer.from(masterEncryptedText, "hex");
|
||||
const masterDecipher = crypto.createDecipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv)
|
||||
let masterDecrypted = masterDecipher.update(unhexMasterText);
|
||||
masterDecrypted = Buffer.concat([masterDecrypted, masterDecipher.final()])
|
||||
|
||||
let decipher = crypto.createDecipheriv('aes-256-cbc', USER_CIPHER_KEY, iv);
|
||||
let decrypted = decipher.update(masterDecrypted);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
const getEncryptionKey = (user) => {
|
||||
|
||||
const userPassword = user.password;
|
||||
const masterEncryptedText = user.privateKey;
|
||||
const masterPassword = env.newKey;
|
||||
const iv = Buffer.from(user.publicKey, "hex");
|
||||
|
||||
const USER_CIPHER_KEY = crypto.createHash('sha256').update(userPassword).digest();
|
||||
const MASTER_CIPHER_KEY = crypto.createHash('sha256').update(masterPassword).digest();
|
||||
|
||||
const unhexMasterText = Buffer.from(masterEncryptedText, "hex");
|
||||
const masterDecipher = crypto.createDecipheriv('aes-256-cbc', MASTER_CIPHER_KEY, iv)
|
||||
let masterDecrypted = masterDecipher.update(unhexMasterText);
|
||||
masterDecrypted = Buffer.concat([masterDecrypted, masterDecipher.final()])
|
||||
|
||||
let decipher = crypto.createDecipheriv('aes-256-cbc', USER_CIPHER_KEY, iv);
|
||||
let decrypted = decipher.update(masterDecrypted);
|
||||
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
const findUsers = async() => {
|
||||
|
||||
const listCursor = await conn.db.collection("temp-users").find({});
|
||||
const listCount = await conn.db.collection("temp-users").find({}).count();
|
||||
const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
|
||||
progressBar.start(listCount, 0);
|
||||
|
||||
for await (const currentUser of listCursor) {
|
||||
|
||||
try {
|
||||
|
||||
const newUser = await generateEncryptionKeys(currentUser);
|
||||
|
||||
await conn.db.collection("users").insertOne(newUser);
|
||||
|
||||
progressBar.increment()
|
||||
|
||||
} catch (e) {
|
||||
console.log("e", e);
|
||||
}
|
||||
}
|
||||
|
||||
progressBar.stop();
|
||||
|
||||
}
|
||||
|
||||
const changeEncryptionPassword = async() => {
|
||||
|
||||
console.log("Waiting For Database...");
|
||||
await waitForDatabase();
|
||||
console.log("Connected To Database...\n");
|
||||
|
||||
const userConfimation = await prompts({
|
||||
type: 'text',
|
||||
message: "Warning: This will automatically run Backup-Database,\n" +
|
||||
"overwriting the current Backup. And will also clear all file chunks\n" +
|
||||
"other than the Data Backup. Then it will re-encrypt files and move them back over.\n" +
|
||||
"(Optional) Create a manual Backup for additional safety.\n" +
|
||||
"Would you like to continue? (Yes/No)",
|
||||
name: "value"
|
||||
})
|
||||
|
||||
if (!userConfimation.value || userConfimation.value.toLowerCase() !== "yes") {
|
||||
|
||||
console.log("Exiting...")
|
||||
process.exit()
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("\nGetting Old Password...");
|
||||
await getKey();
|
||||
console.log("Got Key\n")
|
||||
|
||||
console.log("Getting New Password...");
|
||||
await getNewKey();
|
||||
console.log("Got New Key\n");
|
||||
|
||||
console.log("Creating Temporary Collection...\n");
|
||||
await createTempDirectory();
|
||||
console.log("Temporary Collection Completed\n")
|
||||
|
||||
console.log("Created New Backup Sucessfully\n")
|
||||
|
||||
console.log("Deleting Current Chunks Collection...");
|
||||
try {
|
||||
await conn.db.collection("fs.chunks").drop();
|
||||
} catch (e) {}
|
||||
console.log("Current Chunk Collection Deleted\n");
|
||||
|
||||
console.log("Deleting Current File Collection...");
|
||||
try {
|
||||
await conn.db.collection("fs.files").drop();
|
||||
} catch (e) {}
|
||||
console.log("Deleted Current File Collection\n")
|
||||
|
||||
console.log("Delete Current Users...");
|
||||
try {
|
||||
await conn.db.collection("users").drop();
|
||||
} catch (e) {}
|
||||
console.log("Current Users Deleted\n");
|
||||
|
||||
console.log("Deleting Current Thumbnails...");
|
||||
try {
|
||||
await conn.db.collection("thumbnails").drop();
|
||||
} catch (e) {}
|
||||
console.log("Deleted Current Thumbnails\n");
|
||||
|
||||
console.log("Generating User Encryption Keys...");
|
||||
await findUsers();
|
||||
console.log("Generated User Encryption Keys\n")
|
||||
|
||||
console.log("Moving Files By User...");
|
||||
await findFiles();
|
||||
console.log("Moved All Files...\n")
|
||||
|
||||
process.exit();
|
||||
}
|
||||
|
||||
changeEncryptionPassword();
|
||||
@@ -0,0 +1,118 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const conn = mongoose.connection;
|
||||
const ObjectID = require('mongodb').ObjectID
|
||||
const prompts = require("prompts");
|
||||
const cliProgress = require('cli-progress');
|
||||
const createTempDirectory = require("./createTempDirectory");
|
||||
|
||||
const waitForDatabase = () => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (conn.readyState !== 1) {
|
||||
|
||||
conn.once("open", () => {
|
||||
|
||||
resolve();
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const moveFileChunks = async(fileID, oldDatabaseChunks, newDatabaseChunks) => {
|
||||
|
||||
const listChunkCursor = await conn.db.collection(oldDatabaseChunks).find({files_id: ObjectID(fileID)});
|
||||
|
||||
for await (const currentChunk of listChunkCursor) {
|
||||
|
||||
await conn.db.collection(newDatabaseChunks).insertOne(currentChunk);
|
||||
}
|
||||
}
|
||||
|
||||
const findFiles = async(oldDatabaseList, oldDatabaseChunks, newDatabaseChunks) => {
|
||||
|
||||
const listCursor = await conn.db.collection(oldDatabaseList).find({});
|
||||
const listCount = await conn.db.collection(oldDatabaseList).find({}).count();
|
||||
const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
|
||||
progressBar.start(listCount, 0);
|
||||
|
||||
for await (const currentFile of listCursor) {
|
||||
|
||||
const fileID = currentFile._id;
|
||||
await moveFileChunks(fileID, oldDatabaseChunks, newDatabaseChunks);
|
||||
progressBar.increment();
|
||||
}
|
||||
|
||||
progressBar.stop();
|
||||
}
|
||||
|
||||
const cleanDatabase = async() => {
|
||||
|
||||
console.log("Waiting For Database Connection...");
|
||||
await waitForDatabase();
|
||||
console.log("Connected To Database\n");
|
||||
|
||||
const userConfimation = await prompts({
|
||||
type: 'text',
|
||||
message: "Warning: This will automatically run Backup-Database,\n" +
|
||||
"overwriting the current Backup. And will also clear all file chunks\n" +
|
||||
"other than the Data Backup. Then it will move only used file chunks\n" +
|
||||
"over to the Main Database. If this process fails AFTER the Automatic Backup\n" +
|
||||
"use the Restore-Database feature. \n" +
|
||||
"Would you like to continue? (Yes/No)",
|
||||
name: "value"
|
||||
})
|
||||
|
||||
if (!userConfimation.value || userConfimation.value.toLowerCase() !== "yes") {
|
||||
|
||||
console.log("Exiting...")
|
||||
process.exit()
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Creating Temporary Collection...\n");
|
||||
await createTempDirectory();
|
||||
console.log("Temporary Collection Completed\n")
|
||||
|
||||
console.log("Created New Backup Sucessfully\n")
|
||||
|
||||
console.log("Deleting Current Chunks Collection...");
|
||||
try {
|
||||
await conn.db.collection("fs.chunks").drop();
|
||||
} catch (e) {}
|
||||
console.log("Current Chunk Collection Deleted\n");
|
||||
|
||||
console.log("Moving Used Files...");
|
||||
await findFiles("temp-fs.files", "temp-fs.chunks", "fs.chunks");
|
||||
console.log("Moved All Used Files\n");
|
||||
|
||||
console.log("Creating File Chunks Index...");
|
||||
await conn.db.collection("fs.chunks").createIndex({ files_id: 1, n: 1 }, { unique: true });
|
||||
console.log("Created File Chunks Index\n");
|
||||
|
||||
console.log("Deleteing Current Transcoded Video Chunks Collection...");
|
||||
try {
|
||||
await conn.db.collection("videos.chunks").drop();
|
||||
} catch (e) {}
|
||||
console.log("Deleted Current Transcoded Video Chunks Collection\n")
|
||||
|
||||
console.log("Moving Used Video Files...");
|
||||
await findFiles("temp-videos.files", "temp-videos.chunks", "videos.chunks");
|
||||
console.log("Moved All Used Video Files\n")
|
||||
|
||||
console.log("Creating Transcoded Video Chunks Index...");
|
||||
await conn.db.collection("videos.chunks").createIndex({ files_id: 1, n: 1 }, { unique: true });
|
||||
console.log("Created Transcoded Video Chunks Index")
|
||||
|
||||
process.exit();
|
||||
|
||||
}
|
||||
|
||||
cleanDatabase();
|
||||
@@ -0,0 +1,50 @@
|
||||
const mongoose = require("../src/db/mongoose");
|
||||
const conn = mongoose.connection;
|
||||
|
||||
const waitForDatabase = () => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (conn.readyState !== 1) {
|
||||
|
||||
conn.once("open", () => {
|
||||
|
||||
resolve();
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const createIndexes = async() => {
|
||||
|
||||
console.log("Waiting For Database...");
|
||||
await waitForDatabase();
|
||||
console.log("Connected To Database\n");
|
||||
|
||||
console.log("Creating Indexes...")
|
||||
await conn.db.collection("fs.files").createIndex({uploadDate: 1});
|
||||
await conn.db.collection("fs.files").createIndex({uploadDate: -1});
|
||||
await conn.db.collection("fs.files").createIndex({filename: 1});
|
||||
await conn.db.collection("fs.files").createIndex({filename: -1});
|
||||
await conn.db.collection("fs.files").createIndex({"metadata.owner": 1});
|
||||
|
||||
await conn.db.collection("folders").createIndex({createdAt: 1})
|
||||
await conn.db.collection("folders").createIndex({createdAt: -1})
|
||||
await conn.db.collection("folders").createIndex({name: 1});
|
||||
await conn.db.collection("folders").createIndex({name: -1})
|
||||
await conn.db.collection("folders").createIndex({owner: 1})
|
||||
|
||||
await conn.db.collection("thumbnails").createIndex({owner: 1})
|
||||
console.log("Indexes Created");
|
||||
|
||||
process.exit();
|
||||
|
||||
}
|
||||
|
||||
createIndexes();
|
||||
@@ -0,0 +1,103 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const conn = mongoose.connection;
|
||||
const cliProgress = require('cli-progress');
|
||||
|
||||
const clearTempDirectory = async() => {
|
||||
|
||||
console.log("Removing Temporary Collections...");
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-fs.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-fs.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-thumbnails").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-folders").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-videos.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-videos.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-users").drop();
|
||||
} catch (e) {}
|
||||
|
||||
console.log("Removed Temporary Collections\n")
|
||||
}
|
||||
|
||||
const moveItem = async(oldPath, newPath) => {
|
||||
|
||||
const listCursor = await conn.db.collection(oldPath).find({});
|
||||
const listCount = await conn.db.collection(oldPath).find({}).count();
|
||||
const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
|
||||
progressBar.start(listCount, 0);
|
||||
|
||||
for await (const currentFile of listCursor) {
|
||||
|
||||
await conn.db.collection(newPath).insertOne(currentFile);
|
||||
progressBar.increment();
|
||||
}
|
||||
|
||||
progressBar.stop();
|
||||
}
|
||||
|
||||
const createTempDirectory = async() => {
|
||||
|
||||
await clearTempDirectory();
|
||||
|
||||
console.log("Moving Files...")
|
||||
await moveItem("fs.files", "temp-fs.files")
|
||||
console.log("Moved All Files\n");
|
||||
|
||||
|
||||
console.log(`Moving File Chunks...`);
|
||||
await moveItem("fs.chunks", "temp-fs.chunks");
|
||||
console.log("Moved All Chunks \n");
|
||||
|
||||
console.log("Creating Temp File Chunks Index...");
|
||||
await conn.db.collection("temp-fs.chunks").createIndex({ files_id: 1, n: 1 }, { unique: true });
|
||||
console.log("Created Temp File Chunks Index\n");
|
||||
|
||||
console.log(`Moving Thumbnails...`)
|
||||
await moveItem("thumbnails", "temp-thumbnails");
|
||||
console.log("Moved All Thumbnails \n")
|
||||
|
||||
|
||||
console.log(`Moving Folders...`);
|
||||
await moveItem("folders", "temp-folders");
|
||||
console.log("All Folders Moved \n");
|
||||
|
||||
|
||||
console.log(`Moving Transcoded Video Files...`);
|
||||
await moveItem("videos.files", "temp-videos.files")
|
||||
console.log("All Transcoded Video Files Moved \n");
|
||||
|
||||
|
||||
console.log(`Moving Transcoded Video Chunks...`)
|
||||
await moveItem("videos.chunks", "temp-videos.chunks")
|
||||
console.log("All Transcoded Video Chunks Moved \n");
|
||||
|
||||
console.log("Creating Temp Transcoded Video Chunks Index...");
|
||||
await conn.db.collection("videos.chunks").createIndex({ files_id: 1, n: 1 }, { unique: true })
|
||||
console.log("Created Temp Transcoded Video Chunks Index \n");
|
||||
|
||||
|
||||
console.log(`Moving Users...`)
|
||||
await moveItem("users", "temp-users")
|
||||
console.log("All Users Moved\n");
|
||||
}
|
||||
|
||||
module.exports = createTempDirectory;
|
||||
@@ -0,0 +1,82 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils")
|
||||
const conn = mongoose.connection;
|
||||
const crypto= require("crypto");
|
||||
const env = require("../src/enviroment/env");
|
||||
const Thumbnail = require("../src/models/thumbnail");
|
||||
const ObjectID = require('mongodb').ObjectID
|
||||
const sharp = require("sharp");
|
||||
const concat = require("concat-stream")
|
||||
|
||||
const createThumbnail = async(file, filename, user, newKey) => {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
try {
|
||||
|
||||
const password = newKey;
|
||||
|
||||
let CIPHER_KEY = crypto.createHash('sha256').update(password).digest()
|
||||
|
||||
let bucket = new mongoose.mongo.GridFSBucket(conn.db, {
|
||||
chunkSizeBytes: 1024 * 255,
|
||||
})
|
||||
|
||||
const readStream = bucket.openDownloadStream(ObjectID(file._id))
|
||||
|
||||
readStream.on("error", (e) => {
|
||||
console.log("File service upload thumbnail error", e);
|
||||
resolve(file);
|
||||
})
|
||||
|
||||
const decipher = crypto.createDecipheriv('aes256', CIPHER_KEY, file.metadata.IV.buffer);
|
||||
|
||||
decipher.on("error", (e) => {
|
||||
console.log("File service upload thumbnail decipher error", e);
|
||||
resolve(file)
|
||||
})
|
||||
|
||||
const concatStream = concat(async(bufferData) => {
|
||||
|
||||
const thumbnailIV = crypto.randomBytes(16);
|
||||
|
||||
const thumbnailCipher = crypto.createCipheriv("aes256", CIPHER_KEY, thumbnailIV);
|
||||
|
||||
bufferData = Buffer.concat([thumbnailIV, thumbnailCipher.update(bufferData), thumbnailCipher.final()]);
|
||||
|
||||
const thumbnailModel = new Thumbnail({name: filename, owner: user._id, data: bufferData});
|
||||
|
||||
await thumbnailModel.save();
|
||||
|
||||
let updatedFile = await conn.db.collection("fs.files")
|
||||
.findOneAndUpdate({"_id": file._id}, {"$set": {"metadata.hasThumbnail": true, "metadata.thumbnailID": thumbnailModel._id}})
|
||||
|
||||
updatedFile = updatedFile.value;
|
||||
|
||||
updatedFile = {...updatedFile, metadata: {...updatedFile.metadata, hasThumbnail: true, thumbnailID: thumbnailModel._id}}
|
||||
|
||||
resolve(updatedFile);
|
||||
|
||||
}).on("error", (e) => {
|
||||
console.log("File service upload concat stream error", e);
|
||||
resolve(file);
|
||||
})
|
||||
|
||||
const imageResize = sharp().resize(300).on("error", (e) => {
|
||||
|
||||
console.log("resize error", e);
|
||||
resolve(file);
|
||||
})
|
||||
|
||||
readStream.pipe(decipher).pipe(imageResize).pipe(concatStream);
|
||||
|
||||
|
||||
} catch (e) {
|
||||
|
||||
console.log(e);
|
||||
resolve(file);
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = createThumbnail;
|
||||
@@ -0,0 +1,81 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const prompts = require("prompts");
|
||||
const conn = mongoose.connection;
|
||||
|
||||
const waitForDatabase = () => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (conn.readyState !== 1) {
|
||||
|
||||
conn.once("open", () => {
|
||||
|
||||
resolve();
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const deleteTempDatabase = async() => {
|
||||
|
||||
console.log("Waiting For Database...");
|
||||
await waitForDatabase();
|
||||
console.log("Connected To Database\n")
|
||||
|
||||
const userConfimation = await prompts({
|
||||
type: 'text',
|
||||
message: "Warning: This will delete all the data in the Main Database,\n" +
|
||||
"this will not delete any data in the Database Backup.\n" +
|
||||
"Would you like to continue? (Yes/No)",
|
||||
name: "value"
|
||||
})
|
||||
|
||||
if (!userConfimation.value || userConfimation.value.toLowerCase() !== "yes") {
|
||||
|
||||
console.log("Exiting...")
|
||||
process.exit()
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Removing Collections...");
|
||||
|
||||
try {
|
||||
await conn.db.collection("fs.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("fs.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("thumbnails").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("folders").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("videos.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("videos.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("users").drop();
|
||||
} catch (e) {}
|
||||
|
||||
console.log("Removed Collections\n")
|
||||
|
||||
process.exit();
|
||||
}
|
||||
|
||||
deleteTempDatabase();
|
||||
@@ -0,0 +1,79 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const prompts = require("prompts");
|
||||
const conn = mongoose.connection;
|
||||
|
||||
const waitForDatabase = () => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (conn.readyState !== 1) {
|
||||
|
||||
conn.once("open", () => {
|
||||
|
||||
resolve();
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const deleteTempDatabase = async() => {
|
||||
|
||||
console.log("Waiting For Database...");
|
||||
await waitForDatabase();
|
||||
console.log("Connected To Database\n")
|
||||
|
||||
const userConfimation = await prompts({
|
||||
type: 'text',
|
||||
message: "Warning: Deleting the Backup Database cannot be undone,\n" +
|
||||
"Would you like to continue? (Yes/No)",
|
||||
name: "value"
|
||||
})
|
||||
|
||||
if (!userConfimation.value || userConfimation.value.toLowerCase() !== "yes") {
|
||||
|
||||
console.log("Exiting...")
|
||||
process.exit()
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Removing Temporary Collections...");
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-fs.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-fs.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-thumbnails").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-folders").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-videos.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-videos.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("temp-users").drop();
|
||||
} catch (e) {}
|
||||
|
||||
console.log("Removed Temporary Collections, Exiting...");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
deleteTempDatabase();
|
||||
@@ -0,0 +1,55 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const prompts = require("prompts");
|
||||
const restoreFromTempDirectory = require("./restoreFromTempDirectory");
|
||||
const conn = mongoose.connection;
|
||||
|
||||
const waitForDatabase = () => {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (conn.readyState !== 1) {
|
||||
|
||||
conn.once("open", () => {
|
||||
|
||||
resolve();
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const restoreDatabase = async() => {
|
||||
|
||||
const userConfimation = await prompts({
|
||||
type: 'text',
|
||||
message: "Warning: This will delete ALL data," +
|
||||
" other than the Data Backup created by CopyDatabase. \nMake sure to first run CopyDatabase, and backup" +
|
||||
" your data, \nWould you like to continue? (Yes/No)",
|
||||
name: "value"
|
||||
})
|
||||
|
||||
if (!userConfimation.value || userConfimation.value.toLowerCase() !== "yes") {
|
||||
|
||||
console.log("Exiting...")
|
||||
process.exit()
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
await waitForDatabase();
|
||||
|
||||
await restoreFromTempDirectory();
|
||||
|
||||
console.log("Finished Restoring Data, Exiting...");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
restoreDatabase()
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
const mongoose = require("../src/db/mongooseServerUtils");
|
||||
const cliProgress = require('cli-progress');
|
||||
const conn = mongoose.connection;
|
||||
|
||||
const clearDirectory = async() => {
|
||||
|
||||
console.log("Removing Collections...");
|
||||
|
||||
try {
|
||||
await conn.db.collection("fs.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("fs.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("thumbnails").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("folders").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("videos.files").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("videos.chunks").drop();
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
await conn.db.collection("users").drop();
|
||||
} catch (e) {}
|
||||
|
||||
console.log("Removed Collections\n")
|
||||
}
|
||||
|
||||
const moveItem = async(oldPath, newPath) => {
|
||||
|
||||
const listCursor = await conn.db.collection(oldPath).find({});
|
||||
const listCount = await conn.db.collection(oldPath).find({}).count();
|
||||
const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
|
||||
|
||||
progressBar.start(listCount, 0);
|
||||
|
||||
for await (const currentFile of listCursor) {
|
||||
|
||||
await conn.db.collection(newPath).insertOne(currentFile);
|
||||
progressBar.increment();
|
||||
}
|
||||
|
||||
progressBar.stop();
|
||||
}
|
||||
|
||||
|
||||
const restoreFromTempDirectory = async() => {
|
||||
|
||||
console.log("\n");
|
||||
await clearDirectory();
|
||||
|
||||
console.log("Moving Files...")
|
||||
await moveItem("temp-fs.files", "fs.files")
|
||||
console.log("Moved All Files\n");
|
||||
|
||||
|
||||
console.log(`Moving File Chunks...`);
|
||||
await moveItem("temp-fs.chunks","fs.chunks");
|
||||
console.log("Moved All Chunks \n");
|
||||
|
||||
console.log("Creating File Index...");
|
||||
await conn.db.collection("fs.chunks").createIndex({ files_id: 1, n: 1 }, { unique: true })
|
||||
console.log("File Index Created \n");
|
||||
|
||||
console.log(`Moving Thumbnails...`)
|
||||
await moveItem("temp-thumbnails", "thumbnails");
|
||||
console.log("Moved All Thumbnails \n")
|
||||
|
||||
|
||||
console.log(`Moving Folders...`);
|
||||
await moveItem("temp-folders", "folders");
|
||||
console.log("All Folders Moved \n");
|
||||
|
||||
|
||||
console.log(`Moving Transcoded Video Files...`);
|
||||
await moveItem("temp-videos.files", "videos.files")
|
||||
console.log("All Transcoded Video Files Moved \n");
|
||||
|
||||
|
||||
console.log(`Moving Transcoded Video Chunks...`)
|
||||
await moveItem("temp-videos.chunks", "videos.chunks")
|
||||
console.log("All Transcoded Video Chunks Moved \n");
|
||||
|
||||
console.log("Creating Transcoded Video Chunks Index...");
|
||||
await conn.db.collection("videos.chunks").createIndex({ files_id: 1, n: 1 }, { unique: true })
|
||||
console.log("Created Transcoded Video Chunks Index \n");
|
||||
|
||||
|
||||
console.log(`Moving Users...`)
|
||||
await moveItem("temp-users", "users")
|
||||
console.log("All Users Moved\n");
|
||||
}
|
||||
|
||||
module.exports = restoreFromTempDirectory;
|
||||
@@ -0,0 +1,9 @@
|
||||
export const showAddOptions = (show) => ({
|
||||
type: "SHOW_ADD_OPTIONS",
|
||||
show
|
||||
})
|
||||
|
||||
export const showAddOptions2 = (show) => ({
|
||||
type: "SHOW_ADD_OPTIONS2",
|
||||
show
|
||||
})
|
||||
@@ -0,0 +1,163 @@
|
||||
import {setLoginFailed} from "./main";
|
||||
import {history} from "../routers/AppRouter"
|
||||
import {resetUpload} from "./uploads"
|
||||
import axios from "axios";
|
||||
import env from "../enviroment/envFrontEnd";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
export const login = (id) => ({
|
||||
type: "LOGIN",
|
||||
id
|
||||
})
|
||||
|
||||
export const logout = () => ({
|
||||
type: "LOGOUT"
|
||||
})
|
||||
|
||||
export const startLogin = (email, password, currentRoute) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const dt = {email, password};
|
||||
|
||||
axios.post(currentURL+"/user-service/login", dt).then((response) => {
|
||||
|
||||
const token = response.data.token;
|
||||
const id = response.data.user._id;
|
||||
|
||||
window.localStorage.setItem("token", token);
|
||||
|
||||
dispatch(setLoginFailed(false))
|
||||
dispatch(login(id));
|
||||
history.push(currentRoute);
|
||||
|
||||
}).catch((err) => {
|
||||
dispatch(setLoginFailed("Incorrect Email or Password"))
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const startCreateAccount = (email, password) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
|
||||
const dt = {email, password};
|
||||
axios.post(currentURL+"/user-service/create", dt).then((response) => {
|
||||
|
||||
const token = response.data.token;
|
||||
const id = response.data.user._id;
|
||||
|
||||
window.localStorage.setItem("token", token);
|
||||
|
||||
dispatch(setLoginFailed(false))
|
||||
dispatch(login(id));
|
||||
history.push("/home");
|
||||
|
||||
}).catch((err) => {
|
||||
|
||||
console.log(err);
|
||||
|
||||
if (err.response) {
|
||||
|
||||
const errStatus = err.response.status;
|
||||
|
||||
if (errStatus === 401) {
|
||||
|
||||
dispatch(setLoginFailed("Create Blocked By Admin"))
|
||||
|
||||
} else {
|
||||
|
||||
dispatch(setLoginFailed("Duplicate Email, or Invalid Password"))
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
dispatch(setLoginFailed("Duplicate Email, or Invalid Password"))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const startLoginCheck = (token, currentRoute) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + token}
|
||||
};
|
||||
|
||||
axios.get(currentURL+"/user-service/user", config).then((response) => {
|
||||
|
||||
const id = response.data._id;
|
||||
|
||||
dispatch(setLoginFailed(false))
|
||||
dispatch(login(id))
|
||||
history.push(currentRoute);
|
||||
|
||||
}).catch((err) => {
|
||||
|
||||
console.log("login check error", err);
|
||||
window.localStorage.removeItem("token")
|
||||
dispatch(setLoginFailed("Login Expired"))
|
||||
// history.push("/login")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const startLogoutAll = () => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const token = window.localStorage.getItem("token")
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + token}
|
||||
};
|
||||
|
||||
axios.post(currentURL+"/user-service/logout-all", undefined,config).then(() => {
|
||||
|
||||
window.localStorage.removeItem("token")
|
||||
|
||||
dispatch(resetUpload())
|
||||
dispatch(setLoginFailed(false))
|
||||
dispatch(logout())
|
||||
|
||||
history.push("/")
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const startLogout = () => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const token = window.localStorage.getItem("token")
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + token}
|
||||
};
|
||||
|
||||
axios.post(currentURL+"/user-service/logout", undefined,config).then(() => {
|
||||
|
||||
window.localStorage.removeItem("token")
|
||||
|
||||
dispatch(resetUpload())
|
||||
dispatch(setLoginFailed(false))
|
||||
dispatch(logout())
|
||||
|
||||
history.push("/")
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
import {addUpload, editUpload} from "./uploads";
|
||||
import {loadMoreItems, setLoading} from "./main"
|
||||
import {resetSelected} from "./selectedItem";
|
||||
import {addQuickFile, startSetQuickFiles} from "./quickFiles";
|
||||
import {startSetStorage} from "./storage"
|
||||
import uuid from "uuid";
|
||||
import axios from "axios";
|
||||
import env from "../enviroment/envFrontEnd";
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
export const setFiles = (files) => ({
|
||||
type: "SET_FILES",
|
||||
files
|
||||
})
|
||||
|
||||
export const editFile = (id, file) => ({
|
||||
type: "EDIT_FILE",
|
||||
id,
|
||||
file
|
||||
})
|
||||
|
||||
export const editFileMetadata = (id, metadata) => ({
|
||||
type: "EDIT_FILE_METADATA",
|
||||
id,
|
||||
metadata
|
||||
})
|
||||
|
||||
export const startSetFiles = (parent="/", sortby="DEFAULT", search="") => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
let limit = window.localStorage.getItem("list-size") || 50
|
||||
limit = parseInt(limit)
|
||||
|
||||
dispatch(setFiles([]))
|
||||
|
||||
axios.get(currentURL +`/file-service/list?parent=${parent}&sortby=${sortby}&search=${search}&limit=${limit}`, config).then((results) => {
|
||||
|
||||
dispatch(setLoading(true))
|
||||
dispatch(setFiles(results.data))
|
||||
dispatch(setLoading(false))
|
||||
|
||||
if (results.data.length === limit) {
|
||||
dispatch(loadMoreItems(true))
|
||||
} else {
|
||||
dispatch(loadMoreItems(false))
|
||||
}
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const loadMoreFiles = (files) => ({
|
||||
type: "LOAD_MORE_FILES",
|
||||
files
|
||||
})
|
||||
|
||||
export const startLoadMoreFiles = (parent="/", sortby="DEFAULT", search="", startAtDate, startAtName) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
let limit = window.localStorage.getItem("list-size") || 50
|
||||
limit = parseInt(limit)
|
||||
|
||||
axios.get(currentURL +`/file-service/list?limit=${limit}&parent=${parent}&sortby=${sortby}&search=${search}&startAt=${true}&startAtDate=${startAtDate}&startAtName=${startAtName}`, config).then((results) => {
|
||||
console.log("load more results", results);
|
||||
|
||||
if (results.data.length !== limit) {
|
||||
|
||||
dispatch(loadMoreItems(false))
|
||||
|
||||
} else {
|
||||
dispatch(loadMoreItems(true))
|
||||
}
|
||||
|
||||
dispatch(loadMoreFiles(results.data))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const addFile = (file) => ({
|
||||
type: "ADD_FILE",
|
||||
file
|
||||
})
|
||||
|
||||
export const startAddFile = (uploadInput, parent, parentList) => {
|
||||
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// Store the parent, incase it changes.
|
||||
const prevParent = getState().parent.parent;
|
||||
|
||||
for (let i = 0; i < uploadInput.files.length; i++) {
|
||||
const currentFile = uploadInput.files[i];
|
||||
const currentID = uuid();
|
||||
|
||||
const CancelToken = axios.CancelToken;
|
||||
const source = CancelToken.source();
|
||||
|
||||
const httpAgent = new http.Agent({ keepAlive: true });
|
||||
const httpsAgent = new https.Agent({ keepAlive: true });
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token"),
|
||||
httpAgent,
|
||||
httpsAgent,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
'Transfere-Encoding': "chunked"},
|
||||
onUploadProgress: (progressEvent) => {
|
||||
|
||||
const currentProgress = Math.round(((progressEvent.loaded / progressEvent.total) * 100));
|
||||
|
||||
if (currentProgress !== 100) {
|
||||
|
||||
dispatch(editUpload(currentID, currentProgress))
|
||||
}
|
||||
},
|
||||
cancelToken: source.token
|
||||
};
|
||||
|
||||
dispatch(addUpload({id: currentID, progress: 0, name: currentFile.name, completed: false, source, canceled: false}))
|
||||
|
||||
const data = new FormData();
|
||||
|
||||
data.append('filename', currentFile.name);
|
||||
data.append("parent", parent)
|
||||
data.append("parentList", parentList)
|
||||
data.append("currentID", currentID)
|
||||
data.append("size", currentFile.size)
|
||||
data.append('file', currentFile);
|
||||
|
||||
axios.post(currentURL +'/file-service/upload', data, config)
|
||||
.then(function (response) {
|
||||
|
||||
const currentParent = getState().parent.parent;
|
||||
// This can change by the time the file uploads
|
||||
if (prevParent === currentParent) {
|
||||
dispatch(addFile(response.data));
|
||||
}
|
||||
|
||||
dispatch(addQuickFile(response.data))
|
||||
dispatch(editUpload(currentID, 100, true))
|
||||
dispatch(resetSelected())
|
||||
dispatch(startSetStorage())
|
||||
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const removeFile = (id) => ({
|
||||
type: "REMOVE_FILE",
|
||||
id
|
||||
})
|
||||
|
||||
export const startRemoveFile = (id) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const headers = {'Authorization': "Bearer " + window.localStorage.getItem("token")};
|
||||
const data = {id}
|
||||
|
||||
axios.delete(currentURL+"/file-service/remove", {
|
||||
headers,
|
||||
data
|
||||
}).then(() => {
|
||||
dispatch(removeFile(id))
|
||||
dispatch(startSetStorage())
|
||||
dispatch(startSetQuickFiles());
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const startRenameFile = (id, title) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
const data = {id, title}
|
||||
|
||||
axios.patch(currentURL+"/file-service/rename", data, config).then(() => {
|
||||
|
||||
dispatch(editFile(id, {filename: title}))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
export const setSortBy = (sortBy) => ({
|
||||
type: "SET_SORT_BY",
|
||||
sortBy
|
||||
})
|
||||
|
||||
export const setSearch = (search) => ({
|
||||
type: "SET_SEARCH",
|
||||
search
|
||||
})
|
||||
|
||||
export const resetSearch = () => ({
|
||||
type: "RESET_SEARCH"
|
||||
})
|
||||
|
||||
export const enableListView = () => ({
|
||||
type: "ENABLE_LIST_VIEW"
|
||||
})
|
||||
|
||||
export const disableListView = () => ({
|
||||
type: "DISABLE_LIST_VIEW"
|
||||
})
|
||||
|
||||
export const setCurrentlySearching = () => ({
|
||||
type: "SET_CURRENTLY_SEARCHING"
|
||||
})
|
||||
|
||||
export const resetCurrentlySearching = () => ({
|
||||
type: "RESET_CURRENTLY_SEARCHING"
|
||||
})
|
||||
@@ -0,0 +1,115 @@
|
||||
import {startSetQuickFiles} from "./quickFiles";
|
||||
import env from "../enviroment/envFrontEnd";
|
||||
const axios = require("axios");
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
export const addFolder = (folder) => ({
|
||||
type: "ADD_FOLDER",
|
||||
folder
|
||||
})
|
||||
|
||||
export const startAddFolder = (name, owner, parent, parentList) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
if (name.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
const body = {name, parent, owner, parentList};
|
||||
|
||||
axios.post(currentURL+"/folder-service/upload", body, config).then((response) => {
|
||||
|
||||
const folder = response.data;
|
||||
|
||||
dispatch(addFolder(folder))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const setFolders = (folders) => ({
|
||||
type: "SET_FOLDERS",
|
||||
folders
|
||||
})
|
||||
|
||||
export const startSetFolders = (parent = "/", sortby="DEFAULT", search="") => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
}
|
||||
|
||||
dispatch(setFolders([]))
|
||||
|
||||
axios.get(currentURL+`/folder-service/list?parent=${parent}&sortby=${sortby}&search=${search}`, config).then((response) => {
|
||||
|
||||
const folders = response.data;
|
||||
dispatch(setFolders(folders))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const removeFolder = (id) => ({
|
||||
type: "REMOVE_FOLDER",
|
||||
id
|
||||
})
|
||||
|
||||
export const startRemoveFolder = (id, parentList) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const data = {id, parentList};
|
||||
|
||||
const headers = {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
|
||||
axios.delete(currentURL+`/folder-service/remove`, {
|
||||
headers,
|
||||
data
|
||||
}).then((response) => {
|
||||
|
||||
dispatch(removeFolder(id));
|
||||
dispatch(startSetQuickFiles())
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const editFolder = (id, folder) => ({
|
||||
type: "EDIT_FOLDER",
|
||||
id,
|
||||
folder
|
||||
})
|
||||
|
||||
export const startRenameFolder = (id, title) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
const data = {id, title}
|
||||
|
||||
axios.patch(currentURL+"/folder-service/rename", data, config).then((response) => {
|
||||
|
||||
dispatch(editFolder(id, {name: title}))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
export const showSideBar = () => ({
|
||||
type: "SHOW_SIDEBAR"
|
||||
})
|
||||
|
||||
export const hideSideBar = () => ({
|
||||
type: "HIDE_SIDEBAR"
|
||||
})
|
||||
|
||||
export const goneSideBar = () => ({
|
||||
type: "GONE_SIDEBAR"
|
||||
})
|
||||
|
||||
export const resetItems = () => ({
|
||||
type: "RESET_ITEMS"
|
||||
})
|
||||
|
||||
export const showUploader = () => ({
|
||||
type: "SHOW_UPLOADER"
|
||||
})
|
||||
|
||||
export const hideUploader = () => ({
|
||||
type: "HIDE_UPLOADER"
|
||||
})
|
||||
|
||||
export const loadMoreItems = (load) => ({
|
||||
type: "LOAD_MORE_ITEMS",
|
||||
load
|
||||
})
|
||||
|
||||
export const setLoading = (load) => ({
|
||||
type: "SET_LOADING",
|
||||
load
|
||||
})
|
||||
|
||||
export const setLoginFailed = (message) => ({
|
||||
type: "SET_LOGIN_FAILED",
|
||||
message
|
||||
})
|
||||
@@ -0,0 +1,10 @@
|
||||
export const setMoverID = (id, parent, isFile) => ({
|
||||
type: "SET_MOVER_ID",
|
||||
id,
|
||||
parent,
|
||||
isFile
|
||||
})
|
||||
|
||||
export const resetMoverID = () => ({
|
||||
type: "RESET_MOVER_ID"
|
||||
})
|
||||
@@ -0,0 +1,83 @@
|
||||
import axios from "axios";
|
||||
import env from "../enviroment/envFrontEnd";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
export const setParent = (parent="/") => ({
|
||||
type: "SET_PARENT",
|
||||
parent
|
||||
})
|
||||
|
||||
export const addParentList = (parent, name) => ({
|
||||
type: "ADD_PARENT_LIST",
|
||||
parent,
|
||||
name
|
||||
})
|
||||
|
||||
export const setParentList = (parentList, parentNameList) => ({
|
||||
type: "SET_PARENT_LIST",
|
||||
parentList,
|
||||
parentNameList
|
||||
})
|
||||
|
||||
export const startSetParentList = (id) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
}
|
||||
|
||||
axios.get(currentURL+`/folder-service/subfolder-list/?id=${id}`, config).then((response) => {
|
||||
|
||||
const parentList = response.data.folderIDList;
|
||||
const parentNameList = response.data.folderNameList;
|
||||
|
||||
dispatch(setParentList(parentList, parentNameList))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export const adjustParentList = (parentList, parentNameList) => ({
|
||||
type: "ADJUST_PARENT_LIST",
|
||||
parentList,
|
||||
parentNameList
|
||||
})
|
||||
|
||||
export const startAdjustParentList = (id, parentList, parentNameList) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const adjustedParentList = [];
|
||||
const adjustedParentNameList = [];
|
||||
|
||||
for (let i = 0; i < parentList.length; i++) {
|
||||
|
||||
const currentID = parentList[i];
|
||||
const currentName = parentNameList[i];
|
||||
|
||||
adjustedParentList.push(currentID)
|
||||
adjustedParentNameList.push(currentName)
|
||||
|
||||
if (currentID === id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(adjustParentList(adjustedParentList, adjustedParentNameList));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export const addParentNameList = (name) => ({
|
||||
type: "ADD_PARENT_NAME_LIST",
|
||||
name
|
||||
})
|
||||
|
||||
export const resetParentList = () => ({
|
||||
type: "RESET_PARENT_LIST"
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
export const setPhotoID = (id) => ({
|
||||
type: "SET_PHOTO_ID",
|
||||
id
|
||||
})
|
||||
|
||||
export const resetPhotoID = () => ({
|
||||
type: "RESET_PHOTO_ID"
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
export const setPopupFile = (file) => ({
|
||||
type: "SET_POPUP_FILE",
|
||||
file
|
||||
})
|
||||
|
||||
export const hidePopup = () => ({
|
||||
type: "HIDE_POPUP"
|
||||
})
|
||||
@@ -0,0 +1,32 @@
|
||||
import axios from "axios";
|
||||
import env from "../enviroment/envFrontEnd";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
export const setQuickFiles = (files) => ({
|
||||
type: "SET_QUICK_FILES",
|
||||
files
|
||||
})
|
||||
|
||||
export const startSetQuickFiles = () => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
axios.get(currentURL +`/file-service/quick-list`, config).then((results) => {
|
||||
|
||||
dispatch(setQuickFiles(results.data))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const addQuickFile = (file) => ({
|
||||
type: "ADD_QUICK_FILE",
|
||||
file
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
export const setCurrentRoute = (route) => ({
|
||||
type: "SET_CURRENT_ROUTE",
|
||||
route
|
||||
})
|
||||
|
||||
export const resetCurrentRoute = () => ({
|
||||
type: "RESET_CURRENT_ROUTE"
|
||||
})
|
||||
@@ -0,0 +1,92 @@
|
||||
import axios from "axios";
|
||||
import env from "../enviroment/envFrontEnd";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
export const setSelectedItem = (selectedItem) => ({
|
||||
type: "SET_SELECTED_ITEM",
|
||||
selectedItem
|
||||
})
|
||||
|
||||
export const startSetSelectedItem = (id, file, fromQuickItems) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
const currentDate = Date.now();
|
||||
|
||||
dispatch(setLastSelected(currentDate));
|
||||
|
||||
if (!fromQuickItems) {
|
||||
dispatch(setSelected(id))
|
||||
} else {
|
||||
dispatch(setSelected("quick-"+id))
|
||||
}
|
||||
|
||||
if (file) {
|
||||
|
||||
axios.get(currentURL +`/file-service/info/${id}`, config).then((results) => {
|
||||
|
||||
const {filename: name, length: size, uploadDate: date, parentName: location, metadata, _id: id} = results.data;
|
||||
|
||||
dispatch(setSelectedItem({name, size, date, file, location, transcoded: metadata.transcoded, isVideo: metadata.isVideo, id, linkType: metadata.linkType, link: metadata.link}))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
axios.get(currentURL +`/folder-service/info/${id}`, config).then((results) => {
|
||||
|
||||
const {name, 0: size, createdAt: date, parentName: location} = results.data;
|
||||
|
||||
dispatch(setSelectedItem({name, size, date, file, location}))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const editSelectedItem = (item) => ({
|
||||
type: "EDIT_SELECTED_ITEM",
|
||||
item
|
||||
})
|
||||
|
||||
export const resetSelectedItem = () => ({
|
||||
type: "RESET_SELECTED_ITEM"
|
||||
})
|
||||
|
||||
export const resetSelected = () => ({
|
||||
type: "RESET_SELECTED"
|
||||
})
|
||||
|
||||
export const setLastSelected = (lastSelected) => ({
|
||||
type: "SET_LAST_SELECTED",
|
||||
lastSelected
|
||||
})
|
||||
|
||||
export const setRightSelected = (selected) => ({
|
||||
type: "SET_RIGHT_SELECTED",
|
||||
selected
|
||||
})
|
||||
|
||||
export const setShareSelected = (selected) => ({
|
||||
type: "SET_SHARE_SELECTED",
|
||||
selected
|
||||
})
|
||||
|
||||
export const editShareSelected = (selected) => ({
|
||||
type: "EDIT_SHARE_SELECTED",
|
||||
selected
|
||||
})
|
||||
|
||||
export const setSelected = (selected) => ({
|
||||
type: "SET_SELECTED",
|
||||
selected
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
export const showSettings = () => ({
|
||||
type: "SHOW_SETTINGS"
|
||||
})
|
||||
|
||||
export const hideSettings = () => ({
|
||||
type: "HIDE_SETTINGS"
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
import axios from "axios";
|
||||
import env from "../enviroment/envFrontEnd";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
export const setStorage = (info) => ({
|
||||
type: "SET_STORAGE",
|
||||
info
|
||||
})
|
||||
|
||||
export const startSetStorage = () => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
axios.get(currentURL +`/storage-service/info`, config).then((results) => {
|
||||
|
||||
dispatch(setStorage(results.data))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
export const addUpload = (upload) => ({
|
||||
type: "ADD_UPLOAD",
|
||||
upload
|
||||
})
|
||||
|
||||
export const resetUpload = () => ({
|
||||
type: "RESET_UPLOADS"
|
||||
})
|
||||
|
||||
export const editUpload = (id, progress, completed = false) => ({
|
||||
type: "EDIT_UPLOAD",
|
||||
id,
|
||||
progress,
|
||||
completed
|
||||
})
|
||||
|
||||
export const cancelUpload = (id) => ({
|
||||
type: "CANCEL_UPLOAD",
|
||||
id
|
||||
})
|
||||
|
||||
export const startCancelAllUploads = (uploads) => {
|
||||
|
||||
return (dispatch) => {
|
||||
|
||||
for (let i = 0; i < uploads.length; i++) {
|
||||
|
||||
const upload = uploads[i];
|
||||
|
||||
if (!upload.completed) {
|
||||
|
||||
upload.source.cancel("All uploads cancelling")
|
||||
|
||||
dispatch(cancelUpload(upload.id))
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(resetUpload());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import {Provider} from "react-redux"
|
||||
import configStore from "./store/configureStore"
|
||||
import AppRouter from "./routers/AppRouter"
|
||||
import "normalize.css/normalize.css"
|
||||
import "./styles/styles.scss";
|
||||
import "core-js/stable";
|
||||
import "regenerator-runtime/runtime";
|
||||
import 'react-circular-progressbar/dist/styles.css';
|
||||
|
||||
|
||||
|
||||
const store = configStore();
|
||||
|
||||
const jsxWrapper = (
|
||||
<Provider store={store}>
|
||||
|
||||
<AppRouter />
|
||||
</Provider>
|
||||
)
|
||||
|
||||
ReactDOM.render(jsxWrapper, document.getElementById("app"))
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
const ContextItem = (props) => (
|
||||
<div className="context__item" onClick={props.onClick}>
|
||||
<img className="context__item__image" src={props.image}/>
|
||||
<p className="context__item__title">{props.title}</p>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default ContextItem;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import ContextItem from "./ContextItem";
|
||||
import {setRightSelected, setSelected, setShareSelected} from "../../actions/selectedItem"
|
||||
import {startRemoveFile, startRenameFile} from "../../actions/files"
|
||||
import {setMoverID} from "../../actions/mover";
|
||||
import Swal from "sweetalert2"
|
||||
import {connect} from "react-redux"
|
||||
import React from "react";
|
||||
|
||||
class ContextItemContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
onClick = async(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
this.props.dispatch(setSelected(""))
|
||||
this.props.dispatch(setRightSelected(""))
|
||||
|
||||
const itemTitle = this.props.title;
|
||||
|
||||
if (itemTitle === "Download") {
|
||||
|
||||
this.props.downloadFile(this.props._id, undefined, false, true)
|
||||
|
||||
} else if (itemTitle === "Delete") {
|
||||
|
||||
Swal.fire({
|
||||
title: 'Confirm Deletion',
|
||||
text: "You cannot undo this action",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Yes, delete'
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
this.props.dispatch(startRemoveFile(this.props._id))
|
||||
}
|
||||
})
|
||||
|
||||
} else if (itemTitle === "Rename") {
|
||||
|
||||
let inputValue = this.props.filename;
|
||||
|
||||
const { value: folderName} = await Swal.fire({
|
||||
title: 'Enter A File Name',
|
||||
input: 'text',
|
||||
inputValue: inputValue,
|
||||
showCancelButton: true,
|
||||
inputValidator: (value) => {
|
||||
if (!value) {
|
||||
return 'Please Enter a Name'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (folderName === undefined || folderName === null) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.dispatch(startRenameFile(this.props._id, folderName))
|
||||
|
||||
} else if (itemTitle === "Share") {
|
||||
|
||||
this.props.dispatch(setShareSelected({...this.props.file}))
|
||||
|
||||
} else if (itemTitle === "Move") {
|
||||
|
||||
this.props.dispatch(setMoverID(this.props._id, this.props.parent, this.props.isFile));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <ContextItem onClick={this.onClick} {...this.props}/>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default connect()(ContextItemContainer);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
const ContextItem = (props) => (
|
||||
<div className="context__item" onClick={props.onClick}>
|
||||
<img className="context__item__image" src={props.image}/>
|
||||
<p className="context__item__title">{props.title}</p>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default ContextItem;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import ContextItemFolder from "./ContextItemFolder";
|
||||
import {startRemoveFolder, startRenameFolder} from "../../actions/folders"
|
||||
import {setRightSelected, setSelected, setShareSelected} from "../../actions/selectedItem";
|
||||
import {setMoverID} from "../../actions/mover"
|
||||
import Swal from "sweetalert2"
|
||||
import {connect} from "react-redux"
|
||||
import React from "react";
|
||||
|
||||
class ContextItemFolderContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
|
||||
super(props);
|
||||
}
|
||||
|
||||
onClick = async(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
this.props.dispatch(setSelected(""))
|
||||
this.props.dispatch(setRightSelected(""))
|
||||
|
||||
const itemTitle = this.props.title;
|
||||
|
||||
if (itemTitle === "Download") {
|
||||
|
||||
this.props.downloadFile(this.props._id, undefined, false, true)
|
||||
|
||||
} else if (itemTitle === "Delete") {
|
||||
|
||||
Swal.fire({
|
||||
title: 'Confirm Deletion',
|
||||
text: "You cannot undo this action",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Yes, delete'
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
this.props.dispatch(startRemoveFolder(this.props._id, [...this.props.parentList, this.props._id]))
|
||||
}
|
||||
})
|
||||
|
||||
} else if (itemTitle === "Rename") {
|
||||
|
||||
let inputValue = this.props.name;
|
||||
|
||||
const { value: folderName} = await Swal.fire({
|
||||
title: 'Enter Folder Name',
|
||||
input: 'text',
|
||||
inputValue: inputValue,
|
||||
showCancelButton: true,
|
||||
inputValidator: (value) => {
|
||||
if (!value) {
|
||||
return 'Please Enter a Name'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (folderName === undefined || folderName === null) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.dispatch(startRenameFolder(this.props._id, folderName))
|
||||
|
||||
} else if (itemTitle === "Share") {
|
||||
|
||||
this.props.dispatch(setShareSelected({...this.props.file}))
|
||||
|
||||
} else if (itemTitle === "Move") {
|
||||
|
||||
this.props.dispatch(setMoverID(this.props._id, this.props.parent, this.props.isFile));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <ContextItemFolder onClick={this.onClick} {...this.props}/>
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(ContextItemFolderContainer);
|
||||
@@ -0,0 +1,20 @@
|
||||
import ContextItem from "../ContextItem";
|
||||
import React from "react";
|
||||
|
||||
const ContextMenu = React.forwardRef((props, ref) => (
|
||||
|
||||
<div className="context-menu" ref={ref} style={props.style}>
|
||||
|
||||
<ContextItem _id={props._id} title="Rename" image="/images/rename.svg" filename={props.filename} />
|
||||
<ContextItem title="Share" image="/images/share.svg" _id={props._id} file={props} />
|
||||
<ContextItem downloadFile={props.downloadFile} title="Download" image="/images/download.svg" _id={props._id}/>
|
||||
{props.quickFile ? undefined :
|
||||
<ContextItem title="Move" image="/images/move.svg" _id={props._id} parent={props.metadata.parent} isFile={true}/>
|
||||
}
|
||||
<ContextItem title="Delete" image="/images/trash.svg" _id={props._id}/>
|
||||
|
||||
</div>
|
||||
))
|
||||
|
||||
export default ContextMenu
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import ContextMenu from "./ContextMenu";
|
||||
import {setRightSelected, setSelected} from "../../actions/selectedItem"
|
||||
import {connect} from "react-redux"
|
||||
import React from "react";
|
||||
|
||||
class ContextMenuContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.wrapperRef = React.createRef();
|
||||
}
|
||||
|
||||
handleClickOutside = (e) => {
|
||||
|
||||
if (this.wrapperRef && !this.wrapperRef.current.contains(e.target)) {
|
||||
|
||||
this.props.dispatch(setSelected(""));
|
||||
this.props.dispatch(setRightSelected(""));
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
document.addEventListener('mousedown', this.handleClickOutside);
|
||||
}
|
||||
|
||||
componentWillUnmount = () => {
|
||||
document.removeEventListener('mousedown', this.handleClickOutside);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <ContextMenu ref={this.wrapperRef} {...this.props}/>
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(ContextMenuContainer);
|
||||
@@ -0,0 +1,14 @@
|
||||
import ContextItemFolder from "../ContextItemFolder";
|
||||
import React from "react";
|
||||
|
||||
const ContextMenuFolder = React.forwardRef((props, ref) => (
|
||||
|
||||
<div className="context-menu" ref={ref} style={props.style}>
|
||||
<ContextItemFolder _id={props._id} title="Rename" image="/images/rename.svg" parentList={props.parentList} name={props.name}/>
|
||||
<ContextItemFolder title="Delete" image="/images/trash.svg" _id={props._id} parentList={props.parentList}/>
|
||||
<ContextItemFolder title="Move" image="/images/move.svg" _id={props._id} parent={props.parent} isFile={false}/>
|
||||
</div>
|
||||
))
|
||||
|
||||
export default ContextMenuFolder;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import ContextMenuFolder from "./ContextMenuFolder";
|
||||
import {setRightSelected, setSelected} from "../../actions/selectedItem";
|
||||
import {connect} from "react-redux"
|
||||
import React from "react";
|
||||
|
||||
class ContextMenuFolderContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.wrapperRef = React.createRef()
|
||||
}
|
||||
|
||||
handleClickOutside = (e) => {
|
||||
|
||||
if (this.wrapperRef && !this.wrapperRef.current.contains(e.target)) {
|
||||
|
||||
this.props.dispatch(setSelected(""));
|
||||
this.props.dispatch(setRightSelected(""));
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
document.addEventListener('mousedown', this.handleClickOutside);
|
||||
}
|
||||
|
||||
componentWillUnmount = () => {
|
||||
document.removeEventListener('mousedown', this.handleClickOutside);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <ContextMenuFolder ref={this.wrapperRef} {...this.props}/>
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(ContextMenuFolderContainer);
|
||||
@@ -0,0 +1,52 @@
|
||||
import FileItem from ".././FileItem"
|
||||
import FolderItem from ".././FolderItem"
|
||||
import Spacer from ".././Spacer";
|
||||
import React from "react";
|
||||
|
||||
const DataForm = (props) => (
|
||||
|
||||
<div>
|
||||
|
||||
<div>
|
||||
|
||||
{props.folders.length === 0 ?
|
||||
|
||||
(undefined)
|
||||
:
|
||||
(<div className="dataform">
|
||||
{props.folders.map((folder) =>
|
||||
(<FolderItem
|
||||
{...folder}
|
||||
key={folder._id}
|
||||
itemSelected={folder._id === props.selected}
|
||||
folderClick={props.folderClick}
|
||||
deleteFolder={props.deleteFolder}/>))}
|
||||
</div>)}
|
||||
</div>
|
||||
|
||||
{props.files.length !== 0 ? <Spacer title="Files"/> : undefined}
|
||||
|
||||
<div>
|
||||
|
||||
{props.files.length === 0 ?
|
||||
|
||||
(undefined)
|
||||
:
|
||||
(<div className="dataform">
|
||||
|
||||
{props.files.map((file) =>
|
||||
( <FileItem
|
||||
{...file}
|
||||
key={file._id}
|
||||
itemSelected={file._id === props.selected}
|
||||
downloadFile={props.downloadFile}
|
||||
removeFile={props.removeFile}
|
||||
fileClick={props.fileClick}/>))}
|
||||
|
||||
</div>)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
export default DataForm;
|
||||
@@ -0,0 +1,26 @@
|
||||
import DataForm from "./DataForm";
|
||||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
|
||||
class DataFormContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <DataForm {...this.props}/>
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProp = (state) => ({
|
||||
files: state.files,
|
||||
folders: state.folders,
|
||||
selected: state.selectedItem.selected,
|
||||
resetItems: state.main.resetItems
|
||||
})
|
||||
|
||||
export default connect(mapStateToProp)(DataFormContainer);
|
||||
@@ -0,0 +1,35 @@
|
||||
import Spinner from ".././SpinnerLogin";
|
||||
import React from "react";
|
||||
|
||||
const DownloadPage = ({download,state}) => {
|
||||
|
||||
if (state.size === "" && !state.error) {
|
||||
|
||||
return <div className="downloadpage__box">
|
||||
<Spinner />
|
||||
</div>
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<div className="downloadpage">
|
||||
|
||||
{!state.error ?
|
||||
|
||||
(<div className="downloadpage__box">
|
||||
<p className="downloadpage__box__title">{state.title}</p>
|
||||
<p className="downloadpage__box__subtitle">Type: {state.type}</p>
|
||||
<p className="downloadpage__box__subtitle">Size: {state.size}</p>
|
||||
<button className="button" onClick={download}>Download</button>
|
||||
</div>)
|
||||
:
|
||||
<div className="downloadpage__box">
|
||||
<p>Unauthorized/Not Found Download</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default DownloadPage;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import DownloadPage from "./DownloadPage";
|
||||
import capitalize from "../../utils/capitalize";
|
||||
import env from "../../enviroment/envFrontEnd";
|
||||
import axios from "axios";
|
||||
import bytes from "bytes";
|
||||
import React from "react";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
class DownloadPageContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
error: false,
|
||||
title: "",
|
||||
type: "",
|
||||
size: "",
|
||||
}
|
||||
}
|
||||
|
||||
getFileExtension = (filename) => {
|
||||
|
||||
const filenameSplit = filename.split(".");
|
||||
|
||||
if (filenameSplit.length > 1) {
|
||||
|
||||
const extension = filenameSplit[filenameSplit.length - 1]
|
||||
|
||||
return extension.toUpperCase();
|
||||
|
||||
} else {
|
||||
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
|
||||
const _id = this.props.match.params.id;
|
||||
const tempToken = this.props.match.params.tempToken
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")}
|
||||
};
|
||||
|
||||
axios.get(currentURL +`/file-service/public/info/${_id}/${tempToken}`, config).then((results) => {
|
||||
|
||||
const data = results.data;
|
||||
|
||||
const title = capitalize(data.filename);
|
||||
const size = bytes(data.length);
|
||||
const type = this.getFileExtension(title);
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
title,
|
||||
type,
|
||||
size
|
||||
}))
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
this.setState(() => ({...this.state, error: true}))
|
||||
})
|
||||
}
|
||||
|
||||
download = () => {
|
||||
|
||||
const _id = this.props.match.params.id;
|
||||
const tempToken = this.props.match.params.tempToken
|
||||
const finalUrl = currentURL + `/file-service/public/download/${_id}/${tempToken}`
|
||||
|
||||
const link = document.createElement('a');
|
||||
document.body.appendChild(link);
|
||||
link.href = finalUrl;
|
||||
link.setAttribute('type', 'hidden');
|
||||
link.click();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <DownloadPage state={this.state} download={this.download} {...this.props}/>
|
||||
}
|
||||
}
|
||||
|
||||
export default DownloadPageContainer;
|
||||
@@ -0,0 +1,64 @@
|
||||
import ContextMenu from "../ContextMenu";
|
||||
import capitalize from "../../utils/capitalize";
|
||||
import bytes from "bytes";
|
||||
import moment from "moment";
|
||||
import React from "react"
|
||||
|
||||
|
||||
const FileItem = (props) => {
|
||||
|
||||
const wrapperClassname = props.getWrapperClassname()
|
||||
|
||||
return (
|
||||
<div className={wrapperClassname}>
|
||||
|
||||
{props.listView ?
|
||||
|
||||
<div className={props._id !== props.selected ? "file__item__listview" : "file__item__listview file__item--selected"}
|
||||
onClick={() => {props.fileClick(props._id, props)}}
|
||||
onContextMenu={(e) => props.getContextMenu(e)}>
|
||||
|
||||
<div className="file__item__listview__title__wrapper">
|
||||
<img className={props.state.imageClassname} src={props.state.imageSrc} onError={() => {props.image.src = "/images/file-svg.svg"; props.image.className="file__image__listview"; props.failedToLoad = true}}/>
|
||||
<h5 className={props._id !== props.selected ? "file__title__listview file__title__listview--no-max" : "file__title__listview file__title__listview--no-max file__title--selected"}>{capitalize(props.filename)}</h5>
|
||||
</div>
|
||||
<h5 className={props._id !== props.selected ? "file__title__listview file__title__listview--no-margin" : "file__title__listview file__title__listview--no-margin file__title--selected"}>{bytes(props.length)}</h5>
|
||||
<h5 className={props._id !== props.selected ? "file__title__listview" : "file__title__listview file__title--selected"}>{moment(props.uploadDate).format("L")}</h5>
|
||||
|
||||
{(props.rightSelected === props._id && props._id === props.selected) ?
|
||||
|
||||
<ContextMenu style={props.state} {...props} quickFile={false} downloadFile={props.downloadFile}/>
|
||||
:
|
||||
undefined}
|
||||
|
||||
</div>
|
||||
|
||||
:
|
||||
|
||||
<div className="file__item__wrapper"
|
||||
onClick={() => {props.fileClick(props._id, props)}}
|
||||
onContextMenu={(e) => props.getContextMenu(e)}>
|
||||
|
||||
<div className="file__image__wrapper">
|
||||
<img className={props.state.imageClassname} src={props.state.imageSrc} onError={() => {props.image.src = "/images/file-svg.svg"; props.image.className="file__image"; props.failedToLoad = true;}}/>
|
||||
</div>
|
||||
|
||||
<h5 className={props._id !== props.selected ? "file__title" : "file__title file__title--selected"}>{capitalize(props.filename)}</h5>
|
||||
|
||||
{(props.rightSelected === props._id && props._id === props.selected) ?
|
||||
|
||||
<ContextMenu style={props.state.contextMenuPos} {...props} quickFile={false} downloadFile={props.downloadFile}/>
|
||||
:
|
||||
undefined}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default FileItem;
|
||||
@@ -0,0 +1,182 @@
|
||||
import FileItem from "./FileItem";
|
||||
import {startSetSelectedItem, setRightSelected, setLastSelected} from "../../actions/selectedItem"
|
||||
import mobileCheck from "../../utils/mobileCheck"
|
||||
import env from "../../enviroment/envFrontEnd";
|
||||
import axios from "axios";
|
||||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
|
||||
const currentURL = env.url;
|
||||
|
||||
class FileItemContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.failedToLoad = false;
|
||||
|
||||
this.state = {
|
||||
contextMenuPos: {},
|
||||
imageSrc: "/images/file-svg.svg",
|
||||
imageClassname: this.props.listView ? "file__image__listview" : "file__image"
|
||||
}
|
||||
}
|
||||
|
||||
getThumbnail = async() => {
|
||||
|
||||
const thumbnailID = this.props.metadata.thumbnailID;
|
||||
const imageClassname = this.props.listView ? "file__image__listview--no-opacity" : "file__image--no-opacity"
|
||||
|
||||
const config = {
|
||||
headers: {'Authorization': "Bearer " + window.localStorage.getItem("token")},
|
||||
responseType: 'arraybuffer'
|
||||
};
|
||||
|
||||
await this.setState(() => ({
|
||||
...this.state,
|
||||
imageSrc: "/images/file-svg.svg",
|
||||
imageClassname: this.props.listView ? "file__image__listview" : "file__image"
|
||||
}))
|
||||
|
||||
axios.get(currentURL +`/file-service/thumbnail/${thumbnailID}`, config).then((results) => {
|
||||
|
||||
const imgFile = new Blob([results.data]);
|
||||
const imgUrl = URL.createObjectURL(imgFile);
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
imageSrc: imgUrl,
|
||||
imageClassname: imageClassname
|
||||
}))
|
||||
|
||||
|
||||
}).catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
|
||||
const hasThumbnail = this.props.metadata.hasThumbnail;
|
||||
|
||||
if (hasThumbnail && !this.failedToLoad) {
|
||||
this.getThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate = (nextProp, nextState) => {
|
||||
|
||||
return (nextProp.itemSelected !== this.props.itemSelected
|
||||
|| nextProp.listView !== this.props.listView
|
||||
|| nextProp.rightSelected !== this.props.rightSelected
|
||||
|| nextState.imageSrc !== this.state.imageSrc
|
||||
|| nextState.imageClassname !== this.state.imageClassname
|
||||
|| this.props.filename !== nextProp.filename
|
||||
|| this.props.metadata.transcoded !== nextProp.metadata.transcoded)
|
||||
}
|
||||
|
||||
|
||||
componentDidUpdate = (nextProp) => {
|
||||
|
||||
console.log("file item component updated")
|
||||
|
||||
const hasThumbnail = this.props.metadata.hasThumbnail;
|
||||
|
||||
if (hasThumbnail && !this.failedToLoad && nextProp.listView !== this.props.listView) {
|
||||
|
||||
this.getThumbnail();
|
||||
|
||||
} else if (nextProp.listView !== this.props.listView) {
|
||||
|
||||
this.setState(() => ({
|
||||
...this.state,
|
||||
imageClassname: this.props.listView ? "file__image__listview" : "file__image"
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
getContextMenu = (e) => {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const isMobile = mobileCheck();
|
||||
|
||||
const windowX = window.innerWidth;
|
||||
const windowY = window.innerHeight;
|
||||
|
||||
let styleObj = {right:0, left:0, top: "-38px", bottom: 0}
|
||||
|
||||
const clientY = e.nativeEvent.clientY;
|
||||
const clientX = e.nativeEvent.clientX;
|
||||
|
||||
if (clientY < (windowY / 3)) {
|
||||
|
||||
styleObj = {bottom:"-190px", top:"unset"}
|
||||
}
|
||||
|
||||
if (clientY > ((windowY / 4) * 3.5)) {
|
||||
|
||||
styleObj = {bottom:"unset", top: "-190px"}
|
||||
}
|
||||
|
||||
if (clientX > windowX / 2) {
|
||||
|
||||
styleObj = {...styleObj, left:"unset", right:0}
|
||||
|
||||
} else {
|
||||
|
||||
styleObj = {...styleObj, left:0, right:"unset"}
|
||||
}
|
||||
|
||||
if (isMobile) {
|
||||
|
||||
styleObj = {bottom: 0, left: "2px", top: "unset", right: "unset"}
|
||||
}
|
||||
|
||||
this.setState(() => ({...this.state, contextMenuPos: styleObj}))
|
||||
|
||||
this.props.dispatch(startSetSelectedItem(this.props._id, true, false))
|
||||
this.props.dispatch(setLastSelected(0));
|
||||
this.props.dispatch(setRightSelected(this.props._id))
|
||||
|
||||
}
|
||||
|
||||
getWrapperClassname = () => {
|
||||
|
||||
let classname = "";
|
||||
|
||||
if (this.props.listView) {
|
||||
|
||||
classname += "file__item__listview"
|
||||
|
||||
} else {
|
||||
|
||||
classname += "file__item"
|
||||
}
|
||||
|
||||
if (this.props._id === this.props.selected) {
|
||||
|
||||
classname += " file__item--selected"
|
||||
}
|
||||
|
||||
return classname;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <FileItem
|
||||
getWrapperClassname={this.getWrapperClassname}
|
||||
getContextMenu={this.getContextMenu}
|
||||
state={this.state}
|
||||
{...this.props}/>
|
||||
}
|
||||
}
|
||||
|
||||
const connectStateToProp = (state) => ({
|
||||
listView: state.filter.listView,
|
||||
rightSelected: state.selectedItem.rightSelected,
|
||||
resetSelected: state.selectedItem.resetSelected,
|
||||
selected: state.selectedItem.selected
|
||||
})
|
||||
|
||||
export default connect(connectStateToProp)(FileItemContainer)
|
||||
@@ -0,0 +1,48 @@
|
||||
import React from "react";
|
||||
|
||||
const Filter = (props) => {
|
||||
|
||||
const filterOptionType = props.getFilterOptionType();
|
||||
const filterOptionValue = props.getFilterOptionValue();
|
||||
|
||||
return (
|
||||
|
||||
<div className="filter">
|
||||
|
||||
<div className="filter__folder-title-wrapper">
|
||||
|
||||
{props.folderListLength === 0 ?
|
||||
|
||||
undefined
|
||||
:
|
||||
(<div className="filter__folder-wrapper">
|
||||
<p className="filter__folder-title">Folders</p>
|
||||
</div>)}
|
||||
|
||||
</div>
|
||||
|
||||
<div className="filters__wrapper">
|
||||
|
||||
<div className="filter__select-wrapper">
|
||||
|
||||
<select className="filter__select" value={filterOptionType} onChange={props.selectedOnChange}>
|
||||
<option value="date">Last Modified</option>
|
||||
<option value="name">Name</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="filter__select-image-wrapper">
|
||||
|
||||
<img className="filter__select-image" src={filterOptionValue ?
|
||||
"/images/down-arrow-grey-small.png" : "/images/up-arrow-grey-small.png"}
|
||||
onClick={props.changeSortBy}/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default Filter
|
||||
@@ -0,0 +1,115 @@
|
||||
import Filter from "./Filter";
|
||||
import {setSortBy} from "../../actions/filter";
|
||||
import {startSetFiles} from "../../actions/files"
|
||||
import {startSetFolders} from "../../actions/folders";
|
||||
import {resetItems} from "../../actions/main"
|
||||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
|
||||
class FilterContainer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
changeOrder = () => {
|
||||
|
||||
const sortBySwitch = this.props.filter.sortBy.split("_");
|
||||
const sortByPrefix = sortBySwitch[0];
|
||||
|
||||
if (this.props.filter.sortBy.includes("asc")) {
|
||||
|
||||
return sortByPrefix + "_desc"
|
||||
|
||||
} else {
|
||||
|
||||
return sortByPrefix + "_asc"
|
||||
}
|
||||
}
|
||||
|
||||
changeSortBy = async() => {
|
||||
|
||||
const sortByString = this.changeOrder();
|
||||
|
||||
const parent = this.props.parent;
|
||||
const search = this.props.filter.search;
|
||||
|
||||
this.props.dispatch(setSortBy(sortByString))
|
||||
this.props.dispatch(startSetFiles(parent, sortByString, search))
|
||||
this.props.dispatch(startSetFolders(parent, sortByString, search))
|
||||
this.props.dispatch(resetItems())
|
||||
}
|
||||
|
||||
changeSelected = (e) => {
|
||||
|
||||
const sortBySwitch = this.props.filter.sortBy.split("_");
|
||||
const sortBySuffix = sortBySwitch[1];
|
||||
|
||||
if (sortBySwitch.includes("date")) {
|
||||
|
||||
return "alp_" + sortBySuffix;
|
||||
|
||||
} else {
|
||||
|
||||
return "date_" + sortBySuffix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
selectedOnChange = async(e) => {
|
||||
|
||||
const sortByString = this.changeSelected();
|
||||
|
||||
const parent = this.props.parent;
|
||||
const search = this.props.filter.search;
|
||||
|
||||
this.props.dispatch(setSortBy(sortByString))
|
||||
this.props.dispatch(startSetFiles(parent, sortByString, search))
|
||||
this.props.dispatch(startSetFolders(parent, sortByString, search))
|
||||
this.props.dispatch(resetItems())
|
||||
}
|
||||
|
||||
getFilterOptionType = () => {
|
||||
|
||||
if (this.props.filter.sortBy.includes("alp")) {
|
||||
|
||||
return "name"
|
||||
|
||||
} else {
|
||||
|
||||
return "date"
|
||||
}
|
||||
}
|
||||
|
||||
getFilterOptionValue = () => {
|
||||
|
||||
if (this.props.filter.sortBy.includes("asc")) {
|
||||
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return <Filter
|
||||
selectedOnChange={this.selectedOnChange}
|
||||
changeSortBy={this.changeSortBy}
|
||||
getFilterOptionType={this.getFilterOptionType}
|
||||
getFilterOptionValue={this.getFilterOptionValue}
|
||||
{...this.props}/>
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const connectPropToStore = (state) => ({
|
||||
filter: state.filter,
|
||||
folderListLength: state.folders.length,
|
||||
parent: state.parent.parent
|
||||
})
|
||||
|
||||
|
||||
export default connect(connectPropToStore)(FilterContainer);
|
||||
@@ -0,0 +1,55 @@
|
||||
import ContextMenuFolder from ".././ContextMenuFolder";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
|
||||
const FolderItem = (props) => {
|
||||
|
||||
const wrapperClassname = props.getClassName();
|
||||
|
||||
return (
|
||||
|
||||
<div className={wrapperClassname}>
|
||||
|
||||
{props.listView ?
|
||||
|
||||
<div className={props._id !== props.selected ? "file__item__listview" : "file__item__listview file__item--selected"}
|
||||
onClick={() => props.folderClick(props._id, props.name)}
|
||||
onContextMenu={(e) => props.getContextMenu(e)}>
|
||||
|
||||
<div className="file__item__listview__title__wrapper file__item__listview__title__wrapper--folder">
|
||||
<img className="file__image__listview" src="/images/folder-svg.svg"/>
|
||||
<h5 className={props._id !== props.selected ? "file__title__listview file__title__listview--no-max" : "file__title__listview file__title__listview--no-max file__title--selected"}>{props.name}</h5>
|
||||
</div>
|
||||
<h5 className={props._id !== props.selected ? "file__title__listview" : "file__title__listview file__title--selected"}>{moment(props.createdAt).format("L")}</h5>
|
||||
|
||||
{(props.rightSelected === props._id && props._id === props.selected) ?
|
||||
|
||||
<ContextMenuFolder style={props.state} {...props} downloadFile={props.downloadFile}/>
|
||||
:
|
||||
undefined}
|
||||
</div>
|
||||
|
||||
:
|
||||
|
||||
<div className="folder__item"
|
||||
onClick={() => props.folderClick(props._id, props.name)}
|
||||
onContextMenu={(e) => props.getContextMenu(e)}>
|
||||
|
||||
<img className="folder__image" src="/images/folder-svg.svg"/>
|
||||
<h4 className={props._id !== props.selected ? "folder__title" : "folder__title folder__title--selected"}>{props.name}</h4>
|
||||
|
||||
{(props.rightSelected === props._id && props._id === props.selected) ?
|
||||
|
||||
<ContextMenuFolder style={props.state} {...props} downloadFile={props.downloadFile}/>
|
||||
:
|
||||
undefined}
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FolderItem;
|
||||