박유빈

Merge branch 'develop'

......@@ -5,6 +5,28 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch via NPM",
"request": "launch",
"runtimeArgs": [
"run-script",
"debug"
],
"runtimeExecutable": "npm run start:dev",
"skipFiles": [
"<node_internals>/**"
],
"type": "pwa-node"
},
{"name": "Launch ",
"program": "${workspaceFolder}/app.js",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "pwa-node"
},
{
"type": "pwa-node",
"request": "launch",
"name": "Launch Program",
......
......@@ -19,7 +19,7 @@ server use Node.js, Koa.js and frotend use flutter(Dart)
* [Node.js](https://nodejs.org/)
* [Koa.js](https://koajs.com/)
* [flutter](https://flutter.dev/)
......@@ -31,7 +31,6 @@ server use Node.js, Koa.js and frotend use flutter(Dart)
## Getting Started
Go to the Server [Project folder](http://khuhub.khu.ac.kr/2018102946/likeBack), and git clone.
And go the Frontend [Project folder](http://khuhub.khu.ac.kr/2018102946/likefront)and git clone.
### Installation
......@@ -72,7 +71,7 @@ _Below is an example of how you can instruct your audience on installing and set
Email -- yoobinpark@khu.ac.kr
Project Link: [http://khuhub.khu.ac.kr/2018102946/likeBack](http://khuhub.khu.ac.kr/2018102946/likeBack)
[http://khuhub.khu.ac.kr/2018102946/likefront](http://khuhub.khu.ac.kr/2018102946/likefront)
<p align="right">(<a href="#top">back to top</a>)</p>
......
[debug] [2021-12-06T16:19:50.991Z] ----------------------------------------------------------------------
[debug] [2021-12-06T16:19:50.996Z] Command: /usr/local/bin/node /usr/local/bin/firebase login
[debug] [2021-12-06T16:19:50.997Z] CLI Version: 9.23.0
[debug] [2021-12-06T16:19:50.997Z] Platform: linux
[debug] [2021-12-06T16:19:50.998Z] Node Version: v16.13.0
[debug] [2021-12-06T16:19:51.007Z] Time: Tue Dec 07 2021 01:19:50 GMT+0900 (Korean Standard Time)
[debug] [2021-12-06T16:19:51.008Z] ----------------------------------------------------------------------
[debug]
[debug] [2021-12-06T16:19:51.014Z] >>> [apiv2][query] GET https://firebase-public.firebaseio.com/cli.json [none]
[info] i Firebase optionally collects CLI usage and error reporting information to help improve our products. Data is collected in accordance with Google's privacy policy (https://policies.google.com/privacy) and is not used to identify you.
[debug] [2021-12-06T16:19:52.476Z] <<< [apiv2][status] GET https://firebase-public.firebaseio.com/cli.json 200
[debug] [2021-12-06T16:19:52.476Z] <<< [apiv2][body] GET https://firebase-public.firebaseio.com/cli.json {"cloudBuildErrorAfter":1594252800000,"cloudBuildWarnAfter":1590019200000,"defaultNode10After":1594252800000,"minVersion":"3.0.5","node8DeploysDisabledAfter":1613390400000,"node8RuntimeDisabledAfter":1615809600000,"node8WarnAfter":1600128000000}
[info] i To change your data collection preference at any time, run `firebase logout` and log in again.
[info]
[info] Visit this URL on this device to log in:
[info] https://accounts.google.com/o/oauth2/auth?client_id=563584335869-fgrhgmd47bqnekij5i8b5pr03ho849e6.apps.googleusercontent.com&scope=email%20openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloudplatformprojects.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Ffirebase%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&response_type=code&state=406504610&redirect_uri=http%3A%2F%2Flocalhost%3A9005
[info]
[info] Waiting for authentication...
......@@ -14,6 +14,7 @@
"bcrypt": "^5.0.1",
"crypto": "^1.0.1",
"dotenv": "^10.0.0",
"ejs": "^3.1.6",
"express": "^4.17.1",
"firebase": "^9.6.0",
"http2": "^3.3.7",
......@@ -21,12 +22,16 @@
"koa": "^2.13.4",
"koa-body": "^4.2.0",
"koa-bodyparser": "^4.3.0",
"koa-ejs": "^4.3.0",
"koa-passport": "^4.1.4",
"koa-router": "^10.1.1",
"koa-send": "^5.0.1",
"koa-views": "^8.0.0",
"mongoose": "^6.0.12",
"nodemailer": "^6.7.1",
"passport": "^0.5.0",
"passport-google-oauth": "^2.0.0",
"passport-local": "^1.0.0",
"spdy": "^4.0.2"
},
"devDependencies": {
......@@ -1109,6 +1114,11 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
},
"node_modules/aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
......@@ -1137,6 +1147,11 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"node_modules/async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
......@@ -1182,6 +1197,11 @@
"node": ">= 10.0.0"
}
},
"node_modules/bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"node_modules/body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
......@@ -1357,16 +1377,54 @@
"color-support": "bin.js"
}
},
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"node_modules/condense-newlines": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz",
"integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=",
"dependencies": {
"extend-shallow": "^2.0.1",
"is-whitespace": "^0.3.0",
"kind-of": "^3.0.2"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/config-chain": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
"dependencies": {
"ini": "^1.3.4",
"proto-list": "~1.2.1"
}
},
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"node_modules/consolidate": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
"integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
"dependencies": {
"bluebird": "^3.7.2"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
......@@ -1548,11 +1606,61 @@
"safe-buffer": "^5.0.1"
}
},
"node_modules/editorconfig": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
"integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==",
"dependencies": {
"commander": "^2.19.0",
"lru-cache": "^4.1.5",
"semver": "^5.6.0",
"sigmund": "^1.0.1"
},
"bin": {
"editorconfig": "bin/editorconfig"
}
},
"node_modules/editorconfig/node_modules/lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"dependencies": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"node_modules/editorconfig/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/editorconfig/node_modules/yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"node_modules/ejs": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
"dependencies": {
"jake": "^10.6.1"
},
"bin": {
"ejs": "bin/cli.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
......@@ -1834,6 +1942,17 @@
"node": ">= 0.10.0"
}
},
"node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
......@@ -1875,6 +1994,14 @@
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/filelist": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
"dependencies": {
"minimatch": "^3.0.4"
}
},
"node_modules/finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
......@@ -2018,6 +2145,17 @@
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-paths": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/get-paths/-/get-paths-0.0.7.tgz",
"integrity": "sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA==",
"dependencies": {
"pify": "^4.0.1"
},
"engines": {
"node": ">=6.4"
}
},
"node_modules/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
......@@ -2349,6 +2487,11 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"node_modules/ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
......@@ -2357,6 +2500,19 @@
"node": ">= 0.10"
}
},
"node_modules/is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"node_modules/is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
......@@ -2400,6 +2556,14 @@
"node": ">=0.10.0"
}
},
"node_modules/is-whitespace": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz",
"integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
......@@ -2411,6 +2575,106 @@
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"node_modules/jake": {
"version": "10.8.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
"dependencies": {
"async": "0.9.x",
"chalk": "^2.4.2",
"filelist": "^1.0.1",
"minimatch": "^3.0.4"
},
"bin": {
"jake": "bin/cli.js"
},
"engines": {
"node": "*"
}
},
"node_modules/jake/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/jake/node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/jake/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/jake/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"node_modules/jake/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/jake/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"engines": {
"node": ">=4"
}
},
"node_modules/jake/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/js-beautify": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz",
"integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==",
"dependencies": {
"config-chain": "^1.1.12",
"editorconfig": "^0.15.3",
"glob": "^7.1.3",
"nopt": "^5.0.0"
},
"bin": {
"css-beautify": "js/bin/css-beautify.js",
"html-beautify": "js/bin/html-beautify.js",
"js-beautify": "js/bin/js-beautify.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
......@@ -2537,6 +2801,17 @@
"node": ">= 0.6"
}
},
"node_modules/kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dependencies": {
"is-buffer": "^1.1.5"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/koa": {
"version": "2.13.4",
"resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz",
......@@ -2620,6 +2895,48 @@
"node": ">= 10"
}
},
"node_modules/koa-ejs": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/koa-ejs/-/koa-ejs-4.3.0.tgz",
"integrity": "sha512-KK1B1YEeq8TOt7hrHwohfHxH03ZqsdhQWeFjmvcWk3arVI/uQOyE4FHQVlg0Ud9eXxlgUfkYqA2MJhfK4ADkAw==",
"dependencies": {
"debug": "^2.6.1",
"ejs": "^2.6.1",
"mz": "^2.6.0"
}
},
"node_modules/koa-ejs/node_modules/ejs": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==",
"hasInstallScript": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/koa-passport": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/koa-passport/-/koa-passport-4.1.4.tgz",
"integrity": "sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg==",
"dependencies": {
"passport": "^0.4.0"
},
"engines": {
"node": ">= 4"
}
},
"node_modules/koa-passport/node_modules/passport": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz",
"integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==",
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/koa-router": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/koa-router/-/koa-router-10.1.1.tgz",
......@@ -2761,6 +3078,49 @@
"node": ">=0.6"
}
},
"node_modules/koa-views": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/koa-views/-/koa-views-8.0.0.tgz",
"integrity": "sha512-nvGKdG8yVyomhouwN060SWd7Q9kGYRr322dwN6jvI04hgiDEW9vsPXEje9OEtBgGXxHURe7xOzo3bxQ3DBc1Nw==",
"dependencies": {
"consolidate": "^0.16.0",
"debug": "^4.1.0",
"get-paths": "0.0.7",
"koa-send": "^5.0.0",
"mz": "^2.4.0",
"pretty": "^2.0.0",
"resolve-path": "^1.4.0"
},
"peerDependencies": {
"@types/koa": "^2.13.1"
},
"peerDependenciesMeta": {
"@types/koa": {
"optional": true
}
}
},
"node_modules/koa-views/node_modules/debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/koa-views/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/koa/node_modules/debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
......@@ -3102,6 +3462,16 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"node_modules/mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
"dependencies": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
"thenify-all": "^1.0.0"
}
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
......@@ -3192,6 +3562,14 @@
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
"integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE="
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/obuf": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
......@@ -3310,6 +3688,17 @@
"node": ">= 0.4.0"
}
},
"node_modules/passport-local": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
"integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
"dependencies": {
"passport-strategy": "1.x.x"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/passport-oauth1": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.2.0.tgz",
......@@ -3381,6 +3770,14 @@
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
"node_modules/pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"engines": {
"node": ">=6"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
......@@ -3390,6 +3787,19 @@
"node": ">= 0.8.0"
}
},
"node_modules/pretty": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz",
"integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=",
"dependencies": {
"condense-newlines": "^0.2.1",
"extend-shallow": "^2.0.1",
"js-beautify": "^1.6.12"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
......@@ -3409,6 +3819,11 @@
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz",
"integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g=="
},
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
"integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk="
},
"node_modules/protobufjs": {
"version": "6.11.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz",
......@@ -3446,6 +3861,11 @@
"node": ">= 0.10"
}
},
"node_modules/pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
......@@ -3717,6 +4137,11 @@
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
},
"node_modules/sigmund": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"node_modules/signal-exit": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
......@@ -3911,6 +4336,25 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"dependencies": {
"any-promise": "^1.0.0"
}
},
"node_modules/thenify-all": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
"dependencies": {
"thenify": ">= 3.1.0 < 4"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/tmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
......@@ -5125,6 +5569,11 @@
"color-convert": "^2.0.1"
}
},
"any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
},
"aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
......@@ -5150,6 +5599,11 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
......@@ -5174,6 +5628,11 @@
"node-addon-api": "^3.1.0"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
......@@ -5301,16 +5760,48 @@
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"condense-newlines": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz",
"integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=",
"requires": {
"extend-shallow": "^2.0.1",
"is-whitespace": "^0.3.0",
"kind-of": "^3.0.2"
}
},
"config-chain": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
"requires": {
"ini": "^1.3.4",
"proto-list": "~1.2.1"
}
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"consolidate": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
"integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
"requires": {
"bluebird": "^3.7.2"
}
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
......@@ -5452,11 +5943,51 @@
"safe-buffer": "^5.0.1"
}
},
"editorconfig": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
"integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==",
"requires": {
"commander": "^2.19.0",
"lru-cache": "^4.1.5",
"semver": "^5.6.0",
"sigmund": "^1.0.1"
},
"dependencies": {
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
}
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"ejs": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
"integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
"requires": {
"jake": "^10.6.1"
}
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
......@@ -5671,6 +6202,14 @@
"vary": "~1.1.2"
}
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"requires": {
"is-extendable": "^0.1.0"
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
......@@ -5706,6 +6245,14 @@
"flat-cache": "^3.0.4"
}
},
"filelist": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
"integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
"requires": {
"minimatch": "^3.0.4"
}
},
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
......@@ -5824,6 +6371,14 @@
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-paths": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/get-paths/-/get-paths-0.0.7.tgz",
"integrity": "sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA==",
"requires": {
"pify": "^4.0.1"
}
},
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
......@@ -6072,11 +6627,26 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
......@@ -6105,6 +6675,11 @@
"is-extglob": "^2.1.1"
}
},
"is-whitespace": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz",
"integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
......@@ -6116,6 +6691,79 @@
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"jake": {
"version": "10.8.2",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
"integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
"requires": {
"async": "0.9.x",
"chalk": "^2.4.2",
"filelist": "^1.0.1",
"minimatch": "^3.0.4"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"js-beautify": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz",
"integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==",
"requires": {
"config-chain": "^1.1.12",
"editorconfig": "^0.15.3",
"glob": "^7.1.3",
"nopt": "^5.0.0"
}
},
"js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
......@@ -6233,6 +6881,14 @@
"tsscmp": "1.0.6"
}
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"requires": {
"is-buffer": "^1.1.5"
}
},
"koa": {
"version": "2.13.4",
"resolved": "https://registry.npmjs.org/koa/-/koa-2.13.4.tgz",
......@@ -6329,6 +6985,42 @@
"koa-compose": "^4.1.0"
}
},
"koa-ejs": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/koa-ejs/-/koa-ejs-4.3.0.tgz",
"integrity": "sha512-KK1B1YEeq8TOt7hrHwohfHxH03ZqsdhQWeFjmvcWk3arVI/uQOyE4FHQVlg0Ud9eXxlgUfkYqA2MJhfK4ADkAw==",
"requires": {
"debug": "^2.6.1",
"ejs": "^2.6.1",
"mz": "^2.6.0"
},
"dependencies": {
"ejs": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
}
}
},
"koa-passport": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/koa-passport/-/koa-passport-4.1.4.tgz",
"integrity": "sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg==",
"requires": {
"passport": "^0.4.0"
},
"dependencies": {
"passport": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz",
"integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==",
"requires": {
"passport-strategy": "1.x.x",
"pause": "0.0.1"
}
}
}
},
"koa-router": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/koa-router/-/koa-router-10.1.1.tgz",
......@@ -6440,6 +7132,35 @@
}
}
},
"koa-views": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/koa-views/-/koa-views-8.0.0.tgz",
"integrity": "sha512-nvGKdG8yVyomhouwN060SWd7Q9kGYRr322dwN6jvI04hgiDEW9vsPXEje9OEtBgGXxHURe7xOzo3bxQ3DBc1Nw==",
"requires": {
"consolidate": "^0.16.0",
"debug": "^4.1.0",
"get-paths": "0.0.7",
"koa-send": "^5.0.0",
"mz": "^2.4.0",
"pretty": "^2.0.0",
"resolve-path": "^1.4.0"
},
"dependencies": {
"debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
......@@ -6684,6 +7405,16 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
"requires": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
"thenify-all": "^1.0.0"
}
},
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
......@@ -6758,6 +7489,11 @@
"resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz",
"integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"obuf": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
......@@ -6851,6 +7587,14 @@
"passport-oauth2": "1.x.x"
}
},
"passport-local": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
"integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
"requires": {
"passport-strategy": "1.x.x"
}
},
"passport-oauth1": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.2.0.tgz",
......@@ -6899,12 +7643,27 @@
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
},
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true
},
"pretty": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz",
"integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=",
"requires": {
"condense-newlines": "^0.2.1",
"extend-shallow": "^2.0.1",
"js-beautify": "^1.6.12"
}
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
......@@ -6921,6 +7680,11 @@
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz",
"integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g=="
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
"integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk="
},
"protobufjs": {
"version": "6.11.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz",
......@@ -6950,6 +7714,11 @@
"ipaddr.js": "1.9.1"
}
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
......@@ -7159,6 +7928,11 @@
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
},
"sigmund": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"signal-exit": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
......@@ -7305,6 +8079,22 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
"thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"requires": {
"any-promise": "^1.0.0"
}
},
"thenify-all": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
"requires": {
"thenify": ">= 3.1.0 < 4"
}
},
"tmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
......
......@@ -6,7 +6,7 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node src",
"start:dev": "nodemon --watch src/ src/index.js"
"start:dev": "NODE_PATH=src nodemon --legacy-watch src/ src/index.js"
},
"author": "",
"license": "ISC",
......@@ -16,6 +16,7 @@
"bcrypt": "^5.0.1",
"crypto": "^1.0.1",
"dotenv": "^10.0.0",
"ejs": "^3.1.6",
"express": "^4.17.1",
"firebase": "^9.6.0",
"http2": "^3.3.7",
......@@ -23,12 +24,16 @@
"koa": "^2.13.4",
"koa-body": "^4.2.0",
"koa-bodyparser": "^4.3.0",
"koa-ejs": "^4.3.0",
"koa-passport": "^4.1.4",
"koa-router": "^10.1.1",
"koa-send": "^5.0.1",
"koa-views": "^8.0.0",
"mongoose": "^6.0.12",
"nodemailer": "^6.7.1",
"passport": "^0.5.0",
"passport-google-oauth": "^2.0.0",
"passport-local": "^1.0.0",
"spdy": "^4.0.2"
},
"devDependencies": {
......
......@@ -6,6 +6,9 @@ const nodemailer = require('nodemailer');
const config = require('../../lib/config');
const { Mongoose } = require('mongoose');
const { exist, allow } = require('@hapi/joi');
const index = require('../../../src/index');
const render = index.render;
const fs = require('fs');
exports.test = async (ctx) => {
console.log('cookie');
......@@ -61,7 +64,7 @@ exports.signupLocal = async (ctx) => {
// 응답할 데이터에서 hashedPassword 필드 제거
ctx.status = 200;
ctx.body = await account.serialize();
await ctx.render('users/new');
} catch (e) {
ctx.throw(500, e);
}
......@@ -97,6 +100,7 @@ exports.signinLocal = async (ctx) => {
httpOnly: false,
});
ctx.status = 200;
await ctx.render('users/index');
console.log('토큰나옴');
} catch (e) {
ctx.throw(500, e);
......
require('dotenv').config()
const Router = require("@koa/router");
const authCtrl = require("./auth.ctrl");
const checkLoggedIn = require("../../lib/checkLoggedIn");
var passport = require('passport');
const User = require("../../models/user");
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const auth = new Router();
......@@ -26,12 +29,73 @@ auth.get('/book',checkLoggedIn,authCtrl.getUserBook);
auth.get('/user', checkLoggedIn,authCtrl.userinfo); // show user information
auth.patch('/user', checkLoggedIn, authCtrl.updateUser); // modify user information
auth.patch('/user/password', authCtrl.changePassword); // change password
auth.post('/find/password', authCtrl.findPassword); // 비밀번호 찾기
auth.get('/favorite',checkLoggedIn, authCtrl.showFavorite); // show a list of user's favorites
auth.post('/favorite',checkLoggedIn, authCtrl.addFavorite); // add favorite
auth.delete('/favorite',checkLoggedIn, authCtrl.delFavorite); // delete favorite
auth.post('/find/password', authCtrl.findPassword); // 비밀번호 찾기
auth.get('/new', async (ctx) => {
ctx.render('users/new');
});
auth.get('/', async (ctx) => {
try{
const users = await User.find({}).sort({email:-1}).exec();//1 오름차순 -1내림차순
ctx.render('users/index', {users});
}catch(e){
ctx.throw(500, e);
}
}
);
// show
auth.get('/:id', async (ctx) => {
const user = await User.findOne({_id:ctx.params._id});
ctx.render('users/show', {user});
});
// edit
auth.get('/:id/edit', async (ctx) => {
const user = await User.findOne({username:ctx.params.username});
ctx.render('users/edit', {user:user});
});
// update // 2
auth.post('/:id', async (ctx) => {
await User.findOne({username:ctx.params.username}).select('password').exec();
// update user object
user.originalPassword = user.password;
user.password = ctx.body.newPassword? ctx.body.newPassword : user.password; // 2-3
for(var p in ctx.body) // 2-4
user[p] = ctx.body[p];
// save updated user
await user.save();
ctx.redirect('/users/'+user.nickname);
});
// destroy
module.exports = auth;
function checkPermission(ctx, next){
User.findOne({username:ctx.params.username}, function(err, user){
if(err) return res.json(err);
if(user.id != req.user.id) return util.noPermission(ctx);
next();
});
}
\ No newline at end of file
......
......@@ -5,17 +5,17 @@ const Joi = require('@hapi/joi');
const config = require('../../lib/config');
const { Mongoose } = require('mongoose');
exports.booklist = async (ctx) => {
let user;
try {
book = await Book.find()
.sort({created: -1})
.exec();
const books = await Book.find({}).sort({createDate: -1}).exec();
await ctx.render('books/index', {book:books});
console.log('get /book/');
//ctx.body = books;
} catch (e) {
return ctx.throw(500, e);
}
ctx.body = book;
}
}
......@@ -55,28 +55,24 @@ exports.addBook = async (ctx) => {
if (err) throw err;
const user = await User.findById(ctx.state.user._id).exec();
console.log(book._id);
ctx.redirect('/books');
});
} catch (e) {
ctx.throw(500, e);
}
ctx.body = book;
console.log('저장 성공!');
ctx.status = 200;
};
exports.getOneBook = async (ctx) => {
const bookid = ctx.request.body._id;
const bookid = ctx.params.id;//bookid by parameter
console.log(bookid);
try {
const mybook = await Book.findById(bookid).exec();
const user = await User.findById(mybook.author).exec();//작가정보
const author_name = user.nickname;
const bookInfo = {
"author_name":author_name
}
ctx.body = {mybook,author_name:author_name}
console.log(mybook)
ctx.render('books/show', {book:mybook, user:user});
//ctx.body.authorname = user.nickname;
//ctx.body = mybook;
} catch (e) {
......@@ -84,7 +80,8 @@ exports.getOneBook = async (ctx) => {
}
//const user = await User.findById(mybook.author).exec();
//ctx.body = mybook;
console.log('책 정보 하나! 얻기 성공');
ctx.status = 200;
};
......@@ -95,46 +92,72 @@ exports.updateBook = async (ctx) => {
const file = ctx.request.files;
if(ctx.request.body.cover != undefined) // when user add a new pet image
ctx.request.body.cover = fs.readFileSync(file.image.path);
else
else{
ctx.request.body.cover = ""
}
var book = ctx.request.body; //require books's _id
try {
const mybook = await Book.findOne({ _id: book._id });
mybook.updateB(book);
ctx.body = book._id;
} catch (e) {
ctx.throw(500, e);
const mybook = await Book.findOne({ _id: ctx.params.id });
if(ctx.state.user._id == mybook.author){//작성한 사람이 맞을 때만
await mybook.updateB(book);
await ctx.redirect('/api/page/detail/'+ctx.params.id);
ctx.status = 200;}
else{
console.log('작성자가 아니다. ');
ctx.status = 400;
}
ctx.body = book._id;
}
catch (e) {
ctx.throw(500, e);
console.log(book);
ctx.status = 200;
ctx.status = 400;
ctx.body = {
message: "작성자가 아닙니다. " }
}
};
exports.deleteBook = async (ctx) => {
let bookid =ctx.params.id;
try {
var b = await Book.find(ctx.params.id);
await Page.deleteMany({"pages":{$in:b.pages}});//book에 있던 페이지 다 지우기
//var foundB = await Book.findById(bookid).exec();
//북작가에게서 책 정보 지우기
var author = await User.findById(bookid);//북 작가.
console.log(author);
console.log(author.books);
await User.delBook(ctx.state.user.email,bookid);
//book에 있던 페이지 다 지우기
await Page.deleteMany({"pages":{$in:b.pages}});
//최종 book지우기
var b = await Book.deleteOne({_id:bookid});
} catch (e) {
if(e.name === 'CastError') {
ctx.status = 400;
return;
}
}
ctx.status = 204; // No Content
console.log('delete success');
ctx.body = {
message: "Delete"
}
};
exports.detailBook = async (ctx) => {
var ObjectId = require('mongodb').ObjectId;
var id = req.params.book_id;
var o_id = new ObjectId(id);
const book = await db.Book.find({_id:o_id});
ctx.body = book;
try{
var id = ctx.params.id;
const book = await dBook.find({_id:id});
ctx.render('books/show', {book:book});
ctx.status = 200;
} catch (e) {
ctx.status = 400;
console.log('북 삭제 오류');
}
};
exports.scrollBook = async (ctx) => {
......@@ -154,8 +177,4 @@ exports.scrollBook = async (ctx) => {
ctx.throw(500, e);
}
}
else if(filter === "추천순") { //추천순
}
};
......
......@@ -2,14 +2,154 @@ const Router = require("@koa/router");
const checkLoggedIn = require("../../lib/checkLoggedIn");
const bookCtrl = require("./book.ctrl");
const book = new Router();
const User = require("../../models/user");
const Book = require("../../models/book");
//북id params로 전달. Render books/show
book.get('/',bookCtrl.getOneBook);
book.get('/:id', async (ctx) => {
const bookid = ctx.params.id;//bookid by parameter
console.log(bookid);
try {
const book = await Book.findOne({_id:ctx.params.id});
ctx.render('books/show', {book});
//ctx.body.authorname = user.nickname;
//ctx.body = mybook;
} catch (e) {
ctx.throw(500, e);
}
//const user = await User.findById(mybook.author).exec();
//ctx.body = mybook;
console.log('책 정보 하나! 얻기 성공');
ctx.status = 200;
});
//mybook=page,title
//author_name = author name
book.post('/',checkLoggedIn,bookCtrl.addBook); // add book
book.patch('/', checkLoggedIn, bookCtrl.updateBook); // modify book information
book.delete('/',checkLoggedIn,bookCtrl.deleteBook); // delete book
book.get('/booklist',bookCtrl.booklist);
book.get('/search',bookCtrl.scrollBook);
book.post('/',checkLoggedIn,async (ctx) => {
const {
title,
author,
contents,
cover,
hashtag,
} = ctx.request.body;
const schema = Joi.object().keys({
title: Joi.string().required(),
author: Joi.string(),
contents: Joi.string().allow(null, ''),
hashtag: Joi.string().allow(null, ''),
cover: Joi.allow(null, ''),
});
try {
await schema.validateAsync(ctx.request.body);
} catch (err) {
console.log('add book validaton' + err);
ctx.status = 400;
return;
}
ctx.request.body.author = ctx.state.user;
const book = new Book(ctx.request.body);
try {
book.save(async (err) => {
if (err) throw err;
const user = await User.findById(ctx.state.user._id).exec();
console.log(book._id);
ctx.redirect('/books');
});
} catch (e) {
ctx.throw(500, e);
}
console.log('저장 성공!');
ctx.status = 200;
});
// add book
// redirect posts (create)
book.patch('/:id', checkLoggedIn, async (ctx) => {
const file = ctx.request.files;
if(ctx.request.body.cover != undefined) // when user add a new pet image
ctx.request.body.cover = fs.readFileSync(file.image.path);
else{
ctx.request.body.cover = ""
}
var book = ctx.request.body; //require books's _id
try {
const mybook = await Book.findOne({ _id: ctx.params.id });
if(ctx.state.user._id == mybook.author){//작성한 사람이 맞을 때만
await mybook.updateB(book);
await ctx.redirect('/api/page/detail/'+ctx.params.id);
ctx.status = 200;}
else{
console.log('작성자가 아니다. ');
ctx.status = 400;
}
}
catch (e) {
ctx.throw(500, e);
ctx.status = 400;
ctx.body = {
message: "작성자가 아닙니다. " }
}
});// modify book information
//update book rediret:"/books/"+ctx.params.id
//book.id params
book.delete('/:id',checkLoggedIn,async (ctx) => {
let bookid =ctx.params.id;
try {
//var foundB = await Book.findById(bookid).exec();
//북작가에게서 책 정보 지우기
var author = await User.findById(bookid);//북 작가.
console.log(author);
console.log(author.books);
await User.delBook(ctx.state.user.email,bookid);
//book에 있던 페이지 다 지우기
await Page.deleteMany({"pages":{$in:b.pages}});
//최종 book지우기
var b = await Book.deleteOne({_id:bookid});
} catch (e) {
if(e.name === 'CastError') {
ctx.status = 400;
return;
}
}
console.log('delete success');
ctx.body = {
message: "Delete"
}
}); // delete book
// params.id
//redirect('/books')<-index
book.get('/',async (ctx) => {
try {
const books = await Book.find({}).sort({createDate: -1}).exec();
ctx.render('books/index', {books:books});
} catch (e) {
return ctx.throw(500, e);
}
}
);
book.get('/search', async (ctx) => {
const {filter, renewal} = ctx.query
if(filter === "조회순") { //조회순
try {
const books = await Book.find().sort({'views': -1}).skip(parseInt(renewal)*10).limit(10)
let result = await bookInfo(books);
ctx.status = 200;
ctx.body = result;
} catch (e) {
ctx.throw(500, e);
}
}
});
book.get('/new', async (ctx) => {
ctx.render('books/new');
});
module.exports = book;
......
const Router = require("koa-router");
const page = require("./page");
const auth = require("./auth");
const book = require("./book");
//const page = require("./page");
//const auth = require("./auth");
//const book = require("./book");
//const render = require('../index/');
const api = new Router();
//const path = require('path');
api.use("/auth", auth.routes());
api.use("/book", book.routes());
api.use("/page", page.routes());
api.get('/test', (ctx) => (ctx.body = 'hi'));
module.exports = api;
///api.use("/auth", auth.routes());
//api.use("/book", book.routes());
//api.use("/page", page.routes());
//module.exports = api;
......
......@@ -2,8 +2,12 @@ const Router = require("@koa/router");
const checkLoggedIn = require("../../lib/checkLoggedIn");
const pageCtrl = require("./page.ctrl");
const page = new Router();
const Page = require("../../models/page");
const index = require('../../../src/index');
//const render = require('koa-ejs');
//Page api
/*
page.get('/',pageCtrl.getPage); // show a list of user's pages
page.post('/',checkLoggedIn,pageCtrl.addPage); // add page
page.patch('/', checkLoggedIn,pageCtrl.updatePage); // modify page information
......@@ -11,12 +15,61 @@ page.delete('/',checkLoggedIn,pageCtrl.deletePage); // delete book
page.get('/search', pageCtrl.search); // /search?title=search_query&petType=petType
//page.post('/search/filter', pageCtrl.searchFilter); //아직 구현 안함
page.post('/detail', pageCtrl.detailPage); // detail recipe page
page.post('/:id', pageCtrl.detailPage); // detail recipe page
//page.get('/recipe/slide', pageCtrl.slidRecipe); // 5 recommended videos in main page
// /recipe/scroll?filter=filter_query&renewal=count (filter_query: 추천순 or 조회순)
page.get('/recipe/scroll', pageCtrl.scrollPage); // video list sorted by 추천순 or 조회순 in main page
*/
page.get('/', async (ctx) => {
const page = await Page.find({}).sort({createDate:-1}).exec();
console.log(page);
await ctx.render('posts/index', {page});
});
page.get('/new', async (ctx) => {
await ctx.render('posts/new');
});
// create
page.post('/', async (ctx, next) => {
await Page.create(ctx.body);
ctx.redirect('/posts');
});
// show
page.get('/:id', async (ctx, next) => {
const page = await Page.findOne({_id:ctx.params.id});
console.log('찾은 페이지',page);
ctx.render('posts/show', {page:page,user:ctx.state.user});
});
// update
page.put('/:id', async (ctx, next) => {
ctx.body.updatedAt = Date.now(); //2
const page = await Page.findOneAndUpdate({_id:ctx.params.id}, ctx.body);
ctx.redirect("/posts/"+ctx.params.id);
});
// destroy
page.delete('/:id', async (ctx, next) => {
try{
await Page.deleteOne({_id:ctx.params.id})
ctx.redirect('/posts');
}catch(e){
ctx.throw(500, e);
}
});
//page.post('/postinfo', pageCtrl.uploadInfo);
//page.get('/info',pageCtrl.getbyurl);//url로 recipe정보 가져오기 (flutter 내 레시피에서 쓰임.)
......
......@@ -4,6 +4,8 @@ const Book = require("../../models/book");
const Joi = require('@hapi/joi');
const config = require('../../lib/config');
const { Mongoose } = require('mongoose');
exports.search = async (ctx) => {
const { title } = ctx.query; //search word
console.log(title)
......@@ -19,12 +21,18 @@ exports.search = async (ctx) => {
exports.detailPage = async (ctx) => {
try{
var ObjectId = require('mongodb').ObjectId;
var id = req.params.page_id;
var id = req.params.id;
var o_id = new ObjectId(id);
const page = await db.Page.find({_id:o_id});
await ctx.redirect('/api/page/detail/'+req.params.id);
ctx.body = page;
ctx.status = 200;
}catch(e){
ctx.throw(500,e);
}
};
// parameters: array with book objects as elements
......@@ -149,19 +157,21 @@ exports.scrollPage = async (ctx) => {
else
ctx.request.body.image = ""
var user = ctx.request.body; //require user id
var page = ctx.request.body;
try {
const mybook = await Book.findOne({ _id: book._id });
const mypage = await Page.findOne({ _id: page._id });//require page's _id
if(ctx.state.user._id == mypage.author){
mypage.updateP(book);
ctx.body = mypage;
console.log(mypage);
ctx.status = 200;}
mybook.updateP(book);
ctx.body = user._id;
} catch (e) {
ctx.throw(500, e);
ctx.body = {
message: "작성자가 아닙니다. " }
}
ctx.body = user._id;
console.log(user);
ctx.status = 200;
};
......@@ -178,18 +188,3 @@ exports.deletePage = async (ctx) => {
}
ctx.status = 204; // No Content
};
exports.getPage = async (ctx) => {
const pageid = ctx.request.body._id;
try {
const mypage = await Book.findById(pageid).exec();
const user = await User.findById(mypage.author).exec();//작가정보
const author_name = user.nickname;
ctx.body = {mypage,author_name:author_name}
console.log(mypage)
} catch (e) {
ctx.throw(500, e);
}
};
......
......@@ -9,8 +9,17 @@ const mongoose = require('mongoose');
const bodyParser = require('koa-bodyparser');
const port = process.env.PORT || 3000
//443
const passport = require('koa-passport')
const app = new Koa();
const router = new Router()
const render = require('koa-ejs');
const path = require('path');
//const User = require('../models/user');
//const views = require('koa-views');
const book = require('./routes/book');
const auth = require('./routes/user');
const page = require('./routes/page');
const send = require('koa-send');
var options = {
key: fs.readFileSync('./server.key'),
......@@ -29,53 +38,90 @@ mongoose.connect(process.env.MONGO_URI).then(
console.error(e);
});
var readFileThunk = function(src) {
return new Promise(function (resolve, reject) {
fs.readFile(src, {'encoding': 'utf8'}, function (err, data) {
if(err) return reject(err);
resolve(data);
});
});
}
//app.use(router.routes())
/*
app
.use(router.routes())
.use(router.allowedMethods());
render(app, {
root: path.join(__dirname, 'views'),
layout: false,
viewExt: 'ejs',
cache: false,
debug: true
});
*/
// app.use(async function (ctx) {
// await ctx.render('home/welcome');
// });
app
.use(jwtMiddleware)
.use(bodyParser()) // bodyParser는 라우터 코드보다 상단에 있어야 합니다.
.use(router.routes())
.use(router.allowedMethods());
.use(bodyParser()); // bodyParser는 라우터 코드보다 상단에 있어야 합니다.
render(app, {
root: path.join(__dirname, 'views'),
layout: false,
viewExt: 'ejs',
cache: false,
debug: true
});
app
.use(router.routes())
.use(router.allowedMethods())
.use(passport.initialize());
/*
router.get('/', (ctx, next) => {
ctx.body = '루트 페이지 입니다.';
// .use(views(path.join(__dirname, 'views'), {
//extension: 'ejs'
//}))
//.use(views('views', { map: { html: 'ejs' } }));
router.get('/', async ctx =>{
await ctx.render('home/welcome');
});
*/
/*
router.get('/', async (ctx, next) => {
const rawContent = fs.readFileSync('index.html').toString('utf8')
ctx.body = rawContent
})*/
router.get('/', function *(){
this.body = yield readFileThunk(__dirname + '/public/index.html');
})
router.get('/about', async ctx =>{
ctx.render('home/about');
});
router.get('/auth', async ctx =>{
ctx.render('users/login');
});
//router.use('/', api.routes());
//router.use("/book", require("./routes/book"));
//router.use("/page", require("./routes/page"));
//router.use("/auth", require("./routes/user"));
router.use('/auth', auth.routes());
router.use('/book', book.routes());
router.use('/page', page.routes());
app.use(router.routes()).use(router.allowedMethods());
//router.get('/', async (ctx, next) => {
// const rawContent = fs.readFileSync('index.html').toString('utf8')
//ctx.body = rawContent
//})
//router.use(api.routes());
//app.use(router.routes()).use(router.allowedMethods())
router.use('/api', api.routes());
app.use(router.routes()).use(router.allowedMethods());
//app.use(router.routes()).use(router.allowedMethods());
http2
.createSecureServer(options, app.callback())
.listen(port, () => console.log("listening on port %i", port));
//app.listen(port, function () {
//console.log('server listening on port %d', port);
//});
/*
app.listen(port, function () {
console.log('server listening on port %d', port);
});
*/
\ No newline at end of file
......
......@@ -10,3 +10,13 @@ const checkLoggedIn = (ctx, next) => {
module.exports = checkLoggedIn;
const User = require('../models/user')
const checkPermission = (ctx, next) => {
const user = User.findOne({username:ctx.params.username});
if(user._id != ctx.status.user._id)
return util.noPermission(ctx);
next();
};
module.exports = checkPermission;
\ No newline at end of file
......
const config = {
mailer: {
user: "yoobinpark@khu.ac.kr",
password: "1q2w3e4r!@",
user: "like01test@gmail.com",
password: "like1412",
expiresIn: 60 * 5,
},
};
......
......@@ -5,9 +5,9 @@ const { Schema } = mongoose;
const bookSchema = new Schema({
id: mongoose.Schema.Types.ObjectId,//unique number of page
pages:[{type:String}],//book contains several pages. pages is the list of page id
pages:[{type:mongoose.Schema.Types.ObjectId, ref:'page', required:false}],//book contains several pages. pages is the list of page id
title: {type:String, require:true}, // book title
author: [{type:String, require:true, default:user.user}],//작가복수 가능
author: [{type:mongoose.Schema.Types.ObjectId, ref:'user', required:true}],//작가복수 가능
contents: {type:String}, // book subtitle or detail
createDate: {type:Date, require:true, default:Date.now},
updateDate: {type:Date, default:Date.now},
......@@ -103,4 +103,5 @@ const bookSchema = new Schema({
module.exports = mongoose.model("Book", bookSchema);
\ No newline at end of file
......
......@@ -4,9 +4,9 @@ const { Schema } = mongoose;
const PageSchema = new Schema({
id: mongoose.Schema.Types.ObjectId,//unique number of page
book:{type:String},//book contains several pages
book:[{type:mongoose.Schema.Types.ObjectId, ref:'book', required:false}],//book contains several pages
title: {type:String, require:true}, // title of post
author: [{type:String, require:true, default:user.user}],
author: [{type:mongoose.Schema.Types.ObjectId, ref:'user', required:true}],
contents: {type:String}, // contents of page
createDate: {type:Date, require:true, default:Date.now},
updateDate: {type:Date, default:Date.now},
......
......@@ -12,10 +12,10 @@ const UserSchema = new Schema({
password: String,
token: String,
//user info
username: String,
phone: {type: String, require: true},
nickname: {type: String, default: ""},
books: [{type: String}],//array of bookid
books: [{type:mongoose.Schema.Types.ObjectId, ref:'book', required:false}],//array of bookid
pages:[{type:mongoose.Schema.Types.ObjectId, ref:'page', required:false}],
favorite: [{ type: String }],//String of url(book, page)
});
......
/* global style */
form label{
padding: 3px;
margin-bottom: 0;
font-weight: 300;
}
form .form-control{
padding: 3px 7px;
font-size: inherit;
line-height: 20px;
height: auto;
border: 1px solid #ccc;
border-radius: 3px;
width: 100%;
}
form fieldset{
margin: 7px 0 1px;
padding: 0px 15px;
}
form .form-group{
margin: 0;
padding-bottom: 6px;
}
.ellipsis{
display: block;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.form-horizontal .control-label {
padding-top: 5px;
text-align: left;
}
.buttons {
margin: 7px 0;
padding: 0 5px;
}
.buttons form{
display: inline-block;
}
.buttons .btn-default{
min-width: 55px;
color: #165751;
border: 1px solid #ccc;
border-right: 1px solid #aaa;
border-bottom: 1px solid #aaa;
border-radius: 4px;
padding: 5px 10px;
background-color: #f5f5f5;
font-size: 0.8em;
font-weight: bold;
}
.buttons .btn-default:hover{
text-decoration: none;
position: relative;
top: 1px;
left: 1px;
border: 1px solid #ccc;
border-top: 1px solid #aaa;
border-left: 1px solid #aaa;
}
.contentBox{
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.contentBoxTop {
font-size: 14px;
font-weight: 600;
margin: 0;
border-bottom: 1px solid #ccc;
background-color: #F5F5F5;
padding: 6px 15px;
}
/* home style */
.home h1{
color: darkseagreen;
}
.home-login{
max-width: 330px;
font-family: 'Open Sans', sans-serif;
font-size: 12px;
}
/* post style */
.post {
max-width: 670px;
font-family: 'Open Sans', sans-serif;
font-size: 12px;
}
.post h2 {
color: tomato;
text-align: center;
}
.post .post-body {
white-space: pre-line;
padding: 6px 15px 20px;
}
.post .post-info{
font-size: 11px;
margin: 5px;
padding: 5px 10px;
background-color: #E4E4E4;
border: 0 solid black;
border-radius: 5px;
}
.post .post-info>div{
padding: 5px 0;
border-top: 1px dotted #999;
}
.post .post-info>div:first-child{
border-top: none;
}
.post .post-info span{
display: inline-block;
width: 40px;
}
.post-index .posts{
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
table-layout: fixed;
}
.post .posts th,
.post .posts td
{
padding: 7px 5px;
}
.post .posts th:first-child,
.post .posts td:first-child
{
padding-left: 15px;
}
.post .posts thead{
background-color: #F5F5F5;
}
.post .posts thead tr th{
border-bottom: 1px solid #ccc;
}
.post .posts tbody tr:nth-child(odd){
background-color: #F4FFFF;
}
.post .posts tbody .noData{
background-color: #FFFFFF;
text-align: center;
}
.post .posts .author{
text-align: center;
width: 80px;
}
.post .posts .date{
text-align: center;
width: 100px;
padding-right: 15px;
}
.post-new,
.post-edit{
max-width: 520px;
}
/* user style */
.user {
max-width: 320px;
font-family: 'Open Sans', sans-serif;
font-size: 12px;
}
.user-index ul{
margin: 0;
padding: 3px 12px;
}
.user-index ul:after {
content: "";
display: block;
clear: both;
}
.user-index ul li{
display: inline-block;
list-style-type: none;
}
.user-index ul li a{
display: inline-block;
text-decoration:none;
margin: 3px;
background-color: #eee;
padding: 3px 10px;
border-radius: 3px;
}
.user-index ul li a:hover{
background-color: #ccc;
}
.user-edit hr{
margin-top: 5px;
margin-bottom: 11px;
}
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}
.wrapper {
margin-top: 80px;
margin-bottom: 20px;
}
.form-signin {
max-width: 420px;
padding: 30px 38px 66px;
margin: 0 auto;
background-color: #eee;
border: 3px dotted rgba(0,0,0,0.1);
}
.form-signin-heading {
text-align:center;
margin-bottom: 30px;
}
.form-control {
position: relative;
font-size: 16px;
height: auto;
padding: 10px;
}
input[type="text"] {
margin-bottom: 0px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
input[type="password"] {
margin-bottom: 20px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
$(function(){
function get2digits (num){
return ('0' + num).slice(-2);
}
function getDate(dateObj){
if(dateObj instanceof Date)
return dateObj.getFullYear() + '-' + get2digits(dateObj.getMonth()+1)+ '-' + get2digits(dateObj.getDate());
}
function getTime(dateObj){
if(dateObj instanceof Date)
return get2digits(dateObj.getHours()) + ':' + get2digits(dateObj.getMinutes())+ ':' + get2digits(dateObj.getSeconds());
}
function convertDate(){
$('[data-date]').each(function(index,element){
var dateString = $(element).data('date');
if(dateString){
var date = new Date(dateString);
$(element).html(getDate(date));
}
});
}
function convertDateTime(){
$('[data-date-time]').each(function(index,element){
var dateString = $(element).data('date-time');
if(dateString){
var date = new Date(dateString);
$(element).html(getDate(date)+' '+getTime(date));
}
});
}
convertDate();
convertDateTime();
});
\ No newline at end of file
const Router = require("@koa/router");
const checkLoggedIn = require("../../src/lib/checkLoggedIn");
//const bookCtrl = require("./book.ctrl");
const book = new Router();
const User = require("../models/user")
const Book = require("../models/book");
//북id params로 전달. Render books/show
book.get('/:id', async (ctx) => {
const bookid = ctx.params.id;//bookid by parameter
console.log(bookid);
try {
const book = await Book.findOne({_id:ctx.params.id});
ctx.render('books/show', {book});
//ctx.body.authorname = user.nickname;
//ctx.body = mybook;
} catch (e) {
ctx.throw(500, e);
}
//const user = await User.findById(mybook.author).exec();
//ctx.body = mybook;
console.log('책 정보 하나! 얻기 성공');
ctx.status = 200;
});
//mybook=page,title
//author_name = author name
book.post('/',checkLoggedIn,async (ctx) => {
const {
title,
author,
contents,
cover,
hashtag,
} = ctx.request.body;
const schema = Joi.object().keys({
title: Joi.string().required(),
author: Joi.string(),
contents: Joi.string().allow(null, ''),
hashtag: Joi.string().allow(null, ''),
cover: Joi.allow(null, ''),
});
try {
await schema.validateAsync(ctx.request.body);
} catch (err) {
console.log('add book validaton' + err);
ctx.status = 400;
return;
}
ctx.request.body.author = ctx.state.user;
const book = new Book(ctx.request.body);
try {
book.save(async (err) => {
if (err) throw err;
const user = await User.findById(ctx.state.user._id).exec();
console.log(book._id);
ctx.redirect('/books');
});
} catch (e) {
ctx.throw(500, e);
}
console.log('저장 성공!');
ctx.status = 200;
});
// add book
// redirect posts (create)
book.patch('/:id', checkLoggedIn, async (ctx) => {
const file = ctx.request.files;
if(ctx.request.body.cover != undefined) // when user add a new pet image
ctx.request.body.cover = fs.readFileSync(file.image.path);
else{
ctx.request.body.cover = ""
}
var book = ctx.request.body; //require books's _id
try {
const mybook = await Book.findOne({ _id: ctx.params.id });
if(ctx.state.user._id == mybook.author){//작성한 사람이 맞을 때만
await mybook.updateB(book);
await ctx.redirect('/api/page/detail/'+ctx.params.id);
ctx.status = 200;}
else{
console.log('작성자가 아니다. ');
ctx.status = 400;
}
}
catch (e) {
ctx.throw(500, e);
ctx.status = 400;
ctx.body = {
message: "작성자가 아닙니다. " }
}
});// modify book information
//update book rediret:"/books/"+ctx.params.id
//book.id params
book.delete('/:id',checkLoggedIn,async (ctx) => {
let bookid =ctx.params.id;
try {
//var foundB = await Book.findById(bookid).exec();
//북작가에게서 책 정보 지우기
var author = await User.findById(bookid);//북 작가.
console.log(author);
console.log(author.books);
await User.delBook(ctx.state.user.email,bookid);
//book에 있던 페이지 다 지우기
await Page.deleteMany({"pages":{$in:b.pages}});
//최종 book지우기
var b = await Book.deleteOne({_id:bookid});
} catch (e) {
if(e.name === 'CastError') {
ctx.status = 400;
return;
}
}
console.log('delete success');
ctx.body = {
message: "Delete"
}
}); // delete book
// params.id
//redirect('/books')<-index
book.get('/',async (ctx) => {
try {
const books = await Book.find({}).sort({createDate: -1}).exec();
ctx.render('books/index', {books:books});
} catch (e) {
return ctx.throw(500, e);
}
}
);
book.get('/search', async (ctx) => {
const {filter, renewal} = ctx.query
if(filter === "조회순") { //조회순
try {
const books = await Book.find().sort({'views': -1}).skip(parseInt(renewal)*10).limit(10)
let result = await bookInfo(books);
ctx.status = 200;
ctx.body = result;
} catch (e) {
ctx.throw(500, e);
}
}
});
book.get('/new', async (ctx) => {
ctx.render('books/new');
});
module.exports = book;
\ No newline at end of file
const Router = require("@koa/router");
const checkLoggedIn = require("../../src/lib/checkLoggedIn");
// const pageCtrl = require("./page.ctrl");
const page = new Router();
const Page = require("../models/page");
//const index = require('../../../src/index');
//const render = require('koa-ejs');
//Page api
/*
page.get('/',pageCtrl.getPage); // show a list of user's pages
page.post('/',checkLoggedIn,pageCtrl.addPage); // add page
page.patch('/', checkLoggedIn,pageCtrl.updatePage); // modify page information
page.delete('/',checkLoggedIn,pageCtrl.deletePage); // delete book
page.get('/search', pageCtrl.search); // /search?title=search_query&petType=petType
//page.post('/search/filter', pageCtrl.searchFilter); //아직 구현 안함
page.post('/:id', pageCtrl.detailPage); // detail recipe page
//page.get('/recipe/slide', pageCtrl.slidRecipe); // 5 recommended videos in main page
// /recipe/scroll?filter=filter_query&renewal=count (filter_query: 추천순 or 조회순)
page.get('/recipe/scroll', pageCtrl.scrollPage); // video list sorted by 추천순 or 조회순 in main page
*/
page.get('/tset', async (ctx) => {
console.log('testtest');
});
page.get('/', async (ctx) => {
const page = await Page.find({}).sort({createDate:-1}).exec();
console.log(page);
await ctx.render('posts/index', {page});
});
page.get('/new', async (ctx) => {
await ctx.render('posts/new');
});
// create
page.put('/', checkLoggedIn, async (ctx, next) => {
const {
title,
author,
contents,
cover,
hashtag,
} = ctx.request.body;
const schema = Joi.object().keys({
title: Joi.string().required(),
author: Joi.string(),
contents: Joi.string().allow(null, ''),
hashtag: Joi.string().allow(null, ''),
cover: Joi.allow(null, ''),
});
try {
await schema.validateAsync(ctx.request.body);
} catch (err) {
console.log('add book validaton' + err);
ctx.status = 400;
return;
}
ctx.request.body.author = ctx.state.user;
const book = new Book(ctx.request.body);
try {
book.save(async (err) => {
if (err) throw err;
const user = await User.findById(ctx.state.user._id).exec();
console.log(book._id);
ctx.redirect('/page');
});
} catch (e) {
ctx.throw(500, e);
}
console.log('저장 성공!');
ctx.status = 200;
ctx.redirect('/page');
});
// show
page.get('/:id', async (ctx, next) => {
try{
var id = ctx.params.id;
const page = await Page.findById(id).exec();
await ctx.render('posts/show', {page:page});
ctx.status = 200;
}catch(e){
ctx.throw(500,e);
}
});
// update
page.patch('/:id',checkLoggedIn, async (ctx, next) => {
const id = ctx.params.id;
if(ctx.request.files != undefined) // when user add a new pet image
ctx.request.body.image = fs.readFileSync(file.image.path);
else
ctx.request.body.image = ""
ctx.body.updateDate = Date.now();
var page = ctx.request.body;
try {
const mypage = await Page.findOne({ _id: id });//require page's _id
if(ctx.state.user._id == mypage.author){
mypage.updateP(page);
console.log(mypage);
ctx.redirect("/page/"+id);
ctx.status = 200;}
} catch (e) {
ctx.throw(500, e);
ctx.body = {
message: "작성자가 아닙니다. " }
}
});
// destroy
page.delete('/:id', async (ctx, next) => {
try{
await Page.deleteOne({_id:ctx.params.id})
ctx.redirect('/page');
}catch(e){
ctx.throw(500, e);
}
});
//page.post('/postinfo', pageCtrl.uploadInfo);
//page.get('/info',pageCtrl.getbyurl);//url로 recipe정보 가져오기 (flutter 내 레시피에서 쓰임.)
module.exports = page;
require('dotenv').config()
const Router = require("@koa/router");
//const authCtrl = require("auth.ctrl");
const checkLoggedIn = require("../../src/lib/checkLoggedIn");
//var passport = require('passport');
const User = require("../models/user");
//var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const auth = new Router();
// 회원가입- 로컬 이메일 인증번호 발송 POST auth/signup/email/demand
// 회원가입 이메일 인증번호 확인 POST auth/signup/email/verify
// 로그인 "소셜 로그인
// (페이스북 구글 네이버 카카오)" POST auth/signin/social
// 회원정보갱신 설문이나 설정에서 개인정보 바꾸면 적용 PATCH auth/update/pet
// 회원정보갱신 설문이나 설정에서 개인정보 바꾸면 적용 PATCH auth/update/user
/*
auth.get('/userlist', authCtrl.userlist);
auth.get('/test', authCtrl.test);
auth.post('/signup', authCtrl.signupLocal);
auth.post('/signin', authCtrl.signinLocal);
auth.get('/signout',checkLoggedIn, authCtrl.signout);
auth.get('/check', authCtrl.check2);
auth.delete('/user',checkLoggedIn,authCtrl.Withdrawal); // 회원 탈퇴
auth.post('/validate', authCtrl.exists);
auth.post('/checkpassword', authCtrl.checkPassword);
auth.get('/book',checkLoggedIn,authCtrl.getUserBook);
auth.get('/user', checkLoggedIn,authCtrl.userinfo); // show user information
auth.patch('/user', checkLoggedIn, authCtrl.updateUser); // modify user information
auth.patch('/user/password', authCtrl.changePassword); // change password
auth.post('/find/password', authCtrl.findPassword); // 비밀번호 찾기
auth.get('/favorite',checkLoggedIn, authCtrl.showFavorite); // show a list of user's favorites
auth.post('/favorite',checkLoggedIn, authCtrl.addFavorite); // add favorite
auth.delete('/favorite',checkLoggedIn, authCtrl.delFavorite); // delete favorite
auth.post('/find/password', authCtrl.findPassword); // 비밀번호 찾기
*/
auth.get('/new', async (ctx) => {
ctx.render('users/new');
});
auth.get('/test', async (ctx) => {
ctx.render('users/login');
});
// show
/*
auth.get('/:id', async (ctx) => {
try{
const user = await User.findOne({_id:ctx.params._id});
ctx.render('users/show', {user});
}catch(e){
ctx.throw(500, e);
console.log(e); }
});
*/
auth.get('/login', async (ctx) => {
await ctx.render('home/login')
});
// edit
auth.get('/:id/edit', async (ctx) => {
const user = await User.find({email:ctx.params.email}).exec();
ctx.render('users/edit', {user:user});
});
auth.post('/login',async(ctx) =>{
const { email, password } = ctx.request.body;
const errors ='';
//handle error
if (!email || !password) {
ctx.status = 401; //Unauthorized
errors= '비밀번호, 이메일 중 하나가 틀렸습니다. '
return;
}
try {
//const user = User.findOne({ email: email });
const user = await User.findByEmail(email);
//계정없으면 에러처리
console.log(user);
if (!user) {
ctx.status = 401;
return;
}
const valid = await user.checkPassword(password);
if (!valid) {
ctx.status = 401;
return;
}
ctx.body = await user.serialize();
const token = user.generateToken();
ctx.cookies.set('access_token', token, {
maxAge: 1000 * 60 * 60 * 24 * 7, // 7일
httpOnly: false,
});
ctx.status = 200;
ctx.redirect('/page');
console.log('토큰나옴, 로그인');
} catch (e) {
ctx.throw(500, e);
ctx.redirect('/')
}
});
auth.post('/signup',async(ctx)=>{const { email, password, address } = ctx.request.body;
console.log(ctx.request.body);
const schema = Joi.object().keys({
email: Joi.string().min(3).required(),
password: Joi.string().required(),
phone: Joi.string().allow(null, ''),
nickname:Joi.string().allow(null, '')
});
//검증 결과
try {
const value = await schema.validateAsync(ctx.request.body);
} catch (err) {
console.log(err);
ctx.status = 400;
return;
}
try {
// email 이미 존재하는지 확인
const exists = await User.findByEmail(email);
if (exists) {
ctx.status = 409; // Conflict
return;
}
let account = null;
try {
account = await User.localRegister(ctx.request.body);
} catch (e) {
ctx.throw(500, e);
}
let token = null;
try {
token = await account.generateToken();
console.log('token ok');
} catch (e) {
ctx.throw(500, e);
}
ctx.cookies.set('access_token', token, { maxAge: 1000 * 60 * 60 * 24 * 7 ,httpOnly: true,});
console.log('set cookie ok');
// 응답할 데이터에서 hashedPassword 필드 제거
ctx.status = 200;
await ctx.render('users/new');
} catch (e) {
ctx.throw(500, e);
}});
// update // 2
auth.post('/:id', async (ctx) => {
await User.findOne({username:ctx.params.username}).select('password').exec();
// update user object
user.originalPassword = user.password;
user.password = ctx.body.newPassword? ctx.body.newPassword : user.password; // 2-3
for(var p in ctx.body) // 2-4
user[p] = ctx.body[p];
// save updated user
await user.save();
ctx.redirect('/users/'+user.nickname);
});
// destroy
auth.get('/logout', async (ctx) => {
ctx.cookies.set('access_token');
ctx.status = 204;
ctx.redirect('/');
});
module.exports = auth;
function checkPermission(ctx, next){
User.findOne({username:ctx.params.username}, function(err, user){
if(err) return res.json(err);
if(user.id != req.user.id) return util.noPermission(ctx);
next();
});
}
\ No newline at end of file
var util = {};
util.parseError = function(errors){
var parsed = {};
if(errors.name == 'ValidationError'){
for(var name in errors.errors){
var validationError = errors.errors[name];
parsed[name] = { message:validationError.message };
}
}
else if(errors.code == '11000' && errors.errmsg.indexOf('username') > 0) {
parsed.username = { message:'This username already exists!' };
}
else {
parsed.unhandled = JSON.stringify(errors);
}
return parsed;
}
util.isLoggedin = function(req, res, next){
if(req.isAuthenticated()){
next();
}
else {
req.flash('errors', {login:'Please login first'});
res.redirect('/login');
}
}
util.noPermission = function(ctx){
ctx.request.flash('errors', {login:"You don't have permission"});
ctx.request.logout();
ctx.request.redirect('/login');
}
module.exports = util;
\ No newline at end of file
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<nav aria-label="breadcrumb">
<ol class="breadcrumb p-1 pl-2 pr-2">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/api/page">Page</a></li>
<li class="breadcrumb-item"><a href="/api/book/<%= book._id %>"><%= book.title %></a></li>
<li class="breadcrumb-item active" aria-current="page">Edit Post</li>
</ol>
</nav>
<form action="/api/book/<%= book._id %>?_method=patch" method="patch">
<div class="form-group">
<label for="title">Title</label>
<input type="text" id="title" name="title" value="<%= book.title %>" class="form-control">
</div>
<div class="form-group">
<label for="body">Body</label>
<textarea id="body" name="body" rows="5" class="form-control"><%= book.contents %></textarea>
</div>
<div>
<a class="btn btn-primary" href="/api/book/<%= book._id %>">Back</a>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
<!-- views/books/index.ejs -->
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<h2 class="mb-3">Board</h2>
<table class="board-table table table-sm border-bottom">
<thead class="thead-light">
<tr>
<th scope="col">Title</th>
<th scope="col" class="date">Date</th>
</tr>
</thead>
<tbody>
<% if(books == null || books.length == 0){ %>
<tr>
<td colspan=2> There is no data to show :( </td>
</tr>
<% } %>
<% books.forEach(function(book) { %>
<tr>
<td>
<a href="/api/book/<%= book._id %>"><div class="ellipsis"><%= book.title %></div></a>
</td>
<td class="date">
<span data-date="<%= book.createDate %>"></span> <!-- 1 -->
</td>
</tr>
<% }) %>
</tbody>
</table>
<div>
<a class="btn btn-primary" href="/api/book/new">New</a>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<nav aria-label="breadcrumb"> <!-- 1 -->
<ol class="breadcrumb p-1 pl-2 pr-2">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/api/page">Page</a></li>
<li class="breadcrumb-item active" aria-current="page">New Book</li>
</ol>
</nav>
<form action="/api/book" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" id="title" name="title" value="" class="form-control">
</div>
<div class="form-group">
<label for="body">Body</label>
<textarea id="body" name="body" rows="5" class="form-control"></textarea>
</div>
<div>
<a class="btn btn-primary" href="/api/book">Back</a>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<nav aria-label="breadcrumb">
<ol class="breadcrumb p-1 pl-2 pr-2">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/api/page">Page</a></li>
<li class="breadcrumb-item active" aria-current="page"><%= book.title %></li>
</ol>
</nav>
<div class="card">
<h5 class="card-header p-2"><%= book.title %></h5>
<div class="row"> <!-- 1 -->
<div class="col-md-7 col-lg-8 col-xl-9 order-sm-2 order-md-1"> <!-- 1 -->
<div class="post-body p-2"><%= book.contents %></div>
</div>
<div class="col-md-5 col-lg-4 col-xl-3 order-sm-1 order-md-2"> <!-- 1 -->
<div class="post-info card m-2 p-2">
<div><span>Created</span> : <span data-date-time="<%= book.createDate %>"></span></div> <!-- 2 -->
<% if(book.createDate) { %>
<div><span>Updated</span> : <span data-date-time="<%= book.updateDate %>"></span></div> <!-- 2 -->
<% } %>
</div>
</div>
</div>
</div>
<div class="mt-3">
<a class="btn btn-primary" href="/api/book">Back</a>
<a class="btn btn-primary" href="/api/book/<%= book._id %>/edit">Edit</a>
<form action="/api/book/<%= book._id %>?_method=delete" method="post" class="d-inline">
<a class="btn btn-primary" href="javascript:void(0)" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
</form>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<h2 class="mb-3">About</h2>
<P>이 사이트는 Like Project 임시 페이지 입니다. </p>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Login Example</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="../stylesheets/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="wrapper">
<form action="/auth/login" method="post" name="Login_Form" class="form-signin">
<h3 class="form-signin-heading">Welcome! Please Sign In</h3>
<input type="text" class="form-control" name="email" placeholder="Email Address" required="" autofocus="" />
<input type="password" class="form-control" name="password" placeholder="Password" required=""/>
<button class="btn btn-lg btn-primary btn-block" name="Submit" value="Login" type="Submit">Login</button>
</form>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<div class="jumbotron">
<h1>My Website</h1>
<P>제 웹사이트를 방문해 주셔서 감사합니다!</p>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!-- views/partials/head.ejs -->
<meta name="viewport" content="width=device-width,initial-scale=1">
<!-- jquery & bootstrap -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- web font --> <!-- 1 -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet">
<!-- my css -->
<script src="/src/public/js/script.js"></script>
<title>My Website</title>
\ No newline at end of file
<nav class="navbar navbar-expand-sm navbar-light bg-light mb-3">
<div class="container">
<div class="navbar-brand"></a>Like</div>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav">
<li class="nav-item"><a href="/" class="nav-link">Home</a></li>
<li class="nav-item"><a href="/about" class="nav-link">About</a></li>
<li class="nav-item"><a href="/book" class="nav-link">Book</a></li>
<li class="nav-item"><a href="/page" class="nav-link">Page</a></li>
</ul>
<ul class="navbar-nav ml-auto">
<li class="nav-item"><a href="/auth/new" class="nav-link">Sign Up</a></li>
<li class="nav-item"><a href="/auth/login" class="nav-link">Login</a></li>
</ul>
</div>
</div>
</nav>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<nav aria-label="breadcrumb">
<ol class="breadcrumb p-1 pl-2 pr-2">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/book">Book</a></li>
<li class="breadcrumb-item"><a href="/page/<%= page._id %>"><%= page.title %></a></li>
<li class="breadcrumb-item active" aria-current="page">Edit Post</li>
</ol>
</nav>
<form action="/page<%= page._id %>?_method=put" method="patch">
<div class="form-group">
<label for="title">Title</label>
<input type="text" id="title" name="title" value="<%= page.title %>" class="form-control">
</div>
<div class="form-group">
<label for="body">Body</label>
<textarea id="body" name="body" rows="5" class="form-control"><%= page.contents %></textarea>
</div>
<div>
<a class="btn btn-primary" href="/page/<%= page._id %>">Back</a>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
<!-- views/posts/index.ejs -->
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<h2 class="mb-3">Board</h2>
<table class="board-table table table-sm border-bottom">
<thead class="thead-light">
<tr>
<th scope="col">Title</th>
<th scope="col" class="date">Date</th>
</tr>
</thead>
<tbody>
<% if(page == null || page.length == 0){ %>
<tr>
<td colspan=2> There is no data to show :( </td>
</tr>
<% } %>
<% page.forEach(function(page) { %>
<tr>
<td>
<a href="/page/<%= page._id %>"><div class="ellipsis"><%= page.title %></div></a>
</td>
<td class="date">
<span data-date="<%= page.createDate %>"></span> <!-- 1 -->
</td>
</tr>
<% }) %>
</tbody>
</table>
<div>
<a class="btn btn-primary" href="/page/new">New</a>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<nav aria-label="breadcrumb"> <!-- 1 -->
<ol class="breadcrumb p-1 pl-2 pr-2">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/page">Board</a></li>
<li class="breadcrumb-item active" aria-current="page">New Post</li>
</ol>
</nav>
<form action="/page" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" id="title" name="title" value="" class="form-control">
</div>
<div class="form-group">
<label for="body">Body</label>
<textarea id="body" name="body" rows="5" class="form-control"></textarea>
</div>
<div>
<a class="btn btn-primary" href="/page">Back</a>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<nav aria-label="breadcrumb">
<ol class="breadcrumb p-1 pl-2 pr-2">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/page">Page</a></li>
<li class="breadcrumb-item active" aria-current="page"><%= page.title %></li>
</ol>
</nav>
<div class="card">
<h5 class="card-header p-2"><%= page.title %></h5>
<div class="row"> <!-- 1 -->
<div class="col-md-7 col-lg-8 col-xl-9 order-sm-2 order-md-1"> <!-- 1 -->
<div class="post-body p-2"><%= page.contents %></div>
</div>
<div class="col-md-5 col-lg-4 col-xl-3 order-sm-1 order-md-2"> <!-- 1 -->
<div class="post-info card m-2 p-2">
<div><span>Created</span> : <span data-date-time="<%= page.createDate %>"></span></div> <!-- 2 -->
<% if(page.updateDate) { %>
<div><span>Updated</span> : <span data-date-time="<%= page.updateDate %>"></span></div> <!-- 2 -->
<% } %>
</div>
</div>
</div>
</div>
<div class="mt-3">
<a class="btn btn-primary" href="/page">Back</a>
<a class="btn btn-primary" href="/page/<%= page._id %>/edit">Edit</a>
<form action="/page/<%= page._id %>/_method=delete" method="post" class="d-inline">
<a class="btn btn-primary" href="#" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
</form>
</div>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<h3 class="mb-3">Edit User</h3>
<form action="/auth/users/<%= user.username %>?_method=put" method="post">
<div class="form-group row">
<label for="currentPassword" class="col-sm-3 col-form-label">Current Password*</label>
<div class="col-sm-9 col-sm-offset-3">
<input type="password" id="currentPassword" name="currentPassword" value="" class="form-control">
</div>
</div>
<hr></hr>
<div class="form-group row">
<label for="username" class="col-sm-3 col-form-label">Username*</label>
<div class="col-sm-9">
<input type="text" id="username" name="username" value="<%= user.nickname %>" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="name" class="col-sm-3 col-form-label">Name*</label>
<div class="col-sm-9">
<input type="text" id="name" name="name" value="<%= user.email %>" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="email" class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="text" id="email" name="email" value="<%= user.email %>" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="newPassword" class="col-sm-3 col-form-label">New Password</label>
<div class="col-sm-9 col-sm-offset-3">
<input type="password" id="newPassword" name="newPassword" value="" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="passwordConfirmation" class="col-sm-3 col-form-label">Password Confirmation</label>
<div class="col-sm-9 col-sm-offset-3">
<input type="password" id="passwordConfirmation" name="passwordConfirmation" value="" class="form-control">
</div>
</div>
<p>
<small>*Required</small>
</p>
<div class="buttons">
<a class="btn btn-primary" href="/auth/users/<%= user.username %>">Back</a>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
File mode changed
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<h3 class="contentBoxTop mb-3">New User</h3>
<form action="/auth/signin" method="post">
<div class="form-group row">
<label for="nickname" class="col-sm-3 col-form-label">Username*</label>
<div class="col-sm-9">
<input type="text" id="nickname" name="nickname" value="" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="email" class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="text" id="email" name="email" value="" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="password" class="col-sm-3 col-form-label">Password*</label>
<div class="col-sm-9">
<input type="password" id="password" name="password" value="" class="form-control">
</div>
</div>
<div class="form-group row">
<label for="passwordConfirmation" class="col-sm-3 col-form-label">Password Confirmation*</label>
<div class="col-sm-9 col-sm-offset-3">
<input type="password" id="passwordConfirmation" name="passwordConfirmation" value="" class="form-control">
</div>
</div>
<p>
<small>*Required</small>
</p>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<%- include('../partials/head') %>
</head>
<body>
<%- include('../partials/nav') %>
<div class="container mb-3">
<h3 class="contentBoxTop">usefname</h3>
<form class="user-form" action="/users" method="post">
<fieldset disabled>
<div class="form-group row">
<label for="email" class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input class="form-control" type="text" id="email" name="email" value="<%= 9 %>">
</div>
</div>
</fieldset>
</form>
<div>
<a class="btn btn-primary" href="/auth/users">Back</a>
<a class="btn btn-primary" href="/auth/users/<%= user.email %>/edit">Edit</a>
<form action="/users/<%= user.email %>?_method=delete" method="post" class="d-inline">
<a class="btn btn-primary" href="javascript:void(0)" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
</form>
</div>
</div>
</body>
</html>
\ No newline at end of file