diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..6e867f9 --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": [ "@babel/env", "@babel/preset-react" ], + "plugins": [ "@babel/plugin-proposal-class-properties" ] +} diff --git a/config/default.json b/config/default.json index 13fc7a1..c5f7bf3 100644 --- a/config/default.json +++ b/config/default.json @@ -1,20 +1,18 @@ { "db": { "photos": { - "host": "sqlite:db/photos.db", - "options": { - "logging" : false, - "timezone": "+00:00", - "operatorsAliases": false - } + "dialect": "sqlite", + "host": "db/photos.db", + "logging" : false, + "timezone": "+00:00", + "operatorsAliases": 0 }, "users": { - "host": "sqlite:db/users.db", - "options": { - "logging" : false, - "timezone": "+00:00", - "operatorsAliases": false - } + "dialect": "sqlite", + "host": "db/users.db", + "logging" : false, + "timezone": "+00:00", + "operatorsAliases": 0 } }, "ldap": { diff --git a/package.json b/package.json index 9c223a1..96be536 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,13 @@ "main": "server/app.js", "scripts": { "start": "node ./server/app.js", - "faces": "node ./server/face-recognizer.js" + "faces": "node ./server/face-recognizer.js", + "dev": "webpack-dev-server --mode development --host 0.0.0.0 --config webpack.dev.js", + "build": "webpack --config webpack.prod.js", + "commit-build": "./commit-build.sh", + "watch": "webpack --config webpack.prod.js --watch", + "update": "./update.sh", + "backend": "NODE_CONFIG_ENV='production' node server/app.js" }, "repository": { "type": "git", @@ -17,20 +23,25 @@ "face-recognition": "^0.9.4" }, "dependencies": { - "@tensorflow/tfjs-core": "^1.5.1", - "@tensorflow/tfjs-node": "^1.5.1", + "@tensorflow/tfjs-core": "^1.5.2", + "@tensorflow/tfjs-node": "^1.5.2", + "animakit-expander": "^2.1.4", "bluebird": "^3.7.2", "body-parser": "^1.19.0", + "bootstrap": "^4.4.1", "canvas": "^2.6.1", - "config": "^1.31.0", + "config": "^3.1.0", "connect-sqlite3": "^0.9.11", "cookie-parser": "^1.4.4", + "core-js": "^3.2.1", "exif-reader": "github:paras20xx/exif-reader", "express": "^4.17.1", "express-session": "^1.17.0", "face-api.js": "^0.22.0", - "handlebars": "^4.5.3", - "ldapauth-fork": "^4.2.0", + "googleapis": "^40.0.0", + "handlebars": "^4.7.2", + "jira-connector": "^2.10.0", + "ldapauth-fork": "^4.3.0", "ldapjs": "^1.0.2", "mariasql": "^0.2.6", "moment": "^2.24.0", @@ -38,13 +49,38 @@ "morgan": "^1.9.1", "mustache": "^3.2.1", "node-fetch": "^2.6.0", - "nodemailer": "^4.7.0", + "node-gzip": "^1.1.2", + "nodemailer": "^6.3.0", "qs": "^6.9.1", - "sequelize": "^4.44.3", + "react-app-polyfill": "^1.0.2", + "react-bootstrap": "^1.0.0-beta.16", + "react-date-range": "^1.0.0-beta", + "react-markdown": "^4.2.2", + "react-router-dom": "^5.0.1", + "react-scroll": "^1.7.14", + "react-syntax-highlighter": "^11.0.2", + "sequelize": "^5.21.3", "sequelize-mysql": "^1.7.0", "sharp": "^0.20.8", "sqlite3": "^4.1.1" }, + "devDependencies": { + "@babel/cli": "^7.1.0", + "@babel/core": "^7.1.0", + "@babel/plugin-proposal-class-properties": "^7.4.4", + "@babel/preset-env": "^7.1.0", + "@babel/preset-react": "^7.0.0", + "babel-loader": "^8.0.2", + "css-loader": "^1.0.0", + "file-loader": "^4.1.0", + "react": "^16.8", + "react-dom": "^16.8", + "style-loader": "^0.23.0", + "webpack": "^4.19.1", + "webpack-cli": "^3.1.1", + "webpack-dev-server": "^3.3.1", + "webpack-merge": "^4.2.1" + }, "jshintConfig": { "undef": true, "unused": true, diff --git a/server/db/photos.js b/server/db/photos.js index 4319904..756add6 100755 --- a/server/db/photos.js +++ b/server/db/photos.js @@ -20,7 +20,7 @@ const fs = require('fs'), function init() { const db = { - sequelize: new Sequelize(config.get("db.photos.host"), config.get("db.photos.options")), + sequelize: new Sequelize(config.get("db.photos")), Sequelize: Sequelize }; diff --git a/server/db/users.js b/server/db/users.js index 6e9555b..f7c6c65 100644 --- a/server/db/users.js +++ b/server/db/users.js @@ -18,7 +18,7 @@ const Sequelize = require('sequelize'), function init() { const db = { - sequelize: new Sequelize(config.get("db.users.host"), config.get("db.users.options")), + sequelize: new Sequelize(config.get("db.users")), Sequelize: Sequelize }; diff --git a/src/App.css b/src/App.css new file mode 100755 index 0000000..785f1a3 --- /dev/null +++ b/src/App.css @@ -0,0 +1,180 @@ +body { + font-family: 'Droid Sans', 'Arial Narrow', Arial, sans-serif; +} + +#spinner { + display: none; + position: fixed; + left: 50%; + top: 50%; + width: 60px; + height: 60px; + margin-left: -30px; + margin-top: -30px; + z-index: 100; + background-image: url(../frontend/icons-512.png); + background-color: #0071C5; + border-radius: 50%; +} + +#spinner.spin { + display: inline-block; + -webkit-animation:spin 1s linear infinite; + -moz-animation:spin 1s linear infinite; + animation:spin 1s linear infinite; +} + +@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } } +@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } } +@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } + +.Header { + background-color: #252525; + color: #ffffff; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 20; + display: flex; + box-sizing: border-box; + flex-direction: column; + user-select: none; +} + +.Header .Group { + height: 60px; + display: flex; + padding-left: 1em; + padding-right: calc(1em + 52px); + background-color: #0071C5; + align-items: center; +} + +.Header .Group .Subtitle { + font-size: 0.7em; + line-height: 1.5em; +} + +.Header .Group .Heading { + margin: 0 auto; + width: calc(100% - 8em); + max-width: 90em; +} + +.Header .Pages { + height: 60px; + display: flex; + margin: 0 auto; + width: calc(100% - 8em); + max-width: 90em; +/* justify-content: space-between;*/ + font-size: 1.2em; + align-items: center; +} + +.Header .Pages .Link { + display: inline-flex; + align-items: center; + height: 100%; + box-sizing: border-box; + padding: 0.5em 1em; + border-bottom: 3px solid transparent; + cursor: pointer; +} + +.Header .Pages .Link.Highlight { + border-bottom-color: #0071C5 !important; +} + +.Header .Pages .Link.Active, +.Header .Pages .Link:hover { + border-bottom-color: #003663; + /*border-bottom-color: #00A7FF;*/ +} + +a.Link { + font-family: Oswald; + text-decoration: none; + color: white; +} + +.Footer { + position: fixed; + background-color: #252525; + color: #ffffff; + height: 64px; + bottom: 0; + left: 0; + right: 0; + font-size: 0.9em; + font-family: Droid Sans; + z-index: 20; +} + +.Footer .Copyright { + position: absolute; + line-height: 64px; + text-align: center; + left: 64px; + right: 64px; +} + +.Body { + position: absolute; + margin-top: 120px; /* .Header's two 60px chunks */ + margin-bottom: 64px; + top: 0; + bottom: 0; + left: 0; + right: 0; + box-sizing: border-box; + background-image: linear-gradient(#090B1A, #131524); + color: #ffffff; + z-index: 0; +} + +.Body > * { + box-sizing: border-box; +} + +.Main { + display: inline-flex; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-image: url(../frontend/icons-512.png); + background-repeat: no-repeat; + background-position: center; +} + + +.Content { + position: relative; + box-sizing: border-box; + margin: 1em auto; + width: calc(100% - 8em); + max-width: 90em; + color: black; + z-index: 10; + background-color: #fff; + overflow-y: scroll; + scroll-behavior: smooth; + padding: 1.5em 1.5em 0 1.5em; + box-sizing: border-box; + transition: top 1s ease-in-out; + top: -100%; +} + +.Content #MinBox { + position: relative; + box-sizing: border-box; + min-height: calc(100% - 2.5em); + padding-bottom: 1.3em; +} + +.OnScreen { + top: 0px; +} \ No newline at end of file diff --git a/src/App.js b/src/App.js new file mode 100755 index 0000000..c5d7bd2 --- /dev/null +++ b/src/App.js @@ -0,0 +1,91 @@ +/* Polyfills for IE */ +import 'react-app-polyfill/ie11'; +import 'core-js/features/array/find'; +import 'core-js/features/array/includes'; +import 'core-js/features/number/is-nan'; + +/* App starts here */ +import React from "react"; +import { withRouter, NavLink, Route, Switch } from "react-router-dom"; +import Modal from "react-bootstrap/Modal"; +import Button from "react-bootstrap/Button"; + +import "bootstrap/dist/css/bootstrap.min.css"; + +/* Custom components */ + +import './modest.css'; +import "./App.css"; + +class Header extends React.Component { + constructor(props) { + super(props); + } + + componentDidMount() { + } + + render() { + return ( +