박유빈

seperate back and front code

module.exports = {
"extends": "standard",
"rules": {
"indent": [
"error",
4
],
"semi": [
"error",
"always"
],
"no-trailing-spaces": 0,
"keyword-spacing": 0,
"no-unused-vars": 1,
"no-multiple-empty-lines": 0,
"space-before-function-paren": 0,
"eol-last": 0
}
};
\ No newline at end of file
/node_modules
.env
\ No newline at end of file
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/src/api/book/book.ctrl.js",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIDmTCCAoECFA0G8CsoOzEJaSus1d0/oC6+WzOcMA0GCSqGSIb3DQEBCwUAMIGI
MQswCQYDVQQGEwJLcjEOMAwGA1UECAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1
MQswCQYDVQQKDAJUdzERMA8GA1UECwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2Uu
Y29tMSMwIQYJKoZIhvcNAQkBFhR5b29iaW5wYXJrQGtodS5hYy5rcjAeFw0yMTEx
MTAwNTAzNDhaFw0zMTExMDgwNTAzNDhaMIGIMQswCQYDVQQGEwJLcjEOMAwGA1UE
CAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1MQswCQYDVQQKDAJUdzERMA8GA1UE
CwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2UuY29tMSMwIQYJKoZIhvcNAQkBFhR5
b29iaW5wYXJrQGtodS5hYy5rcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBANHhAjf8HAfdy0v15teX1ENK3eaLF14GiguOc5/KmaAYYj1nIl7LGdjiumB6
VJT0elRIAx1DCGoPDN8d5Dhfrpftblv7lPFUOVKpI6Rjcl6EVRCOm3I6TehXazg9
ACdHRA/8uxLG8MFKsmAVh1wQXGnBVoobgZyNDq3yU4d0y6paCvHCVVBTIB/Mdikp
vLiDRfrB9m6L5YC6Aux6Dn2nfX+GTUvxXzks4RoDtJAiklnfczgFDVc8oN6ZMplq
A4TPF67TLsY071x2XQIpUruWleWo4MdZPIQr/ex2WFvbJT8+Y6wsEfD2AgCxBBuT
hVYhmsFaAf0fYv+ftQwd60oBdoMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPIuB
rauwsJoEQvMH6G4b7AXyyKytfmOkK3e8RSvNeeu/IUoAPX1SuaLcGmVTF5q2tf8z
a3qwCqJxuChHWfL5C0F/iq24OYEPEFQAKqWqSJXk8Y5icuu8ZyPEaEjBJqCxoWdn
bfc4OHwfSxvpg3AbaCuB9DsjF0zUmYZYSAPSduMOrDUo2fC2AI3A0UgjJex0pD0q
ricy3QCWIzVPdWYThthWwuMnND7oiqhOrweZlH2FiSodkvbyFkENQFRjvDmWoM7J
93ryfbcDOJfnBEA07S/3ljwFBwzNs5pw4h8LzRRNHg1tXk1Eu4kecGHmiW5bej4H
l4/nnfqOSyRtOoLaAQ==
-----END CERTIFICATE-----
RSA Private-Key: (2048 bit, 2 primes)
modulus:
00:d1:e1:02:37:fc:1c:07:dd:cb:4b:f5:e6:d7:97:
d4:43:4a:dd:e6:8b:17:5e:06:8a:0b:8e:73:9f:ca:
99:a0:18:62:3d:67:22:5e:cb:19:d8:e2:ba:60:7a:
54:94:f4:7a:54:48:03:1d:43:08:6a:0f:0c:df:1d:
e4:38:5f:ae:97:ed:6e:5b:fb:94:f1:54:39:52:a9:
23:a4:63:72:5e:84:55:10:8e:9b:72:3a:4d:e8:57:
6b:38:3d:00:27:47:44:0f:fc:bb:12:c6:f0:c1:4a:
b2:60:15:87:5c:10:5c:69:c1:56:8a:1b:81:9c:8d:
0e:ad:f2:53:87:74:cb:aa:5a:0a:f1:c2:55:50:53:
20:1f:cc:76:29:29:bc:b8:83:45:fa:c1:f6:6e:8b:
e5:80:ba:02:ec:7a:0e:7d:a7:7d:7f:86:4d:4b:f1:
5f:39:2c:e1:1a:03:b4:90:22:92:59:df:73:38:05:
0d:57:3c:a0:de:99:32:99:6a:03:84:cf:17:ae:d3:
2e:c6:34:ef:5c:76:5d:02:29:52:bb:96:95:e5:a8:
e0:c7:59:3c:84:2b:fd:ec:76:58:5b:db:25:3f:3e:
63:ac:2c:11:f0:f6:02:00:b1:04:1b:93:85:56:21:
9a:c1:5a:01:fd:1f:62:ff:9f:b5:0c:1d:eb:4a:01:
76:83
publicExponent: 65537 (0x10001)
privateExponent:
58:e9:ad:fa:f1:bf:1e:46:03:fe:26:2a:a9:63:14:
f5:7d:1e:0c:b1:18:31:29:2c:0a:41:4b:12:82:ce:
1a:58:ba:25:b1:2f:8a:61:18:8e:1d:5f:3f:c8:13:
55:17:4d:4b:af:46:42:7b:47:71:46:f6:f8:fe:bc:
d4:75:14:8e:20:74:04:5b:cc:79:80:68:d8:6f:f7:
3d:89:33:c6:7e:e1:5a:a6:4f:8c:50:ce:f8:83:30:
55:1e:e2:95:c1:47:40:4e:9d:22:13:4d:a3:55:75:
c3:e6:da:f5:51:a9:14:d4:67:49:12:e6:11:e0:60:
3b:a8:d1:62:2d:44:aa:e1:bd:db:44:de:61:aa:41:
a0:24:92:e7:2f:ec:59:34:7a:13:d5:5e:4e:b8:14:
66:26:2f:31:42:1b:61:46:ef:a6:c5:31:9c:65:f6:
35:a8:76:ef:fd:12:d1:1f:7d:cc:62:34:5b:42:47:
fa:33:58:46:58:80:23:63:48:36:70:4b:e9:a4:88:
81:c2:33:d9:6a:49:a8:b8:ce:7f:ea:09:82:6b:78:
ac:4f:59:9d:d0:37:59:38:03:14:38:94:c0:2f:23:
de:ab:c4:90:2e:9c:95:3c:e0:f0:8b:d2:16:40:7f:
01:39:5a:fa:c7:68:09:ab:60:b0:f0:b9:3b:1b:08:
21
prime1:
00:f4:8c:0f:79:cc:a7:df:76:72:7a:f9:05:02:47:
95:e7:7b:ad:9f:ae:45:ac:f1:81:d1:5c:eb:38:c5:
fc:90:ce:79:0a:9c:c2:bd:4f:08:ef:3a:46:e9:4d:
22:29:93:50:3d:54:98:a8:74:ca:f5:c7:4b:60:7d:
d3:b7:c8:ca:f3:d6:14:8b:45:9f:04:7f:71:03:3f:
30:f3:2d:fb:bd:83:81:22:d6:9a:3d:cd:f2:8e:d5:
0a:6e:17:a4:2c:62:46:da:4a:f6:d9:98:cf:1d:67:
72:45:dd:70:4f:0c:69:11:9c:a0:25:26:25:a4:59:
b3:ea:6e:39:7e:4c:a6:b1:cf
prime2:
00:db:b5:4d:6a:7b:ce:a1:16:2b:bd:56:b2:3f:fb:
43:dd:5e:5e:b5:f1:86:eb:ad:1b:73:2d:f4:96:52:
8d:4c:ae:34:3d:d6:8a:1d:07:fd:8b:7c:0b:66:b3:
49:72:37:f8:f1:f9:7d:d8:b0:c5:12:c0:66:f3:99:
10:e5:71:a8:22:47:9b:d6:bf:5f:05:91:d5:c7:f0:
2a:48:3c:a4:ae:00:5f:09:70:c3:a9:48:1d:22:6f:
d5:94:83:52:cf:2d:d9:cf:1b:80:f2:4e:2a:18:3c:
36:e7:6d:57:01:e5:60:8f:52:e6:3a:ec:dc:94:ec:
a1:3b:07:f3:e5:72:e5:61:0d
exponent1:
00:e8:f9:d6:74:8f:49:0f:57:64:d1:4b:14:3e:8b:
bc:80:80:0f:75:25:2e:34:09:11:48:48:61:c0:00:
bf:11:a5:e3:22:fd:1d:7a:05:25:d9:e3:87:53:14:
ad:0b:36:d1:26:dc:c5:63:17:81:94:8d:7d:7e:3b:
e1:cc:21:7b:58:ba:07:70:77:af:7b:35:7e:91:3d:
4e:81:1e:b9:ca:5e:d2:54:42:67:47:a2:41:07:5a:
67:49:63:34:81:24:4f:a3:ff:ef:14:76:c4:3a:9b:
26:fe:f0:6b:e2:a3:4c:25:ff:35:82:ae:c9:05:be:
7f:ed:43:7d:7a:99:c3:e5:79
exponent2:
00:b7:52:28:dd:4f:9e:92:84:68:4c:9c:79:30:af:
9b:e9:aa:a3:46:16:d8:67:ef:51:b7:22:42:31:e7:
81:a4:d8:ba:18:5a:d9:74:ed:c4:dd:cc:cb:ca:8e:
90:1a:f0:9f:14:70:03:54:79:f2:85:f9:ea:2d:19:
ab:a2:76:da:3e:78:17:8c:f0:b2:fd:77:b8:b4:12:
2d:85:86:ac:35:cf:73:7c:f2:0d:20:43:5e:a3:ec:
42:7e:9f:b0:c9:d3:cd:28:65:1f:8b:8e:32:cb:73:
fa:af:d1:68:c6:d9:38:5f:7e:61:42:0b:7e:e5:f8:
27:73:94:e8:29:ac:5b:be:45
coefficient:
19:e9:84:ba:58:9b:8f:dc:52:4b:03:3f:9b:65:cc:
d7:6a:04:9a:2c:66:40:2d:cf:2e:90:32:52:44:f6:
21:74:65:dc:6a:27:8d:23:79:09:ea:53:45:39:e4:
40:e7:d2:d0:1c:aa:1a:68:fe:56:69:2b:3b:55:20:
ff:0b:84:b0:c4:af:ed:33:dd:c4:fe:5c:10:5d:b9:
5b:6d:b2:bd:2f:e9:03:8f:29:5e:38:17:a3:2c:14:
6c:08:cb:cb:10:5c:9e:c6:cb:c4:9f:99:6e:76:96:
2a:0a:19:cf:33:f3:d0:ba:b0:d6:77:0d:71:1f:3f:
5c:95:ff:9e:61:ce:ab:49
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0eECN/wcB93LS/Xm15fUQ0rd5osXXgaKC45zn8qZoBhiPWci
XssZ2OK6YHpUlPR6VEgDHUMIag8M3x3kOF+ul+1uW/uU8VQ5UqkjpGNyXoRVEI6b
cjpN6FdrOD0AJ0dED/y7EsbwwUqyYBWHXBBcacFWihuBnI0OrfJTh3TLqloK8cJV
UFMgH8x2KSm8uINF+sH2bovlgLoC7HoOfad9f4ZNS/FfOSzhGgO0kCKSWd9zOAUN
Vzyg3pkymWoDhM8XrtMuxjTvXHZdAilSu5aV5ajgx1k8hCv97HZYW9slPz5jrCwR
8PYCALEEG5OFViGawVoB/R9i/5+1DB3rSgF2gwIDAQABAoIBAFjprfrxvx5GA/4m
KqljFPV9HgyxGDEpLApBSxKCzhpYuiWxL4phGI4dXz/IE1UXTUuvRkJ7R3FG9vj+
vNR1FI4gdARbzHmAaNhv9z2JM8Z+4VqmT4xQzviDMFUe4pXBR0BOnSITTaNVdcPm
2vVRqRTUZ0kS5hHgYDuo0WItRKrhvdtE3mGqQaAkkucv7Fk0ehPVXk64FGYmLzFC
G2FG76bFMZxl9jWodu/9EtEffcxiNFtCR/ozWEZYgCNjSDZwS+mkiIHCM9lqSai4
zn/qCYJreKxPWZ3QN1k4AxQ4lMAvI96rxJAunJU84PCL0hZAfwE5WvrHaAmrYLDw
uTsbCCECgYEA9IwPecyn33ZyevkFAkeV53utn65FrPGB0VzrOMX8kM55CpzCvU8I
7zpG6U0iKZNQPVSYqHTK9cdLYH3Tt8jK89YUi0WfBH9xAz8w8y37vYOBItaaPc3y
jtUKbhekLGJG2kr22ZjPHWdyRd1wTwxpEZygJSYlpFmz6m45fkymsc8CgYEA27VN
anvOoRYrvVayP/tD3V5etfGG660bcy30llKNTK40PdaKHQf9i3wLZrNJcjf48fl9
2LDFEsBm85kQ5XGoIkeb1r9fBZHVx/AqSDykrgBfCXDDqUgdIm/VlINSzy3ZzxuA
8k4qGDw2521XAeVgj1LmOuzclOyhOwfz5XLlYQ0CgYEA6PnWdI9JD1dk0UsUPou8
gIAPdSUuNAkRSEhhwAC/EaXjIv0degUl2eOHUxStCzbRJtzFYxeBlI19fjvhzCF7
WLoHcHevezV+kT1OgR65yl7SVEJnR6JBB1pnSWM0gSRPo//vFHbEOpsm/vBr4qNM
Jf81gq7JBb5/7UN9epnD5XkCgYEAt1Io3U+ekoRoTJx5MK+b6aqjRhbYZ+9RtyJC
MeeBpNi6GFrZdO3E3czLyo6QGvCfFHADVHnyhfnqLRmronbaPngXjPCy/Xe4tBIt
hYasNc9zfPINIENeo+xCfp+wydPNKGUfi44yy3P6r9Foxtk4X35hQgt+5fgnc5To
KaxbvkUCgYAZ6YS6WJuP3FJLAz+bZczXagSaLGZALc8ukDJSRPYhdGXcaieNI3kJ
6lNFOeRA59LQHKoaaP5WaSs7VSD/C4SwxK/tM93E/lwQXblbbbK9L+kDjyleOBej
LBRsCMvLEFyexsvEn5ludpYqChnPM/PQurDWdw1xHz9clf+eYc6rSQ==
-----END RSA PRIVATE KEY-----
This diff could not be displayed because it is too large.
{
"name": "likeback",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node src",
"start:dev": "nodemon --watch src/ src/index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"@hapi/joi": "^17.1.1",
"@koa/router": "^10.1.1",
"bcrypt": "^5.0.1",
"crypto": "^1.0.1",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"firebase": "^9.6.0",
"http2": "^3.3.7",
"jsonwebtoken": "^8.5.1",
"koa": "^2.13.4",
"koa-body": "^4.2.0",
"koa-bodyparser": "^4.3.0",
"koa-router": "^10.1.1",
"koa-send": "^5.0.1",
"mongoose": "^6.0.12",
"nodemailer": "^6.7.1",
"passport": "^0.5.0",
"passport-google-oauth": "^2.0.0",
"spdy": "^4.0.2"
},
"devDependencies": {
"eslint": "^8.2.0"
}
}
-----BEGIN CERTIFICATE-----
MIIDmTCCAoECFA0G8CsoOzEJaSus1d0/oC6+WzOcMA0GCSqGSIb3DQEBCwUAMIGI
MQswCQYDVQQGEwJLcjEOMAwGA1UECAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1
MQswCQYDVQQKDAJUdzERMA8GA1UECwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2Uu
Y29tMSMwIQYJKoZIhvcNAQkBFhR5b29iaW5wYXJrQGtodS5hYy5rcjAeFw0yMTEx
MTAwNTAzNDhaFw0zMTExMDgwNTAzNDhaMIGIMQswCQYDVQQGEwJLcjEOMAwGA1UE
CAwFU2VvdWwxETAPBgNVBAcMCEd3YW5ha0d1MQswCQYDVQQKDAJUdzERMA8GA1UE
CwwIVHdTaXN0ZXIxETAPBgNVBAMMCGxpa2UuY29tMSMwIQYJKoZIhvcNAQkBFhR5
b29iaW5wYXJrQGtodS5hYy5rcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBANHhAjf8HAfdy0v15teX1ENK3eaLF14GiguOc5/KmaAYYj1nIl7LGdjiumB6
VJT0elRIAx1DCGoPDN8d5Dhfrpftblv7lPFUOVKpI6Rjcl6EVRCOm3I6TehXazg9
ACdHRA/8uxLG8MFKsmAVh1wQXGnBVoobgZyNDq3yU4d0y6paCvHCVVBTIB/Mdikp
vLiDRfrB9m6L5YC6Aux6Dn2nfX+GTUvxXzks4RoDtJAiklnfczgFDVc8oN6ZMplq
A4TPF67TLsY071x2XQIpUruWleWo4MdZPIQr/ex2WFvbJT8+Y6wsEfD2AgCxBBuT
hVYhmsFaAf0fYv+ftQwd60oBdoMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPIuB
rauwsJoEQvMH6G4b7AXyyKytfmOkK3e8RSvNeeu/IUoAPX1SuaLcGmVTF5q2tf8z
a3qwCqJxuChHWfL5C0F/iq24OYEPEFQAKqWqSJXk8Y5icuu8ZyPEaEjBJqCxoWdn
bfc4OHwfSxvpg3AbaCuB9DsjF0zUmYZYSAPSduMOrDUo2fC2AI3A0UgjJex0pD0q
ricy3QCWIzVPdWYThthWwuMnND7oiqhOrweZlH2FiSodkvbyFkENQFRjvDmWoM7J
93ryfbcDOJfnBEA07S/3ljwFBwzNs5pw4h8LzRRNHg1tXk1Eu4kecGHmiW5bej4H
l4/nnfqOSyRtOoLaAQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIICzjCCAbYCAQAwgYgxCzAJBgNVBAYTAktyMQ4wDAYDVQQIDAVTZW91bDERMA8G
A1UEBwwIR3dhbmFrR3UxCzAJBgNVBAoMAlR3MREwDwYDVQQLDAhUd1Npc3RlcjER
MA8GA1UEAwwIbGlrZS5jb20xIzAhBgkqhkiG9w0BCQEWFHlvb2JpbnBhcmtAa2h1
LmFjLmtyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0eECN/wcB93L
S/Xm15fUQ0rd5osXXgaKC45zn8qZoBhiPWciXssZ2OK6YHpUlPR6VEgDHUMIag8M
3x3kOF+ul+1uW/uU8VQ5UqkjpGNyXoRVEI6bcjpN6FdrOD0AJ0dED/y7EsbwwUqy
YBWHXBBcacFWihuBnI0OrfJTh3TLqloK8cJVUFMgH8x2KSm8uINF+sH2bovlgLoC
7HoOfad9f4ZNS/FfOSzhGgO0kCKSWd9zOAUNVzyg3pkymWoDhM8XrtMuxjTvXHZd
AilSu5aV5ajgx1k8hCv97HZYW9slPz5jrCwR8PYCALEEG5OFViGawVoB/R9i/5+1
DB3rSgF2gwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBACC2EZvLB/YvSLHgDVoE
QDefpbCLJ2Dm8/CeRrGPKpJK4ozGFNox026SM+UH0zU3V3kLqu41uN7Jgofc3XTU
cpmTeMRmFgd8+csXwM1evuFJUNfcwQTxNDlbn9IOsdn7TXF5uhjt4+nAZ0SvRSGg
59VsZEXUNnbevFN87ihd8AVjTGz0nuYLIxJ51s98ND32R0/UaofZqu4niH6FcKNR
U9NlHPTL1/XPqC+qSBlPVlADeUEBobEXzFo4yzPlv4JLFWV0gVOGYLtoK5m+Q2WS
xbhL+c+S8Dz87aJ2wlj8lDYbRsUqu+GCNjcOqAmSnZPkq1UoObzV01pXMtqL2jry
ebw=
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0eECN/wcB93LS/Xm15fUQ0rd5osXXgaKC45zn8qZoBhiPWci
XssZ2OK6YHpUlPR6VEgDHUMIag8M3x3kOF+ul+1uW/uU8VQ5UqkjpGNyXoRVEI6b
cjpN6FdrOD0AJ0dED/y7EsbwwUqyYBWHXBBcacFWihuBnI0OrfJTh3TLqloK8cJV
UFMgH8x2KSm8uINF+sH2bovlgLoC7HoOfad9f4ZNS/FfOSzhGgO0kCKSWd9zOAUN
Vzyg3pkymWoDhM8XrtMuxjTvXHZdAilSu5aV5ajgx1k8hCv97HZYW9slPz5jrCwR
8PYCALEEG5OFViGawVoB/R9i/5+1DB3rSgF2gwIDAQABAoIBAFjprfrxvx5GA/4m
KqljFPV9HgyxGDEpLApBSxKCzhpYuiWxL4phGI4dXz/IE1UXTUuvRkJ7R3FG9vj+
vNR1FI4gdARbzHmAaNhv9z2JM8Z+4VqmT4xQzviDMFUe4pXBR0BOnSITTaNVdcPm
2vVRqRTUZ0kS5hHgYDuo0WItRKrhvdtE3mGqQaAkkucv7Fk0ehPVXk64FGYmLzFC
G2FG76bFMZxl9jWodu/9EtEffcxiNFtCR/ozWEZYgCNjSDZwS+mkiIHCM9lqSai4
zn/qCYJreKxPWZ3QN1k4AxQ4lMAvI96rxJAunJU84PCL0hZAfwE5WvrHaAmrYLDw
uTsbCCECgYEA9IwPecyn33ZyevkFAkeV53utn65FrPGB0VzrOMX8kM55CpzCvU8I
7zpG6U0iKZNQPVSYqHTK9cdLYH3Tt8jK89YUi0WfBH9xAz8w8y37vYOBItaaPc3y
jtUKbhekLGJG2kr22ZjPHWdyRd1wTwxpEZygJSYlpFmz6m45fkymsc8CgYEA27VN
anvOoRYrvVayP/tD3V5etfGG660bcy30llKNTK40PdaKHQf9i3wLZrNJcjf48fl9
2LDFEsBm85kQ5XGoIkeb1r9fBZHVx/AqSDykrgBfCXDDqUgdIm/VlINSzy3ZzxuA
8k4qGDw2521XAeVgj1LmOuzclOyhOwfz5XLlYQ0CgYEA6PnWdI9JD1dk0UsUPou8
gIAPdSUuNAkRSEhhwAC/EaXjIv0degUl2eOHUxStCzbRJtzFYxeBlI19fjvhzCF7
WLoHcHevezV+kT1OgR65yl7SVEJnR6JBB1pnSWM0gSRPo//vFHbEOpsm/vBr4qNM
Jf81gq7JBb5/7UN9epnD5XkCgYEAt1Io3U+ekoRoTJx5MK+b6aqjRhbYZ+9RtyJC
MeeBpNi6GFrZdO3E3czLyo6QGvCfFHADVHnyhfnqLRmronbaPngXjPCy/Xe4tBIt
hYasNc9zfPINIENeo+xCfp+wydPNKGUfi44yy3P6r9Foxtk4X35hQgt+5fgnc5To
KaxbvkUCgYAZ6YS6WJuP3FJLAz+bZczXagSaLGZALc8ukDJSRPYhdGXcaieNI3kJ
6lNFOeRA59LQHKoaaP5WaSs7VSD/C4SwxK/tM93E/lwQXblbbbK9L+kDjyleOBej
LBRsCMvLEFyexsvEn5ludpYqChnPM/PQurDWdw1xHz9clf+eYc6rSQ==
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,25A9EC1BE53CDC74
FQR3tdxyJp2QHgJv+IqGVa3yAbOtR7J0AoLccoWmEMRN8Ch8Iso3RkKDpXo7Awa7
EjnsIqTHqJl8AyD9DlkBRNnFog0mfnJJ1rHUyU9fOL+I2/B8R6qYFjvDpnTiC6Cp
9Dz+Wn2KdhgkkoufvLEBW/BiiD2ScB/zk1POPXAWEBI8wQYSPsdWrxw8PtNbExt+
9LApwYsDKpQnNAuYjiD/kZp9mz3qKO/kHS9R8nX8ZJq1c7D/SyN0in276T+OPk9C
11Tcw86p+aoMVT2sU9CJ9N7rkFaOg1w1Hl27d4R6jvDDaYuvbsp41SKNJJbpnAQS
+GtruJMjED8SOb4Sy4dRzZ6pZV/zPr/X7GcyANPC1RlxGjoWqLTuzruv4BSXf2Qk
vLQF67FqpVBwIMY6GmzMrWeGfiK3i3WsqtMvCAPNPSO1d6EWzGNK5n68rBGk4fKF
20gBWiab2f4osY4N7hPrDRRROVVlVFj9VUppQunyPYu5VEwAW+IQrb537QJp77ww
ppAYoOjaiJHHPvnXP8JFCLSK1t8AeXl2GcrP5NEzCq8sMUXbClgd+gVynrqhN68I
F7EOAYrvELapcURwu6Rnfxk9v8BTQoOt1hvcdLVcPah5+pkeGXy6JoHusDH+/3O7
fi92tTPB2astbdPottuJuCHeyNaGRlFO+f81iePT91389jBDNFUNacERUwlQIZzd
d8MXwHFlf4kUxlu6PXl8JeAXKHXrL9q3HAzeOZu+sJBt8cscQ/FVMjx4svYPCndl
WGgb7Be052e1R/dOclfTKC6C24/6ek/UsPRIFem5BzP8lLocSDEp8Z55j3pGgyt0
OAAuaVYwPVj56pXFoTWWModyux7YhBmqAl8Gguv53w5SyKviSPs0SoSWSQ3RaZig
1f+rC1yBm2/kVV4Upbc2Jd5FGMjkUOPSbPKnk4yyZNEaIpuDkwjWdp9JU3DF2Zuh
o+ZUkLZwmYYNFLB7ODwkekS4xE3M/YD4Dxn9D2VvZ7CUUP4FxqU3qPsdpzSgG9p9
4FBmvmBxl6nMRLaOKwWeyj8SOtmm3x+OUs+meHL0T417CDQqv+wy7F9ikmxvo8/H
XdRaKLemziI9R4NLJvmoFVJbrAP2CDM2DiiuMPcWv3WHBVSPU2s0fnNG75tS4iHl
ZD/gCvL8jDMRml/r4kbwogg7YK/Ac6mmf5WqWK+t4QwDg6YwsKt5MDq8rf/7W5Lf
TemIi8uoriE75XpCoMTqNWbdVUolos4n09B1l5Xx14fiOo9HGrhz7CgEpalNidqM
0X3OLeZm/wdoJ3rusPRv5r/giObMRvOc9qN3RJpKYcEK99xHLVAPV6V6DASWMnCs
Iknz4cBOdpR+WDcEUUi9aFkRuc9mw/iI/JMY5MDZzbWod2hF7VZ2Yko6JTuW9Y8R
Jk0HgoI0YZdrnD6b/EmLdJcsZIIg6H4wBg56KTuP/jxOGgvcD03tPnyCOGaXOdCH
c1kKo8N55Q0oFfdrVlBriptZeiqdFZ52vhThDR0z1DIeVuOiDeALvYdEhzR8oTJC
ZKtqaQsUQiMVn4ZHiKex+9+OWhkArXoPYcyGuaT7coM5rWiwwbqP89tgPMUaIbbo
-----END RSA PRIVATE KEY-----
const Joi = require('@hapi/joi');
const User = require('../../models/user');
const Book = require('../../models/book');
const Page = require('../../models/page');
const nodemailer = require('nodemailer');
const config = require('../../lib/config');
const { Mongoose } = require('mongoose');
const { exist, allow } = require('@hapi/joi');
const fs = require('fs');
exports.test = async (ctx) => {
console.log('cookie');
ctx.cookies.set('second', 22222, {
httpOnly: false
})
ctx.body = {code: 200, message: 'success'}
};
exports.signupLocal = 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;
ctx.body = await account.serialize();
} catch (e) {
ctx.throw(500, e);
}
};
exports.signinLocal = async (ctx) => {
// 로그인
const { email, password } = ctx.request.body;
//handle error
if (!email || !password) {
ctx.status = 401; //Unauthorized
return;
}
try {
const user = await 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;
console.log('토큰나옴');
} catch (e) {
ctx.throw(500, e);
}
};
/*
exports.localLogin = async (ctx) => {
// 데이터 검증
const schema = Joi.object().keys({
email: Joi.string().email().required(),
password: Joi.string().required()
});
const result = Joi.validate(ctx.request.body, schema);
if (result.error) {
ctx.status = 400; // Bad Request
return;
}
const { email, password } = ctx.request.body;
let account = null;
try {
// 이메일로 계정 찾기
account = await User.findByEmail(email);
}
catch (e) {
ctx.throw(500, e);
}
if (!account || !account.checkPassword(password)) {
// 유저가 존재하지 않거나 || 비밀번호가 일치하지 않으면
ctx.status = 403; // Forbidden
return;
}
let token = null;
try {
token = await account.generateToken();
} catch (e) {
ctx.throw(500, e);
}
ctx.cookies.set('access_token', token, { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 });
ctx.body = account.email;
};*/
exports.userlist = async (ctx) => {
let user;
try {
user = await User.find()
.sort({created: -1})
.exec();
} catch (e) {
return ctx.throw(500, e);
}
ctx.body = user;
}
exports.exists = async (ctx) => {
const { email } = ctx.request.body;
try {
const exists = await User.findByEmail(email);
if (exists) {
ctx.status = 409;
return;
}
ctx.status = 200;
} catch (e) {
ctx.throw(500, e);
}
};
exports.checkPassword = async (ctx) => {
const { email, password } = ctx.request.body;
try {
const user = await User.findOne({ email: email });
const valid = await user.checkPassword(password);
if (valid) {
ctx.status = 200;
console.log("Check password success");
return;
} else if(!valid){
ctx.status = 401;
console.log("Check password fail");
return;
}
} catch (e) {
ctx.throw(500, e);
}
};
//회원가입
exports.signup = async (ctx) => {
const { email, password, phone, fcmToken } = ctx.request.body;
const schema = Joi.object().keys({
email: Joi.string().min(3).required(),
password: Joi.string().required().min(6),
phone: Joi.string().allow(null, ''),
fcmToken: Joi.string().allow(null, ''),
nickname:Joi.string().allow(null, '')
});
let value= null;
try {
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
ctx.body = {
key: exists.email === ctx.request.body.email ? 'email' : 'username'
};
return;
}
}catch(e)
{
ctx.throw(500, e);
}
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');
// const user = new User(ctx.request.body);
console.log(ctx.cookies);
ctx.status = 200;
};
exports.signin = async (ctx) => {
// 로그인
const { email, password } = ctx.request.body;
//handle error
if (!email || !password) {
ctx.status = 401; //Unauthorized
return;
}
let user = null;
try {
user = await User.findOne({ email: email });
//const user = await User.findByEmail(email);
//계정없으면 에러처리
if (!user) {
ctx.status = 401;
return;
}
} catch (e) {
ctx.throw(500, e);
}
const valid = await user.checkPassword(password);
if (!valid) {
ctx.status = 401;
return;
}
console.log(user);
console.log('check password');
let token = null;
try{
token = await user.generateToken();
}catch (e) {
ctx.throw(500, e);
}
ctx.cookies.set('access_token', token, {
maxAge: 1000 * 60 * 60 * 24 * 7, // 7일
httpOnly: true,
});
console.log('login cookie');
ctx.status = 200;
console.log('200');
};
exports.check = async (ctx) => {
const { user } = ctx.state;
if (!user) {
ctx.status = 401;
return;
}
ctx.body = user;
// 로그인 상태 확인
};
exports.check2 = (ctx) => {
const { user } = ctx.request;
if(!user) {
ctx.status = 403; // Forbidden
return;
}
ctx.body = user.profile;
};
exports.signout = async (ctx) => {
ctx.cookies.set('access_token');
ctx.status = 204;
};
exports.Withdrawal = async (ctx) => {
try {
ctx.cookies.set('access_token');
await Book. //delete pets owned by user
User.deleteOne({ email: ctx.state.user.email }, function (err) {}); //delete user
} catch (err) {
ctx.throw(500, e);
}
ctx.status = 200;
};
exports.userinfo = async (ctx) => {
const { _id } = ctx.state.user;
try {
const user = await User.findById(_id).exec();
ctx.status = 200;
ctx.body = await user.serialize();
} catch (e) {
ctx.throw(500, e);
}
};
exports.updateUser = async (ctx) => {
// 이메일 변경 불가
// 비밀번호 변경은 따로
//책과 게시글은 따로
const schema = Joi.object().keys({
// password: Joi.string().min(6).max(20).required(),
username: Joi.string().allow(null, ''),
phone: Joi.string().allow(null, ''),
nickname: Joi.string().allow(null, ''),
fcmToken: Joi.string(),
// birth: Joi.date()
});
try {
const value = await schema.validateAsync(ctx.request.body);
} catch (err) {
console.log(err);
ctx.status = 400;
return;
}
ctx.request.body.email = ctx.state.user.email;
try {
User.updateUser(ctx.request.body);
} catch (e) {
ctx.throw(500, e);
}
ctx.status = 200;
};
exports.changePassword = async (ctx) => {
const schema = Joi.object().keys({
email: Joi.string(),
password: Joi.string().min(6).max(20).required(),
});
try {
const value = await schema.validateAsync(ctx.request.body);
} catch (err) {
ctx.status = 400;
return;
}
User.updatePassword(ctx.request.body.email, ctx.request.body.password);
ctx.status = 200;
ctx.body = { message: '비밀번호 변경 완료' };
};
exports.findPassword = async (ctx) => {
var status = 400;
// 전송 옵션 설정
// trainsporter: is going to be an object that is able to send mail
let transporter = nodemailer.createTransport({
service: 'gmail',
host: 'smtp.gmail.com',
// port: 587,
port: 465,
secure: true,
auth: {
user: config.mailer.user, //gmail주소입력
pass: config.mailer.password, //gmail패스워드 입력
},
});
var mailOptions = {
from: `"Like project"<${config.mailer.user}>`, //enter the send's name and email
to: ctx.request.body.email, // recipient's email
subject: 'Like password', // title of mail
html: `안녕하세요, 글을 나누는 즐거움 Like 입니다.
<br />
인증번호는 다음과 같습니다.
<br />
${ctx.request.body.numsend}`,
};
try {
await transporter.sendMail(mailOptions, async function (error, info) {
if (error) {
ctx.status = 401;
return;
} else {
console.log('Email sent: ' + info.response);
ctx.body = { success: true };
status = 200;
}
});
} catch (e) {
ctx.throw(500, e);
}
ctx.status = 200;
};
//favorite(즐겨찾기)
exports.addFavorite = async (ctx) => {
id = ctx.request.body.contentsid;
try {
await User.updateFavorite(ctx.state.user.email, id);
} catch (e) {
console.log(e);
}
ctx.status = 200;
};
exports.delFavorite = async (ctx) => {
try {
await User.delFavorites(ctx.state.user.email, ctx.query.contentsid);
} catch (e) {
ctx.throw(500, e);
}
ctx.status = 200;
};
exports.showFavorite = async (ctx) => {
try {
const user = await User.findById(ctx.state.user._id).exec();
//url, title, image
const favbooks = await Book.find({_id:{$in:user.favorite}});
ctx.status = 200;
ctx.body = favbooks;
} catch (e) {
ctx.throw(500, e);
}
};
exports.getUserBook = async (ctx) => {
const user = await User.findById(ctx.state.user._id).exec();
try {
const mybook = await Book.find({_id:{$in:user.books}});
ctx.body = mybook;
} catch (e) {
ctx.throw(500, e);
}
//const user = await User.findById(mybook.author).exec();
};
\ No newline at end of file
require('dotenv').config()
const Router = require("@koa/router");
const authCtrl = require("./auth.ctrl");
const checkLoggedIn = require("../../lib/checkLoggedIn");
var passport = require('passport');
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.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); // 비밀번호 찾기
module.exports = auth;
\ No newline at end of file
const Page = require("../../models/page");
const User = require("../../models/user");
const Book = require("../../models/book");
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();
} catch (e) {
return ctx.throw(500, e);
}
ctx.body = book;
}
exports.addBook = async (ctx) => {
//const file = ctx.request.files;
// console.log("file\n", file)
// console.log(file.image.path)
//ctx.request.body.image = fs.readFileSync(file.image.path);
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);
});
} catch (e) {
ctx.throw(500, e);
}
ctx.body = book;
ctx.status = 200;
};
exports.getOneBook = async (ctx) => {
const bookid = ctx.request.body._id;
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.body.authorname = user.nickname;
//ctx.body = mybook;
} catch (e) {
ctx.throw(500, e);
}
//const user = await User.findById(mybook.author).exec();
//ctx.body = mybook;
};
exports.updateBook = async (ctx) => {
// validation추가 필요
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: book._id });
mybook.updateB(book);
ctx.body = book._id;
} catch (e) {
ctx.throw(500, e);
}
ctx.body = book._id;
console.log(book);
ctx.status = 200;
};
exports.deleteBook = async (ctx) => {
try {
var b = await Book.find(ctx.params.id);
await Page.deleteMany({"pages":{$in:b.pages}});//book에 있던 페이지 다 지우기
} catch (e) {
if(e.name === 'CastError') {
ctx.status = 400;
return;
}
}
ctx.status = 204; // No Content
};
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;
ctx.status = 200;
};
exports.scrollBook = async (ctx) => {
//클라이언트에서 미리 요청하는 방법 사용하자
//select: 조회순 or 추천순
//renewal: 앱 화면 바닥에 도달한 횟수 (처음으로 데이터를 추가로 가져올때 1, 그다음 2 ...)
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);
}
}
else if(filter === "추천순") { //추천순
}
};
const Router = require("@koa/router");
const checkLoggedIn = require("../../lib/checkLoggedIn");
const bookCtrl = require("./book.ctrl");
const book = new Router();
book.get('/',bookCtrl.getOneBook);
//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);
module.exports = book;
\ No newline at end of file
const Router = require("koa-router");
const Koa = require('koa');
// Import the functions you need from the SDKs you need
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "AIzaSyDZw-VXcu0yP3m9r11fe3JiJ-_ksEQDX-E",
authDomain: "like-c93bb.firebaseapp.com",
projectId: "like-c93bb",
storageBucket: "like-c93bb.appspot.com",
messagingSenderId: "514516382912",
appId: "1:514516382912:web:17460502317f4c51166925"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig)
let database = firebase.database();
module.exports = database;
\ No newline at end of file
const Router = require("koa-router");
const page = require("./page");
const auth = require("./auth");
const book = require("./book");
const api = new Router();
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;
const Router = require("@koa/router");
const checkLoggedIn = require("../../lib/checkLoggedIn");
const pageCtrl = require("./page.ctrl");
const page = new Router();
//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('/detail', 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.post('/postinfo', pageCtrl.uploadInfo);
//page.get('/info',pageCtrl.getbyurl);//url로 recipe정보 가져오기 (flutter 내 레시피에서 쓰임.)
module.exports = page;
\ No newline at end of file
const Page = require("../../models/page");
const User = require("../../models/user");
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)
try {
var pages = await Page.findBySearchWord(title);
ctx.status = 200;
ctx.body = pages;
} catch (e) {
ctx.throw(500, e);
}
ctx.status = 200;
};
exports.detailPage = async (ctx) => {
var ObjectId = require('mongodb').ObjectId;
var id = req.params.page_id;
var o_id = new ObjectId(id);
const page = await db.Page.find({_id:o_id});
ctx.body = page;
ctx.status = 200;
};
// parameters: array with book objects as elements
// return image, title and author of book DB information
//list에 보여질 정보 일부분
async function bookInfo (arr) {
let result = []
arr.map(obj => {
temp = new Object();
temp.image = obj.image;
temp.title = obj.title;
temp.author = obj.author;
temp.views = obj.views;
result.push(temp);
delete temp;
})
return result;
}
async function pageInfo (arr) {
let result = []
arr.map(obj => {
temp = new Object();
temp.image = obj.image;
temp.title = obj.title;
temp.author = obj.author;
temp.views = obj.views;
result.push(temp);
delete temp;
})
return result;
}
exports.scrollPage = async (ctx) => {
//클라이언트에서 미리 요청하는 방법 사용하자
//select: 조회순 or 추천순
//renewal: 앱 화면 바닥에 도달한 횟수 (처음으로 데이터를 추가로 가져올때 1, 그다음 2 ...)
const {filter, renewal} = ctx.query
if(filter === "조회순") { //조회순
try {
const pages = await Page.find().sort({'views': -1}).skip(parseInt(renewal)*10).limit(10)
let result = await pageInfo(pages);
ctx.status = 200;
ctx.body = result;
} catch (e) {
ctx.throw(500, e);
}
}
else if(filter === "추천순") { //추천순
}
};
//pet
exports.addPage = async (ctx) => {
//const file = ctx.request.files;
// console.log("file\n", file)
// console.log(file.image.path)
//ctx.request.body.image = fs.readFileSync(file.image.path);
if( ctx.request.files==undefined)
console.log("파일없음");
else
ctx.request.body.cover = ""
const {
title,
author,
contents,
cover,
hashtag,
book,
} = ctx.request.body;
const schema = Joi.object().keys({
title: Joi.string().required(),
author: Joi.string(),
contents: Joi.string().required(),
hashtag: Joi.string().allow(null, ''),
cover: Joi.allow(null, ''),
book: Joi.string().allow(null, ''),
});
//검증 결과
try {
await schema.validateAsync(ctx.request.body);
} catch (err) {
console.log('add page validaton' + err);
ctx.status = 400;
return;
}
ctx.request.body.author = ctx.state.user;
const page = new Page(ctx.request.body);
try {
page.save(async (err, page) => {
if (err) throw err;
const user = await User.findById(ctx.state.user._id).exec();
if(page.book!='')
{
const result = await Book.findOneAndUpdate({_id: page.book}, {$push: {pages: page._id}});
console.log(result);
}
});
} catch (e) {
ctx.throw(500, e);
}
ctx.body = page;
ctx.status = 200;
};
exports.updatePage = async (ctx) => {
// validation추가 필요
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 = ""
var user = ctx.request.body; //require user id
try {
const mybook = await Book.findOne({ _id: book._id });
mybook.updateP(book);
ctx.body = user._id;
} catch (e) {
ctx.throw(500, e);
}
ctx.body = user._id;
console.log(user);
ctx.status = 200;
};
exports.deletePage = async (ctx) => {
try {
var b = await Page.find(ctx.params.id);
await Page.deleteMany({"pages":{$in:b.pages}});
} catch (e) {
if(e.name === 'CastError') {
ctx.status = 400;
return;
}
}
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);
}
};
const http2 = require('http2');
var fs = require('fs');
const api = require('./api');
const Koa = require('koa');
const Router = require("koa-router");
const jwtMiddleware = require('./lib/jwtMiddleware');
require('dotenv').config();
const mongoose = require('mongoose');
const bodyParser = require('koa-bodyparser');
const port = process.env.PORT || 3000
//443
const app = new Koa();
const router = new Router()
const send = require('koa-send');
var options = {
key: fs.readFileSync('./server.key'),
cert: fs.readFileSync('./server.crt'),
allowHTTP1: true
};
//app.use(express.static('images'))
mongoose.Promise = global.Promise; // Node 의 네이티브 Promise 사용
// mongodb 연결
mongoose.connect(process.env.MONGO_URI).then(
(response) => {
console.log('Successfully connected to mongodb');
}
).catch(e => {
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());
*/
app
.use(jwtMiddleware)
.use(bodyParser()) // bodyParser는 라우터 코드보다 상단에 있어야 합니다.
.use(router.routes())
.use(router.allowedMethods());
/*
router.get('/', (ctx, next) => {
ctx.body = '루트 페이지 입니다.';
});
*/
/*
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.use(api.routes());
//app.use(router.routes()).use(router.allowedMethods())
router.use('/api', api.routes());
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);
//});
const checkLoggedIn = (ctx, next) => {
if (!ctx.state.user) {
//debug
console.log('checkLoggedin error');
ctx.status = 401;
return;
}
return next();
};
module.exports = checkLoggedIn;
\ No newline at end of file
const config = {
mailer: {
user: "yoobinpark@khu.ac.kr",
password: "1q2w3e4r!@",
expiresIn: 60 * 5,
},
};
module.exports = config;
\ No newline at end of file
const jwt = require("jsonwebtoken");
const User = require("../models/user");
/*function generateToken(payload) {
return new Promise((resolve, reject) => {
jwt.sign(
payload,
jwtSecret,
{
expiresIn: '7d' // 토큰 유효기간 7일 설정
}, (error, token) => {
if (error) reject(error);
resolve(token);
}
);
}
);
};
function decodeToken(token) {
return new Promise(
(resolve, reject) => {
jwt.verify(token, jwtSecret, (error, decoded) => {
if(error) reject(error);
resolve(decoded);
});
}
);
}
const jwtMiddleware = async (ctx, next) => {
const token = ctx.cookies.get("access_token");
if (!token) {
return next();} //token이 없음
try {
const decoded = await decodeToken(token); // 토큰을 디코딩 합니다
const user = await User.findById(decoded._id).exec();
ctx.state.user = {
_id: decoded._id,
email: decoded.email
};
//특정 시간 남았으면 재발급
const now = Math.floor(Date.now() / 1000);
if (decoded.exp - now < 60 * 60 * 24 * 3.5) {
const user = await User.findById(decoded._id);
const token = user.generateToken();
ctx.cookies.set("access_token", token, {
maxAge: 1000 * 60 * 60 * 24 * 7, // 7일
httpOnly: true
});
}
ctx.request.user = decoded;
return next();
} catch (e) {
//검증 실패
return next();
}
};
*/
const jwtMiddleware = async (ctx, next) => {
const token = ctx.cookies.get("access_token");
if (!token) {
return next();} //token이 없음
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decoded._id).exec();
ctx.state.user = {
_id: decoded._id,
email: decoded.email
};
//특정 시간 남았으면 재발급
const now = Math.floor(Date.now() / 1000);
if (decoded.exp - now < 60 * 60 * 24 * 3.5) {
const user = await User.findById(decoded._id);
const token = user.generateToken();
ctx.cookies.set("access_token", token, {
maxAge: 1000 * 60 * 60 * 24 * 7, // 7일
httpOnly: true,
});
}
return next();
} catch (e) {
//검증 실패
return next();
}
};
module.exports = jwtMiddleware;
\ No newline at end of file
const user = require('./user');
const page = require('./page');
const mongoose = require('mongoose');
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
title: {type:String, require:true}, // book title
author: [{type:String, require:true, default:user.user}],//작가복수 가능
contents: {type:String}, // book subtitle or detail
createDate: {type:Date, require:true, default:Date.now},
updateDate: {type:Date, default:Date.now},
views: {type: Number, default: 0},//how many people open this book
favoritenum:{type: Number, default: 0},
cover:{
data: {type: Buffer,default:null},
contentType: {type:String, default:null}
},
hashtag: [{type: String}],
});
bookSchema.statics.upload = async function ({title, author, contents, views, hashtag,cover}) {
const page = new this({
title: title,
author: author,
contents: contents,
views: views,
hashtag:hashtag,
});
await page.save(function(err){
if(err) return console.error(err);
});
return page;
};
bookSchema.statics.ListofPage = async function () {
var book = this;
var pages = await page.find({"_id": book.ObjectId});
return pages;
};
bookSchema.statics.findBySearchWord = async function (word) {
var book = this;
const reg = new RegExp(word, 'i');
var result = []
var books=await book.find();
await books.map(obj => {
// obj.hashtag.inclues
if (obj.title.match(reg)) { //제목에 검색어가 들어가는가
temp = new Object();
temp.url = obj.url;
temp.image = obj.image;
temp.title = obj.title;
temp.author = obj.author;
result.push(temp);
delete temp;
}
else if (obj.contents.match(reg))
{
temp = new Object();
temp.url = obj.url;
temp.image = obj.image;
temp.title = obj.title;
temp.author = obj.author;
result.push(temp);
delete temp;
}
else {
for (let i = 0; i < obj.hashtag.length; i++)
{
if (obj.hashtag[i].match(reg)) { //hashtag에 검색어가 들어가는가
temp = new Object();
temp.url = obj.url;
temp.image = obj.image;
temp.title = obj.title;
temp.author = obj.author;
result.push(temp);
delete temp;
break
}
}
}
})
return result
}
bookSchema.methods.updateB = async function (book) {
this.title = book.title;
this.author = book.author;
this.contents = book.contents;
this.author = book.author;
if(book.cover != ""){
this.cover = [];
//this.cover.push(book.cover);
}
this.save();
};
module.exports = mongoose.model("Book", bookSchema);
\ No newline at end of file
const user = require('./user');
const mongoose = require('mongoose');
const { Schema } = mongoose;
const PageSchema = new Schema({
id: mongoose.Schema.Types.ObjectId,//unique number of page
book:{type:String},//book contains several pages
title: {type:String, require:true}, // title of post
author: [{type:String, require:true, default:user.user}],
contents: {type:String}, // contents of page
createDate: {type:Date, require:true, default:Date.now},
updateDate: {type:Date, default:Date.now},
views: {type: Number, default: 0},//how many people open this page
cover:{
data: {type: Buffer,default:null},
contentType: {type:String, default:null}
},
hashtag: [{type: String}],
comment: {
writer: {type: String},
contents: {type:String}, //comment text
createDate: {type:Date, require:true, default:Date.now},
updateDate: {type:Date, default:Date.now},
},
});
PageSchema.statics.updateP = async function ({title, author, contents, hashtag,book,cover}) {
const page = new this({
title: title,
book: book,//book으로 들어와서 생성한 경우, 그 book의 id를 넘겨주기
author: author,
contents: contents,
hashtag:hashtag,
cover:cover
});
await page.save(function(err){
if(err) return console.error(err);
});
return page;
};
// parameters: search word
PageSchema.statics.findBySearchWord = async function (word) {
var page = this;
const reg = new RegExp(word, 'i');
var result = []
var pages = await page.find();
console.log(petType)
await pages.map(obj => {
// obj.hashtag.inclues
if (obj.title.match(reg)) { //제목에 검색어가 들어가는가
temp = new Object();
temp.url = obj.url;
temp.cover = obj.cover;
temp.title = obj.title;
temp.author = obj.author;
result.push(temp);
delete temp;
}
else {
for (let i = 0; i < obj.hashtag.length; i++) {
if (obj.hashtag[i].match(reg)) { //hashtag에 검색어가 들어가는가
temp = new Object();
temp.url = obj.url;
temp.cover = obj.cover;
temp.title = obj.title;
temp.author = obj.author;
result.push(temp);
delete temp;
break
}
}
}
})
return result
}
// parameters: user's favorites page list
PageSchema.statics.favoriteRecipe = async function (pageUrlArr) {
var pgList = []
for(let i=0; i<pageUrlArr.length; i++) {
const page = await this.findOne({ url: pageUrlArr[i] }).exec();
temp = new Object();
temp.url = page.url;
temp.title = page.title;
temp.cover = page.cover;
pgList.push(temp);
delete temp;
}
return pgList;
}
module.exports = mongoose.model("Page", PageSchema);
\ No newline at end of file
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const crypto = require('crypto');
//const Pet = require("./pet");
const UserSchema = new Schema({
//login require
//email == id
email: { type: String, required: true, unique: true },
password: String,
token: String,
//user info
username: String,
phone: {type: String, require: true},
nickname: {type: String, default: ""},
books: [{type: String}],//array of bookid
favorite: [{ type: String }],//String of url(book, page)
});
function hash(password) {
return crypto.createHmac('sha256', process.env.SECRET_KEY).update(password).digest('hex');
}
UserSchema.statics.localRegister = function ({ nickname,phone, email, password }) {
const user = new this({
phone,
email,
password: hash(password),
nickname
});
return user.save();
};
//User 모델에 정보를 save하기 전에 실행
/*
UserSchema.pre('save', function( next ){
var user = this;
//비밀번호를 바꿀때만 비밀번호를 암호화해준다
if (user.isModified('password')) {
// 비밀번호를 암호화 시킨다
bcrypt.hash(user.password, 10, function (err, hash) { //hash: 암호화된 비밀번호
if (err) return next(err);
user.password = hash();
next();
});
} else {
next();
}
});
*/
// parameters: login user email, new password to change
UserSchema.statics.updatePassword = async function (email, password) {
const hash = await hash(password);
this.findOneAndUpdate({email: email} , {$set: {password: hash}}, function(err, user) {
if(err) throw err;
console.log(user)
})
console.log("hash", hash);
};
UserSchema.methods.generateToken = function () {
const token = jwt.sign(
// 첫번째 파라미터엔 토큰 안에 집어넣고 싶은 데이터를 넣습니다
{
_id: this.id,
email: this.email,
},
process.env.JWT_SECRET, // 두번째 파라미터에는 JWT 암호를 넣습니다
{
expiresIn: "7d", // 7일동안 유효함
}
);
return token;
};
UserSchema.statics.updateFcm = async function (email, fcm){
this.findOneAndUpdate({email: email}, {$set: {fcmToken: fcm}}, function(err,user){
if(err) throw err;
//console.log(user);
})
};
//응답하는 JSON에서 비밀번호 정보 삭제
UserSchema.methods.serialize = async function () {
const data = this.toJSON();
delete data.password;
delete data._id;
return data;
};
UserSchema.methods.checkPassword = async function (password) {
const hashed = hash(password);
return this.password === hashed;
};
//static method
UserSchema.statics.findByEmail = async function (email) {
return this.findOne({ email: email, logintype: "local" });
};
// parameters: user information to be updated
UserSchema.statics.updateUser = async function (user) {
this.findOneAndUpdate({ email: user.email }, { $set: user },
function (err, result) {
if (err) throw err;
return result;
});
};
// parameters: book's object id
UserSchema.methods.addBook = async function (bookId) {
console.log(bookId);
this.books.push(bookId);
this.save();
}
//parameters: login user email, pet's object id
UserSchema.statics.delBook = async function (email, bookId) {
return this.findOneAndUpdate({email: email}, {$pull: {books: bookId}});
}
// parameters: login user email, url of the book or page
UserSchema.statics.updateFavorite = async function (email, contentsID) {
return this.findOneAndUpdate(
{
email: email,
},
{ $addToSet: { favorite: contentsID } }
);
};
// parameters: login user email, url of the book or page
UserSchema.statics.delFavorites = async function (email, contentsID) {
return this.findOneAndUpdate(
{
email: email,
},
{ $pull: { favorite: contentsID } }
);
};
UserSchema.statics.showFavorites = async function (email) {
this.books
return (
{
email: email,
},
{ $pull: { favorite: contentsID } }
);
};
module.exports = mongoose.model("User", UserSchema, "Users");
\ No newline at end of file