Showing
26 changed files
with
1831 additions
and
0 deletions
.eslintrc.js
0 → 100644
1 | +module.exports = { | ||
2 | + "extends": "standard", | ||
3 | + "rules": { | ||
4 | + "indent": [ | ||
5 | + "error", | ||
6 | + 4 | ||
7 | + ], | ||
8 | + "semi": [ | ||
9 | + "error", | ||
10 | + "always" | ||
11 | + ], | ||
12 | + "no-trailing-spaces": 0, | ||
13 | + "keyword-spacing": 0, | ||
14 | + "no-unused-vars": 1, | ||
15 | + "no-multiple-empty-lines": 0, | ||
16 | + "space-before-function-paren": 0, | ||
17 | + "eol-last": 0 | ||
18 | + } | ||
19 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
.gitignore
0 → 100644
.vscode/launch.json
0 → 100644
1 | +{ | ||
2 | + // Use IntelliSense to learn about possible attributes. | ||
3 | + // Hover to view descriptions of existing attributes. | ||
4 | + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||
5 | + "version": "0.2.0", | ||
6 | + "configurations": [ | ||
7 | + { | ||
8 | + "type": "pwa-node", | ||
9 | + "request": "launch", | ||
10 | + "name": "Launch Program", | ||
11 | + "skipFiles": [ | ||
12 | + "<node_internals>/**" | ||
13 | + ], | ||
14 | + "program": "${workspaceFolder}/src/api/book/book.ctrl.js", | ||
15 | + "outFiles": [ | ||
16 | + "${workspaceFolder}/**/*.js" | ||
17 | + ] | ||
18 | + } | ||
19 | + ] | ||
20 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
cert.pem
0 → 100644
1 | +-----BEGIN CERTIFICATE----- | ||
2 | +MIIDmTCCAoECFA0G8CsoOzEJaSus1d0/oC6+WzOcMA0GCSqGSIb3DQEBCwUAMIGI | ||
3 | +MQswCQYDVQQGEwJLcjEOMAwGA1UECAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1 | ||
4 | +MQswCQYDVQQKDAJUdzERMA8GA1UECwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2Uu | ||
5 | +Y29tMSMwIQYJKoZIhvcNAQkBFhR5b29iaW5wYXJrQGtodS5hYy5rcjAeFw0yMTEx | ||
6 | +MTAwNTAzNDhaFw0zMTExMDgwNTAzNDhaMIGIMQswCQYDVQQGEwJLcjEOMAwGA1UE | ||
7 | +CAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1MQswCQYDVQQKDAJUdzERMA8GA1UE | ||
8 | +CwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2UuY29tMSMwIQYJKoZIhvcNAQkBFhR5 | ||
9 | +b29iaW5wYXJrQGtodS5hYy5rcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC | ||
10 | +ggEBANHhAjf8HAfdy0v15teX1ENK3eaLF14GiguOc5/KmaAYYj1nIl7LGdjiumB6 | ||
11 | +VJT0elRIAx1DCGoPDN8d5Dhfrpftblv7lPFUOVKpI6Rjcl6EVRCOm3I6TehXazg9 | ||
12 | +ACdHRA/8uxLG8MFKsmAVh1wQXGnBVoobgZyNDq3yU4d0y6paCvHCVVBTIB/Mdikp | ||
13 | +vLiDRfrB9m6L5YC6Aux6Dn2nfX+GTUvxXzks4RoDtJAiklnfczgFDVc8oN6ZMplq | ||
14 | +A4TPF67TLsY071x2XQIpUruWleWo4MdZPIQr/ex2WFvbJT8+Y6wsEfD2AgCxBBuT | ||
15 | +hVYhmsFaAf0fYv+ftQwd60oBdoMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPIuB | ||
16 | +rauwsJoEQvMH6G4b7AXyyKytfmOkK3e8RSvNeeu/IUoAPX1SuaLcGmVTF5q2tf8z | ||
17 | +a3qwCqJxuChHWfL5C0F/iq24OYEPEFQAKqWqSJXk8Y5icuu8ZyPEaEjBJqCxoWdn | ||
18 | +bfc4OHwfSxvpg3AbaCuB9DsjF0zUmYZYSAPSduMOrDUo2fC2AI3A0UgjJex0pD0q | ||
19 | +ricy3QCWIzVPdWYThthWwuMnND7oiqhOrweZlH2FiSodkvbyFkENQFRjvDmWoM7J | ||
20 | +93ryfbcDOJfnBEA07S/3ljwFBwzNs5pw4h8LzRRNHg1tXk1Eu4kecGHmiW5bej4H | ||
21 | +l4/nnfqOSyRtOoLaAQ== | ||
22 | +-----END CERTIFICATE----- |
key.pem
0 → 100644
1 | +RSA Private-Key: (2048 bit, 2 primes) | ||
2 | +modulus: | ||
3 | + 00:d1:e1:02:37:fc:1c:07:dd:cb:4b:f5:e6:d7:97: | ||
4 | + d4:43:4a:dd:e6:8b:17:5e:06:8a:0b:8e:73:9f:ca: | ||
5 | + 99:a0:18:62:3d:67:22:5e:cb:19:d8:e2:ba:60:7a: | ||
6 | + 54:94:f4:7a:54:48:03:1d:43:08:6a:0f:0c:df:1d: | ||
7 | + e4:38:5f:ae:97:ed:6e:5b:fb:94:f1:54:39:52:a9: | ||
8 | + 23:a4:63:72:5e:84:55:10:8e:9b:72:3a:4d:e8:57: | ||
9 | + 6b:38:3d:00:27:47:44:0f:fc:bb:12:c6:f0:c1:4a: | ||
10 | + b2:60:15:87:5c:10:5c:69:c1:56:8a:1b:81:9c:8d: | ||
11 | + 0e:ad:f2:53:87:74:cb:aa:5a:0a:f1:c2:55:50:53: | ||
12 | + 20:1f:cc:76:29:29:bc:b8:83:45:fa:c1:f6:6e:8b: | ||
13 | + e5:80:ba:02:ec:7a:0e:7d:a7:7d:7f:86:4d:4b:f1: | ||
14 | + 5f:39:2c:e1:1a:03:b4:90:22:92:59:df:73:38:05: | ||
15 | + 0d:57:3c:a0:de:99:32:99:6a:03:84:cf:17:ae:d3: | ||
16 | + 2e:c6:34:ef:5c:76:5d:02:29:52:bb:96:95:e5:a8: | ||
17 | + e0:c7:59:3c:84:2b:fd:ec:76:58:5b:db:25:3f:3e: | ||
18 | + 63:ac:2c:11:f0:f6:02:00:b1:04:1b:93:85:56:21: | ||
19 | + 9a:c1:5a:01:fd:1f:62:ff:9f:b5:0c:1d:eb:4a:01: | ||
20 | + 76:83 | ||
21 | +publicExponent: 65537 (0x10001) | ||
22 | +privateExponent: | ||
23 | + 58:e9:ad:fa:f1:bf:1e:46:03:fe:26:2a:a9:63:14: | ||
24 | + f5:7d:1e:0c:b1:18:31:29:2c:0a:41:4b:12:82:ce: | ||
25 | + 1a:58:ba:25:b1:2f:8a:61:18:8e:1d:5f:3f:c8:13: | ||
26 | + 55:17:4d:4b:af:46:42:7b:47:71:46:f6:f8:fe:bc: | ||
27 | + d4:75:14:8e:20:74:04:5b:cc:79:80:68:d8:6f:f7: | ||
28 | + 3d:89:33:c6:7e:e1:5a:a6:4f:8c:50:ce:f8:83:30: | ||
29 | + 55:1e:e2:95:c1:47:40:4e:9d:22:13:4d:a3:55:75: | ||
30 | + c3:e6:da:f5:51:a9:14:d4:67:49:12:e6:11:e0:60: | ||
31 | + 3b:a8:d1:62:2d:44:aa:e1:bd:db:44:de:61:aa:41: | ||
32 | + a0:24:92:e7:2f:ec:59:34:7a:13:d5:5e:4e:b8:14: | ||
33 | + 66:26:2f:31:42:1b:61:46:ef:a6:c5:31:9c:65:f6: | ||
34 | + 35:a8:76:ef:fd:12:d1:1f:7d:cc:62:34:5b:42:47: | ||
35 | + fa:33:58:46:58:80:23:63:48:36:70:4b:e9:a4:88: | ||
36 | + 81:c2:33:d9:6a:49:a8:b8:ce:7f:ea:09:82:6b:78: | ||
37 | + ac:4f:59:9d:d0:37:59:38:03:14:38:94:c0:2f:23: | ||
38 | + de:ab:c4:90:2e:9c:95:3c:e0:f0:8b:d2:16:40:7f: | ||
39 | + 01:39:5a:fa:c7:68:09:ab:60:b0:f0:b9:3b:1b:08: | ||
40 | + 21 | ||
41 | +prime1: | ||
42 | + 00:f4:8c:0f:79:cc:a7:df:76:72:7a:f9:05:02:47: | ||
43 | + 95:e7:7b:ad:9f:ae:45:ac:f1:81:d1:5c:eb:38:c5: | ||
44 | + fc:90:ce:79:0a:9c:c2:bd:4f:08:ef:3a:46:e9:4d: | ||
45 | + 22:29:93:50:3d:54:98:a8:74:ca:f5:c7:4b:60:7d: | ||
46 | + d3:b7:c8:ca:f3:d6:14:8b:45:9f:04:7f:71:03:3f: | ||
47 | + 30:f3:2d:fb:bd:83:81:22:d6:9a:3d:cd:f2:8e:d5: | ||
48 | + 0a:6e:17:a4:2c:62:46:da:4a:f6:d9:98:cf:1d:67: | ||
49 | + 72:45:dd:70:4f:0c:69:11:9c:a0:25:26:25:a4:59: | ||
50 | + b3:ea:6e:39:7e:4c:a6:b1:cf | ||
51 | +prime2: | ||
52 | + 00:db:b5:4d:6a:7b:ce:a1:16:2b:bd:56:b2:3f:fb: | ||
53 | + 43:dd:5e:5e:b5:f1:86:eb:ad:1b:73:2d:f4:96:52: | ||
54 | + 8d:4c:ae:34:3d:d6:8a:1d:07:fd:8b:7c:0b:66:b3: | ||
55 | + 49:72:37:f8:f1:f9:7d:d8:b0:c5:12:c0:66:f3:99: | ||
56 | + 10:e5:71:a8:22:47:9b:d6:bf:5f:05:91:d5:c7:f0: | ||
57 | + 2a:48:3c:a4:ae:00:5f:09:70:c3:a9:48:1d:22:6f: | ||
58 | + d5:94:83:52:cf:2d:d9:cf:1b:80:f2:4e:2a:18:3c: | ||
59 | + 36:e7:6d:57:01:e5:60:8f:52:e6:3a:ec:dc:94:ec: | ||
60 | + a1:3b:07:f3:e5:72:e5:61:0d | ||
61 | +exponent1: | ||
62 | + 00:e8:f9:d6:74:8f:49:0f:57:64:d1:4b:14:3e:8b: | ||
63 | + bc:80:80:0f:75:25:2e:34:09:11:48:48:61:c0:00: | ||
64 | + bf:11:a5:e3:22:fd:1d:7a:05:25:d9:e3:87:53:14: | ||
65 | + ad:0b:36:d1:26:dc:c5:63:17:81:94:8d:7d:7e:3b: | ||
66 | + e1:cc:21:7b:58:ba:07:70:77:af:7b:35:7e:91:3d: | ||
67 | + 4e:81:1e:b9:ca:5e:d2:54:42:67:47:a2:41:07:5a: | ||
68 | + 67:49:63:34:81:24:4f:a3:ff:ef:14:76:c4:3a:9b: | ||
69 | + 26:fe:f0:6b:e2:a3:4c:25:ff:35:82:ae:c9:05:be: | ||
70 | + 7f:ed:43:7d:7a:99:c3:e5:79 | ||
71 | +exponent2: | ||
72 | + 00:b7:52:28:dd:4f:9e:92:84:68:4c:9c:79:30:af: | ||
73 | + 9b:e9:aa:a3:46:16:d8:67:ef:51:b7:22:42:31:e7: | ||
74 | + 81:a4:d8:ba:18:5a:d9:74:ed:c4:dd:cc:cb:ca:8e: | ||
75 | + 90:1a:f0:9f:14:70:03:54:79:f2:85:f9:ea:2d:19: | ||
76 | + ab:a2:76:da:3e:78:17:8c:f0:b2:fd:77:b8:b4:12: | ||
77 | + 2d:85:86:ac:35:cf:73:7c:f2:0d:20:43:5e:a3:ec: | ||
78 | + 42:7e:9f:b0:c9:d3:cd:28:65:1f:8b:8e:32:cb:73: | ||
79 | + fa:af:d1:68:c6:d9:38:5f:7e:61:42:0b:7e:e5:f8: | ||
80 | + 27:73:94:e8:29:ac:5b:be:45 | ||
81 | +coefficient: | ||
82 | + 19:e9:84:ba:58:9b:8f:dc:52:4b:03:3f:9b:65:cc: | ||
83 | + d7:6a:04:9a:2c:66:40:2d:cf:2e:90:32:52:44:f6: | ||
84 | + 21:74:65:dc:6a:27:8d:23:79:09:ea:53:45:39:e4: | ||
85 | + 40:e7:d2:d0:1c:aa:1a:68:fe:56:69:2b:3b:55:20: | ||
86 | + ff:0b:84:b0:c4:af:ed:33:dd:c4:fe:5c:10:5d:b9: | ||
87 | + 5b:6d:b2:bd:2f:e9:03:8f:29:5e:38:17:a3:2c:14: | ||
88 | + 6c:08:cb:cb:10:5c:9e:c6:cb:c4:9f:99:6e:76:96: | ||
89 | + 2a:0a:19:cf:33:f3:d0:ba:b0:d6:77:0d:71:1f:3f: | ||
90 | + 5c:95:ff:9e:61:ce:ab:49 | ||
91 | +-----BEGIN RSA PRIVATE KEY----- | ||
92 | +MIIEpAIBAAKCAQEA0eECN/wcB93LS/Xm15fUQ0rd5osXXgaKC45zn8qZoBhiPWci | ||
93 | +XssZ2OK6YHpUlPR6VEgDHUMIag8M3x3kOF+ul+1uW/uU8VQ5UqkjpGNyXoRVEI6b | ||
94 | +cjpN6FdrOD0AJ0dED/y7EsbwwUqyYBWHXBBcacFWihuBnI0OrfJTh3TLqloK8cJV | ||
95 | +UFMgH8x2KSm8uINF+sH2bovlgLoC7HoOfad9f4ZNS/FfOSzhGgO0kCKSWd9zOAUN | ||
96 | +Vzyg3pkymWoDhM8XrtMuxjTvXHZdAilSu5aV5ajgx1k8hCv97HZYW9slPz5jrCwR | ||
97 | +8PYCALEEG5OFViGawVoB/R9i/5+1DB3rSgF2gwIDAQABAoIBAFjprfrxvx5GA/4m | ||
98 | +KqljFPV9HgyxGDEpLApBSxKCzhpYuiWxL4phGI4dXz/IE1UXTUuvRkJ7R3FG9vj+ | ||
99 | +vNR1FI4gdARbzHmAaNhv9z2JM8Z+4VqmT4xQzviDMFUe4pXBR0BOnSITTaNVdcPm | ||
100 | +2vVRqRTUZ0kS5hHgYDuo0WItRKrhvdtE3mGqQaAkkucv7Fk0ehPVXk64FGYmLzFC | ||
101 | +G2FG76bFMZxl9jWodu/9EtEffcxiNFtCR/ozWEZYgCNjSDZwS+mkiIHCM9lqSai4 | ||
102 | +zn/qCYJreKxPWZ3QN1k4AxQ4lMAvI96rxJAunJU84PCL0hZAfwE5WvrHaAmrYLDw | ||
103 | +uTsbCCECgYEA9IwPecyn33ZyevkFAkeV53utn65FrPGB0VzrOMX8kM55CpzCvU8I | ||
104 | +7zpG6U0iKZNQPVSYqHTK9cdLYH3Tt8jK89YUi0WfBH9xAz8w8y37vYOBItaaPc3y | ||
105 | +jtUKbhekLGJG2kr22ZjPHWdyRd1wTwxpEZygJSYlpFmz6m45fkymsc8CgYEA27VN | ||
106 | +anvOoRYrvVayP/tD3V5etfGG660bcy30llKNTK40PdaKHQf9i3wLZrNJcjf48fl9 | ||
107 | +2LDFEsBm85kQ5XGoIkeb1r9fBZHVx/AqSDykrgBfCXDDqUgdIm/VlINSzy3ZzxuA | ||
108 | +8k4qGDw2521XAeVgj1LmOuzclOyhOwfz5XLlYQ0CgYEA6PnWdI9JD1dk0UsUPou8 | ||
109 | +gIAPdSUuNAkRSEhhwAC/EaXjIv0degUl2eOHUxStCzbRJtzFYxeBlI19fjvhzCF7 | ||
110 | +WLoHcHevezV+kT1OgR65yl7SVEJnR6JBB1pnSWM0gSRPo//vFHbEOpsm/vBr4qNM | ||
111 | +Jf81gq7JBb5/7UN9epnD5XkCgYEAt1Io3U+ekoRoTJx5MK+b6aqjRhbYZ+9RtyJC | ||
112 | +MeeBpNi6GFrZdO3E3czLyo6QGvCfFHADVHnyhfnqLRmronbaPngXjPCy/Xe4tBIt | ||
113 | +hYasNc9zfPINIENeo+xCfp+wydPNKGUfi44yy3P6r9Foxtk4X35hQgt+5fgnc5To | ||
114 | +KaxbvkUCgYAZ6YS6WJuP3FJLAz+bZczXagSaLGZALc8ukDJSRPYhdGXcaieNI3kJ | ||
115 | +6lNFOeRA59LQHKoaaP5WaSs7VSD/C4SwxK/tM93E/lwQXblbbbK9L+kDjyleOBej | ||
116 | +LBRsCMvLEFyexsvEn5ludpYqChnPM/PQurDWdw1xHz9clf+eYc6rSQ== | ||
117 | +-----END RSA PRIVATE KEY----- |
package-lock.json
0 → 100644
This diff could not be displayed because it is too large.
package.json
0 → 100644
1 | +{ | ||
2 | + "name": "likeback", | ||
3 | + "version": "1.0.0", | ||
4 | + "description": "", | ||
5 | + "main": "index.js", | ||
6 | + "scripts": { | ||
7 | + "test": "echo \"Error: no test specified\" && exit 1", | ||
8 | + "start": "node src", | ||
9 | + "start:dev": "nodemon --watch src/ src/index.js" | ||
10 | + }, | ||
11 | + "author": "", | ||
12 | + "license": "ISC", | ||
13 | + "dependencies": { | ||
14 | + "@hapi/joi": "^17.1.1", | ||
15 | + "@koa/router": "^10.1.1", | ||
16 | + "bcrypt": "^5.0.1", | ||
17 | + "crypto": "^1.0.1", | ||
18 | + "dotenv": "^10.0.0", | ||
19 | + "express": "^4.17.1", | ||
20 | + "firebase": "^9.6.0", | ||
21 | + "http2": "^3.3.7", | ||
22 | + "jsonwebtoken": "^8.5.1", | ||
23 | + "koa": "^2.13.4", | ||
24 | + "koa-body": "^4.2.0", | ||
25 | + "koa-bodyparser": "^4.3.0", | ||
26 | + "koa-router": "^10.1.1", | ||
27 | + "koa-send": "^5.0.1", | ||
28 | + "mongoose": "^6.0.12", | ||
29 | + "nodemailer": "^6.7.1", | ||
30 | + "passport": "^0.5.0", | ||
31 | + "passport-google-oauth": "^2.0.0", | ||
32 | + "spdy": "^4.0.2" | ||
33 | + }, | ||
34 | + "devDependencies": { | ||
35 | + "eslint": "^8.2.0" | ||
36 | + } | ||
37 | +} |
server.crt
0 → 100644
1 | +-----BEGIN CERTIFICATE----- | ||
2 | +MIIDmTCCAoECFA0G8CsoOzEJaSus1d0/oC6+WzOcMA0GCSqGSIb3DQEBCwUAMIGI | ||
3 | +MQswCQYDVQQGEwJLcjEOMAwGA1UECAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1 | ||
4 | +MQswCQYDVQQKDAJUdzERMA8GA1UECwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2Uu | ||
5 | +Y29tMSMwIQYJKoZIhvcNAQkBFhR5b29iaW5wYXJrQGtodS5hYy5rcjAeFw0yMTEx | ||
6 | +MTAwNTAzNDhaFw0zMTExMDgwNTAzNDhaMIGIMQswCQYDVQQGEwJLcjEOMAwGA1UE | ||
7 | +CAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1MQswCQYDVQQKDAJUdzERMA8GA1UE | ||
8 | +CwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2UuY29tMSMwIQYJKoZIhvcNAQkBFhR5 | ||
9 | +b29iaW5wYXJrQGtodS5hYy5rcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC | ||
10 | +ggEBANHhAjf8HAfdy0v15teX1ENK3eaLF14GiguOc5/KmaAYYj1nIl7LGdjiumB6 | ||
11 | +VJT0elRIAx1DCGoPDN8d5Dhfrpftblv7lPFUOVKpI6Rjcl6EVRCOm3I6TehXazg9 | ||
12 | +ACdHRA/8uxLG8MFKsmAVh1wQXGnBVoobgZyNDq3yU4d0y6paCvHCVVBTIB/Mdikp | ||
13 | +vLiDRfrB9m6L5YC6Aux6Dn2nfX+GTUvxXzks4RoDtJAiklnfczgFDVc8oN6ZMplq | ||
14 | +A4TPF67TLsY071x2XQIpUruWleWo4MdZPIQr/ex2WFvbJT8+Y6wsEfD2AgCxBBuT | ||
15 | +hVYhmsFaAf0fYv+ftQwd60oBdoMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPIuB | ||
16 | +rauwsJoEQvMH6G4b7AXyyKytfmOkK3e8RSvNeeu/IUoAPX1SuaLcGmVTF5q2tf8z | ||
17 | +a3qwCqJxuChHWfL5C0F/iq24OYEPEFQAKqWqSJXk8Y5icuu8ZyPEaEjBJqCxoWdn | ||
18 | +bfc4OHwfSxvpg3AbaCuB9DsjF0zUmYZYSAPSduMOrDUo2fC2AI3A0UgjJex0pD0q | ||
19 | +ricy3QCWIzVPdWYThthWwuMnND7oiqhOrweZlH2FiSodkvbyFkENQFRjvDmWoM7J | ||
20 | +93ryfbcDOJfnBEA07S/3ljwFBwzNs5pw4h8LzRRNHg1tXk1Eu4kecGHmiW5bej4H | ||
21 | +l4/nnfqOSyRtOoLaAQ== | ||
22 | +-----END CERTIFICATE----- |
server.csr
0 → 100644
1 | +-----BEGIN CERTIFICATE REQUEST----- | ||
2 | +MIICzjCCAbYCAQAwgYgxCzAJBgNVBAYTAktyMQ4wDAYDVQQIDAVTZW91bDERMA8G | ||
3 | +A1UEBwwIR3dhbmFrR3UxCzAJBgNVBAoMAlR3MREwDwYDVQQLDAhUd1Npc3RlcjER | ||
4 | +MA8GA1UEAwwIbGlrZS5jb20xIzAhBgkqhkiG9w0BCQEWFHlvb2JpbnBhcmtAa2h1 | ||
5 | +LmFjLmtyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0eECN/wcB93L | ||
6 | +S/Xm15fUQ0rd5osXXgaKC45zn8qZoBhiPWciXssZ2OK6YHpUlPR6VEgDHUMIag8M | ||
7 | +3x3kOF+ul+1uW/uU8VQ5UqkjpGNyXoRVEI6bcjpN6FdrOD0AJ0dED/y7EsbwwUqy | ||
8 | +YBWHXBBcacFWihuBnI0OrfJTh3TLqloK8cJVUFMgH8x2KSm8uINF+sH2bovlgLoC | ||
9 | +7HoOfad9f4ZNS/FfOSzhGgO0kCKSWd9zOAUNVzyg3pkymWoDhM8XrtMuxjTvXHZd | ||
10 | +AilSu5aV5ajgx1k8hCv97HZYW9slPz5jrCwR8PYCALEEG5OFViGawVoB/R9i/5+1 | ||
11 | +DB3rSgF2gwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBACC2EZvLB/YvSLHgDVoE | ||
12 | +QDefpbCLJ2Dm8/CeRrGPKpJK4ozGFNox026SM+UH0zU3V3kLqu41uN7Jgofc3XTU | ||
13 | +cpmTeMRmFgd8+csXwM1evuFJUNfcwQTxNDlbn9IOsdn7TXF5uhjt4+nAZ0SvRSGg | ||
14 | +59VsZEXUNnbevFN87ihd8AVjTGz0nuYLIxJ51s98ND32R0/UaofZqu4niH6FcKNR | ||
15 | +U9NlHPTL1/XPqC+qSBlPVlADeUEBobEXzFo4yzPlv4JLFWV0gVOGYLtoK5m+Q2WS | ||
16 | +xbhL+c+S8Dz87aJ2wlj8lDYbRsUqu+GCNjcOqAmSnZPkq1UoObzV01pXMtqL2jry | ||
17 | +ebw= | ||
18 | +-----END CERTIFICATE REQUEST----- |
server.key
0 → 100644
1 | +-----BEGIN RSA PRIVATE KEY----- | ||
2 | +MIIEpAIBAAKCAQEA0eECN/wcB93LS/Xm15fUQ0rd5osXXgaKC45zn8qZoBhiPWci | ||
3 | +XssZ2OK6YHpUlPR6VEgDHUMIag8M3x3kOF+ul+1uW/uU8VQ5UqkjpGNyXoRVEI6b | ||
4 | +cjpN6FdrOD0AJ0dED/y7EsbwwUqyYBWHXBBcacFWihuBnI0OrfJTh3TLqloK8cJV | ||
5 | +UFMgH8x2KSm8uINF+sH2bovlgLoC7HoOfad9f4ZNS/FfOSzhGgO0kCKSWd9zOAUN | ||
6 | +Vzyg3pkymWoDhM8XrtMuxjTvXHZdAilSu5aV5ajgx1k8hCv97HZYW9slPz5jrCwR | ||
7 | +8PYCALEEG5OFViGawVoB/R9i/5+1DB3rSgF2gwIDAQABAoIBAFjprfrxvx5GA/4m | ||
8 | +KqljFPV9HgyxGDEpLApBSxKCzhpYuiWxL4phGI4dXz/IE1UXTUuvRkJ7R3FG9vj+ | ||
9 | +vNR1FI4gdARbzHmAaNhv9z2JM8Z+4VqmT4xQzviDMFUe4pXBR0BOnSITTaNVdcPm | ||
10 | +2vVRqRTUZ0kS5hHgYDuo0WItRKrhvdtE3mGqQaAkkucv7Fk0ehPVXk64FGYmLzFC | ||
11 | +G2FG76bFMZxl9jWodu/9EtEffcxiNFtCR/ozWEZYgCNjSDZwS+mkiIHCM9lqSai4 | ||
12 | +zn/qCYJreKxPWZ3QN1k4AxQ4lMAvI96rxJAunJU84PCL0hZAfwE5WvrHaAmrYLDw | ||
13 | +uTsbCCECgYEA9IwPecyn33ZyevkFAkeV53utn65FrPGB0VzrOMX8kM55CpzCvU8I | ||
14 | +7zpG6U0iKZNQPVSYqHTK9cdLYH3Tt8jK89YUi0WfBH9xAz8w8y37vYOBItaaPc3y | ||
15 | +jtUKbhekLGJG2kr22ZjPHWdyRd1wTwxpEZygJSYlpFmz6m45fkymsc8CgYEA27VN | ||
16 | +anvOoRYrvVayP/tD3V5etfGG660bcy30llKNTK40PdaKHQf9i3wLZrNJcjf48fl9 | ||
17 | +2LDFEsBm85kQ5XGoIkeb1r9fBZHVx/AqSDykrgBfCXDDqUgdIm/VlINSzy3ZzxuA | ||
18 | +8k4qGDw2521XAeVgj1LmOuzclOyhOwfz5XLlYQ0CgYEA6PnWdI9JD1dk0UsUPou8 | ||
19 | +gIAPdSUuNAkRSEhhwAC/EaXjIv0degUl2eOHUxStCzbRJtzFYxeBlI19fjvhzCF7 | ||
20 | +WLoHcHevezV+kT1OgR65yl7SVEJnR6JBB1pnSWM0gSRPo//vFHbEOpsm/vBr4qNM | ||
21 | +Jf81gq7JBb5/7UN9epnD5XkCgYEAt1Io3U+ekoRoTJx5MK+b6aqjRhbYZ+9RtyJC | ||
22 | +MeeBpNi6GFrZdO3E3czLyo6QGvCfFHADVHnyhfnqLRmronbaPngXjPCy/Xe4tBIt | ||
23 | +hYasNc9zfPINIENeo+xCfp+wydPNKGUfi44yy3P6r9Foxtk4X35hQgt+5fgnc5To | ||
24 | +KaxbvkUCgYAZ6YS6WJuP3FJLAz+bZczXagSaLGZALc8ukDJSRPYhdGXcaieNI3kJ | ||
25 | +6lNFOeRA59LQHKoaaP5WaSs7VSD/C4SwxK/tM93E/lwQXblbbbK9L+kDjyleOBej | ||
26 | +LBRsCMvLEFyexsvEn5ludpYqChnPM/PQurDWdw1xHz9clf+eYc6rSQ== | ||
27 | +-----END RSA PRIVATE KEY----- |
server.key.origin
0 → 100644
1 | +-----BEGIN RSA PRIVATE KEY----- | ||
2 | +Proc-Type: 4,ENCRYPTED | ||
3 | +DEK-Info: DES-EDE3-CBC,25A9EC1BE53CDC74 | ||
4 | + | ||
5 | +FQR3tdxyJp2QHgJv+IqGVa3yAbOtR7J0AoLccoWmEMRN8Ch8Iso3RkKDpXo7Awa7 | ||
6 | +EjnsIqTHqJl8AyD9DlkBRNnFog0mfnJJ1rHUyU9fOL+I2/B8R6qYFjvDpnTiC6Cp | ||
7 | +9Dz+Wn2KdhgkkoufvLEBW/BiiD2ScB/zk1POPXAWEBI8wQYSPsdWrxw8PtNbExt+ | ||
8 | +9LApwYsDKpQnNAuYjiD/kZp9mz3qKO/kHS9R8nX8ZJq1c7D/SyN0in276T+OPk9C | ||
9 | +11Tcw86p+aoMVT2sU9CJ9N7rkFaOg1w1Hl27d4R6jvDDaYuvbsp41SKNJJbpnAQS | ||
10 | ++GtruJMjED8SOb4Sy4dRzZ6pZV/zPr/X7GcyANPC1RlxGjoWqLTuzruv4BSXf2Qk | ||
11 | +vLQF67FqpVBwIMY6GmzMrWeGfiK3i3WsqtMvCAPNPSO1d6EWzGNK5n68rBGk4fKF | ||
12 | +20gBWiab2f4osY4N7hPrDRRROVVlVFj9VUppQunyPYu5VEwAW+IQrb537QJp77ww | ||
13 | +ppAYoOjaiJHHPvnXP8JFCLSK1t8AeXl2GcrP5NEzCq8sMUXbClgd+gVynrqhN68I | ||
14 | +F7EOAYrvELapcURwu6Rnfxk9v8BTQoOt1hvcdLVcPah5+pkeGXy6JoHusDH+/3O7 | ||
15 | +fi92tTPB2astbdPottuJuCHeyNaGRlFO+f81iePT91389jBDNFUNacERUwlQIZzd | ||
16 | +d8MXwHFlf4kUxlu6PXl8JeAXKHXrL9q3HAzeOZu+sJBt8cscQ/FVMjx4svYPCndl | ||
17 | +WGgb7Be052e1R/dOclfTKC6C24/6ek/UsPRIFem5BzP8lLocSDEp8Z55j3pGgyt0 | ||
18 | +OAAuaVYwPVj56pXFoTWWModyux7YhBmqAl8Gguv53w5SyKviSPs0SoSWSQ3RaZig | ||
19 | +1f+rC1yBm2/kVV4Upbc2Jd5FGMjkUOPSbPKnk4yyZNEaIpuDkwjWdp9JU3DF2Zuh | ||
20 | +o+ZUkLZwmYYNFLB7ODwkekS4xE3M/YD4Dxn9D2VvZ7CUUP4FxqU3qPsdpzSgG9p9 | ||
21 | +4FBmvmBxl6nMRLaOKwWeyj8SOtmm3x+OUs+meHL0T417CDQqv+wy7F9ikmxvo8/H | ||
22 | +XdRaKLemziI9R4NLJvmoFVJbrAP2CDM2DiiuMPcWv3WHBVSPU2s0fnNG75tS4iHl | ||
23 | +ZD/gCvL8jDMRml/r4kbwogg7YK/Ac6mmf5WqWK+t4QwDg6YwsKt5MDq8rf/7W5Lf | ||
24 | +TemIi8uoriE75XpCoMTqNWbdVUolos4n09B1l5Xx14fiOo9HGrhz7CgEpalNidqM | ||
25 | +0X3OLeZm/wdoJ3rusPRv5r/giObMRvOc9qN3RJpKYcEK99xHLVAPV6V6DASWMnCs | ||
26 | +Iknz4cBOdpR+WDcEUUi9aFkRuc9mw/iI/JMY5MDZzbWod2hF7VZ2Yko6JTuW9Y8R | ||
27 | +Jk0HgoI0YZdrnD6b/EmLdJcsZIIg6H4wBg56KTuP/jxOGgvcD03tPnyCOGaXOdCH | ||
28 | +c1kKo8N55Q0oFfdrVlBriptZeiqdFZ52vhThDR0z1DIeVuOiDeALvYdEhzR8oTJC | ||
29 | +ZKtqaQsUQiMVn4ZHiKex+9+OWhkArXoPYcyGuaT7coM5rWiwwbqP89tgPMUaIbbo | ||
30 | +-----END RSA PRIVATE KEY----- |
src/api/auth/auth.ctrl.js
0 → 100644
1 | +const Joi = require('@hapi/joi'); | ||
2 | +const User = require('../../models/user'); | ||
3 | +const Book = require('../../models/book'); | ||
4 | +const Page = require('../../models/page'); | ||
5 | +const nodemailer = require('nodemailer'); | ||
6 | +const config = require('../../lib/config'); | ||
7 | +const { Mongoose } = require('mongoose'); | ||
8 | +const { exist, allow } = require('@hapi/joi'); | ||
9 | +const fs = require('fs'); | ||
10 | +exports.test = async (ctx) => { | ||
11 | + console.log('cookie'); | ||
12 | + ctx.cookies.set('second', 22222, { | ||
13 | + httpOnly: false | ||
14 | + }) | ||
15 | + ctx.body = {code: 200, message: 'success'} | ||
16 | +}; | ||
17 | + | ||
18 | +exports.signupLocal = async (ctx) => { | ||
19 | + const { email, password, address } = ctx.request.body; | ||
20 | + console.log(ctx.request.body); | ||
21 | + const schema = Joi.object().keys({ | ||
22 | + email: Joi.string().min(3).required(), | ||
23 | + password: Joi.string().required(), | ||
24 | + phone: Joi.string().allow(null, ''), | ||
25 | + nickname:Joi.string().allow(null, '') | ||
26 | + }); | ||
27 | + | ||
28 | + //검증 결과 | ||
29 | + try { | ||
30 | + const value = await schema.validateAsync(ctx.request.body); | ||
31 | + } catch (err) { | ||
32 | + console.log(err); | ||
33 | + ctx.status = 400; | ||
34 | + return; | ||
35 | + } | ||
36 | + | ||
37 | + try { | ||
38 | + // email 이미 존재하는지 확인 | ||
39 | + const exists = await User.findByEmail(email); | ||
40 | + if (exists) { | ||
41 | + ctx.status = 409; // Conflict | ||
42 | + return; | ||
43 | + } | ||
44 | + | ||
45 | + let account = null; | ||
46 | + try { | ||
47 | + account = await User.localRegister(ctx.request.body); | ||
48 | + } catch (e) { | ||
49 | + ctx.throw(500, e); | ||
50 | + } | ||
51 | + | ||
52 | + let token = null; | ||
53 | + try { | ||
54 | + token = await account.generateToken(); | ||
55 | + console.log('token ok'); | ||
56 | + } catch (e) { | ||
57 | + ctx.throw(500, e); | ||
58 | + } | ||
59 | + ctx.cookies.set('access_token', token, { maxAge: 1000 * 60 * 60 * 24 * 7 ,httpOnly: true,}); | ||
60 | + console.log('set cookie ok'); | ||
61 | + | ||
62 | + // 응답할 데이터에서 hashedPassword 필드 제거 | ||
63 | + ctx.status = 200; | ||
64 | + ctx.body = await account.serialize(); | ||
65 | + } catch (e) { | ||
66 | + ctx.throw(500, e); | ||
67 | + } | ||
68 | +}; | ||
69 | +exports.signinLocal = async (ctx) => { | ||
70 | + // 로그인 | ||
71 | + const { email, password } = ctx.request.body; | ||
72 | + | ||
73 | + //handle error | ||
74 | + if (!email || !password) { | ||
75 | + ctx.status = 401; //Unauthorized | ||
76 | + return; | ||
77 | + } | ||
78 | + try { | ||
79 | + const user = await User.findOne({ email: email }); | ||
80 | + //const user = await User.findByEmail(email); | ||
81 | + //계정없으면 에러처리 | ||
82 | + console.log(user); | ||
83 | + if (!user) { | ||
84 | + ctx.status = 401; | ||
85 | + return; | ||
86 | + } | ||
87 | + | ||
88 | + const valid = await user.checkPassword(password); | ||
89 | + if (!valid) { | ||
90 | + ctx.status = 401; | ||
91 | + return; | ||
92 | + } | ||
93 | + ctx.body = await user.serialize(); | ||
94 | + const token = user.generateToken(); | ||
95 | + ctx.cookies.set('access_token', token, { | ||
96 | + maxAge: 1000 * 60 * 60 * 24 * 7, // 7일 | ||
97 | + httpOnly: false, | ||
98 | + }); | ||
99 | + ctx.status = 200; | ||
100 | + console.log('토큰나옴'); | ||
101 | + } catch (e) { | ||
102 | + ctx.throw(500, e); | ||
103 | + } | ||
104 | +}; | ||
105 | + | ||
106 | + | ||
107 | +/* | ||
108 | +exports.localLogin = async (ctx) => { | ||
109 | + // 데이터 검증 | ||
110 | + const schema = Joi.object().keys({ | ||
111 | + email: Joi.string().email().required(), | ||
112 | + password: Joi.string().required() | ||
113 | + }); | ||
114 | + | ||
115 | + const result = Joi.validate(ctx.request.body, schema); | ||
116 | + | ||
117 | + if (result.error) { | ||
118 | + ctx.status = 400; // Bad Request | ||
119 | + return; | ||
120 | + } | ||
121 | + | ||
122 | + const { email, password } = ctx.request.body; | ||
123 | + | ||
124 | + let account = null; | ||
125 | + try { | ||
126 | + // 이메일로 계정 찾기 | ||
127 | + account = await User.findByEmail(email); | ||
128 | + } | ||
129 | + catch (e) { | ||
130 | + ctx.throw(500, e); | ||
131 | + } | ||
132 | + | ||
133 | + if (!account || !account.checkPassword(password)) { | ||
134 | + // 유저가 존재하지 않거나 || 비밀번호가 일치하지 않으면 | ||
135 | + ctx.status = 403; // Forbidden | ||
136 | + return; | ||
137 | + } | ||
138 | + | ||
139 | + let token = null; | ||
140 | + try { | ||
141 | + token = await account.generateToken(); | ||
142 | + } catch (e) { | ||
143 | + ctx.throw(500, e); | ||
144 | + } | ||
145 | + | ||
146 | + ctx.cookies.set('access_token', token, { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 }); | ||
147 | + ctx.body = account.email; | ||
148 | +};*/ | ||
149 | +exports.userlist = async (ctx) => { | ||
150 | + let user; | ||
151 | + | ||
152 | + try { | ||
153 | + user = await User.find() | ||
154 | + .sort({created: -1}) | ||
155 | + .exec(); | ||
156 | + } catch (e) { | ||
157 | + return ctx.throw(500, e); | ||
158 | + } | ||
159 | + | ||
160 | + ctx.body = user; | ||
161 | +} | ||
162 | + | ||
163 | +exports.exists = async (ctx) => { | ||
164 | + const { email } = ctx.request.body; | ||
165 | + | ||
166 | + try { | ||
167 | + const exists = await User.findByEmail(email); | ||
168 | + if (exists) { | ||
169 | + ctx.status = 409; | ||
170 | + return; | ||
171 | + } | ||
172 | + ctx.status = 200; | ||
173 | + } catch (e) { | ||
174 | + ctx.throw(500, e); | ||
175 | + } | ||
176 | +}; | ||
177 | + | ||
178 | +exports.checkPassword = async (ctx) => { | ||
179 | + const { email, password } = ctx.request.body; | ||
180 | + | ||
181 | + try { | ||
182 | + const user = await User.findOne({ email: email }); | ||
183 | + const valid = await user.checkPassword(password); | ||
184 | + if (valid) { | ||
185 | + ctx.status = 200; | ||
186 | + console.log("Check password success"); | ||
187 | + return; | ||
188 | + } else if(!valid){ | ||
189 | + ctx.status = 401; | ||
190 | + console.log("Check password fail"); | ||
191 | + return; | ||
192 | + } | ||
193 | + } catch (e) { | ||
194 | + ctx.throw(500, e); | ||
195 | + } | ||
196 | +}; | ||
197 | +//회원가입 | ||
198 | +exports.signup = async (ctx) => { | ||
199 | + const { email, password, phone, fcmToken } = ctx.request.body; | ||
200 | + const schema = Joi.object().keys({ | ||
201 | + email: Joi.string().min(3).required(), | ||
202 | + password: Joi.string().required().min(6), | ||
203 | + phone: Joi.string().allow(null, ''), | ||
204 | + fcmToken: Joi.string().allow(null, ''), | ||
205 | + nickname:Joi.string().allow(null, '') | ||
206 | + }); | ||
207 | + | ||
208 | + let value= null; | ||
209 | + try { | ||
210 | + value = await schema.validateAsync(ctx.request.body); | ||
211 | + } catch (err) { | ||
212 | + console.log(err); | ||
213 | + ctx.status = 400; | ||
214 | + return; | ||
215 | + } | ||
216 | + | ||
217 | + try { | ||
218 | + // email 이미 존재하는지 확인 | ||
219 | + const exists = await User.findByEmail(email); | ||
220 | + if (exists) { | ||
221 | + ctx.status = 409; // Conflict | ||
222 | + ctx.body = { | ||
223 | + key: exists.email === ctx.request.body.email ? 'email' : 'username' | ||
224 | + }; | ||
225 | + return; | ||
226 | + } | ||
227 | + }catch(e) | ||
228 | + { | ||
229 | + ctx.throw(500, e); | ||
230 | + } | ||
231 | + | ||
232 | + let account = null; | ||
233 | + try { | ||
234 | + account = await User.localRegister(ctx.request.body); | ||
235 | + } catch (e) { | ||
236 | + ctx.throw(500, e); | ||
237 | + } | ||
238 | + | ||
239 | + let token = null; | ||
240 | + try { | ||
241 | + token = await account.generateToken(); | ||
242 | + console.log('token ok'); | ||
243 | + } catch (e) { | ||
244 | + ctx.throw(500, e); | ||
245 | + } | ||
246 | + ctx.cookies.set('access_token', token, { maxAge: 1000 * 60 * 60 * 24 * 7 ,httpOnly: true,}); | ||
247 | + console.log('set cookie ok'); | ||
248 | + | ||
249 | + // const user = new User(ctx.request.body); | ||
250 | + console.log(ctx.cookies); | ||
251 | + ctx.status = 200; | ||
252 | +}; | ||
253 | + | ||
254 | +exports.signin = async (ctx) => { | ||
255 | + // 로그인 | ||
256 | + const { email, password } = ctx.request.body; | ||
257 | + | ||
258 | + //handle error | ||
259 | + if (!email || !password) { | ||
260 | + ctx.status = 401; //Unauthorized | ||
261 | + return; | ||
262 | + } | ||
263 | + let user = null; | ||
264 | + try { | ||
265 | + user = await User.findOne({ email: email }); | ||
266 | + //const user = await User.findByEmail(email); | ||
267 | + //계정없으면 에러처리 | ||
268 | + if (!user) { | ||
269 | + ctx.status = 401; | ||
270 | + return; | ||
271 | + } | ||
272 | + } catch (e) { | ||
273 | + ctx.throw(500, e); | ||
274 | + } | ||
275 | + const valid = await user.checkPassword(password); | ||
276 | + if (!valid) { | ||
277 | + ctx.status = 401; | ||
278 | + return; | ||
279 | + } | ||
280 | + console.log(user); | ||
281 | + console.log('check password'); | ||
282 | + let token = null; | ||
283 | + try{ | ||
284 | + token = await user.generateToken(); | ||
285 | + }catch (e) { | ||
286 | + ctx.throw(500, e); | ||
287 | + } | ||
288 | + ctx.cookies.set('access_token', token, { | ||
289 | + maxAge: 1000 * 60 * 60 * 24 * 7, // 7일 | ||
290 | + httpOnly: true, | ||
291 | + }); | ||
292 | + console.log('login cookie'); | ||
293 | + | ||
294 | + ctx.status = 200; | ||
295 | + console.log('200'); | ||
296 | +}; | ||
297 | + | ||
298 | +exports.check = async (ctx) => { | ||
299 | + const { user } = ctx.state; | ||
300 | + if (!user) { | ||
301 | + ctx.status = 401; | ||
302 | + return; | ||
303 | + } | ||
304 | + ctx.body = user; | ||
305 | + // 로그인 상태 확인 | ||
306 | +}; | ||
307 | +exports.check2 = (ctx) => { | ||
308 | + const { user } = ctx.request; | ||
309 | + | ||
310 | + if(!user) { | ||
311 | + ctx.status = 403; // Forbidden | ||
312 | + return; | ||
313 | + } | ||
314 | + | ||
315 | + ctx.body = user.profile; | ||
316 | +}; | ||
317 | + | ||
318 | + | ||
319 | + | ||
320 | +exports.signout = async (ctx) => { | ||
321 | + ctx.cookies.set('access_token'); | ||
322 | + ctx.status = 204; | ||
323 | +}; | ||
324 | + | ||
325 | +exports.Withdrawal = async (ctx) => { | ||
326 | + try { | ||
327 | + ctx.cookies.set('access_token'); | ||
328 | + await Book. //delete pets owned by user | ||
329 | + User.deleteOne({ email: ctx.state.user.email }, function (err) {}); //delete user | ||
330 | + } catch (err) { | ||
331 | + ctx.throw(500, e); | ||
332 | + } | ||
333 | + | ||
334 | + ctx.status = 200; | ||
335 | +}; | ||
336 | + | ||
337 | +exports.userinfo = async (ctx) => { | ||
338 | + const { _id } = ctx.state.user; | ||
339 | + try { | ||
340 | + const user = await User.findById(_id).exec(); | ||
341 | + ctx.status = 200; | ||
342 | + ctx.body = await user.serialize(); | ||
343 | + } catch (e) { | ||
344 | + ctx.throw(500, e); | ||
345 | + } | ||
346 | +}; | ||
347 | + | ||
348 | +exports.updateUser = async (ctx) => { | ||
349 | + // 이메일 변경 불가 | ||
350 | + // 비밀번호 변경은 따로 | ||
351 | + //책과 게시글은 따로 | ||
352 | + const schema = Joi.object().keys({ | ||
353 | + // password: Joi.string().min(6).max(20).required(), | ||
354 | + username: Joi.string().allow(null, ''), | ||
355 | + phone: Joi.string().allow(null, ''), | ||
356 | + nickname: Joi.string().allow(null, ''), | ||
357 | + fcmToken: Joi.string(), | ||
358 | + // birth: Joi.date() | ||
359 | + }); | ||
360 | + | ||
361 | + try { | ||
362 | + const value = await schema.validateAsync(ctx.request.body); | ||
363 | + } catch (err) { | ||
364 | + console.log(err); | ||
365 | + ctx.status = 400; | ||
366 | + return; | ||
367 | + } | ||
368 | + | ||
369 | + ctx.request.body.email = ctx.state.user.email; | ||
370 | + | ||
371 | + try { | ||
372 | + User.updateUser(ctx.request.body); | ||
373 | + } catch (e) { | ||
374 | + ctx.throw(500, e); | ||
375 | + } | ||
376 | + ctx.status = 200; | ||
377 | +}; | ||
378 | + | ||
379 | +exports.changePassword = async (ctx) => { | ||
380 | + const schema = Joi.object().keys({ | ||
381 | + email: Joi.string(), | ||
382 | + password: Joi.string().min(6).max(20).required(), | ||
383 | + }); | ||
384 | + | ||
385 | + try { | ||
386 | + const value = await schema.validateAsync(ctx.request.body); | ||
387 | + } catch (err) { | ||
388 | + ctx.status = 400; | ||
389 | + return; | ||
390 | + } | ||
391 | + User.updatePassword(ctx.request.body.email, ctx.request.body.password); | ||
392 | + ctx.status = 200; | ||
393 | + ctx.body = { message: '비밀번호 변경 완료' }; | ||
394 | +}; | ||
395 | + | ||
396 | +exports.findPassword = async (ctx) => { | ||
397 | + var status = 400; | ||
398 | + | ||
399 | + // 전송 옵션 설정 | ||
400 | + // trainsporter: is going to be an object that is able to send mail | ||
401 | + let transporter = nodemailer.createTransport({ | ||
402 | + service: 'gmail', | ||
403 | + host: 'smtp.gmail.com', | ||
404 | + // port: 587, | ||
405 | + port: 465, | ||
406 | + secure: true, | ||
407 | + auth: { | ||
408 | + user: config.mailer.user, //gmail주소입력 | ||
409 | + pass: config.mailer.password, //gmail패스워드 입력 | ||
410 | + }, | ||
411 | + }); | ||
412 | + | ||
413 | + var mailOptions = { | ||
414 | + from: `"Like project"<${config.mailer.user}>`, //enter the send's name and email | ||
415 | + to: ctx.request.body.email, // recipient's email | ||
416 | + subject: 'Like password', // title of mail | ||
417 | + html: `안녕하세요, 글을 나누는 즐거움 Like 입니다. | ||
418 | + <br /> | ||
419 | + 인증번호는 다음과 같습니다. | ||
420 | + <br /> | ||
421 | + ${ctx.request.body.numsend}`, | ||
422 | + }; | ||
423 | + | ||
424 | + try { | ||
425 | + await transporter.sendMail(mailOptions, async function (error, info) { | ||
426 | + if (error) { | ||
427 | + ctx.status = 401; | ||
428 | + return; | ||
429 | + } else { | ||
430 | + console.log('Email sent: ' + info.response); | ||
431 | + ctx.body = { success: true }; | ||
432 | + status = 200; | ||
433 | + } | ||
434 | + }); | ||
435 | + } catch (e) { | ||
436 | + ctx.throw(500, e); | ||
437 | + } | ||
438 | + ctx.status = 200; | ||
439 | + | ||
440 | +}; | ||
441 | + | ||
442 | +//favorite(즐겨찾기) | ||
443 | +exports.addFavorite = async (ctx) => { | ||
444 | + id = ctx.request.body.contentsid; | ||
445 | + try { | ||
446 | + await User.updateFavorite(ctx.state.user.email, id); | ||
447 | + } catch (e) { | ||
448 | + console.log(e); | ||
449 | + } | ||
450 | + | ||
451 | + ctx.status = 200; | ||
452 | +}; | ||
453 | + | ||
454 | +exports.delFavorite = async (ctx) => { | ||
455 | + try { | ||
456 | + await User.delFavorites(ctx.state.user.email, ctx.query.contentsid); | ||
457 | + } catch (e) { | ||
458 | + ctx.throw(500, e); | ||
459 | + } | ||
460 | + ctx.status = 200; | ||
461 | +}; | ||
462 | + | ||
463 | +exports.showFavorite = async (ctx) => { | ||
464 | + try { | ||
465 | + const user = await User.findById(ctx.state.user._id).exec(); | ||
466 | + //url, title, image | ||
467 | + const favbooks = await Book.find({_id:{$in:user.favorite}}); | ||
468 | + ctx.status = 200; | ||
469 | + ctx.body = favbooks; | ||
470 | + } catch (e) { | ||
471 | + ctx.throw(500, e); | ||
472 | + } | ||
473 | +}; | ||
474 | + | ||
475 | + | ||
476 | +exports.getUserBook = async (ctx) => { | ||
477 | + const user = await User.findById(ctx.state.user._id).exec(); | ||
478 | + try { | ||
479 | + const mybook = await Book.find({_id:{$in:user.books}}); | ||
480 | + ctx.body = mybook; | ||
481 | + } catch (e) { | ||
482 | + ctx.throw(500, e); | ||
483 | + } | ||
484 | + //const user = await User.findById(mybook.author).exec(); | ||
485 | + | ||
486 | + | ||
487 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/api/auth/index.js
0 → 100644
1 | +require('dotenv').config() | ||
2 | +const Router = require("@koa/router"); | ||
3 | +const authCtrl = require("./auth.ctrl"); | ||
4 | +const checkLoggedIn = require("../../lib/checkLoggedIn"); | ||
5 | +var passport = require('passport'); | ||
6 | +var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy; | ||
7 | +const auth = new Router(); | ||
8 | + | ||
9 | +// 회원가입- 로컬 이메일 인증번호 발송 POST auth/signup/email/demand | ||
10 | +// 회원가입 이메일 인증번호 확인 POST auth/signup/email/verify | ||
11 | +// 로그인 "소셜 로그인 | ||
12 | +// (페이스북 구글 네이버 카카오)" POST auth/signin/social | ||
13 | +// 회원정보갱신 설문이나 설정에서 개인정보 바꾸면 적용 PATCH auth/update/pet | ||
14 | +// 회원정보갱신 설문이나 설정에서 개인정보 바꾸면 적용 PATCH auth/update/user | ||
15 | + | ||
16 | +auth.get('/userlist', authCtrl.userlist); | ||
17 | +auth.get('/test', authCtrl.test); | ||
18 | +auth.post('/signup', authCtrl.signupLocal); | ||
19 | +auth.post('/signin', authCtrl.signinLocal); | ||
20 | +auth.get('/signout',checkLoggedIn, authCtrl.signout); | ||
21 | +auth.get('/check', authCtrl.check2); | ||
22 | +auth.delete('/user',checkLoggedIn,authCtrl.Withdrawal); // 회원 탈퇴 | ||
23 | +auth.post('/validate', authCtrl.exists); | ||
24 | +auth.post('/checkpassword', authCtrl.checkPassword); | ||
25 | +auth.get('/book',checkLoggedIn,authCtrl.getUserBook); | ||
26 | +auth.get('/user', checkLoggedIn,authCtrl.userinfo); // show user information | ||
27 | +auth.patch('/user', checkLoggedIn, authCtrl.updateUser); // modify user information | ||
28 | +auth.patch('/user/password', authCtrl.changePassword); // change password | ||
29 | + | ||
30 | +auth.get('/favorite',checkLoggedIn, authCtrl.showFavorite); // show a list of user's favorites | ||
31 | +auth.post('/favorite',checkLoggedIn, authCtrl.addFavorite); // add favorite | ||
32 | +auth.delete('/favorite',checkLoggedIn, authCtrl.delFavorite); // delete favorite | ||
33 | + | ||
34 | +auth.post('/find/password', authCtrl.findPassword); // 비밀번호 찾기 | ||
35 | + | ||
36 | + | ||
37 | +module.exports = auth; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/api/book/book.ctrl.js
0 → 100644
1 | +const Page = require("../../models/page"); | ||
2 | +const User = require("../../models/user"); | ||
3 | +const Book = require("../../models/book"); | ||
4 | +const Joi = require('@hapi/joi'); | ||
5 | +const config = require('../../lib/config'); | ||
6 | +const { Mongoose } = require('mongoose'); | ||
7 | +exports.booklist = async (ctx) => { | ||
8 | + let user; | ||
9 | + | ||
10 | + try { | ||
11 | + book = await Book.find() | ||
12 | + .sort({created: -1}) | ||
13 | + .exec(); | ||
14 | + } catch (e) { | ||
15 | + return ctx.throw(500, e); | ||
16 | + } | ||
17 | + | ||
18 | + ctx.body = book; | ||
19 | +} | ||
20 | + | ||
21 | + | ||
22 | +exports.addBook = async (ctx) => { | ||
23 | + //const file = ctx.request.files; | ||
24 | + // console.log("file\n", file) | ||
25 | + // console.log(file.image.path) | ||
26 | + //ctx.request.body.image = fs.readFileSync(file.image.path); | ||
27 | + | ||
28 | + const { | ||
29 | + title, | ||
30 | + author, | ||
31 | + contents, | ||
32 | + cover, | ||
33 | + hashtag, | ||
34 | + } = ctx.request.body; | ||
35 | + | ||
36 | + const schema = Joi.object().keys({ | ||
37 | + title: Joi.string().required(), | ||
38 | + author: Joi.string(), | ||
39 | + contents: Joi.string().allow(null, ''), | ||
40 | + hashtag: Joi.string().allow(null, ''), | ||
41 | + cover: Joi.allow(null, ''), | ||
42 | + }); | ||
43 | + try { | ||
44 | + await schema.validateAsync(ctx.request.body); | ||
45 | + } catch (err) { | ||
46 | + console.log('add book validaton' + err); | ||
47 | + ctx.status = 400; | ||
48 | + return; | ||
49 | + } | ||
50 | + ctx.request.body.author = ctx.state.user; | ||
51 | + const book = new Book(ctx.request.body); | ||
52 | + | ||
53 | + try { | ||
54 | + book.save(async (err) => { | ||
55 | + if (err) throw err; | ||
56 | + const user = await User.findById(ctx.state.user._id).exec(); | ||
57 | + console.log(book._id); | ||
58 | + | ||
59 | + }); | ||
60 | + } catch (e) { | ||
61 | + ctx.throw(500, e); | ||
62 | + } | ||
63 | + ctx.body = book; | ||
64 | + ctx.status = 200; | ||
65 | +}; | ||
66 | + | ||
67 | +exports.getOneBook = async (ctx) => { | ||
68 | + | ||
69 | + const bookid = ctx.request.body._id; | ||
70 | + console.log(bookid); | ||
71 | + try { | ||
72 | + const mybook = await Book.findById(bookid).exec(); | ||
73 | + const user = await User.findById(mybook.author).exec();//작가정보 | ||
74 | + const author_name = user.nickname; | ||
75 | + const bookInfo = { | ||
76 | + "author_name":author_name | ||
77 | + } | ||
78 | + ctx.body = {mybook,author_name:author_name} | ||
79 | + console.log(mybook) | ||
80 | + //ctx.body.authorname = user.nickname; | ||
81 | + //ctx.body = mybook; | ||
82 | + } catch (e) { | ||
83 | + ctx.throw(500, e); | ||
84 | + } | ||
85 | + //const user = await User.findById(mybook.author).exec(); | ||
86 | + //ctx.body = mybook; | ||
87 | + | ||
88 | + | ||
89 | +}; | ||
90 | + | ||
91 | + | ||
92 | + | ||
93 | +exports.updateBook = async (ctx) => { | ||
94 | + // validation추가 필요 | ||
95 | + const file = ctx.request.files; | ||
96 | + if(ctx.request.body.cover != undefined) // when user add a new pet image | ||
97 | + ctx.request.body.cover = fs.readFileSync(file.image.path); | ||
98 | + else | ||
99 | + ctx.request.body.cover = "" | ||
100 | + | ||
101 | + var book = ctx.request.body; //require books's _id | ||
102 | + try { | ||
103 | + const mybook = await Book.findOne({ _id: book._id }); | ||
104 | + | ||
105 | + mybook.updateB(book); | ||
106 | + | ||
107 | + ctx.body = book._id; | ||
108 | + } catch (e) { | ||
109 | + ctx.throw(500, e); | ||
110 | + } | ||
111 | + ctx.body = book._id; | ||
112 | + | ||
113 | + console.log(book); | ||
114 | + ctx.status = 200; | ||
115 | + }; | ||
116 | + | ||
117 | + | ||
118 | +exports.deleteBook = async (ctx) => { | ||
119 | + try { | ||
120 | + var b = await Book.find(ctx.params.id); | ||
121 | + await Page.deleteMany({"pages":{$in:b.pages}});//book에 있던 페이지 다 지우기 | ||
122 | + } catch (e) { | ||
123 | + if(e.name === 'CastError') { | ||
124 | + ctx.status = 400; | ||
125 | + return; | ||
126 | + } | ||
127 | + } | ||
128 | + ctx.status = 204; // No Content | ||
129 | +}; | ||
130 | + | ||
131 | +exports.detailBook = async (ctx) => { | ||
132 | + var ObjectId = require('mongodb').ObjectId; | ||
133 | + var id = req.params.book_id; | ||
134 | + var o_id = new ObjectId(id); | ||
135 | + const book = await db.Book.find({_id:o_id}); | ||
136 | + ctx.body = book; | ||
137 | + ctx.status = 200; | ||
138 | +}; | ||
139 | + | ||
140 | +exports.scrollBook = async (ctx) => { | ||
141 | + //클라이언트에서 미리 요청하는 방법 사용하자 | ||
142 | + | ||
143 | + //select: 조회순 or 추천순 | ||
144 | + //renewal: 앱 화면 바닥에 도달한 횟수 (처음으로 데이터를 추가로 가져올때 1, 그다음 2 ...) | ||
145 | + const {filter, renewal} = ctx.query | ||
146 | + | ||
147 | + if(filter === "조회순") { //조회순 | ||
148 | + try { | ||
149 | + const books = await Book.find().sort({'views': -1}).skip(parseInt(renewal)*10).limit(10) | ||
150 | + let result = await bookInfo(books); | ||
151 | + ctx.status = 200; | ||
152 | + ctx.body = result; | ||
153 | + } catch (e) { | ||
154 | + ctx.throw(500, e); | ||
155 | + } | ||
156 | + } | ||
157 | + | ||
158 | + else if(filter === "추천순") { //추천순 | ||
159 | + | ||
160 | + } | ||
161 | +}; |
src/api/book/index.js
0 → 100644
1 | +const Router = require("@koa/router"); | ||
2 | +const checkLoggedIn = require("../../lib/checkLoggedIn"); | ||
3 | +const bookCtrl = require("./book.ctrl"); | ||
4 | +const book = new Router(); | ||
5 | + | ||
6 | +book.get('/',bookCtrl.getOneBook); | ||
7 | +//mybook=page,title | ||
8 | +//author_name = author name | ||
9 | +book.post('/',checkLoggedIn,bookCtrl.addBook); // add book | ||
10 | +book.patch('/', checkLoggedIn, bookCtrl.updateBook); // modify book information | ||
11 | +book.delete('/',checkLoggedIn,bookCtrl.deleteBook); // delete book | ||
12 | +book.get('/booklist',bookCtrl.booklist); | ||
13 | +book.get('/search',bookCtrl.scrollBook); | ||
14 | + | ||
15 | +module.exports = book; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/api/fireabse/config.js
0 → 100644
1 | + | ||
2 | +const Router = require("koa-router"); | ||
3 | +const Koa = require('koa'); | ||
4 | +// Import the functions you need from the SDKs you need | ||
5 | + | ||
6 | +// TODO: Add SDKs for Firebase products that you want to use | ||
7 | +// https://firebase.google.com/docs/web/setup#available-libraries | ||
8 | + | ||
9 | +// Your web app's Firebase configuration | ||
10 | +const firebaseConfig = { | ||
11 | + apiKey: "AIzaSyDZw-VXcu0yP3m9r11fe3JiJ-_ksEQDX-E", | ||
12 | + authDomain: "like-c93bb.firebaseapp.com", | ||
13 | + projectId: "like-c93bb", | ||
14 | + storageBucket: "like-c93bb.appspot.com", | ||
15 | + messagingSenderId: "514516382912", | ||
16 | + appId: "1:514516382912:web:17460502317f4c51166925" | ||
17 | +}; | ||
18 | + | ||
19 | +// Initialize Firebase | ||
20 | + | ||
21 | +firebase.initializeApp(firebaseConfig) | ||
22 | +let database = firebase.database(); | ||
23 | + | ||
24 | +module.exports = database; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/api/index.js
0 → 100644
1 | +const Router = require("koa-router"); | ||
2 | +const page = require("./page"); | ||
3 | +const auth = require("./auth"); | ||
4 | +const book = require("./book"); | ||
5 | +const api = new Router(); | ||
6 | + | ||
7 | +api.use("/auth", auth.routes()); | ||
8 | +api.use("/book", book.routes()); | ||
9 | +api.use("/page", page.routes()); | ||
10 | + | ||
11 | +api.get('/test', (ctx) => (ctx.body = 'hi')); | ||
12 | +module.exports = api; | ||
13 | + |
src/api/page/index.js
0 → 100644
1 | +const Router = require("@koa/router"); | ||
2 | +const checkLoggedIn = require("../../lib/checkLoggedIn"); | ||
3 | +const pageCtrl = require("./page.ctrl"); | ||
4 | +const page = new Router(); | ||
5 | + | ||
6 | +//Page api | ||
7 | +page.get('/',pageCtrl.getPage); // show a list of user's pages | ||
8 | +page.post('/',checkLoggedIn,pageCtrl.addPage); // add page | ||
9 | +page.patch('/', checkLoggedIn,pageCtrl.updatePage); // modify page information | ||
10 | +page.delete('/',checkLoggedIn,pageCtrl.deletePage); // delete book | ||
11 | + | ||
12 | +page.get('/search', pageCtrl.search); // /search?title=search_query&petType=petType | ||
13 | +//page.post('/search/filter', pageCtrl.searchFilter); //아직 구현 안함 | ||
14 | +page.post('/detail', pageCtrl.detailPage); // detail recipe page | ||
15 | + | ||
16 | +//page.get('/recipe/slide', pageCtrl.slidRecipe); // 5 recommended videos in main page | ||
17 | + | ||
18 | +// /recipe/scroll?filter=filter_query&renewal=count (filter_query: 추천순 or 조회순) | ||
19 | +page.get('/recipe/scroll', pageCtrl.scrollPage); // video list sorted by 추천순 or 조회순 in main page | ||
20 | + | ||
21 | +//page.post('/postinfo', pageCtrl.uploadInfo); | ||
22 | +//page.get('/info',pageCtrl.getbyurl);//url로 recipe정보 가져오기 (flutter 내 레시피에서 쓰임.) | ||
23 | +module.exports = page; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/api/page/page.ctrl.js
0 → 100644
1 | +const Page = require("../../models/page"); | ||
2 | +const User = require("../../models/user"); | ||
3 | +const Book = require("../../models/book"); | ||
4 | +const Joi = require('@hapi/joi'); | ||
5 | +const config = require('../../lib/config'); | ||
6 | +const { Mongoose } = require('mongoose'); | ||
7 | +exports.search = async (ctx) => { | ||
8 | + const { title } = ctx.query; //search word | ||
9 | + console.log(title) | ||
10 | + try { | ||
11 | + var pages = await Page.findBySearchWord(title); | ||
12 | + ctx.status = 200; | ||
13 | + ctx.body = pages; | ||
14 | + } catch (e) { | ||
15 | + ctx.throw(500, e); | ||
16 | + } | ||
17 | + ctx.status = 200; | ||
18 | +}; | ||
19 | + | ||
20 | + | ||
21 | +exports.detailPage = async (ctx) => { | ||
22 | + var ObjectId = require('mongodb').ObjectId; | ||
23 | + var id = req.params.page_id; | ||
24 | + var o_id = new ObjectId(id); | ||
25 | + const page = await db.Page.find({_id:o_id}); | ||
26 | + ctx.body = page; | ||
27 | + ctx.status = 200; | ||
28 | +}; | ||
29 | + | ||
30 | +// parameters: array with book objects as elements | ||
31 | +// return image, title and author of book DB information | ||
32 | +//list에 보여질 정보 일부분 | ||
33 | +async function bookInfo (arr) { | ||
34 | + let result = [] | ||
35 | + arr.map(obj => { | ||
36 | + temp = new Object(); | ||
37 | + temp.image = obj.image; | ||
38 | + temp.title = obj.title; | ||
39 | + temp.author = obj.author; | ||
40 | + temp.views = obj.views; | ||
41 | + result.push(temp); | ||
42 | + delete temp; | ||
43 | + }) | ||
44 | + return result; | ||
45 | +} | ||
46 | + | ||
47 | +async function pageInfo (arr) { | ||
48 | + let result = [] | ||
49 | + arr.map(obj => { | ||
50 | + temp = new Object(); | ||
51 | + temp.image = obj.image; | ||
52 | + temp.title = obj.title; | ||
53 | + temp.author = obj.author; | ||
54 | + temp.views = obj.views; | ||
55 | + result.push(temp); | ||
56 | + delete temp; | ||
57 | + }) | ||
58 | + return result; | ||
59 | +} | ||
60 | + | ||
61 | + | ||
62 | + | ||
63 | + | ||
64 | +exports.scrollPage = async (ctx) => { | ||
65 | + //클라이언트에서 미리 요청하는 방법 사용하자 | ||
66 | + | ||
67 | + //select: 조회순 or 추천순 | ||
68 | + //renewal: 앱 화면 바닥에 도달한 횟수 (처음으로 데이터를 추가로 가져올때 1, 그다음 2 ...) | ||
69 | + const {filter, renewal} = ctx.query | ||
70 | + | ||
71 | + if(filter === "조회순") { //조회순 | ||
72 | + try { | ||
73 | + const pages = await Page.find().sort({'views': -1}).skip(parseInt(renewal)*10).limit(10) | ||
74 | + let result = await pageInfo(pages); | ||
75 | + ctx.status = 200; | ||
76 | + ctx.body = result; | ||
77 | + } catch (e) { | ||
78 | + ctx.throw(500, e); | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | + else if(filter === "추천순") { //추천순 | ||
83 | + | ||
84 | + } | ||
85 | +}; | ||
86 | + | ||
87 | +//pet | ||
88 | + exports.addPage = async (ctx) => { | ||
89 | + //const file = ctx.request.files; | ||
90 | + // console.log("file\n", file) | ||
91 | + // console.log(file.image.path) | ||
92 | + //ctx.request.body.image = fs.readFileSync(file.image.path); | ||
93 | + if( ctx.request.files==undefined) | ||
94 | + console.log("파일없음"); | ||
95 | + else | ||
96 | + ctx.request.body.cover = "" | ||
97 | + const { | ||
98 | + title, | ||
99 | + author, | ||
100 | + contents, | ||
101 | + cover, | ||
102 | + hashtag, | ||
103 | + book, | ||
104 | + } = ctx.request.body; | ||
105 | + | ||
106 | + const schema = Joi.object().keys({ | ||
107 | + title: Joi.string().required(), | ||
108 | + author: Joi.string(), | ||
109 | + contents: Joi.string().required(), | ||
110 | + hashtag: Joi.string().allow(null, ''), | ||
111 | + cover: Joi.allow(null, ''), | ||
112 | + book: Joi.string().allow(null, ''), | ||
113 | + }); | ||
114 | + | ||
115 | + | ||
116 | + //검증 결과 | ||
117 | + try { | ||
118 | + await schema.validateAsync(ctx.request.body); | ||
119 | + } catch (err) { | ||
120 | + console.log('add page validaton' + err); | ||
121 | + ctx.status = 400; | ||
122 | + return; | ||
123 | + } | ||
124 | + ctx.request.body.author = ctx.state.user; | ||
125 | + const page = new Page(ctx.request.body); | ||
126 | + | ||
127 | + try { | ||
128 | + page.save(async (err, page) => { | ||
129 | + if (err) throw err; | ||
130 | + const user = await User.findById(ctx.state.user._id).exec(); | ||
131 | + if(page.book!='') | ||
132 | + { | ||
133 | + const result = await Book.findOneAndUpdate({_id: page.book}, {$push: {pages: page._id}}); | ||
134 | + console.log(result); | ||
135 | + } | ||
136 | + | ||
137 | + }); | ||
138 | + } catch (e) { | ||
139 | + ctx.throw(500, e); | ||
140 | + } | ||
141 | + ctx.body = page; | ||
142 | + ctx.status = 200; | ||
143 | + }; | ||
144 | + | ||
145 | + exports.updatePage = async (ctx) => { | ||
146 | + // validation추가 필요 | ||
147 | + if(ctx.request.files != undefined) // when user add a new pet image | ||
148 | + ctx.request.body.image = fs.readFileSync(file.image.path); | ||
149 | + else | ||
150 | + ctx.request.body.image = "" | ||
151 | + | ||
152 | + var user = ctx.request.body; //require user id | ||
153 | + try { | ||
154 | + const mybook = await Book.findOne({ _id: book._id }); | ||
155 | + | ||
156 | + mybook.updateP(book); | ||
157 | + | ||
158 | + ctx.body = user._id; | ||
159 | + } catch (e) { | ||
160 | + ctx.throw(500, e); | ||
161 | + } | ||
162 | + ctx.body = user._id; | ||
163 | + | ||
164 | + console.log(user); | ||
165 | + ctx.status = 200; | ||
166 | + }; | ||
167 | + | ||
168 | + | ||
169 | +exports.deletePage = async (ctx) => { | ||
170 | + try { | ||
171 | + var b = await Page.find(ctx.params.id); | ||
172 | + await Page.deleteMany({"pages":{$in:b.pages}}); | ||
173 | + } catch (e) { | ||
174 | + if(e.name === 'CastError') { | ||
175 | + ctx.status = 400; | ||
176 | + return; | ||
177 | + } | ||
178 | + } | ||
179 | + ctx.status = 204; // No Content | ||
180 | +}; | ||
181 | + | ||
182 | +exports.getPage = async (ctx) => { | ||
183 | + const pageid = ctx.request.body._id; | ||
184 | + try { | ||
185 | + const mypage = await Book.findById(pageid).exec(); | ||
186 | + const user = await User.findById(mypage.author).exec();//작가정보 | ||
187 | + const author_name = user.nickname; | ||
188 | + ctx.body = {mypage,author_name:author_name} | ||
189 | + console.log(mypage) | ||
190 | + | ||
191 | + } catch (e) { | ||
192 | + ctx.throw(500, e); | ||
193 | + } | ||
194 | + | ||
195 | +}; |
src/index.js
0 → 100644
1 | +const http2 = require('http2'); | ||
2 | +var fs = require('fs'); | ||
3 | +const api = require('./api'); | ||
4 | +const Koa = require('koa'); | ||
5 | +const Router = require("koa-router"); | ||
6 | +const jwtMiddleware = require('./lib/jwtMiddleware'); | ||
7 | +require('dotenv').config(); | ||
8 | +const mongoose = require('mongoose'); | ||
9 | +const bodyParser = require('koa-bodyparser'); | ||
10 | +const port = process.env.PORT || 3000 | ||
11 | +//443 | ||
12 | +const app = new Koa(); | ||
13 | +const router = new Router() | ||
14 | +const send = require('koa-send'); | ||
15 | +var options = { | ||
16 | + key: fs.readFileSync('./server.key'), | ||
17 | + cert: fs.readFileSync('./server.crt'), | ||
18 | + allowHTTP1: true | ||
19 | +}; | ||
20 | +//app.use(express.static('images')) | ||
21 | + | ||
22 | +mongoose.Promise = global.Promise; // Node 의 네이티브 Promise 사용 | ||
23 | +// mongodb 연결 | ||
24 | +mongoose.connect(process.env.MONGO_URI).then( | ||
25 | + (response) => { | ||
26 | + console.log('Successfully connected to mongodb'); | ||
27 | + } | ||
28 | +).catch(e => { | ||
29 | + console.error(e); | ||
30 | +}); | ||
31 | + | ||
32 | +var readFileThunk = function(src) { | ||
33 | + return new Promise(function (resolve, reject) { | ||
34 | + fs.readFile(src, {'encoding': 'utf8'}, function (err, data) { | ||
35 | + if(err) return reject(err); | ||
36 | + resolve(data); | ||
37 | + }); | ||
38 | + }); | ||
39 | +} | ||
40 | +//app.use(router.routes()) | ||
41 | +/* | ||
42 | +app | ||
43 | + .use(router.routes()) | ||
44 | + .use(router.allowedMethods()); | ||
45 | + */ | ||
46 | + app | ||
47 | + .use(jwtMiddleware) | ||
48 | + .use(bodyParser()) // bodyParser는 라우터 코드보다 상단에 있어야 합니다. | ||
49 | + .use(router.routes()) | ||
50 | + .use(router.allowedMethods()); | ||
51 | + | ||
52 | + | ||
53 | + | ||
54 | +/* | ||
55 | +router.get('/', (ctx, next) => { | ||
56 | + ctx.body = '루트 페이지 입니다.'; | ||
57 | +}); | ||
58 | +*/ | ||
59 | +/* | ||
60 | +router.get('/', async (ctx, next) => { | ||
61 | + const rawContent = fs.readFileSync('index.html').toString('utf8') | ||
62 | + ctx.body = rawContent | ||
63 | +})*/ | ||
64 | + | ||
65 | +router.get('/', function *(){ | ||
66 | + this.body = yield readFileThunk(__dirname + '/public/index.html'); | ||
67 | +}) | ||
68 | +//router.use(api.routes()); | ||
69 | +//app.use(router.routes()).use(router.allowedMethods()) | ||
70 | +router.use('/api', api.routes()); | ||
71 | +app.use(router.routes()).use(router.allowedMethods()); | ||
72 | + | ||
73 | +http2 | ||
74 | + .createSecureServer(options, app.callback()) | ||
75 | + .listen(port, () => console.log("listening on port %i", port)); | ||
76 | +//app.listen(port, function () { | ||
77 | +//console.log('server listening on port %d', port); | ||
78 | + //}); | ||
79 | + | ||
80 | + | ||
81 | + |
src/lib/checkLoggedIn.js
0 → 100644
src/lib/config.js
0 → 100644
src/lib/jwtMiddleware.js
0 → 100644
1 | +const jwt = require("jsonwebtoken"); | ||
2 | +const User = require("../models/user"); | ||
3 | +/*function generateToken(payload) { | ||
4 | + return new Promise((resolve, reject) => { | ||
5 | + jwt.sign( | ||
6 | + payload, | ||
7 | + jwtSecret, | ||
8 | + { | ||
9 | + expiresIn: '7d' // 토큰 유효기간 7일 설정 | ||
10 | + }, (error, token) => { | ||
11 | + if (error) reject(error); | ||
12 | + resolve(token); | ||
13 | + } | ||
14 | + ); | ||
15 | + } | ||
16 | + ); | ||
17 | +}; | ||
18 | + | ||
19 | + | ||
20 | +function decodeToken(token) { | ||
21 | + return new Promise( | ||
22 | + (resolve, reject) => { | ||
23 | + jwt.verify(token, jwtSecret, (error, decoded) => { | ||
24 | + if(error) reject(error); | ||
25 | + resolve(decoded); | ||
26 | + }); | ||
27 | + } | ||
28 | + ); | ||
29 | +} | ||
30 | + | ||
31 | + | ||
32 | +const jwtMiddleware = async (ctx, next) => { | ||
33 | + const token = ctx.cookies.get("access_token"); | ||
34 | + if (!token) { | ||
35 | + return next();} //token이 없음 | ||
36 | + try { | ||
37 | + const decoded = await decodeToken(token); // 토큰을 디코딩 합니다 | ||
38 | + const user = await User.findById(decoded._id).exec(); | ||
39 | + ctx.state.user = { | ||
40 | + _id: decoded._id, | ||
41 | + email: decoded.email | ||
42 | + }; | ||
43 | + //특정 시간 남았으면 재발급 | ||
44 | + const now = Math.floor(Date.now() / 1000); | ||
45 | + if (decoded.exp - now < 60 * 60 * 24 * 3.5) { | ||
46 | + const user = await User.findById(decoded._id); | ||
47 | + const token = user.generateToken(); | ||
48 | + ctx.cookies.set("access_token", token, { | ||
49 | + maxAge: 1000 * 60 * 60 * 24 * 7, // 7일 | ||
50 | + httpOnly: true | ||
51 | + }); | ||
52 | + } | ||
53 | + ctx.request.user = decoded; | ||
54 | + return next(); | ||
55 | + } catch (e) { | ||
56 | + //검증 실패 | ||
57 | + return next(); | ||
58 | + } | ||
59 | +}; | ||
60 | +*/ | ||
61 | + | ||
62 | +const jwtMiddleware = async (ctx, next) => { | ||
63 | + const token = ctx.cookies.get("access_token"); | ||
64 | + if (!token) { | ||
65 | + return next();} //token이 없음 | ||
66 | + try { | ||
67 | + const decoded = jwt.verify(token, process.env.JWT_SECRET); | ||
68 | + const user = await User.findById(decoded._id).exec(); | ||
69 | + ctx.state.user = { | ||
70 | + _id: decoded._id, | ||
71 | + email: decoded.email | ||
72 | + }; | ||
73 | + //특정 시간 남았으면 재발급 | ||
74 | + const now = Math.floor(Date.now() / 1000); | ||
75 | + if (decoded.exp - now < 60 * 60 * 24 * 3.5) { | ||
76 | + const user = await User.findById(decoded._id); | ||
77 | + const token = user.generateToken(); | ||
78 | + ctx.cookies.set("access_token", token, { | ||
79 | + maxAge: 1000 * 60 * 60 * 24 * 7, // 7일 | ||
80 | + httpOnly: true, | ||
81 | + }); | ||
82 | + } | ||
83 | + | ||
84 | + return next(); | ||
85 | + } catch (e) { | ||
86 | + //검증 실패 | ||
87 | + return next(); | ||
88 | + } | ||
89 | +}; | ||
90 | + | ||
91 | +module.exports = jwtMiddleware; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/models/book.js
0 → 100644
1 | +const user = require('./user'); | ||
2 | +const page = require('./page'); | ||
3 | +const mongoose = require('mongoose'); | ||
4 | +const { Schema } = mongoose; | ||
5 | + | ||
6 | +const bookSchema = new Schema({ | ||
7 | + id: mongoose.Schema.Types.ObjectId,//unique number of page | ||
8 | + pages:[{type:String}],//book contains several pages. pages is the list of page id | ||
9 | + title: {type:String, require:true}, // book title | ||
10 | + author: [{type:String, require:true, default:user.user}],//작가복수 가능 | ||
11 | + contents: {type:String}, // book subtitle or detail | ||
12 | + createDate: {type:Date, require:true, default:Date.now}, | ||
13 | + updateDate: {type:Date, default:Date.now}, | ||
14 | + views: {type: Number, default: 0},//how many people open this book | ||
15 | + favoritenum:{type: Number, default: 0}, | ||
16 | + cover:{ | ||
17 | + data: {type: Buffer,default:null}, | ||
18 | + contentType: {type:String, default:null} | ||
19 | + }, | ||
20 | + hashtag: [{type: String}], | ||
21 | + }); | ||
22 | + | ||
23 | + | ||
24 | + bookSchema.statics.upload = async function ({title, author, contents, views, hashtag,cover}) { | ||
25 | + const page = new this({ | ||
26 | + title: title, | ||
27 | + author: author, | ||
28 | + contents: contents, | ||
29 | + views: views, | ||
30 | + hashtag:hashtag, | ||
31 | + }); | ||
32 | + await page.save(function(err){ | ||
33 | + if(err) return console.error(err); | ||
34 | + }); | ||
35 | + return page; | ||
36 | + }; | ||
37 | + | ||
38 | + | ||
39 | + bookSchema.statics.ListofPage = async function () { | ||
40 | + var book = this; | ||
41 | + var pages = await page.find({"_id": book.ObjectId}); | ||
42 | + return pages; | ||
43 | +}; | ||
44 | + | ||
45 | + bookSchema.statics.findBySearchWord = async function (word) { | ||
46 | + var book = this; | ||
47 | + const reg = new RegExp(word, 'i'); | ||
48 | + var result = [] | ||
49 | + var books=await book.find(); | ||
50 | + | ||
51 | + await books.map(obj => { | ||
52 | + // obj.hashtag.inclues | ||
53 | + if (obj.title.match(reg)) { //제목에 검색어가 들어가는가 | ||
54 | + temp = new Object(); | ||
55 | + temp.url = obj.url; | ||
56 | + temp.image = obj.image; | ||
57 | + temp.title = obj.title; | ||
58 | + temp.author = obj.author; | ||
59 | + result.push(temp); | ||
60 | + delete temp; | ||
61 | + } | ||
62 | + else if (obj.contents.match(reg)) | ||
63 | + { | ||
64 | + temp = new Object(); | ||
65 | + temp.url = obj.url; | ||
66 | + temp.image = obj.image; | ||
67 | + temp.title = obj.title; | ||
68 | + temp.author = obj.author; | ||
69 | + result.push(temp); | ||
70 | + delete temp; | ||
71 | + } | ||
72 | + else { | ||
73 | + for (let i = 0; i < obj.hashtag.length; i++) | ||
74 | + { | ||
75 | + if (obj.hashtag[i].match(reg)) { //hashtag에 검색어가 들어가는가 | ||
76 | + temp = new Object(); | ||
77 | + temp.url = obj.url; | ||
78 | + temp.image = obj.image; | ||
79 | + temp.title = obj.title; | ||
80 | + temp.author = obj.author; | ||
81 | + result.push(temp); | ||
82 | + delete temp; | ||
83 | + break | ||
84 | + } | ||
85 | + } | ||
86 | + } | ||
87 | + }) | ||
88 | + | ||
89 | + return result | ||
90 | + } | ||
91 | + | ||
92 | + bookSchema.methods.updateB = async function (book) { | ||
93 | + this.title = book.title; | ||
94 | + this.author = book.author; | ||
95 | + this.contents = book.contents; | ||
96 | + this.author = book.author; | ||
97 | + if(book.cover != ""){ | ||
98 | + this.cover = []; | ||
99 | + //this.cover.push(book.cover); | ||
100 | + } | ||
101 | + this.save(); | ||
102 | + }; | ||
103 | + | ||
104 | + | ||
105 | + | ||
106 | +module.exports = mongoose.model("Book", bookSchema); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/models/page.js
0 → 100644
1 | +const user = require('./user'); | ||
2 | +const mongoose = require('mongoose'); | ||
3 | +const { Schema } = mongoose; | ||
4 | + | ||
5 | +const PageSchema = new Schema({ | ||
6 | + id: mongoose.Schema.Types.ObjectId,//unique number of page | ||
7 | + book:{type:String},//book contains several pages | ||
8 | + title: {type:String, require:true}, // title of post | ||
9 | + author: [{type:String, require:true, default:user.user}], | ||
10 | + contents: {type:String}, // contents of page | ||
11 | + createDate: {type:Date, require:true, default:Date.now}, | ||
12 | + updateDate: {type:Date, default:Date.now}, | ||
13 | + views: {type: Number, default: 0},//how many people open this page | ||
14 | + cover:{ | ||
15 | + data: {type: Buffer,default:null}, | ||
16 | + contentType: {type:String, default:null} | ||
17 | + }, | ||
18 | + hashtag: [{type: String}], | ||
19 | + comment: { | ||
20 | + writer: {type: String}, | ||
21 | + contents: {type:String}, //comment text | ||
22 | + createDate: {type:Date, require:true, default:Date.now}, | ||
23 | + updateDate: {type:Date, default:Date.now}, | ||
24 | + | ||
25 | + }, | ||
26 | + }); | ||
27 | + | ||
28 | + | ||
29 | + PageSchema.statics.updateP = async function ({title, author, contents, hashtag,book,cover}) { | ||
30 | + | ||
31 | + const page = new this({ | ||
32 | + title: title, | ||
33 | + book: book,//book으로 들어와서 생성한 경우, 그 book의 id를 넘겨주기 | ||
34 | + author: author, | ||
35 | + contents: contents, | ||
36 | + hashtag:hashtag, | ||
37 | + cover:cover | ||
38 | + | ||
39 | + }); | ||
40 | + await page.save(function(err){ | ||
41 | + if(err) return console.error(err); | ||
42 | + }); | ||
43 | + return page; | ||
44 | + }; | ||
45 | + | ||
46 | + | ||
47 | + // parameters: search word | ||
48 | + PageSchema.statics.findBySearchWord = async function (word) { | ||
49 | + var page = this; | ||
50 | + const reg = new RegExp(word, 'i'); | ||
51 | + var result = [] | ||
52 | + var pages = await page.find(); | ||
53 | + | ||
54 | + console.log(petType) | ||
55 | + await pages.map(obj => { | ||
56 | + // obj.hashtag.inclues | ||
57 | + if (obj.title.match(reg)) { //제목에 검색어가 들어가는가 | ||
58 | + temp = new Object(); | ||
59 | + temp.url = obj.url; | ||
60 | + temp.cover = obj.cover; | ||
61 | + temp.title = obj.title; | ||
62 | + temp.author = obj.author; | ||
63 | + result.push(temp); | ||
64 | + delete temp; | ||
65 | + } | ||
66 | + else { | ||
67 | + for (let i = 0; i < obj.hashtag.length; i++) { | ||
68 | + if (obj.hashtag[i].match(reg)) { //hashtag에 검색어가 들어가는가 | ||
69 | + temp = new Object(); | ||
70 | + temp.url = obj.url; | ||
71 | + temp.cover = obj.cover; | ||
72 | + temp.title = obj.title; | ||
73 | + temp.author = obj.author; | ||
74 | + result.push(temp); | ||
75 | + delete temp; | ||
76 | + break | ||
77 | + } | ||
78 | + } | ||
79 | + } | ||
80 | + }) | ||
81 | + | ||
82 | + return result | ||
83 | + } | ||
84 | + | ||
85 | + // parameters: user's favorites page list | ||
86 | + PageSchema.statics.favoriteRecipe = async function (pageUrlArr) { | ||
87 | + var pgList = [] | ||
88 | + for(let i=0; i<pageUrlArr.length; i++) { | ||
89 | + const page = await this.findOne({ url: pageUrlArr[i] }).exec(); | ||
90 | + | ||
91 | + temp = new Object(); | ||
92 | + temp.url = page.url; | ||
93 | + temp.title = page.title; | ||
94 | + temp.cover = page.cover; | ||
95 | + pgList.push(temp); | ||
96 | + delete temp; | ||
97 | + } | ||
98 | + | ||
99 | + return pgList; | ||
100 | + } | ||
101 | + | ||
102 | +module.exports = mongoose.model("Page", PageSchema); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
src/models/user.js
0 → 100644
1 | +var mongoose = require("mongoose"); | ||
2 | +var Schema = mongoose.Schema; | ||
3 | +const bcrypt = require("bcrypt"); | ||
4 | +const jwt = require("jsonwebtoken"); | ||
5 | +const crypto = require('crypto'); | ||
6 | +//const Pet = require("./pet"); | ||
7 | + | ||
8 | +const UserSchema = new Schema({ | ||
9 | + //login require | ||
10 | + //email == id | ||
11 | + email: { type: String, required: true, unique: true }, | ||
12 | + password: String, | ||
13 | + token: String, | ||
14 | + //user info | ||
15 | + username: String, | ||
16 | + phone: {type: String, require: true}, | ||
17 | + nickname: {type: String, default: ""}, | ||
18 | + books: [{type: String}],//array of bookid | ||
19 | + favorite: [{ type: String }],//String of url(book, page) | ||
20 | + }); | ||
21 | + | ||
22 | + | ||
23 | +function hash(password) { | ||
24 | + return crypto.createHmac('sha256', process.env.SECRET_KEY).update(password).digest('hex'); | ||
25 | +} | ||
26 | +UserSchema.statics.localRegister = function ({ nickname,phone, email, password }) { | ||
27 | + const user = new this({ | ||
28 | + phone, | ||
29 | + email, | ||
30 | + password: hash(password), | ||
31 | + nickname | ||
32 | + }); | ||
33 | + | ||
34 | + return user.save(); | ||
35 | +}; | ||
36 | + //User 모델에 정보를 save하기 전에 실행 | ||
37 | + /* | ||
38 | +UserSchema.pre('save', function( next ){ | ||
39 | + var user = this; | ||
40 | + | ||
41 | + //비밀번호를 바꿀때만 비밀번호를 암호화해준다 | ||
42 | + if (user.isModified('password')) { | ||
43 | + // 비밀번호를 암호화 시킨다 | ||
44 | + bcrypt.hash(user.password, 10, function (err, hash) { //hash: 암호화된 비밀번호 | ||
45 | + if (err) return next(err); | ||
46 | + user.password = hash(); | ||
47 | + next(); | ||
48 | + }); | ||
49 | + | ||
50 | + } else { | ||
51 | + next(); | ||
52 | + } | ||
53 | + }); | ||
54 | + | ||
55 | +*/ | ||
56 | + // parameters: login user email, new password to change | ||
57 | +UserSchema.statics.updatePassword = async function (email, password) { | ||
58 | + const hash = await hash(password); | ||
59 | + this.findOneAndUpdate({email: email} , {$set: {password: hash}}, function(err, user) { | ||
60 | + if(err) throw err; | ||
61 | + console.log(user) | ||
62 | + }) | ||
63 | + | ||
64 | + console.log("hash", hash); | ||
65 | + }; | ||
66 | + | ||
67 | + UserSchema.methods.generateToken = function () { | ||
68 | + const token = jwt.sign( | ||
69 | + // 첫번째 파라미터엔 토큰 안에 집어넣고 싶은 데이터를 넣습니다 | ||
70 | + { | ||
71 | + _id: this.id, | ||
72 | + email: this.email, | ||
73 | + }, | ||
74 | + process.env.JWT_SECRET, // 두번째 파라미터에는 JWT 암호를 넣습니다 | ||
75 | + { | ||
76 | + expiresIn: "7d", // 7일동안 유효함 | ||
77 | + } | ||
78 | + ); | ||
79 | + return token; | ||
80 | + }; | ||
81 | + | ||
82 | + | ||
83 | +UserSchema.statics.updateFcm = async function (email, fcm){ | ||
84 | + this.findOneAndUpdate({email: email}, {$set: {fcmToken: fcm}}, function(err,user){ | ||
85 | + if(err) throw err; | ||
86 | + //console.log(user); | ||
87 | + }) | ||
88 | + }; | ||
89 | + | ||
90 | + //응답하는 JSON에서 비밀번호 정보 삭제 | ||
91 | + UserSchema.methods.serialize = async function () { | ||
92 | + const data = this.toJSON(); | ||
93 | + delete data.password; | ||
94 | + delete data._id; | ||
95 | + return data; | ||
96 | + }; | ||
97 | + | ||
98 | + | ||
99 | + UserSchema.methods.checkPassword = async function (password) { | ||
100 | + const hashed = hash(password); | ||
101 | + return this.password === hashed; | ||
102 | + }; | ||
103 | + | ||
104 | + //static method | ||
105 | + UserSchema.statics.findByEmail = async function (email) { | ||
106 | + return this.findOne({ email: email, logintype: "local" }); | ||
107 | + }; | ||
108 | + | ||
109 | + | ||
110 | + // parameters: user information to be updated | ||
111 | + UserSchema.statics.updateUser = async function (user) { | ||
112 | + this.findOneAndUpdate({ email: user.email }, { $set: user }, | ||
113 | + function (err, result) { | ||
114 | + if (err) throw err; | ||
115 | + return result; | ||
116 | + }); | ||
117 | + }; | ||
118 | + | ||
119 | + // parameters: book's object id | ||
120 | + UserSchema.methods.addBook = async function (bookId) { | ||
121 | + console.log(bookId); | ||
122 | + this.books.push(bookId); | ||
123 | + this.save(); | ||
124 | + } | ||
125 | + | ||
126 | +//parameters: login user email, pet's object id | ||
127 | +UserSchema.statics.delBook = async function (email, bookId) { | ||
128 | + return this.findOneAndUpdate({email: email}, {$pull: {books: bookId}}); | ||
129 | +} | ||
130 | + | ||
131 | +// parameters: login user email, url of the book or page | ||
132 | +UserSchema.statics.updateFavorite = async function (email, contentsID) { | ||
133 | + return this.findOneAndUpdate( | ||
134 | + { | ||
135 | + email: email, | ||
136 | + }, | ||
137 | + { $addToSet: { favorite: contentsID } } | ||
138 | + ); | ||
139 | +}; | ||
140 | + | ||
141 | +// parameters: login user email, url of the book or page | ||
142 | +UserSchema.statics.delFavorites = async function (email, contentsID) { | ||
143 | + return this.findOneAndUpdate( | ||
144 | + { | ||
145 | + email: email, | ||
146 | + }, | ||
147 | + { $pull: { favorite: contentsID } } | ||
148 | + ); | ||
149 | +}; | ||
150 | + | ||
151 | +UserSchema.statics.showFavorites = async function (email) { | ||
152 | + this.books | ||
153 | + return ( | ||
154 | + { | ||
155 | + email: email, | ||
156 | + }, | ||
157 | + { $pull: { favorite: contentsID } } | ||
158 | + ); | ||
159 | +}; | ||
160 | + | ||
161 | +module.exports = mongoose.model("User", UserSchema, "Users"); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment